py domain: Generate node_id for objects in the right way

This commit is contained in:
Takeshi KOMIYA 2020-03-02 00:45:50 +09:00
parent 5ff3b9dc4d
commit 729efd28b0
6 changed files with 96 additions and 88 deletions

View File

@ -31,8 +31,10 @@ Incompatible changes
node_id for cross reference node_id for cross reference
* #7229: rst domain: Non intended behavior is removed such as ``numref_`` links * #7229: rst domain: Non intended behavior is removed such as ``numref_`` links
to ``.. rst:role:: numref`` to ``.. rst:role:: numref``
* #6903: py domain: Internal data structure has changed. Now modules have * #6903: py domain: Internal data structure has changed. Both objects and
node_id for cross reference modules have node_id for cross reference
* #6903: py domain: Non intended behavior is removed such as ``say_hello_``
links to ``.. py:function:: say_hello()``
Deprecated Deprecated
---------- ----------

View File

@ -358,19 +358,22 @@ class PyObject(ObjectDescription):
signode: desc_signature) -> None: signode: desc_signature) -> None:
modname = self.options.get('module', self.env.ref_context.get('py:module')) modname = self.options.get('module', self.env.ref_context.get('py:module'))
fullname = (modname + '.' if modname else '') + name_cls[0] fullname = (modname + '.' if modname else '') + name_cls[0]
# note target node_id = make_id(self.env, self.state.document, modname or '', name_cls[0])
if fullname not in self.state.document.ids: signode['ids'].append(node_id)
signode['names'].append(fullname)
signode['ids'].append(fullname)
self.state.document.note_explicit_target(signode)
domain = cast(PythonDomain, self.env.get_domain('py')) # Assign old styled node_id(fullname) not to break old hyperlinks (if possible)
domain.note_object(fullname, self.objtype, location=signode) # Note: Will removed in Sphinx-5.0 (RemovedInSphinx50Warning)
if node_id != fullname and fullname not in self.state.document.ids:
signode['ids'].append(fullname)
self.state.document.note_explicit_target(signode)
domain = cast(PythonDomain, self.env.get_domain('py'))
domain.note_object(fullname, self.objtype, node_id, location=signode)
indextext = self.get_index_text(modname, name_cls) indextext = self.get_index_text(modname, name_cls)
if indextext: if indextext:
self.indexnode['entries'].append(('single', indextext, self.indexnode['entries'].append(('single', indextext, node_id, '', None))
fullname, '', None))
def before_content(self) -> None: def before_content(self) -> None:
"""Handle object nesting before content """Handle object nesting before content
@ -805,7 +808,7 @@ class PyModule(SphinxDirective):
self.options.get('synopsis', ''), self.options.get('synopsis', ''),
self.options.get('platform', ''), self.options.get('platform', ''),
'deprecated' in self.options) 'deprecated' in self.options)
domain.note_object(modname, 'module', location=target) domain.note_object(modname, 'module', node_id, location=target)
# the platform and synopsis aren't printed; in fact, they are only # the platform and synopsis aren't printed; in fact, they are only
# used in the modindex currently # used in the modindex currently
@ -1008,10 +1011,10 @@ class PythonDomain(Domain):
] ]
@property @property
def objects(self) -> Dict[str, Tuple[str, str]]: def objects(self) -> Dict[str, Tuple[str, str, str]]:
return self.data.setdefault('objects', {}) # fullname -> docname, objtype return self.data.setdefault('objects', {}) # fullname -> docname, node_id, objtype
def note_object(self, name: str, objtype: str, location: Any = None) -> None: def note_object(self, name: str, objtype: str, node_id: str, location: Any = None) -> None:
"""Note a python object for cross reference. """Note a python object for cross reference.
.. versionadded:: 2.1 .. versionadded:: 2.1
@ -1021,7 +1024,7 @@ class PythonDomain(Domain):
logger.warning(__('duplicate object description of %s, ' logger.warning(__('duplicate object description of %s, '
'other instance in %s, use :noindex: for one of them'), 'other instance in %s, use :noindex: for one of them'),
name, docname, location=location) name, docname, location=location)
self.objects[name] = (self.env.docname, objtype) self.objects[name] = (self.env.docname, node_id, objtype)
@property @property
def modules(self) -> Dict[str, Tuple[str, str, str, str, bool]]: def modules(self) -> Dict[str, Tuple[str, str, str, str, bool]]:
@ -1036,7 +1039,7 @@ class PythonDomain(Domain):
self.modules[name] = (self.env.docname, node_id, synopsis, platform, deprecated) self.modules[name] = (self.env.docname, node_id, synopsis, platform, deprecated)
def clear_doc(self, docname: str) -> None: def clear_doc(self, docname: str) -> None:
for fullname, (fn, _l) in list(self.objects.items()): for fullname, (fn, _x, _x) in list(self.objects.items()):
if fn == docname: if fn == docname:
del self.objects[fullname] del self.objects[fullname]
for modname, (fn, _x, _x, _x, _y) in list(self.modules.items()): for modname, (fn, _x, _x, _x, _y) in list(self.modules.items()):
@ -1045,16 +1048,16 @@ class PythonDomain(Domain):
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
# XXX check duplicates? # XXX check duplicates?
for fullname, (fn, objtype) in otherdata['objects'].items(): for fullname, (fn, node_id, objtype) in otherdata['objects'].items():
if fn in docnames: if fn in docnames:
self.objects[fullname] = (fn, objtype) self.objects[fullname] = (fn, node_id, objtype)
for modname, data in otherdata['modules'].items(): for modname, data in otherdata['modules'].items():
if data[0] in docnames: if data[0] in docnames:
self.modules[modname] = data self.modules[modname] = data
def find_obj(self, env: BuildEnvironment, modname: str, classname: str, def find_obj(self, env: BuildEnvironment, modname: str, classname: str,
name: str, type: str, searchmode: int = 0 name: str, type: str, searchmode: int = 0
) -> List[Tuple[str, Tuple[str, str]]]: ) -> List[Tuple[str, Tuple[str, str, str]]]:
"""Find a Python object for "name", perhaps using the given module """Find a Python object for "name", perhaps using the given module
and/or classname. Returns a list of (name, object entry) tuples. and/or classname. Returns a list of (name, object entry) tuples.
""" """
@ -1065,7 +1068,7 @@ class PythonDomain(Domain):
if not name: if not name:
return [] return []
matches = [] # type: List[Tuple[str, Tuple[str, str]]] matches = [] # type: List[Tuple[str, Tuple[str, str, str]]]
newname = None newname = None
if searchmode == 1: if searchmode == 1:
@ -1076,20 +1079,20 @@ class PythonDomain(Domain):
if objtypes is not None: if objtypes is not None:
if modname and classname: if modname and classname:
fullname = modname + '.' + classname + '.' + name fullname = modname + '.' + classname + '.' + name
if fullname in self.objects and self.objects[fullname][1] in objtypes: if fullname in self.objects and self.objects[fullname][2] in objtypes:
newname = fullname newname = fullname
if not newname: if not newname:
if modname and modname + '.' + name in self.objects and \ if modname and modname + '.' + name in self.objects and \
self.objects[modname + '.' + name][1] in objtypes: self.objects[modname + '.' + name][2] in objtypes:
newname = modname + '.' + name newname = modname + '.' + name
elif name in self.objects and self.objects[name][1] in objtypes: elif name in self.objects and self.objects[name][2] in objtypes:
newname = name newname = name
else: else:
# "fuzzy" searching mode # "fuzzy" searching mode
searchname = '.' + name searchname = '.' + name
matches = [(oname, self.objects[oname]) for oname in self.objects matches = [(oname, self.objects[oname]) for oname in self.objects
if oname.endswith(searchname) and if oname.endswith(searchname) and
self.objects[oname][1] in objtypes] self.objects[oname][2] in objtypes]
else: else:
# NOTE: searching for exact match, object type is not considered # NOTE: searching for exact match, object type is not considered
if name in self.objects: if name in self.objects:
@ -1137,10 +1140,10 @@ class PythonDomain(Domain):
type='ref', subtype='python', location=node) type='ref', subtype='python', location=node)
name, obj = matches[0] name, obj = matches[0]
if obj[1] == 'module': if obj[2] == 'module':
return self._make_module_refnode(builder, fromdocname, name, contnode) return self._make_module_refnode(builder, fromdocname, name, contnode)
else: else:
return make_refnode(builder, fromdocname, obj[0], name, contnode, name) return make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name)
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
target: str, node: pending_xref, contnode: Element target: str, node: pending_xref, contnode: Element
@ -1152,13 +1155,13 @@ class PythonDomain(Domain):
# always search in "refspecific" mode with the :any: role # always search in "refspecific" mode with the :any: role
matches = self.find_obj(env, modname, clsname, target, None, 1) matches = self.find_obj(env, modname, clsname, target, None, 1)
for name, obj in matches: for name, obj in matches:
if obj[1] == 'module': if obj[2] == 'module':
results.append(('py:mod', results.append(('py:mod',
self._make_module_refnode(builder, fromdocname, self._make_module_refnode(builder, fromdocname,
name, contnode))) name, contnode)))
else: else:
results.append(('py:' + self.role_for_objtype(obj[1]), results.append(('py:' + self.role_for_objtype(obj[2]),
make_refnode(builder, fromdocname, obj[0], name, make_refnode(builder, fromdocname, obj[0], obj[1],
contnode, name))) contnode, name)))
return results return results
@ -1178,9 +1181,9 @@ class PythonDomain(Domain):
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]: def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
for modname, info in self.modules.items(): for modname, info in self.modules.items():
yield (modname, modname, 'module', info[0], info[1], 0) yield (modname, modname, 'module', info[0], info[1], 0)
for refname, (docname, type) in self.objects.items(): for refname, (docname, node_id, type) in self.objects.items():
if type != 'module': # modules are already handled if type != 'module': # modules are already handled
yield (refname, refname, type, docname, refname, 1) yield (refname, refname, type, docname, node_id, 1)
def get_full_qualified_name(self, node: Element) -> str: def get_full_qualified_name(self, node: Element) -> str:
modname = node.get('py:module') modname = node.get('py:module')

