diff --git a/docs/_extend_docstrings.py b/docs/_extend_docstrings.py index 6a7bd4327..c1527b070 100644 --- a/docs/_extend_docstrings.py +++ b/docs/_extend_docstrings.py @@ -300,13 +300,7 @@ def extend_FormFactor() -> None: s, m_a, m_b, L, d = sp.symbols("s m_a m_b L d") form_factor = FormFactor(s, m_a, m_b, angular_momentum=L, meson_radius=d) - _append_to_docstring( - FormFactor, - f""" - .. math:: {sp.latex(form_factor)} - :label: FormFactor - """, - ) + _append_latex_doit_definition(form_factor) def extend_Kallen() -> None: @@ -726,8 +720,10 @@ def _create_latex_doit_definition(expr: sp.Expr, deep: bool = False) -> str: def _append_to_docstring(class_type: Callable | type, appended_text: str) -> None: - assert class_type.__doc__ is not None - class_type.__doc__ += appended_text + if class_type.__doc__ is None: + class_type.__doc__ = appended_text + else: + class_type.__doc__ += appended_text def __generate_transitions_cached( diff --git a/docs/conf.py b/docs/conf.py index 36bfc41bc..a86580f52 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,7 +1,10 @@ from __future__ import annotations +import importlib +import inspect import os import sys +from dataclasses import is_dataclass from sphinx_api_relink.helpers import ( get_branch_name, @@ -12,9 +15,51 @@ set_intersphinx_version_remapping, ) +from ampform.sympy._decorator import get_sympy_fields # noqa: PLC2701 + sys.path.insert(0, os.path.abspath(".")) from _extend_docstrings import extend_docstrings # noqa: PLC2701 + +def _get_excluded_members() -> list[str]: + default_exclusions = { + "as_explicit", + "default_assumptions", + "doit", + "evaluate", + "is_commutative", + "is_extended_real", + "items", + "keys", + "precedence", + "values", + } + for cls in [ + *_get_dataclasses_recursive("ampform"), + ]: + fields = get_sympy_fields(cls) + arg_names = {f.name for f in fields} + default_exclusions.update(arg_names) + return sorted(default_exclusions) + + +def _get_dataclasses_recursive(module_name: str) -> list[type]: + module = importlib.import_module(module_name) + dataclass_list = _get_dataclasses(module) + for _, submodule in inspect.getmembers(module, inspect.ismodule): + if submodule.__name__.startswith(module_name): + dataclass_list.extend(_get_dataclasses_recursive(submodule.__name__)) + return dataclass_list + + +def _get_dataclasses(module): + dataclass_list = [] + for _, obj in inspect.getmembers(module): + if inspect.isclass(obj) and is_dataclass(obj): + dataclass_list.append(obj) + return dataclass_list + + extend_docstrings() set_intersphinx_version_remapping({ "ipython": { @@ -85,18 +130,7 @@ } author = "Common Partial Wave Analysis" autodoc_default_options = { - "exclude-members": ", ".join([ - "as_explicit", - "default_assumptions", - "doit", - "evaluate", - "is_commutative", - "is_extended_real", - "items", - "keys", - "precedence", - "values", - ]), + "exclude-members": ", ".join(_get_excluded_members()), "members": True, "undoc-members": True, "show-inheritance": True, diff --git a/src/ampform/sympy/_decorator.py b/src/ampform/sympy/_decorator.py index 557e8e80f..c7c417d6e 100644 --- a/src/ampform/sympy/_decorator.py +++ b/src/ampform/sympy/_decorator.py @@ -251,12 +251,11 @@ def _implement_new_method(cls: type[ExprClass]) -> type[ExprClass]: frozen=False, )(cls) cls = _update_field_metadata(cls) - sympy_fields = _get_sympy_fields(cls) non_sympy_fields = tuple(f for f in _get_fields(cls) if not _is_sympify(f)) # type: ignore[arg-type] cls.__slots__ = tuple(f.name for f in non_sympy_fields) # type: ignore[arg-type] @functools.wraps(cls.__new__) - @_insert_args_in_signature([f.name for f in sympy_fields], idx=1) + @_insert_args_in_signature([f.name for f in _get_fields(cls)], idx=1) # type:ignore[arg-type] def new_method(cls, *args, evaluate: bool = False, **kwargs) -> type[ExprClass]: fields_with_values, hints = _extract_field_values(cls, *args, **kwargs) fields_with_sympified_values = { @@ -548,7 +547,7 @@ def _xreplace_method(self, rule) -> tuple[sp.Expr, bool]: return self, False -def _get_sympy_fields(cls) -> tuple: +def get_sympy_fields(cls) -> tuple[Field, ...]: return tuple(f for f in _get_fields(cls) if _is_sympify(f))