summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2021-04-24 01:56:34 +0900
committerGitHub <noreply@github.com>2021-04-24 01:56:34 +0900
commit5e1e747e8f3ac85b27947ca92d9e796f4b489908 (patch)
treefca58ba1f8b20ee215cd15029e8965ad7df9c1ce
parentdfdc7626b5dd06bff3d326e6efddc492ef00c471 (diff)
parentd02a466cb50f059d938ea892f26bf4af1bd68d47 (diff)
downloadsphinx-git-5e1e747e8f3ac85b27947ca92d9e796f4b489908.tar.gz
Merge pull request #9128 from tk0miya/9121_duplicated_warning_for_canonical
Fix #9121: py domain: duplicated warning for canonical and alias
-rw-r--r--CHANGES2
-rw-r--r--sphinx/domains/python.py26
-rw-r--r--tests/test_domain_py.py33
3 files changed, 52 insertions, 9 deletions
diff --git a/CHANGES b/CHANGES
index 5edc80e38..71236232c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -23,6 +23,8 @@ Features added
* #9098: html: copy-range protection for doctests doesn't work in Safari
* #9103: LaTeX: imgconverter: conversion runs even if not needed
* #8127: py domain: Ellipsis in info-field-list causes nit-picky warning
+* #9121: py domain: duplicated warning is emitted when both canonical and its
+ alias objects are defined on the document
* #9023: More CSS classes on domain descriptions, see :ref:`nodes` for details.
Bugs fixed
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index dbb315e6e..fb8a4d84f 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -68,7 +68,7 @@ class ObjectEntry(NamedTuple):
docname: str
node_id: str
objtype: str
- canonical: bool
+ aliased: bool
class ModuleEntry(NamedTuple):
@@ -505,7 +505,7 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
canonical_name = self.options.get('canonical')
if canonical_name:
- domain.note_object(canonical_name, self.objtype, node_id, canonical=True,
+ domain.note_object(canonical_name, self.objtype, node_id, aliased=True,
location=signode)
if 'noindexentry' not in self.options:
@@ -1138,17 +1138,25 @@ class PythonDomain(Domain):
return self.data.setdefault('objects', {}) # fullname -> ObjectEntry
def note_object(self, name: str, objtype: str, node_id: str,
- canonical: bool = False, location: Any = None) -> None:
+ aliased: bool = False, location: Any = None) -> None:
"""Note a python object for cross reference.
.. versionadded:: 2.1
"""
if name in self.objects:
other = self.objects[name]
- logger.warning(__('duplicate object description of %s, '
- 'other instance in %s, use :noindex: for one of them'),
- name, other.docname, location=location)
- self.objects[name] = ObjectEntry(self.env.docname, node_id, objtype, canonical)
+ if other.aliased and aliased is False:
+ # The original definition found. Override it!
+ pass
+ elif other.aliased is False and aliased:
+ # The original definition is already registered.
+ return
+ else:
+ # duplicated
+ logger.warning(__('duplicate object description of %s, '
+ 'other instance in %s, use :noindex: for one of them'),
+ name, other.docname, location=location)
+ self.objects[name] = ObjectEntry(self.env.docname, node_id, objtype, aliased)
@property
def modules(self) -> Dict[str, ModuleEntry]:
@@ -1326,8 +1334,8 @@ class PythonDomain(Domain):
yield (modname, modname, 'module', mod.docname, mod.node_id, 0)
for refname, obj in self.objects.items():
if obj.objtype != 'module': # modules are already handled
- if obj.canonical:
- # canonical names are not full-text searchable.
+ if obj.aliased:
+ # aliased names are not full-text searchable.
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, -1)
else:
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, 1)
diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py
index 214cb58a0..e5616a6eb 100644
--- a/tests/test_domain_py.py
+++ b/tests/test_domain_py.py
@@ -870,6 +870,39 @@ def test_canonical(app):
assert domain.objects['_io.StringIO'] == ('index', 'io.StringIO', 'class', True)
+def test_canonical_definition_overrides(app, warning):
+ text = (".. py:class:: io.StringIO\n"
+ " :canonical: _io.StringIO\n"
+ ".. py:class:: _io.StringIO\n")
+ restructuredtext.parse(app, text)
+ assert warning.getvalue() == ""
+
+ domain = app.env.get_domain('py')
+ assert domain.objects['_io.StringIO'] == ('index', 'id0', 'class', False)
+
+
+def test_canonical_definition_skip(app, warning):
+ text = (".. py:class:: _io.StringIO\n"
+ ".. py:class:: io.StringIO\n"
+ " :canonical: _io.StringIO\n")
+
+ restructuredtext.parse(app, text)
+ assert warning.getvalue() == ""
+
+ domain = app.env.get_domain('py')
+ assert domain.objects['_io.StringIO'] == ('index', 'io.StringIO', 'class', False)
+
+
+def test_canonical_duplicated(app, warning):
+ text = (".. py:class:: mypackage.StringIO\n"
+ " :canonical: _io.StringIO\n"
+ ".. py:class:: io.StringIO\n"
+ " :canonical: _io.StringIO\n")
+
+ restructuredtext.parse(app, text)
+ assert warning.getvalue() != ""
+
+
def test_info_field_list(app):
text = (".. py:module:: example\n"
".. py:class:: Class\n"