Skip to content

Commit 5ab4a2c

Browse files
committed
feat(docs): add an autoregistry to discover the get_ utils functions more easily.
1 parent 4dc1a2d commit 5ab4a2c

File tree

9 files changed

+193
-14
lines changed

9 files changed

+193
-14
lines changed

docs/_templates/autoregistry.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
.. tip::
3+
4+
This module has a `registry` builtin.
5+
6+
You can get easy access to the functions below by calling ``get_{{registry_key}}(<key>)`` or with ``get_{{registry_key}}(<key>, *args, **kwargs)``. Here are the function available from the registry:
7+
8+
.. list-table::
9+
:header-rows: 1
10+
:widths: 20 80
11+
12+
* - Key
13+
- Function
14+
{% for item in items %}
15+
* - ``"{{item.name}}"``
16+
- :py:obj:`{{item.truename}} <{{ item.path }}>` `{{item.sig}}`
17+
{% endfor %}

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"sphinxcontrib.video",
4545
"sphinx_gallery.gen_gallery",
4646
"sphinx_add_colab_link",
47+
"sphinx_autoregistry",
4748
]
4849

4950
# Add any paths that contain templates here, relative to this directory.

docs/getting_started.rst

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,64 @@ Getting Started
44
Installing MRI-NUFFT
55
--------------------
66

7-
mri-nufft is available on PyPi
7+
mri-nufft is available on `PyPi <https://pypi.org/project/mri-nufft/>`_
8+
9+
10+
.. tip::
11+
12+
TLDR: If you have a GPU and CUDA>=12.0, you probably want to install MRI-NUFFT like so:
13+
``pip install mri-nufft[cufinufft]`` or ``pip install mri-nufft[gpunufft]``
14+
For CPU only setup we recommend ``pip install mri-nufft[finufft]``
15+
16+
Then, use the ``get_operator(backend=<your backend>, ... )`` to initialize your MRI-NUFFT operator.
17+
18+
For more information , check the :ref:`general_examples`
19+
820

921
.. code-block:: sh
1022
1123
pip install mri-nufft
1224
25+
26+
However, if you want to use some specific backends or develop on mri-nufft, you can install it with extra dependencies. notably `extra`, `io`, and `autodiff`
27+
28+
.. code-block:: sh
29+
30+
pip install mri-nufft[extra,io,autodiff]
31+
32+
33+
Using ``uv``
34+
~~~~~~~~~~~~
35+
If you are using ``uv`` as your package installer you will need to do ::
36+
.. code-block:: sh
37+
38+
uv pip install mri-nufft[extra,io,autodiff] --no-build-isolation
39+
40+
1341
Development Version
1442
~~~~~~~~~~~~~~~~~~~
1543

16-
If you want to modifiy the mri-nufft code base
44+
If you want to modify the mri-nufft code base
45+
46+
.. code-block:: sh
47+
48+
git clone https://github.com:mind-inria/mri-nufft
49+
pip install -e ./mri-nufft[dev,doc,extra,io,autodiff,tests,cufinufft,gpunufft,finufft]
50+
51+
or using ``uv``
1752

1853
.. code-block:: sh
1954
2055
git clone https://github.com:mind-inria/mri-nufft
21-
pip install -e ./mri-nufft[dev]
56+
uv venv
57+
uv sync --all-extras --no-build-isolation --no-extra <backend-you-don't-need>
2258
2359
60+
2461
Choosing a NUFFT Backend
2562
========================
2663
27-
In order to perform Non-Uniform fast Fourier transform you need to install a specific :ref:`NUFFT` computation library backend.
64+
In order to perform Non-Uniform fast Fourier transform you need to install a specific :ref:``NUFFT` computation library backend.
2865
2966
.. tip::
3067
@@ -48,8 +85,8 @@ These libraries need to be installed separately from this package.
4885
Backend Hardward Batch computation Precision Array Interface
4986
==================== ============ =================== =============== =================
5087
cufinufft_ GPU (CUDA) ✔ single cupy/torch/numpy
51-
finufft_ CPU ✔ single/double numpy
52-
gpunufft_ GPU ✔ single/double numpy
88+
finufft_ CPU ✔ single/double numpy/torch
89+
gpunufft_ GPU ✔ single/double numpy/torch/cupy
5390
tensorflow-nufft_ GPU (CUDA) ✘ single tensorflow
5491
pynufft-cpu_ CPU ✘ single/double numpy
5592
pynfft_ CPU ✘ single/double numpy
@@ -97,18 +134,24 @@ gpuNUFFT
97134

98135
an active gpuNUFFT fork is maintained by `chaithyagr <https://github.com/chaithyagr/gpunufft/>`_.
99136

100-
.. warning::
101-
102-
This is compatible only up to CUDA 11.8 !
103137

104-
To install it use `pip install gpuNUFFT` or for local development.
138+
To install it use `pip install gpuNUFFT` or for local development, use the following:
105139

106140
.. code-block:: sh
107141
108142
git clone https://github.com/chaythiagr/gpuNUFFT
109143
cd gpuNUFFT
110144
python setup.py install
111145
146+
.. warning::
147+
148+
If you are using ``uv`` as your package installer you will need to do ::
149+
150+
.. code-block:: sh
151+
152+
uv pip install wheel pip pybind11
153+
uv pip install mri-nufft[gpunufft] --no-build-isolation
154+
112155
BART
113156
~~~~
114157

