diff --git a/sphinx_autosummary_accessors/__init__.py b/sphinx_autosummary_accessors/__init__.py index c7aeab6..af46b60 100644 --- a/sphinx_autosummary_accessors/__init__.py +++ b/sphinx_autosummary_accessors/__init__.py @@ -5,7 +5,7 @@ import pathlib -import packaging.version +import packaging import sphinx from .documenters import ( @@ -15,12 +15,6 @@ AccessorMethodDocumenter, ) -if packaging.version.parse(sphinx.__version__) >= packaging.version.parse("3.1"): - from .autosummary import CustomAutosummary -else: - CustomAutosummary = None - - try: __version__ = version("sphinx-autosummary-accessors") except Exception: @@ -29,6 +23,12 @@ templates_path = str(pathlib.Path(__file__).parent / "templates") +def add_autosummary_get_documenter(func): + import sphinx.ext.autosummary + + sphinx.ext.autosummary.Autosummary.create_documenter = func + + def setup(app): app.setup_extension("sphinx.ext.autosummary") @@ -37,5 +37,7 @@ def setup(app): app.add_autodocumenter(AccessorMethodDocumenter) app.add_autodocumenter(AccessorCallableDocumenter) - if CustomAutosummary is not None: - app.add_directive("autosummary", CustomAutosummary, override=True) + if packaging.version.parse(sphinx.__version__) >= packaging.version.parse("3.2.0"): + from .autosummary import create_documenter_from_template + + add_autosummary_get_documenter(create_documenter_from_template) diff --git a/sphinx_autosummary_accessors/autosummary.py b/sphinx_autosummary_accessors/autosummary.py index 2a6f1c8..9f1f650 100644 --- a/sphinx_autosummary_accessors/autosummary.py +++ b/sphinx_autosummary_accessors/autosummary.py @@ -1,7 +1,10 @@ import re -from sphinx.ext import autosummary -from sphinx.ext.autosummary import Autosummary, __, generate +from sphinx.ext.autosummary import Autosummary, generate + +original_create_documenter = getattr( + Autosummary, "create_documenter", lambda *args: None +) def extract_documenter(content): @@ -15,135 +18,34 @@ def extract_documenter(content): return directive_name, "::".join([modname, name]) -class CustomAutosummary(Autosummary): - def get_documenter_from_template(self, name, obj, parent, options): - options = options.copy() - options.pop("toctree") - template_name = options.pop("template") - options["imported_members"] = options.get("imported_members", False) - options["recursive"] = options.get("recursive", False) - - app = self.env.app - - context = {} - context.update(app.config.autosummary_context) - - rendered = generate.generate_autosummary_content( - name, - obj, - parent, - template=generate.AutosummaryRenderer(app), - template_name=template_name, - app=app, - context=context, - **options, - ) - - documenter_name, real_name = extract_documenter(rendered) - documenter = app.registry.documenters.get(documenter_name) - - return documenter, real_name - - def get_items(self, names): - """Try to import the given names, and return a list of - ``[(name, signature, summary_string, real_name), ...]``. - """ - prefixes = autosummary.get_import_prefixes_from_env(self.env) - - items = [] - - max_item_chars = 50 - - for name in names: - display_name = name - if name.startswith("~"): - name = name[1:] - display_name = name.split(".")[-1] - - try: - with autosummary.mock(self.config.autosummary_mock_imports): - real_name, obj, parent, modname = autosummary.import_by_name( - name, prefixes=prefixes - ) - except ImportError: - autosummary.logger.warning( - __("autosummary: failed to import %s"), - name, - location=self.get_source_info(), - ) - continue - - # initialize for each documenter - self.bridge.result = autosummary.StringList() - full_name = real_name - if not isinstance(obj, autosummary.ModuleType): - # give explicitly separated module name, so that members - # of inner classes can be documented - full_name = modname + "::" + full_name[len(modname) + 1 :] - # NB. using full_name here is important, since Documenters - # handle module prefixes slightly differently - - if "template" in self.options: - doccls, full_name = self.get_documenter_from_template( - real_name, obj, parent, self.options - ) - else: - doccls = autosummary.get_documenter(self.env.app, obj, parent) - - documenter = doccls(self.bridge, full_name) - if not documenter.parse_name(): - autosummary.logger.warning( - __("failed to parse name %s"), - real_name, - location=self.get_source_info(), - ) - items.append((display_name, "", "", real_name)) - continue - if not documenter.import_object(): - autosummary.logger.warning( - __("failed to import object %s"), - real_name, - location=self.get_source_info(), - ) - items.append((display_name, "", "", real_name)) - continue - if documenter.options.members and not documenter.check_module(): - continue - - # try to also get a source code analyzer for attribute docs - try: - documenter.analyzer = autosummary.ModuleAnalyzer.for_module( - documenter.get_real_modname() - ) - # parse right now, to get PycodeErrors on parsing (results will - # be cached anyway) - documenter.analyzer.find_attr_docs() - except autosummary.PycodeError as err: - autosummary.logger.debug("[autodoc] module analyzer failed: %s", err) - # no source file -- e.g. for builtin and C modules - documenter.analyzer = None - - # -- Grab the signature +def create_documenter_from_template(autosummary, app, obj, parent, full_name): + real_name = ".".join(full_name.split("::")) - try: - sig = documenter.format_signature(show_annotation=False) - except TypeError: - # the documenter does not support ``show_annotation`` option - sig = documenter.format_signature() + options = autosummary.options.copy() + template_name = options.pop("template") + if template_name is None: + return original_create_documenter(autosummary, app, obj, parent, full_name) - if not sig: - sig = "" - else: - max_chars = max(10, max_item_chars - len(display_name)) - sig = autosummary.mangle_signature(sig, max_chars=max_chars) + options.pop("toctree") + options["imported_members"] = options.get("imported_members", False) + options["recursive"] = options.get("recursive", False) - # -- Grab the summary + context = {} + context.update(app.config.autosummary_context) - documenter.add_content(None) - summary = autosummary.extract_summary( - self.bridge.result.data[:], self.state.document - ) + rendered = generate.generate_autosummary_content( + real_name, + obj, + parent, + template=generate.AutosummaryRenderer(app), + template_name=template_name, + app=app, + context=context, + **options, + ) - items.append((display_name, sig, summary, real_name)) + documenter_name, real_name = extract_documenter(rendered) + doccls = app.registry.documenters.get(documenter_name) + documenter = doccls(autosummary.bridge, full_name) - return items + return documenter