Skip to content

Commit 24b6814

Browse files
committed
Fix #7199: py domain: Add a new confval: python_use_unqualified_type_names
Add a new config variable: python_use_unqualified_type_names. If enabled, it goes to suppress the module name of the python reference if it can be resolved.
1 parent d991326 commit 24b6814

File tree

7 files changed

+73
-8
lines changed

7 files changed

+73
-8
lines changed

CHANGES

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ Features added
6060
* #8924: autodoc: Support ``bound`` argument for TypeVar
6161
* #4826: py domain: Add ``:canonical:`` option to python directives to describe
6262
the location where the object is defined
63+
* #7199: py domain: Add :confval:`python_use_unqualified_type_names` to suppress
64+
the module name of the python reference if it can be resolved (experimental)
6365
* #7784: i18n: The alt text for image is translated by default (without
6466
:confval:`gettext_additional_targets` setting)
6567
* #2018: html: :confval:`html_favicon` and :confval:`html_logo` now accept URL

doc/usage/configuration.rst

+11
Original file line numberDiff line numberDiff line change
@@ -2714,6 +2714,17 @@ Options for the C++ domain
27142714

27152715
.. versionadded:: 1.5
27162716

2717+
Options for the Python domain
2718+
-----------------------------
2719+
2720+
.. confval:: python_use_unqualified_type_names
2721+
2722+
If true, suppress the module name of the python reference if it can be
2723+
resolved. The default is ``False``.
2724+
2725+
.. versionadded:: 4.0
2726+
2727+
.. note:: This configuration is still in experimental
27172728

27182729
Example of configuration file
27192730
=============================

sphinx/domains/python.py

+29-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from docutils.parsers.rst import directives
2323

2424
from sphinx import addnodes
25-
from sphinx.addnodes import desc_signature, pending_xref
25+
from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition
2626
from sphinx.application import Sphinx
2727
from sphinx.builders import Builder
2828
from sphinx.deprecation import RemovedInSphinx50Warning
@@ -37,7 +37,7 @@
3737
from sphinx.util.docfields import Field, GroupedField, TypedField
3838
from sphinx.util.docutils import SphinxDirective
3939
from sphinx.util.inspect import signature_from_str
40-
from sphinx.util.nodes import make_id, make_refnode
40+
from sphinx.util.nodes import find_pending_xref_condition, make_id, make_refnode
4141
from sphinx.util.typing import TextlikeNode
4242

4343
logger = logging.getLogger(__name__)
@@ -92,7 +92,14 @@ def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xr
9292
else:
9393
kwargs = {}
9494

95-
return pending_xref('', nodes.Text(text),
95+
if env.config.python_use_unqualified_type_names:
96+
shortname = text.split('.')[-1]
97+
contnodes = [pending_xref_condition('', shortname, condition='resolved'),
98+
pending_xref_condition('', text, condition='*')] # type: List[Node]
99+
else:
100+
contnodes = [nodes.Text(text)]
101+
102+
return pending_xref('', *contnodes,
96103
refdomain='py', reftype=reftype, reftarget=text, **kwargs)
97104

98105

@@ -1209,7 +1216,15 @@ def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder
12091216
if obj[2] == 'module':
12101217
return self._make_module_refnode(builder, fromdocname, name, contnode)
12111218
else:
1212-
return make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name)
1219+
# determine the content of the reference by conditions
1220+
content = find_pending_xref_condition(node, 'resolved')
1221+
if content:
1222+
children = content.children
1223+
else:
1224+
# if not found, use contnode
1225+
children = [contnode]
1226+
1227+
return make_refnode(builder, fromdocname, obj[0], obj[1], children, name)
12131228