docs/sphinx_autoregistry.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/env python
2+
3+
import inspect
4+
from docutils import nodes
5+
from sphinx.util import logging
6+
from sphinx.util.docutils import SphinxDirective # <--- New Base Class
7+
8+
logger = logging.getLogger(__name__)
9+
10+
from mrinufft._utils import MethodRegister
11+
12+
import inspect
13+
import re
14+
15+
16+
def get_signature(func):
17+
"""Safely extracts a clean function signature, without type annotations."""
18+
sig = str(inspect.signature(func))
19+
sig = sig.split("->")[0].strip()
20+
# iterative removal of bracketed expressions:
21+
while "[" in sig:
22+
sig = re.sub(r"\[[^\[\]]*\]", "", sig)
23+
sig = re.sub(r"\[.*?\]", "", sig) # remove complex type annotation with brackets
24+
sig = re.sub(r":\s*[^,=\)]+", " ", sig) # remove type annotations
25+
sig = re.sub(r"\s{2,}", " ", sig) # collapse multiple spaces
26+
sig = re.sub(r"\s,", ",", sig) # collapse multiple spaces
27+
sig = re.sub(r"\s=\s", "=", sig) # collapse multiple spaces
28+
return sig
29+
30+
31+
class AutoregistryDirective(SphinxDirective): # <--- Inherit from SphinxDirective
32+
"""Directive to list all entries in a specified sub-registry key."""
33+
34+
required_arguments = 1
35+
has_content = False
36+
37+
# We now have access to self.env, self.app, and self.parse_text_to_nodes
38+
39+
def run(self):
40+
registry_key = self.arguments[0]
41+
42+
try:
43+
# 1. Build rendering context
44+
registry_dict = MethodRegister.registry[registry_key]
45+
items_context = [
46+
{
47+
"name": name,
48+
"truename": (
49+
func.__name__ if hasattr(func, "__name__") else str(func)
50+
),
51+
"path": (
52+
(func.__module__ + "." + func.__name__)
53+
if hasattr(func, "__module__")
54+
else str(func)
55+
),
56+
"sig": get_signature(func),
57+
# ... (rest of your context building logic) ...
58+
}
59+
for name, func in registry_dict.items()
60+
]
61+
62+
context = {
63+
"registry_key": registry_key,
64+
"items": items_context,
65+
}
66+
67+
# 2. Render template to RST string
68+
# self.app is available because we inherit from SphinxDirective
69+
rst_content = self.env.app.builder.templates.render(
70+
"autoregistry.rst", context
71+
)
72+
73+
# 3. THE FIX: Use the built-in utility
74+
# self.parse_text_to_nodes is a simple wrapper for nested_parse_to_nodes
75+
# that correctly passes the required RSTState (self.state).
76+
result_nodes = self.parse_text_to_nodes(rst_content)
77+
78+
# The nodes are now fully parsed and contain pending_xref nodes
79+
# which Sphinx will automatically resolve later in the build process.
80+
# No manual env.resolve_references call is needed!
81+
return result_nodes
82+
83+
except Exception as e:
84+
error_message = (
85+
f"Error resolving autoregistry for key '{registry_key}': {e}"
86+
)
87+
logger.error(error_message)
88+
return [nodes.literal_block(error_message, error_message)]
89+
90+
91+
# Delete resolve_autoregistry function
92+
def setup(app):
93+
"""Main Sphinx extension entry point."""
94+
app.add_directive("autoregistry", AutoregistryDirective)
95+
96+
return {
97+
"version": "0.4",
98+
"parallel_read_safe": True,
99+
"parallel_write_safe": True,
100+
}

src/mrinufft/_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ def decorator(func):
145145
return decorator
146146

147147
def make_getter(self) -> Callable:
148+
"""Create a `get_{register_name}` function to get methods from the registry."""
149+
148150
def getter(method_name, *args, **kwargs):
149151
try:
150152
method = self.registry[self.register_name][method_name]

src/mrinufft/density/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
"""Density compensation methods."""
1+
"""Density compensation methods.
2+
3+
.. autoregistry:: density
4+
"""
25

36
from .geometry_based import voronoi, voronoi_unique, cell_count
47
from .nufft_based import pipe
58
from .utils import get_density
69

710

811
__all__ = [
12+
"register_density",
913
"voronoi",
1014
"voronoi_unique",
1115
"pipe",

src/mrinufft/extras/field_map.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
This module provides methods to generate dummy B0map as well as estimation of the
44
bilinearization of the off-resonance model (See :ref:`nufft-orc` for a detailed
55
explanation).
6+
7+
8+
9+
.. autoregistry:: orc_factorization
10+
611
"""
712

813
import numpy as np

src/mrinufft/extras/optim.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
"""Implements the LSQR algorithm."""
1+
"""Implements Optimization algorithms.
2+
3+
.. autoregistry :: optimizer
4+
"""
25

36
from collections.abc import Callable
47
import numpy as np
@@ -42,7 +45,7 @@
4245
)
4346

4447

45-
register_optim = MethodRegister("optim", _optim_docs)
48+
register_optim = MethodRegister("optimizer", _optim_docs)
4649
get_optimizer = register_optim.make_getter()
4750

4851

src/mrinufft/extras/smaps.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
"""SMaps module for sensitivity maps estimation."""
1+
"""Smaps module for sensitivity maps estimation.
2+
3+
.. autoregistry:: smaps
4+
5+
"""
26

37
from __future__ import annotations
48

0 commit comments

Comments
 (0)