Skip to content

Commit d7fdfa0

Browse files
committed
Make it serious
1 parent 27ca032 commit d7fdfa0

46 files changed

Lines changed: 2553 additions & 629 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ docs/src/mtt_README.md
188188
# Sphinx architecture docs
189189
docs/src/architectures/generated/*
190190
docs/src/architectures/default_hypers/*
191+
# Sphinx hooks docs
192+
docs/src/hooks/generated/*
193+
docs/src/hooks/default_hypers/*
191194

192195
# JavaScript
193196
node_modules/

docs/src/concepts/hooks.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.. _hooks:
2+
3+
Using hooks
4+
===========
5+
6+
Hooks are a powerful way to extend the functionality of architectures in ``metatrain``.

docs/src/concepts/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ such as output naming, auxiliary outputs, and wrapper models.
1212
output-naming
1313
fine-tuning
1414
loss-functions
15+
hooks
1516
scale-targets
1617
auxiliary-outputs
1718
batch-bounds

docs/src/conf.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
sys.path.append(os.path.join(ROOT, "docs"))
3030
from generate_examples.conf import sphinx_gallery_conf # noqa
3131
from src.architectures.generate import setup_architectures_docs # noqa
32+
from docs.src.hooks.generate_hooks_docs import setup_hooks_docs # noqa
3233

3334

3435
# -- Project information -----------------------------------------------------
@@ -89,6 +90,7 @@ def generate_examples():
8990
def setup(app):
9091
copy_readme()
9192
generate_examples()
93+
setup_hooks_docs()
9294
setup_architectures_docs()
9395

9496

@@ -119,6 +121,7 @@ def setup(app):
119121
"sg_execution_times.rst",
120122
"architectures/templates/*",
121123
"architectures/README.md",
124+
"hooks/templates/*",
122125
]
123126

124127

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import ast
2+
from pathlib import Path
3+
from typing import TypedDict
4+
5+
from jinja2 import Environment, FileSystemLoader
6+
7+
from metatrain.utils import hooks as hooks_module
8+
from metatrain.utils.hooks.helpers import (
9+
find_all_hooks,
10+
get_hypers_class,
11+
preload_documentation_module,
12+
write_hypers_yaml,
13+
)
14+
from metatrain.utils.hypers import get_hypers_list
15+
16+
17+
HOOKS_DIR = Path(__file__).parent
18+
TEMPLATES_DIR = HOOKS_DIR / "templates"
19+
DEFAULT_HYPERS_DIR = HOOKS_DIR / "default_hypers"
20+
GENERATED_DIR = HOOKS_DIR / "generated"
21+
22+
23+
JINJA_ENV = Environment(
24+
loader=FileSystemLoader(TEMPLATES_DIR),
25+
trim_blocks=True,
26+
lstrip_blocks=True,
27+
)
28+
29+
30+
SECTIONS = [
31+
"installation",
32+
"hook_hypers",
33+
"references",
34+
]
35+
36+
37+
class HookDocVariables(TypedDict):
38+
"""Variables to use inside the hook documentation.
39+
40+
The docstring of the hook will be processed as a
41+
``jinja`` template. You can find documentation about them
42+
`here <https://jinja.palletsprojects.com/en/stable/templates>`_ , but
43+
the simplest functionality consists of using variables enclosed in
44+
double curly braces ``{{variable_name}}``, which will be replaced by
45+
their corresponding value.
46+
47+
For example, a file with the following content:
48+
49+
.. code-block:: rst
50+
51+
This is the documentation for {{hook}}.
52+
53+
generates a documentation file that for the hook ``tensor_basis`` would be:
54+
55+
.. code-block:: rst
56+
57+
This is the documentation for tensor_basis.
58+
59+
There are some special variables that start with ``SECTION_``. These contain
60+
the content of different sections of the documentation, and they will be
61+
appended to the docstring if they are not already present. For example, given
62+
the docstring:
63+
64+
.. code-block:: python
65+
66+
\"""
67+
My hook
68+
=======
69+
70+
This is my hook.
71+
72+
{{SECTION_DEFAULT_HYPERS}}
73+
74+
Some important section
75+
======================
76+
77+
Explain something important here.
78+
\"""
79+
80+
The final documentation will append to the docstring all the sections except
81+
``SECTION_DEFAULT_HYPERS``, since it is already present.
82+
83+
Following you can find a description of all the available variables. The
84+
sections are appended in the order documented here.
85+
"""
86+
87+
SECTION_INSTALLATION: str
88+
"""Section containing installation instructions for this hook."""
89+
SECTION_HOOK_HYPERS: str
90+
"""Section containing the description of the hook hyperparameters for
91+
this hook."""
92+
SECTION_REFERENCES: str
93+
"""Section containing references for this hook. It will render the
94+
references that have been used as ``:footcite:p:`` during the hook
95+
documentation."""
96+
97+
hook: str
98+
"""The name of the hook.
99+
100+
This excludes any 'experimental.' or 'deprecated.' prefix."""
101+
default_hypers_path: str
102+
"""Path to the yaml file with the default hyperparameters for this
103+
hook.
104+
105+
This is a path relative to the ``docs/src/hooks/generated``
106+
directory.
107+
"""
108+
hook_hypers_path: str
109+
"""The full python import path to the hook's hypers class of this
110+
hook.
111+
112+
E.g.: ``"metatrain.utils.hooks.<hook_name>.Hypers"``
113+
"""
114+
hook_hypers: list[str]
115+
"""List of hyperparameter names for this hook."""
116+
117+
118+
def setup_hooks_docs():
119+
"""Generate the hook documentation files.
120+
121+
This function goes through all available hooks, and for each of them
122+
generates a yaml file with the default hyperparameters (so that it can be
123+
easily included in the documentation) and their rst documentation file.
124+
125+
See :ref:`newarchitecture-documentation-page` for more information.
126+
"""
127+
# If the default_hypers directory does not exist, create it
128+
DEFAULT_HYPERS_DIR.mkdir(exist_ok=True)
129+
# Same for the generated directory
130+
GENERATED_DIR.mkdir(exist_ok=True)
131+
132+
for name in find_all_hooks():
133+
# Load documentation module in an isolated way to avoid
134+
# requiring dependencies for every architecture.
135+
preload_documentation_module(name)
136+
137+
# Write default hypers file
138+
yaml_path = DEFAULT_HYPERS_DIR / f"{name}-default-hypers.yaml"
139+
write_hypers_yaml(name, yaml_path, include_name=True)
140+
141+
generate_rst(name, yaml_path=yaml_path)
142+
143+
144+
def generate_rst(
145+
hook_name: str,
146+
yaml_path: Path,
147+
):
148+
"""Generate the rst documentation file for a given hook.
149+
150+
:param hook_name: The name of the hook to generate the
151+
documentation for.
152+
:param yaml_path: Path to the yaml file with the default hyperparameters
153+
for this architecture.
154+
"""
155+
156+
# Get the full python import path to the hook
157+
hook_path = f"metatrain.utils.hooks.{hook_name}"
158+
159+
# Get the docstring from the documentation.py file
160+
doc_file = Path(hooks_module.__file__).parent / hook_name / "documentation.py"
161+
with open(doc_file, "r") as f:
162+
module = ast.parse(f.read(), filename=str(doc_file))
163+
docstring = ast.get_docstring(module)
164+
if docstring is None:
165+
raise ValueError(
166+
f"The documentation.py file for hook "
167+
f"'{hook_name}' does not have a module docstring."
168+
)
169+
170+
hypers_class = get_hypers_class(hook_name)
171+
172+
# Prepare template variables
173+
template_variables = dict(
174+
hook=hook_name,
175+
default_hypers_path=".." / yaml_path.relative_to(HOOKS_DIR),
176+
hook_hypers_path=f"{hook_path}.documentation.Hypers",
177+
hook_hypers=get_hypers_list(hypers_class),
178+
)
179+
180+
# Read section templates and render them
181+
for section in SECTIONS:
182+
template = JINJA_ENV.get_template(f"{section}.rst")
183+
template_variables[f"SECTION_{section.upper()}"] = template.render(
184+
**template_variables
185+
)
186+
187+
# Check for missing sections and add them to the end of the docstring
188+
for section in SECTIONS:
189+
section_var = "{{SECTION_" + section.upper() + "}}"
190+
if section_var not in docstring:
191+
docstring += f"\n\n{section_var}"
192+
193+
# Render docstring template
194+
docstring = JINJA_ENV.from_string(docstring).render(**template_variables)
195+
196+
# Write to file
197+
with open(GENERATED_DIR / f"{hook_name}.rst", "w") as f:
198+
f.write(docstring + "\n")

docs/src/hooks/index.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.. _available-hooks:
2+
3+
Available Hooks
4+
===============
5+
6+
This is a list of all hooks available in ``metatrain``.
7+
The concept of hooks is explained in :ref:`hooks`.
8+
9+
.. toctree::
10+
:maxdepth: 1
11+
:glob:
12+
13+
./generated/*
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{{hook}}
2+
==============
3+
4+
This page gives an overview of the ``{{hook}}`` hook available in
5+
the ``metatrain`` package.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.. _hook-{{hook}}_hypers:
2+
3+
Hook hyperparameters
4+
------------------------
5+
6+
{% if hook_hypers %}
7+
The default hyperparameters for this hook are:
8+
9+
.. literalinclude:: {{default_hypers_path}}
10+
:language: yaml
11+
12+
and here is the documentation for each hyperparameter:
13+
14+
.. container:: mtt-hypers-remove-classname
15+
16+
..
17+
18+
{% for hyper in hook_hypers %}
19+
.. autoattribute:: {{hook_hypers_path}}.{{hyper}}
20+
21+
{% endfor %}
22+
{% else %}
23+
This hook has no hyperparameters.
24+
{% endif %}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.. _hook-{{hook}}_installation:
2+
3+
Installation
4+
------------
5+
6+
To install this hook along with the ``metatrain`` package, run:
7+
8+
.. code-block:: bash
9+
10+
pip install metatrain[hook-{{hook}}]
11+
12+
where the square brackets indicate that you want to install the optional
13+
dependencies required for the ``{{hook}}`` hook.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.. _hook-{{hook}}_references:
2+
3+
References
4+
----------
5+
6+
.. footbibliography::

0 commit comments

Comments
 (0)