Source code for autodoc2.sphinx.utils

"""Handle sphinx logging."""
from __future__ import annotations

import typing as t

from docutils.nodes import Element
from docutils.statemachine import StringList
from sphinx.application import Sphinx
from sphinx.environment import BuildEnvironment
from sphinx.util import logging

from autodoc2.config import CONFIG_PREFIX, Config, ValidationError
from autodoc2.db import Database, InMemoryDb
from autodoc2.resolve_all import AllResolver
from autodoc2.utils import WarningSubtypes

if t.TYPE_CHECKING:
    from docutils.parsers.rst.states import RSTStateMachine

LOGGER = logging.getLogger("autodoc2")


[docs]def load_config( app: Sphinx, *, overrides: None | dict[str, t.Any] = None, location: None | Element = None, ) -> Config: """Load the configuration.""" values: dict[str, t.Any] = {} overrides = overrides or {} config_fields = {name: field for name, _, field in Config().as_triple()} # check if keys in overrides are valid difference = set(overrides.keys()) - set(config_fields.keys()) if difference: warn_sphinx( f"Unknown configuration keys: {', '.join(difference)}", WarningSubtypes.CONFIG_ERROR, location, ) for name, field in config_fields.items(): sphinx_name = f"{CONFIG_PREFIX}{name}" value = overrides.get(name, app.config[sphinx_name]) if "sphinx_validate" in field.metadata: try: value = field.metadata["sphinx_validate"](sphinx_name, value) except ValidationError as err: warn_sphinx(str(err), WarningSubtypes.CONFIG_ERROR, location) continue values[name] = value return Config(**values)
[docs]def warn_sphinx( msg: str, subtype: WarningSubtypes, location: None | Element = None ) -> None: """Log a warning in Sphinx.""" LOGGER.warning( f"{msg} [autodoc2.{subtype.value}]", type="autodoc2", subtype=subtype.value, location=location, )
[docs]def get_database(env: BuildEnvironment) -> Database: """Get the database from the environment.""" # We store it persistently in the environment so that it can be # accessed by directives and other extensions. if not hasattr(env, "autodoc2_db"): env.autodoc2_db = InMemoryDb() # type: ignore return env.autodoc2_db # type: ignore
[docs]def _warn(msg: str) -> None: warn_sphinx(msg, WarningSubtypes.ALL_RESOLUTION)
[docs]def get_all_analyser(env: BuildEnvironment) -> AllResolver: """Get the all analyser from the environment.""" # We store it persistently in the environment so that it can be # accessed by directives and other extensions. if not hasattr(env, "autodoc2_all_analyser"): env.autodoc2_all_analyser = AllResolver(get_database(env), _warn) # type: ignore return env.autodoc2_all_analyser # type: ignore
[docs]def nested_parse_generated( state: RSTStateMachine, content: list[str], source: str, line: int, *, match_titles: bool = False, base: Element | None = None, ) -> Element: """This function, nested parses generated content in a directive. All reported warnings are redirected to a specific source document and line. This is useful for directives that want to parse generated content. """ base = Element() if base is None else base base.source = source base.line = line string_list = StringList( content, items=[(source, line - 1) for _ in content], ) line_func = getattr(state.reporter, "get_source_and_line", None) state.reporter.get_source_and_line = lambda li: ( source, line, ) try: state.nested_parse(string_list, 0, base, match_titles=match_titles) finally: if line_func is not None: state.reporter.get_source_and_line = line_func else: del state.reporter.get_source_and_line return base