Source code for esrfpath_autodoc

import pathlib
from typing import Any

from sphinx.util import logging

import esrf_pathlib
from esrf_pathlib._schemas.definitions import load

logger = logging.getLogger(__name__)


def make_schema_stub_class(schema) -> type:
    """
    Dynamically create a stub class for a given ESRFPath schema.
    Attributes correspond to concepts, derived concepts, and templates.
    """
    stub_attrs = {}

    for cname, concept in schema.concepts.items():
        stub_attrs[cname] = make_property(concept.annotation(), concept.docstring)

    for dname, derived in schema.derived_concepts.items():
        stub_attrs[dname] = make_property(concept.annotation(), derived.docstring)

    for tname, template in schema.templates.items():
        stub_attrs[tname] = make_property(concept.annotation(), template.docstring)

    docstring = f"""{schema.docstring}

Derive a class from :class:`ESRFPath` to restrict path matching, parsing and rendering to this schema:

.. code-block:: python

    from esrf_pathlib import ESRFPath

    class {schema.identifier.name.capitalize()}Path(ESRFPath, {schema.identifier.name}={schema.identifier.version}, fallback_depth=0):
        pass
"""

    stub_attrs["__doc__"] = docstring

    class_name = f"ESRFPath_{schema.identifier}"

    return type(class_name, (pathlib.Path,), stub_attrs)


def make_property(annotation: Any, doc: str):
    def prop(self):
        pass

    prop.__annotations__ = {"return": annotation}
    prop.__doc__ = doc
    return property(prop)


def setup(app):
    for sname, sversions in load._ALL_VERSIONS.items():
        for sversion in sversions:
            schema = load.get_schema(sname, sversion)
            stub_cls = make_schema_stub_class(schema)
            setattr(esrf_pathlib, stub_cls.__name__, stub_cls)
            logger.info(
                f"Created stub class esrf_pathlib.{stub_cls.__name__} for schema '{schema.identifier}'"
            )

    # Add config for the new module path if needed
    app.add_css_file("custom.css")

    # No directives or roles to add here, just generating classes
    return {
        "version": "0.1",
        "parallel_read_safe": True,
        "parallel_write_safe": True,
    }