From 4ab0dba7555356e9f4ff2946a6b43fe4d1c82c78 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 11 May 2021 01:06:42 +0900 Subject: [PATCH] Fix #9205: py domain: canonical option causes xref resolution error The :canonical: option causes "more than one target for cross-reference" warning because the class having the same name is registered. --- CHANGES | 2 ++ sphinx/domains/python.py | 10 +++++++--- tests/roots/test-domain-py/canonical.rst | 9 +++++++++ tests/roots/test-domain-py/index.rst | 3 +++ tests/test_domain_py.py | 11 +++++++++++ 5 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 tests/roots/test-domain-py/canonical.rst diff --git a/CHANGES b/CHANGES index ce959b3a1bd..2dfc594f701 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,8 @@ Bugs fixed autosummary_generate * #8380: html search: tags for search result are broken * #9198: i18n: Babel emits errors when running compile_catalog +* #9205: py domain: The :canonical: option causes "more than one target for + cross-reference" warning Testing -------- diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 4464895efa9..069737bde29 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -1269,9 +1269,13 @@ def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder if not matches: return None elif len(matches) > 1: - logger.warning(__('more than one target found for cross-reference %r: %s'), - target, ', '.join(match[0] for match in matches), - type='ref', subtype='python', location=node) + canonicals = [m for m in matches if not m[1].aliased] + if len(canonicals) == 1: + matches = canonicals + else: + logger.warning(__('more than one target found for cross-reference %r: %s'), + target, ', '.join(match[0] for match in matches), + type='ref', subtype='python', location=node) name, obj = matches[0] if obj[2] == 'module': diff --git a/tests/roots/test-domain-py/canonical.rst b/tests/roots/test-domain-py/canonical.rst new file mode 100644 index 00000000000..eff783aadde --- /dev/null +++ b/tests/roots/test-domain-py/canonical.rst @@ -0,0 +1,9 @@ +caninical +========= + +:py:class:`.Foo` + +.. py:module:: canonical + +.. py:class:: Foo + :canonical: original.module.Foo diff --git a/tests/roots/test-domain-py/index.rst b/tests/roots/test-domain-py/index.rst index 35a0c192787..b24bbea244a 100644 --- a/tests/roots/test-domain-py/index.rst +++ b/tests/roots/test-domain-py/index.rst @@ -5,3 +5,6 @@ test-domain-py roles module + module_option + abbr + canonical diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index e5616a6eb81..569390c403d 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -236,6 +236,17 @@ def find_obj(modname, prefix, obj_name, obj_type, searchmode=0): ('roles', 'NestedParentA.NestedChildA.subchild_1', 'method', False))]) +@pytest.mark.sphinx('html', testroot='domain-py', freshenv=True) +def test_domain_py_canonical(app, status, warning): + app.builder.build_all() + + content = (app.outdir / 'canonical.html').read_text() + assert ('' + '' + 'Foo' in content) + assert warning.getvalue() == '' + + def test_get_full_qualified_name(): env = Mock(domaindata={}) domain = PythonDomain(env)