diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index a9938c256..e51441caa 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -130,7 +130,7 @@ class CObject(ObjectDescription): if m: name = m.group(1) - typename = self.env.temp_data.get('c:type') + typename = self.env.ref_context.get('c:type') if self.name == 'c:member' and typename: fullname = typename + '.' + name else: @@ -212,12 +212,12 @@ class CObject(ObjectDescription): self.typename_set = False if self.name == 'c:type': if self.names: - self.env.temp_data['c:type'] = self.names[0] + self.env.ref_context['c:type'] = self.names[0] self.typename_set = True def after_content(self): if self.typename_set: - self.env.temp_data['c:type'] = None + self.env.ref_context.pop('c:type', None) class CXRefRole(XRefRole): diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 8992991d3..fb0b23f31 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -434,7 +434,7 @@ class ASTNestedNameElement(ASTBase): '', refdomain='cpp', reftype='type', reftarget=targetText, modname=None, classname=None) if env: # during testing we don't have an env, do we? - pnode['cpp:parent'] = env.temp_data.get('cpp:parent') + pnode['cpp:parent'] = env.ref_context.get('cpp:parent') pnode += nodes.Text(text_type(self.identifier)) signode += pnode elif mode == 'lastIsName': @@ -1666,7 +1666,7 @@ class CPPObject(ObjectDescription): signode['names'].append(uninstantiated) objects.setdefault(uninstantiated, ( self.env.docname, ast.objectType, theid)) - self.env.temp_data['cpp:lastname'] = ast.prefixedName + self.env.ref_context['cpp:lastname'] = ast.prefixedName indextext = self.get_index_text(name) if not re.compile(r'^[a-zA-Z0-9_]*$').match(theid): @@ -1693,7 +1693,7 @@ class CPPObject(ObjectDescription): raise ValueError self.describe_signature(signode, ast) - parent = self.env.temp_data.get('cpp:parent') + parent = self.env.ref_context.get('cpp:parent') if parent and len(parent) > 0: ast = ast.clone() ast.prefixedName = ast.name.prefix_nested_name(parent[-1]) @@ -1741,15 +1741,15 @@ class CPPClassObject(CPPObject): return _('%s (C++ class)') % name def before_content(self): - lastname = self.env.temp_data['cpp:lastname'] + lastname = self.env.ref_context['cpp:lastname'] assert lastname - if 'cpp:parent' in self.env.temp_data: - self.env.temp_data['cpp:parent'].append(lastname) + if 'cpp:parent' in self.env.ref_context: + self.env.ref_context['cpp:parent'].append(lastname) else: - self.env.temp_data['cpp:parent'] = [lastname] + self.env.ref_context['cpp:parent'] = [lastname] def after_content(self): - self.env.temp_data['cpp:parent'].pop() + self.env.ref_context['cpp:parent'].pop() def parse_definition(self, parser): return parser.parse_class_object() @@ -1774,7 +1774,7 @@ class CPPNamespaceObject(Directive): def run(self): env = self.state.document.settings.env if self.arguments[0].strip() in ('NULL', '0', 'nullptr'): - env.temp_data['cpp:parent'] = [] + env.ref_context['cpp:parent'] = [] else: parser = DefinitionParser(self.arguments[0]) try: @@ -1784,13 +1784,13 @@ class CPPNamespaceObject(Directive): self.state_machine.reporter.warning(e.description, line=self.lineno) else: - env.temp_data['cpp:parent'] = [prefix] + env.ref_context['cpp:parent'] = [prefix] return [] class CPPXRefRole(XRefRole): def process_link(self, env, refnode, has_explicit_title, title, target): - parent = env.temp_data.get('cpp:parent') + parent = env.ref_context.get('cpp:parent') if parent: refnode['cpp:parent'] = parent[:] if not has_explicit_title: diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index dc65b2a39..1169036c9 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -45,7 +45,7 @@ class JSObject(ObjectDescription): nameprefix = None name = prefix - objectname = self.env.temp_data.get('js:object') + objectname = self.env.ref_context.get('js:object') if nameprefix: if objectname: # someone documenting the method of an attribute of the current @@ -77,7 +77,7 @@ class JSObject(ObjectDescription): def add_target_and_index(self, name_obj, sig, signode): objectname = self.options.get( - 'object', self.env.temp_data.get('js:object')) + 'object', self.env.ref_context.get('js:object')) fullname = name_obj[0] if fullname not in self.state.document.ids: signode['names'].append(fullname) @@ -140,7 +140,7 @@ class JSConstructor(JSCallable): class JSXRefRole(XRefRole): def process_link(self, env, refnode, has_explicit_title, title, target): # basically what sphinx.domains.python.PyXRefRole does - refnode['js:object'] = env.temp_data.get('js:object') + refnode['js:object'] = env.ref_context.get('js:object') if not has_explicit_title: title = title.lstrip('.') target = target.lstrip('~') @@ -216,7 +216,7 @@ class JavaScriptDomain(Domain): def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): - objectname = node.get('js:object') # not likely + objectname = node.get('js:object') name, obj = self.find_obj(env, objectname, target, None, 1) if not obj: return [] diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 17609692d..79577a0e6 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -156,8 +156,8 @@ class PyObject(ObjectDescription): # determine module and class name (if applicable), as well as full name modname = self.options.get( - 'module', self.env.temp_data.get('py:module')) - classname = self.env.temp_data.get('py:class') + 'module', self.env.ref_context.get('py:module')) + classname = self.env.ref_context.get('py:class') if classname: add_module = False if name_prefix and name_prefix.startswith(classname): @@ -194,7 +194,7 @@ class PyObject(ObjectDescription): # 'exceptions' module. elif add_module and self.env.config.add_module_names: modname = self.options.get( - 'module', self.env.temp_data.get('py:module')) + 'module', self.env.ref_context.get('py:module')) if modname and modname != 'exceptions': nodetext = modname + '.' signode += addnodes.desc_addname(nodetext, nodetext) @@ -225,7 +225,7 @@ class PyObject(ObjectDescription): def add_target_and_index(self, name_cls, sig, signode): modname = self.options.get( - 'module', self.env.temp_data.get('py:module')) + 'module', self.env.ref_context.get('py:module')) fullname = (modname and modname + '.' or '') + name_cls[0] # note target if fullname not in self.state.document.ids: @@ -254,7 +254,7 @@ class PyObject(ObjectDescription): def after_content(self): if self.clsname_set: - self.env.temp_data['py:class'] = None + self.env.ref_context.pop('py:class', None) class PyModulelevel(PyObject): @@ -299,7 +299,7 @@ class PyClasslike(PyObject): def before_content(self): PyObject.before_content(self) if self.names: - self.env.temp_data['py:class'] = self.names[0][0] + self.env.ref_context['py:class'] = self.names[0][0] self.clsname_set = True @@ -377,8 +377,8 @@ class PyClassmember(PyObject): def before_content(self): PyObject.before_content(self) lastname = self.names and self.names[-1][1] - if lastname and not self.env.temp_data.get('py:class'): - self.env.temp_data['py:class'] = lastname.strip('.') + if lastname and not self.env.ref_context.get('py:class'): + self.env.ref_context['py:class'] = lastname.strip('.') self.clsname_set = True @@ -434,7 +434,7 @@ class PyModule(Directive): env = self.state.document.settings.env modname = self.arguments[0].strip() noindex = 'noindex' in self.options - env.temp_data['py:module'] = modname + env.ref_context['py:module'] = modname ret = [] if not noindex: env.domaindata['py']['modules'][modname] = \ @@ -472,16 +472,16 @@ class PyCurrentModule(Directive): env = self.state.document.settings.env modname = self.arguments[0].strip() if modname == 'None': - env.temp_data['py:module'] = None + env.ref_context.pop('py:module', None) else: - env.temp_data['py:module'] = modname + env.ref_context['py:module'] = modname return [] class PyXRefRole(XRefRole): def process_link(self, env, refnode, has_explicit_title, title, target): - refnode['py:module'] = env.temp_data.get('py:module') - refnode['py:class'] = env.temp_data.get('py:class') + refnode['py:module'] = env.ref_context.get('py:module') + refnode['py:class'] = env.ref_context.get('py:class') if not has_explicit_title: title = title.lstrip('.') # only has a meaning for the target target = target.lstrip('~') # only has a meaning for the title diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index 618af66c6..4cdd96f2b 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -163,7 +163,7 @@ class Cmdoption(ObjectDescription): return firstname def add_target_and_index(self, firstname, sig, signode): - currprogram = self.env.temp_data.get('std:program') + currprogram = self.env.ref_context.get('std:program') for optname in signode.get('allnames', []): targetname = optname.replace('/', '-') if not targetname.startswith('-'): @@ -198,9 +198,9 @@ class Program(Directive): env = self.state.document.settings.env program = ws_re.sub('-', self.arguments[0].strip()) if program == 'None': - env.temp_data['std:program'] = None + env.ref_context.pop('std:program', None) else: - env.temp_data['std:program'] = program + env.ref_context['std:program'] = program return [] @@ -219,7 +219,7 @@ class OptionXRefRole(XRefRole): innernodeclass = addnodes.literal_emphasis def process_link(self, env, refnode, has_explicit_title, title, target): - program = env.temp_data.get('std:program') + program = env.ref_context.get('std:program') if not has_explicit_title: if ' ' in title and not (title.startswith('/') or title.startswith('-')): diff --git a/sphinx/environment.py b/sphinx/environment.py index 8f96584b2..a2399422d 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -225,6 +225,10 @@ class BuildEnvironment: # temporary data storage while reading a document self.temp_data = {} + # context for cross-references (e.g. current module or class) + # this is similar to temp_data, but will for example be copied to + # attributes of "any" cross references + self.ref_context = {} def set_warnfunc(self, func): self._warnfunc = func @@ -681,6 +685,7 @@ class BuildEnvironment: # cleanup self.temp_data.clear() + self.ref_context.clear() roles._roles.pop('', None) # if a document has set a local default role if save_parsed: @@ -747,7 +752,7 @@ class BuildEnvironment: def note_versionchange(self, type, version, node, lineno): self.versionchanges.setdefault(version, []).append( (type, self.temp_data['docname'], lineno, - self.temp_data.get('py:module'), + self.ref_context.get('py:module'), self.temp_data.get('object'), node.astext())) # post-processing of read doctrees diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 5b014d0d5..58067aaab 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -891,7 +891,7 @@ class ModuleLevelDocumenter(Documenter): modname = self.env.temp_data.get('autodoc:module') # ... or in the scope of a module directive if not modname: - modname = self.env.temp_data.get('py:module') + modname = self.env.ref_context.get('py:module') # ... else, it stays None, which means invalid return modname, parents + [base] @@ -913,7 +913,7 @@ class ClassLevelDocumenter(Documenter): mod_cls = self.env.temp_data.get('autodoc:class') # ... or from a class directive if mod_cls is None: - mod_cls = self.env.temp_data.get('py:class') + mod_cls = self.env.ref_context.get('py:class') # ... if still None, there's no way to know if mod_cls is None: return None, [] @@ -923,7 +923,7 @@ class ClassLevelDocumenter(Documenter): if not modname: modname = self.env.temp_data.get('autodoc:module') if not modname: - modname = self.env.temp_data.get('py:module') + modname = self.env.ref_context.get('py:module') # ... else, it stays None, which means invalid return modname, parents + [base] diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 31bbfb8a5..cbdc16e5f 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -432,11 +432,11 @@ def get_import_prefixes_from_env(env): """ prefixes = [None] - currmodule = env.temp_data.get('py:module') + currmodule = env.ref_context.get('py:module') if currmodule: prefixes.insert(0, currmodule) - currclass = env.temp_data.get('py:class') + currclass = env.ref_context.get('py:class') if currclass: if currmodule: prefixes.insert(0, currmodule + "." + currclass) diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index bbae5c110..33f2b2501 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -310,7 +310,7 @@ class InheritanceDiagram(Directive): # Create a graph starting with the list of classes try: graph = InheritanceGraph( - class_names, env.temp_data.get('py:module'), + class_names, env.ref_context.get('py:module'), parts=node['parts'], private_bases='private-bases' in self.options) except InheritanceException as err: diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index e0d39f091..192820bf3 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -123,24 +123,24 @@ def test_parse_name(): directive.env.temp_data['autodoc:module'] = 'util' verify('function', 'raises', ('util', ['raises'], None, None)) del directive.env.temp_data['autodoc:module'] - directive.env.temp_data['py:module'] = 'util' + directive.env.ref_context['py:module'] = 'util' verify('function', 'raises', ('util', ['raises'], None, None)) verify('class', 'TestApp', ('util', ['TestApp'], None, None)) # for members - directive.env.temp_data['py:module'] = 'foo' + directive.env.ref_context['py:module'] = 'foo' verify('method', 'util.TestApp.cleanup', ('util', ['TestApp', 'cleanup'], None, None)) - directive.env.temp_data['py:module'] = 'util' - directive.env.temp_data['py:class'] = 'Foo' + directive.env.ref_context['py:module'] = 'util' + directive.env.ref_context['py:class'] = 'Foo' directive.env.temp_data['autodoc:class'] = 'TestApp' verify('method', 'cleanup', ('util', ['TestApp', 'cleanup'], None, None)) verify('method', 'TestApp.cleanup', ('util', ['TestApp', 'cleanup'], None, None)) # and clean up - del directive.env.temp_data['py:module'] - del directive.env.temp_data['py:class'] + del directive.env.ref_context['py:module'] + del directive.env.ref_context['py:class'] del directive.env.temp_data['autodoc:class'] @@ -584,7 +584,7 @@ def test_generate(): 'method', 'test_autodoc.Class.foobar', more_content=None) # test auto and given content mixing - directive.env.temp_data['py:module'] = 'test_autodoc' + directive.env.ref_context['py:module'] = 'test_autodoc' assert_result_contains(' Function.', 'method', 'Class.meth') add_content = ViewList() add_content.append('Content.', '', 0) @@ -682,12 +682,12 @@ def test_generate(): 'attribute', 'test_autodoc.Class.descr') # test generation for C modules (which have no source file) - directive.env.temp_data['py:module'] = 'time' + directive.env.ref_context['py:module'] = 'time' assert_processes([('function', 'time.asctime')], 'function', 'asctime') assert_processes([('function', 'time.asctime')], 'function', 'asctime') # test autodoc_member_order == 'source' - directive.env.temp_data['py:module'] = 'test_autodoc' + directive.env.ref_context['py:module'] = 'test_autodoc' assert_order(['.. py:class:: Class(arg)', ' .. py:attribute:: Class.descr', ' .. py:method:: Class.meth()', @@ -704,7 +704,7 @@ def test_generate(): ' .. py:method:: Class.inheritedmeth()', ], 'class', 'Class', member_order='bysource', all_members=True) - del directive.env.temp_data['py:module'] + del directive.env.ref_context['py:module'] # test attribute initialized to class instance from other module directive.env.temp_data['autodoc:class'] = 'test_autodoc.Class' @@ -729,7 +729,7 @@ def test_generate(): 'test_autodoc.Class.moore') # test new attribute documenter behavior - directive.env.temp_data['py:module'] = 'test_autodoc' + directive.env.ref_context['py:module'] = 'test_autodoc' options.undoc_members = True assert_processes([('class', 'test_autodoc.AttCls'), ('attribute', 'test_autodoc.AttCls.a1'), @@ -743,7 +743,7 @@ def test_generate(): # test explicit members with instance attributes del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:module'] - directive.env.temp_data['py:module'] = 'test_autodoc' + directive.env.ref_context['py:module'] = 'test_autodoc' options.inherited_members = False options.undoc_members = False options.members = ALL @@ -765,7 +765,7 @@ def test_generate(): ], 'class', 'InstAttCls') del directive.env.temp_data['autodoc:class'] del directive.env.temp_data['autodoc:module'] - del directive.env.temp_data['py:module'] + del directive.env.ref_context['py:module'] # test descriptor class documentation options.members = ['CustomDataDescriptor']