View File

@ -176,8 +176,8 @@ def test_html4_output(app, status, warning):
r'-| |-'), r'-| |-'),
], ],
'autodoc.html': [ 'autodoc.html': [
(".//dl[@class='py class']/dt[@id='autodoc_target.Class']", ''), (".//dl[@class='py class']/dt[@id='autodoc-target-class']", ''),
(".//dl[@class='py function']/dt[@id='autodoc_target.function']/em", r'\*\*kwds'), (".//dl[@class='py function']/dt[@id='autodoc-target-function']/em", r'\*\*kwds'),
(".//dd/p", r'Return spam\.'), (".//dd/p", r'Return spam\.'),
], ],
'extapi.html': [ 'extapi.html': [
@ -262,7 +262,7 @@ def test_html4_output(app, status, warning):
(".//p", 'Always present'), (".//p", 'Always present'),
# tests for ``any`` role # tests for ``any`` role
(".//a[@href='#with']/span", 'headings'), (".//a[@href='#with']/span", 'headings'),
(".//a[@href='objects.html#func_without_body']/code/span", 'objects'), (".//a[@href='objects.html#func-without-body']/code/span", 'objects'),
# tests for numeric labels # tests for numeric labels
(".//a[@href='#id1'][@class='reference internal']/span", 'Testing various markup'), (".//a[@href='#id1'][@class='reference internal']/span", 'Testing various markup'),
# tests for smartypants # tests for smartypants
@ -274,18 +274,18 @@ def test_html4_output(app, status, warning):
(".//p", 'Il dit : « Cest “super” ! »'), (".//p", 'Il dit : « Cest “super” ! »'),
], ],
'objects.html': [ 'objects.html': [
(".//dt[@id='mod.Cls.meth1']", ''), (".//dt[@id='mod-cls-meth1']", ''),
(".//dt[@id='errmod.Error']", ''), (".//dt[@id='errmod-error']", ''),
(".//dt/code", r'long\(parameter,\s* list\)'), (".//dt/code", r'long\(parameter,\s* list\)'),
(".//dt/code", 'another one'), (".//dt/code", 'another one'),
(".//a[@href='#mod.Cls'][@class='reference internal']", ''), (".//a[@href='#mod-cls'][@class='reference internal']", ''),
(".//dl[@class='std userdesc']", ''), (".//dl[@class='std userdesc']", ''),
(".//dt[@id='userdesc-myobj']", ''), (".//dt[@id='userdesc-myobj']", ''),
(".//a[@href='#userdesc-myobj'][@class='reference internal']", ''), (".//a[@href='#userdesc-myobj'][@class='reference internal']", ''),
# docfields # docfields
(".//a[@class='reference internal'][@href='#TimeInt']/em", 'TimeInt'), (".//a[@class='reference internal'][@href='#timeint']/em", 'TimeInt'),
(".//a[@class='reference internal'][@href='#Time']", 'Time'), (".//a[@class='reference internal'][@href='#time']", 'Time'),
(".//a[@class='reference internal'][@href='#errmod.Error']/strong", 'Error'), (".//a[@class='reference internal'][@href='#errmod-error']/strong", 'Error'),
# C references # C references
(".//span[@class='pre']", 'CFunction()'), (".//span[@class='pre']", 'CFunction()'),
(".//a[@href='#c.Sphinx_DoSomething']", ''), (".//a[@href='#c.Sphinx_DoSomething']", ''),

View File

@ -145,24 +145,24 @@ def test_domain_py_objects(app, status, warning):
assert 'module_b.submodule' in modules assert 'module_b.submodule' in modules
assert 'module_b.submodule' in objects assert 'module_b.submodule' in objects
assert objects['module_a.submodule.ModTopLevel'] == ('module', 'class') assert objects['module_a.submodule.ModTopLevel'][2] == 'class'
assert objects['module_a.submodule.ModTopLevel.mod_child_1'] == ('module', 'method') assert objects['module_a.submodule.ModTopLevel.mod_child_1'][2] == 'method'
assert objects['module_a.submodule.ModTopLevel.mod_child_2'] == ('module', 'method') assert objects['module_a.submodule.ModTopLevel.mod_child_2'][2] == 'method'
assert 'ModTopLevel.ModNoModule' not in objects assert 'ModTopLevel.ModNoModule' not in objects
assert objects['ModNoModule'] == ('module', 'class') assert objects['ModNoModule'][2] == 'class'
assert objects['module_b.submodule.ModTopLevel'] == ('module', 'class') assert objects['module_b.submodule.ModTopLevel'][2] == 'class'
assert objects['TopLevel'] == ('roles', 'class') assert objects['TopLevel'][2] == 'class'
assert objects['top_level'] == ('roles', 'method') assert objects['top_level'][2] == 'method'
assert objects['NestedParentA'] == ('roles', 'class') assert objects['NestedParentA'][2] == 'class'
assert objects['NestedParentA.child_1'] == ('roles', 'method') assert objects['NestedParentA.child_1'][2] == 'method'
assert objects['NestedParentA.any_child'] == ('roles', 'method') assert objects['NestedParentA.any_child'][2] == 'method'
assert objects['NestedParentA.NestedChildA'] == ('roles', 'class') assert objects['NestedParentA.NestedChildA'][2] == 'class'
assert objects['NestedParentA.NestedChildA.subchild_1'] == ('roles', 'method') assert objects['NestedParentA.NestedChildA.subchild_1'][2] == 'method'
assert objects['NestedParentA.NestedChildA.subchild_2'] == ('roles', 'method') assert objects['NestedParentA.NestedChildA.subchild_2'][2] == 'method'
assert objects['NestedParentA.child_2'] == ('roles', 'method') assert objects['NestedParentA.child_2'][2] == 'method'
assert objects['NestedParentB'] == ('roles', 'class') assert objects['NestedParentB'][2] == 'class'
assert objects['NestedParentB.child_1'] == ('roles', 'method') assert objects['NestedParentB.child_1'][2] == 'method'
@pytest.mark.sphinx('html', testroot='domain-py') @pytest.mark.sphinx('html', testroot='domain-py')
@ -170,11 +170,11 @@ def test_resolve_xref_for_properties(app, status, warning):
app.builder.build_all() app.builder.build_all()
content = (app.outdir / 'module.html').read_text() content = (app.outdir / 'module.html').read_text()
assert ('Link to <a class="reference internal" href="#module_a.submodule.ModTopLevel.prop"' assert ('Link to <a class="reference internal" href="#module-a-submodule-modtoplevel-prop"'
' title="module_a.submodule.ModTopLevel.prop">' ' title="module_a.submodule.ModTopLevel.prop">'
'<code class="xref py py-attr docutils literal notranslate"><span class="pre">' '<code class="xref py py-attr docutils literal notranslate"><span class="pre">'
'prop</span> <span class="pre">attribute</span></code></a>' in content) 'prop</span> <span class="pre">attribute</span></code></a>' in content)
assert ('Link to <a class="reference internal" href="#module_a.submodule.ModTopLevel.prop"' assert ('Link to <a class="reference internal" href="#module-a-submodule-modtoplevel-prop"'
' title="module_a.submodule.ModTopLevel.prop">' ' title="module_a.submodule.ModTopLevel.prop">'
'<code class="xref py py-meth docutils literal notranslate"><span class="pre">' '<code class="xref py py-meth docutils literal notranslate"><span class="pre">'
'prop</span> <span class="pre">method</span></code></a>' in content) 'prop</span> <span class="pre">method</span></code></a>' in content)
@ -191,17 +191,20 @@ def test_domain_py_find_obj(app, status, warning):
assert (find_obj(None, None, 'NONEXISTANT', 'class') == []) assert (find_obj(None, None, 'NONEXISTANT', 'class') == [])
assert (find_obj(None, None, 'NestedParentA', 'class') == assert (find_obj(None, None, 'NestedParentA', 'class') ==
[('NestedParentA', ('roles', 'class'))]) [('NestedParentA', ('roles', 'nestedparenta', 'class'))])
assert (find_obj(None, None, 'NestedParentA.NestedChildA', 'class') == assert (find_obj(None, None, 'NestedParentA.NestedChildA', 'class') ==
[('NestedParentA.NestedChildA', ('roles', 'class'))]) [('NestedParentA.NestedChildA', ('roles', 'nestedparenta-nestedchilda', 'class'))])
assert (find_obj(None, 'NestedParentA', 'NestedChildA', 'class') == assert (find_obj(None, 'NestedParentA', 'NestedChildA', 'class') ==
[('NestedParentA.NestedChildA', ('roles', 'class'))]) [('NestedParentA.NestedChildA', ('roles', 'nestedparenta-nestedchilda', 'class'))])
assert (find_obj(None, None, 'NestedParentA.NestedChildA.subchild_1', 'meth') == assert (find_obj(None, None, 'NestedParentA.NestedChildA.subchild_1', 'meth') ==
[('NestedParentA.NestedChildA.subchild_1', ('roles', 'method'))]) [('NestedParentA.NestedChildA.subchild_1',
('roles', 'nestedparenta-nestedchilda-subchild-1', 'method'))])
assert (find_obj(None, 'NestedParentA', 'NestedChildA.subchild_1', 'meth') == assert (find_obj(None, 'NestedParentA', 'NestedChildA.subchild_1', 'meth') ==
[('NestedParentA.NestedChildA.subchild_1', ('roles', 'method'))]) [('NestedParentA.NestedChildA.subchild_1',
('roles', 'nestedparenta-nestedchilda-subchild-1', 'method'))])
assert (find_obj(None, 'NestedParentA.NestedChildA', 'subchild_1', 'meth') == assert (find_obj(None, 'NestedParentA.NestedChildA', 'subchild_1', 'meth') ==
[('NestedParentA.NestedChildA.subchild_1', ('roles', 'method'))]) [('NestedParentA.NestedChildA.subchild_1',
('roles', 'nestedparenta-nestedchilda-subchild-1', 'method'))])
def test_get_full_qualified_name(): def test_get_full_qualified_name():
@ -402,7 +405,7 @@ def test_pydata(app):
[desc, ([desc_signature, desc_name, "var"], [desc, ([desc_signature, desc_name, "var"],
[desc_content, ()])])) [desc_content, ()])]))
assert 'var' in domain.objects assert 'var' in domain.objects
assert domain.objects['var'] == ('index', 'data') assert domain.objects['var'] == ('index', 'var', 'data')
def test_pyfunction(app): def test_pyfunction(app):
@ -421,9 +424,9 @@ def test_pyfunction(app):
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])])) [desc_content, ()])]))
assert 'func1' in domain.objects assert 'func1' in domain.objects
assert domain.objects['func1'] == ('index', 'function') assert domain.objects['func1'] == ('index', 'func1', 'function')
assert 'func2' in domain.objects assert 'func2' in domain.objects
assert domain.objects['func2'] == ('index', 'function') assert domain.objects['func2'] == ('index', 'func2', 'function')
def test_pymethod_options(app): def test_pymethod_options(app):
@ -460,61 +463,61 @@ def test_pymethod_options(app):
# method # method
assert_node(doctree[1][1][0], addnodes.index, assert_node(doctree[1][1][0], addnodes.index,
entries=[('single', 'meth1() (Class method)', 'Class.meth1', '', None)]) entries=[('single', 'meth1() (Class method)', 'class-meth1', '', None)])
assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "meth1"], assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "meth1"],
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth1' in domain.objects assert 'Class.meth1' in domain.objects
assert domain.objects['Class.meth1'] == ('index', 'method') assert domain.objects['Class.meth1'] == ('index', 'class-meth1', 'method')
# :classmethod: # :classmethod:
assert_node(doctree[1][1][2], addnodes.index, assert_node(doctree[1][1][2], addnodes.index,
entries=[('single', 'meth2() (Class class method)', 'Class.meth2', '', None)]) entries=[('single', 'meth2() (Class class method)', 'class-meth2', '', None)])
assert_node(doctree[1][1][3], ([desc_signature, ([desc_annotation, "classmethod "], assert_node(doctree[1][1][3], ([desc_signature, ([desc_annotation, "classmethod "],
[desc_name, "meth2"], [desc_name, "meth2"],
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth2' in domain.objects assert 'Class.meth2' in domain.objects
assert domain.objects['Class.meth2'] == ('index', 'method') assert domain.objects['Class.meth2'] == ('index', 'class-meth2', 'method')
# :staticmethod: # :staticmethod:
assert_node(doctree[1][1][4], addnodes.index, assert_node(doctree[1][1][4], addnodes.index,
entries=[('single', 'meth3() (Class static method)', 'Class.meth3', '', None)]) entries=[('single', 'meth3() (Class static method)', 'class-meth3', '', None)])
assert_node(doctree[1][1][5], ([desc_signature, ([desc_annotation, "static "], assert_node(doctree[1][1][5], ([desc_signature, ([desc_annotation, "static "],
[desc_name, "meth3"], [desc_name, "meth3"],
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth3' in domain.objects assert 'Class.meth3' in domain.objects
assert domain.objects['Class.meth3'] == ('index', 'method') assert domain.objects['Class.meth3'] == ('index', 'class-meth3', 'method')
# :async: # :async:
assert_node(doctree[1][1][6], addnodes.index, assert_node(doctree[1][1][6], addnodes.index,
entries=[('single', 'meth4() (Class method)', 'Class.meth4', '', None)]) entries=[('single', 'meth4() (Class method)', 'class-meth4', '', None)])
assert_node(doctree[1][1][7], ([desc_signature, ([desc_annotation, "async "], assert_node(doctree[1][1][7], ([desc_signature, ([desc_annotation, "async "],
[desc_name, "meth4"], [desc_name, "meth4"],
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth4' in domain.objects assert 'Class.meth4' in domain.objects
assert domain.objects['Class.meth4'] == ('index', 'method') assert domain.objects['Class.meth4'] == ('index', 'class-meth4', 'method')
# :property: # :property:
assert_node(doctree[1][1][8], addnodes.index, assert_node(doctree[1][1][8], addnodes.index,
entries=[('single', 'meth5() (Class property)', 'Class.meth5', '', None)]) entries=[('single', 'meth5() (Class property)', 'class-meth5', '', None)])
assert_node(doctree[1][1][9], ([desc_signature, ([desc_annotation, "property "], assert_node(doctree[1][1][9], ([desc_signature, ([desc_annotation, "property "],
[desc_name, "meth5"])], [desc_name, "meth5"])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth5' in domain.objects assert 'Class.meth5' in domain.objects
assert domain.objects['Class.meth5'] == ('index', 'method') assert domain.objects['Class.meth5'] == ('index', 'class-meth5', 'method')
# :abstractmethod: # :abstractmethod:
assert_node(doctree[1][1][10], addnodes.index, assert_node(doctree[1][1][10], addnodes.index,
entries=[('single', 'meth6() (Class method)', 'Class.meth6', '', None)]) entries=[('single', 'meth6() (Class method)', 'class-meth6', '', None)])
assert_node(doctree[1][1][11], ([desc_signature, ([desc_annotation, "abstract "], assert_node(doctree[1][1][11], ([desc_signature, ([desc_annotation, "abstract "],
[desc_name, "meth6"], [desc_name, "meth6"],
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth6' in domain.objects assert 'Class.meth6' in domain.objects
assert domain.objects['Class.meth6'] == ('index', 'method') assert domain.objects['Class.meth6'] == ('index', 'class-meth6', 'method')
def test_pyclassmethod(app): def test_pyclassmethod(app):
@ -529,13 +532,13 @@ def test_pyclassmethod(app):
[desc_content, (addnodes.index, [desc_content, (addnodes.index,
desc)])])) desc)])]))
assert_node(doctree[1][1][0], addnodes.index, assert_node(doctree[1][1][0], addnodes.index,
entries=[('single', 'meth() (Class class method)', 'Class.meth', '', None)]) entries=[('single', 'meth() (Class class method)', 'class-meth', '', None)])
assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, "classmethod "], assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, "classmethod "],
[desc_name, "meth"], [desc_name, "meth"],
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth' in domain.objects assert 'Class.meth' in domain.objects
assert domain.objects['Class.meth'] == ('index', 'method') assert domain.objects['Class.meth'] == ('index', 'class-meth', 'method')
def test_pystaticmethod(app): def test_pystaticmethod(app):
@ -550,13 +553,13 @@ def test_pystaticmethod(app):
[desc_content, (addnodes.index, [desc_content, (addnodes.index,
desc)])])) desc)])]))
assert_node(doctree[1][1][0], addnodes.index, assert_node(doctree[1][1][0], addnodes.index,
entries=[('single', 'meth() (Class static method)', 'Class.meth', '', None)]) entries=[('single', 'meth() (Class static method)', 'class-meth', '', None)])
assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, "static "], assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, "static "],
[desc_name, "meth"], [desc_name, "meth"],
[desc_parameterlist, ()])], [desc_parameterlist, ()])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.meth' in domain.objects assert 'Class.meth' in domain.objects
assert domain.objects['Class.meth'] == ('index', 'method') assert domain.objects['Class.meth'] == ('index', 'class-meth', 'method')
def test_pyattribute(app): def test_pyattribute(app):
@ -573,13 +576,13 @@ def test_pyattribute(app):
[desc_content, (addnodes.index, [desc_content, (addnodes.index,
desc)])])) desc)])]))
assert_node(doctree[1][1][0], addnodes.index, assert_node(doctree[1][1][0], addnodes.index,
entries=[('single', 'attr (Class attribute)', 'Class.attr', '', None)]) entries=[('single', 'attr (Class attribute)', 'class-attr', '', None)])
assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "attr"], assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "attr"],
[desc_annotation, ": str"], [desc_annotation, ": str"],
[desc_annotation, " = ''"])], [desc_annotation, " = ''"])],
[desc_content, ()])) [desc_content, ()]))
assert 'Class.attr' in domain.objects assert 'Class.attr' in domain.objects
assert domain.objects['Class.attr'] == ('index', 'attribute') assert domain.objects['Class.attr'] == ('index', 'class-attr', 'attribute')
@pytest.mark.sphinx(freshenv=True) @pytest.mark.sphinx(freshenv=True)

View File

@ -84,7 +84,7 @@ def test_object_inventory(app):
refs = app.env.domaindata['py']['objects'] refs = app.env.domaindata['py']['objects']
assert 'func_without_module' in refs assert 'func_without_module' in refs
assert refs['func_without_module'] == ('objects', 'function') assert refs['func_without_module'] == ('objects', 'func-without-module', 'function')
assert 'func_without_module2' in refs assert 'func_without_module2' in refs
assert 'mod.func_in_module' in refs assert 'mod.func_in_module' in refs
assert 'mod.Cls' in refs assert 'mod.Cls' in refs

View File

@ -870,7 +870,7 @@ def test_xml_refs_in_python_domain(app):
assert_elem( assert_elem(
para0[0], para0[0],
['SEE THIS DECORATOR:', 'sensitive_variables()', '.'], ['SEE THIS DECORATOR:', 'sensitive_variables()', '.'],
['sensitive.sensitive_variables']) ['sensitive-sensitive-variables'])
@sphinx_intl @sphinx_intl