diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 23318ca6fbd..a7c0bb425dd 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -870,6 +870,8 @@ class _CurrentDocument: '_serial_numbers', '_ext_props', 'autodoc_annotations', + 'autodoc_class', + 'autodoc_module', 'default_domain', 'default_role', 'docname', @@ -913,6 +915,9 @@ def __init__( #: Maps object names to maps of attribute names -> type hints. self.autodoc_annotations: dict[str, dict[str, str]] = {} + self.autodoc_class: str = '' + self.autodoc_module: str = '' + #: Records the time when reading begain for the current document. #: Used in ``sphinx.ext.duration``. self.reading_started_at: float = 0.0 @@ -937,6 +942,10 @@ def new_serial_number(self, category: str = '', /) -> int: def __getitem__(self, item: str) -> Any: if item == 'annotations': return self.autodoc_annotations + if item == 'autodoc:class': + return self.autodoc_class + if item == 'autodoc:module': + return self.autodoc_module if item == 'object': return self.obj_desc_name if item == 'started_at': @@ -957,6 +966,10 @@ def __getitem__(self, item: str) -> Any: def __setitem__(self, key: str, value: Any) -> None: if key == 'annotations': self.autodoc_annotations = value + elif key == 'autodoc:class': + self.autodoc_class = value + elif key == 'autodoc:module': + self.autodoc_module = value elif key == 'object': self.obj_desc_name = value elif key == 'started_at': @@ -981,6 +994,8 @@ def __delitem__(self, key: str) -> None: def __contains__(self, item: str) -> bool: if item in { 'annotations', + 'autodoc:class', + 'autodoc:module', 'object', 'started_at', }: @@ -990,6 +1005,8 @@ def __contains__(self, item: str) -> bool: '_serial_numbers', '_ext_props', 'autodoc_annotations', + 'autodoc_class', + 'autodoc_module', 'default_domain', 'default_role', 'docname', @@ -1009,6 +1026,10 @@ def get(self, key: str, default: Any | None = None) -> Any | None: def pop(self, key: str, default: Any | None = None) -> Any | None: if key == 'annotations': key = 'autodoc_annotations' + if key == 'autodoc:class': + key = 'autodoc_class' + if key == 'autodoc:module': + key = 'autodoc_module' elif key == 'object': key = 'obj_desc_name' elif key == 'started_at': @@ -1017,6 +1038,8 @@ def pop(self, key: str, default: Any | None = None) -> Any | None: blank: str | float | dict[str, dict[str, str]] | None = { '_parser': None, 'autodoc_annotations': {}, + 'autodoc_class': '', + 'autodoc_module': '', 'default_domain': None, 'default_role': '', 'docname': '', diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index a8b96fe6cd2..2b09f28d792 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -821,9 +821,9 @@ def document_members(self, all_members: bool = False) -> None: *self.options.members*. """ # set current namespace for finding members - self.env.current_document['autodoc:module'] = self.modname + self.env.current_document.autodoc_class = self.modname if self.objpath: - self.env.current_document['autodoc:class'] = self.objpath[0] + self.env.current_document.autodoc_class = self.objpath[0] want_all = (all_members or self.options.inherited_members or @@ -856,8 +856,8 @@ def document_members(self, all_members: bool = False) -> None: check_module=members_check_module and not isattr) # reset current objects - self.env.current_document['autodoc:module'] = None - self.env.current_document['autodoc:class'] = None + self.env.current_document.autodoc_module = '' + self.env.current_document.autodoc_class = '' def sort_members(self, documenters: list[tuple[Documenter, bool]], order: str) -> list[tuple[Documenter, bool]]: @@ -1159,7 +1159,7 @@ def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, # if documenting a toplevel object without explicit module, # it can be contained in another auto directive ... - modname = self.env.current_document.get('autodoc:module') + modname = self.env.current_document.autodoc_module # ... or in the scope of a module directive if not modname: modname = self.env.ref_context.get('py:module') @@ -1184,7 +1184,7 @@ def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, # if documenting a class-level object without path, # there must be a current class, either from a parent # auto directive ... - mod_cls_ = self.env.current_document.get('autodoc:class') + mod_cls_ = self.env.current_document.autodoc_class # ... or from a class directive if mod_cls_ is None: mod_cls_ = self.env.ref_context.get('py:class') @@ -1196,7 +1196,7 @@ def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, parents = [cls] # if the module name is still missing, get it like above if not modname: - modname = self.env.current_document.get('autodoc:module') + modname = self.env.current_document.autodoc_module if not modname: modname = self.env.ref_context.get('py:module') # ... else, it stays None, which means invalid diff --git a/tests/test_extensions/test_ext_autodoc.py b/tests/test_extensions/test_ext_autodoc.py index 02a521fdcdf..89d8d037269 100644 --- a/tests/test_extensions/test_ext_autodoc.py +++ b/tests/test_extensions/test_ext_autodoc.py @@ -95,9 +95,10 @@ def verify(objtype, name, result): 'test_ext_autodoc.raises(exc) -> None', ('test_ext_autodoc', ['raises'], 'exc', 'None'), ) - directive.env.current_document['autodoc:module'] = 'test_ext_autodoc' + directive.env.current_document.autodoc_module = 'test_ext_autodoc' verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None)) - del directive.env.current_document['autodoc:module'] + directive.env.current_document.autodoc_module = '' + directive.env.ref_context['py:module'] = 'test_ext_autodoc' verify('function', 'raises', ('test_ext_autodoc', ['raises'], None, None)) verify('class', 'Base', ('test_ext_autodoc', ['Base'], None, None)) @@ -111,7 +112,7 @@ def verify(objtype, name, result): ) directive.env.ref_context['py:module'] = 'sphinx.testing.util' directive.env.ref_context['py:class'] = 'Foo' - directive.env.current_document['autodoc:class'] = 'SphinxTestApp' + directive.env.current_document.autodoc_class = 'SphinxTestApp' verify( 'method', 'cleanup', @@ -1299,7 +1300,7 @@ def test_autodoc_module_member_order(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_module_scope(app): - app.env.current_document['autodoc:module'] = 'target' + app.env.current_document.autodoc_module = 'target' actual = do_autodoc(app, 'attribute', 'Class.mdocattr') assert list(actual) == [ '', @@ -1314,8 +1315,8 @@ def test_autodoc_module_scope(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_class_scope(app): - app.env.current_document['autodoc:module'] = 'target' - app.env.current_document['autodoc:class'] = 'Class' + app.env.current_document.autodoc_module = 'target' + app.env.current_document.autodoc_class = 'Class' actual = do_autodoc(app, 'attribute', 'mdocattr') assert list(actual) == [ '',