diff options
Diffstat (limited to 'sphinx/ext/autosummary/generate.py')
-rw-r--r-- | sphinx/ext/autosummary/generate.py | 83 |
1 files changed, 52 insertions, 31 deletions
diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 4dde73829..0240d2c7c 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -13,7 +13,7 @@ generate: sphinx-autogen -o source/generated source/*.rst - :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -34,20 +34,18 @@ from jinja2 import TemplateNotFound from jinja2.sandbox import SandboxedEnvironment import sphinx.locale -from sphinx import __display_version__ -from sphinx import package_dir +from sphinx import __display_version__, package_dir from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning from sphinx.ext.autodoc import Documenter -from sphinx.ext.autosummary import import_by_name, get_documenter +from sphinx.ext.autodoc.importer import import_module +from sphinx.ext.autosummary import get_documenter, import_by_name, import_ivar_by_name from sphinx.locale import __ from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.registry import SphinxComponentRegistry -from sphinx.util import logging -from sphinx.util import rst -from sphinx.util import split_full_qualified_name +from sphinx.util import logging, rst, split_full_qualified_name from sphinx.util.inspect import safe_getattr from sphinx.util.osutil import ensuredir from sphinx.util.template import SphinxTemplateLoader @@ -74,6 +72,7 @@ class DummyApplication: self.warningiserror = False self.config.add('autosummary_context', {}, True, None) + self.config.add('autosummary_filename_map', {}, True, None) self.config.init_values() def emit_firstresult(self, *args: Any) -> None: @@ -87,29 +86,29 @@ AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str), def setup_documenters(app: Any) -> None: - from sphinx.ext.autodoc import ( - ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, - FunctionDocumenter, MethodDocumenter, AttributeDocumenter, - InstanceAttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, - SlotsAttributeDocumenter, DataDeclarationDocumenter, GenericAliasDocumenter, - SingledispatchFunctionDocumenter, - ) + from sphinx.ext.autodoc import (AttributeDocumenter, ClassDocumenter, DataDocumenter, + DecoratorDocumenter, ExceptionDocumenter, + FunctionDocumenter, MethodDocumenter, ModuleDocumenter, + NewTypeAttributeDocumenter, NewTypeDataDocumenter, + PropertyDocumenter) documenters = [ ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, - FunctionDocumenter, MethodDocumenter, AttributeDocumenter, - InstanceAttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, - SlotsAttributeDocumenter, DataDeclarationDocumenter, GenericAliasDocumenter, - SingledispatchFunctionDocumenter, + FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter, + NewTypeDataDocumenter, AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter, ] # type: List[Type[Documenter]] for documenter in documenters: app.registry.add_documenter(documenter.objtype, documenter) def _simple_info(msg: str) -> None: + warnings.warn('_simple_info() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) print(msg) def _simple_warn(msg: str) -> None: + warnings.warn('_simple_warn() is deprecated.', + RemovedInSphinx50Warning, stacklevel=2) print('WARNING: ' + msg, file=sys.stderr) @@ -143,11 +142,11 @@ class AutosummaryRenderer: if isinstance(app, (Sphinx, DummyApplication)): if app.translator: self.env.add_extension("jinja2.ext.i18n") - self.env.install_gettext_translations(app.translator) # type: ignore + self.env.install_gettext_translations(app.translator) elif isinstance(app, Builder): if app.app.translator: self.env.add_extension("jinja2.ext.i18n") - self.env.install_gettext_translations(app.app.translator) # type: ignore + self.env.install_gettext_translations(app.app.translator) def exists(self, template_name: str) -> bool: """Check if template file exists.""" @@ -230,7 +229,8 @@ class ModuleScanner: def generate_autosummary_content(name: str, obj: Any, parent: Any, template: AutosummaryRenderer, template_name: str, imported_members: bool, app: Any, - recursive: bool, context: Dict) -> str: + recursive: bool, context: Dict, + modname: str = None, qualname: str = None) -> str: doc = get_documenter(app, obj, parent) def skip_member(obj: Any, name: str, objtype: str) -> bool: @@ -289,6 +289,13 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, items = [] # type: List[str] for _, modname, ispkg in pkgutil.iter_modules(obj.__path__): fullname = name + '.' + modname + try: + module = import_module(fullname) + if module and hasattr(module, '__sphinx_mock__'): + continue + except ImportError: + pass + items.append(fullname) public = [x for x in items if not x.split('.')[-1].startswith('_')] return public, items @@ -319,7 +326,9 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any, ns['attributes'], ns['all_attributes'] = \ get_members(obj, {'attribute', 'property'}) - modname, qualname = split_full_qualified_name(name) + if modname is None or qualname is None: + modname, qualname = split_full_qualified_name(name) + if doc.objtype in ('method', 'attribute', 'property'): ns['class'] = qualname.rsplit(".", 1)[0] @@ -347,7 +356,7 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, info: Callable = None, base_path: str = None, builder: Builder = None, template_dir: str = None, imported_members: bool = False, app: Any = None, - overwrite: bool = True) -> None: + overwrite: bool = True, encoding: str = 'utf-8') -> None: if info: warnings.warn('info argument for generate_autosummary_docs() is deprecated.', RemovedInSphinx40Warning, stacklevel=2) @@ -390,6 +399,11 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, # keep track of new files new_files = [] + if app: + filename_map = app.config.autosummary_filename_map + else: + filename_map = {} + # write for entry in sorted(set(items), key=str): if entry.path is None: @@ -401,31 +415,38 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None, ensuredir(path) try: - name, obj, parent, mod_name = import_by_name(entry.name) + name, obj, parent, modname = import_by_name(entry.name) + qualname = name.replace(modname + ".", "") except ImportError as e: - _warn(__('[autosummary] failed to import %r: %s') % (entry.name, e)) - continue + try: + # try to importl as an instance attribute + name, obj, parent, modname = import_ivar_by_name(entry.name) + qualname = name.replace(modname + ".", "") + except ImportError: + _warn(__('[autosummary] failed to import %r: %s') % (entry.name, e)) + continue context = {} if app: context.update(app.config.autosummary_context) content = generate_autosummary_content(name, obj, parent, template, entry.template, - imported_members, app, entry.recursive, context) + imported_members, app, entry.recursive, context, + modname, qualname) - filename = os.path.join(path, name + suffix) + filename = os.path.join(path, filename_map.get(name, name) + suffix) if os.path.isfile(filename): - with open(filename) as f: + with open(filename, encoding=encoding) as f: old_content = f.read() if content == old_content: continue elif overwrite: # content has changed - with open(filename, 'w') as f: + with open(filename, 'w', encoding=encoding) as f: f.write(content) new_files.append(filename) else: - with open(filename, 'w') as f: + with open(filename, 'w', encoding=encoding) as f: f.write(content) new_files.append(filename) |