12141229
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
12151230
target: str, node: pending_xref, contnode: Element
@@ -1226,9 +1241,17 @@ def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Bui
12261241
self._make_module_refnode(builder, fromdocname,
12271242
name, contnode)))
12281243
else:
1244+
# determine the content of the reference by conditions
1245+
content = find_pending_xref_condition(node, 'resolved')
1246+
if content:
1247+
children = content.children
1248+
else:
1249+
# if not found, use contnode
1250+
children = [contnode]
1251+
12291252
results.append(('py:' + self.role_for_objtype(obj[2]),
12301253
make_refnode(builder, fromdocname, obj[0], obj[1],
1231-
contnode, name)))
1254+
children, name)))
12321255
return results
12331256

12341257
def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str,
@@ -1295,6 +1318,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
12951318
app.setup_extension('sphinx.directives')
12961319

12971320
app.add_domain(PythonDomain)
1321+
app.add_config_value('python_use_unqualified_type_names', False, 'env')
12981322
app.connect('object-description-transform', filter_meta_fields)
12991323
app.connect('missing-reference', builtin_resolver, priority=900)
13001324

sphinx/util/nodes.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import re
1212
import unicodedata
13-
from typing import TYPE_CHECKING, Any, Callable, Iterable, List, Set, Tuple, Type, cast
13+
from typing import TYPE_CHECKING, Any, Callable, Iterable, List, Set, Tuple, Type, Union, cast
1414

1515
from docutils import nodes
1616
from docutils.nodes import Element, Node
@@ -542,7 +542,7 @@ def find_pending_xref_condition(node: addnodes.pending_xref, condition: str) ->
542542

543543

544544
def make_refnode(builder: "Builder", fromdocname: str, todocname: str, targetid: str,
545-
child: Node, title: str = None) -> nodes.reference:
545+
child: Union[Node, List[Node]], title: str = None) -> nodes.reference:
546546
"""Shortcut to create a reference node."""
547547
node = nodes.reference('', '', internal=True)
548548
if fromdocname == todocname and targetid:
@@ -555,7 +555,7 @@ def make_refnode(builder: "Builder", fromdocname: str, todocname: str, targetid:
555555
node['refuri'] = builder.get_relative_uri(fromdocname, todocname)
556556
if title:
557557
node['reftitle'] = title
558-
node.append(child)
558+
node += child
559559
return node
560560

561561

Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
python_use_unqualified_type_names = True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
domain-py-smart_reference
2+
=========================
3+
4+
.. py:class:: Name
5+
:module: foo
6+
7+
8+
.. py:function:: hello(name: foo.Name, age: foo.Age)

tests/test_domain_py.py

+19
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,25 @@ def test_noindexentry(app):
999999
assert_node(doctree[2], addnodes.index, entries=[])
10001000

10011001

1002+
@pytest.mark.sphinx('html', testroot='domain-py-python_use_unqualified_type_names')
1003+
def test_python_python_use_unqualified_type_names(app, status, warning):
1004+
app.build()
1005+
content = (app.outdir / 'index.html').read_text()
1006+
assert ('<span class="n"><a class="reference internal" href="#foo.Name" title="foo.Name">'
1007+
'Name</a></span>' in content)
1008+
assert '<span class="n">foo.Age</span>' in content
1009+
1010+
1011+
@pytest.mark.sphinx('html', testroot='domain-py-python_use_unqualified_type_names',
1012+
confoverrides={'python_use_unqualified_type_names': False})
1013+
def test_python_python_use_unqualified_type_names_disabled(app, status, warning):
1014+
app.build()
1015+
content = (app.outdir / 'index.html').read_text()
1016+
assert ('<span class="n"><a class="reference internal" href="#foo.Name" title="foo.Name">'
1017+
'foo.Name</a></span>' in content)
1018+
assert '<span class="n">foo.Age</span>' in content
1019+
1020+
10021021
@pytest.mark.sphinx('dummy', testroot='domain-py-xref-warning')
10031022
def test_warn_missing_reference(app, status, warning):
10041023
app.build()

0 commit comments

Comments
 (0)