Skip to content

Commit

Permalink
Fix sphinx-doc#7199: py domain: Add a new confval: python_use_unquali…
Browse files Browse the repository at this point in the history
…fied_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.
  • Loading branch information
tk0miya committed Dec 25, 2020
1 parent c58b2a1 commit e6674ec
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -13,6 +13,8 @@ Deprecated
Features added
--------------

* #7199: py domain: Add :confval:`python_use_unqualified_type_names` to suppress
the module name of the python reference if it can be resolved (experimental)
* #7199: A new node, ``sphinx.addnodes.pending_xref_condition`` has been added.
It can be used to choose appropriate content of the reference by conditions.

Expand Down
11 changes: 11 additions & 0 deletions doc/usage/configuration.rst
Expand Up @@ -2632,6 +2632,17 @@ Options for the C++ domain

.. versionadded:: 1.5

Options for the Python domain
-----------------------------

.. confval:: python_use_unqualified_type_names

If true, suppress the module name of the python reference if it can be
resolved. The default is ``False``.

.. versionadded:: 3.4

.. note:: This configuration is still in experimental

Example of configuration file
=============================
Expand Down
34 changes: 29 additions & 5 deletions sphinx/domains/python.py
Expand Up @@ -22,7 +22,7 @@
from docutils.parsers.rst import directives

from sphinx import addnodes
from sphinx.addnodes import desc_signature, pending_xref
from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
Expand All @@ -37,7 +37,7 @@
from sphinx.util.docfields import Field, GroupedField, TypedField
from sphinx.util.docutils import SphinxDirective
from sphinx.util.inspect import signature_from_str
from sphinx.util.nodes import make_id, make_refnode
from sphinx.util.nodes import find_pending_xref_condition, make_id, make_refnode
from sphinx.util.typing import TextlikeNode

if False:
Expand Down Expand Up @@ -91,7 +91,14 @@ def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xr
else:
kwargs = {}

return pending_xref('', nodes.Text(text),
if env.config.python_use_unqualified_type_names:
shortname = text.split('.')[-1]
contnodes = [pending_xref_condition('', shortname, condition='resolved'),
pending_xref_condition('', text, condition='*')] # type: List[Node]
else:
contnodes = [nodes.Text(text)]

return pending_xref('', *contnodes,
refdomain='py', reftype=reftype, reftarget=text, **kwargs)


Expand Down Expand Up @@ -1315,7 +1322,15 @@ def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder
if obj[2] == 'module':
return self._make_module_refnode(builder, fromdocname, name, contnode)
else:
return make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name)
# determine the content of the reference by conditions
content = find_pending_xref_condition(node, 'resolved')
if content:
children = content.children
else:
# if not found, use contnode
children = [contnode]

return make_refnode(builder, fromdocname, obj[0], obj[1], children, name)

def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
target: str, node: pending_xref, contnode: Element
Expand All @@ -1332,9 +1347,17 @@ def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Bui
self._make_module_refnode(builder, fromdocname,
name, contnode)))
else:
# determine the content of the reference by conditions
content = find_pending_xref_condition(node, 'resolved')
if content:
children = content.children
else:
# if not found, use contnode
children = [contnode]

results.append(('py:' + self.role_for_objtype(obj[2]),
make_refnode(builder, fromdocname, obj[0], obj[1],
contnode, name)))
children, name)))
return results

def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str,
Expand Down Expand Up @@ -1397,6 +1420,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.setup_extension('sphinx.directives')

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

Expand Down
6 changes: 3 additions & 3 deletions sphinx/util/nodes.py
Expand Up @@ -11,7 +11,7 @@
import re
import unicodedata
import warnings
from typing import Any, Callable, Iterable, List, Set, Tuple, cast
from typing import Any, Callable, Iterable, List, Set, Tuple, Union, cast

from docutils import nodes
from docutils.nodes import Element, Node
Expand Down Expand Up @@ -549,7 +549,7 @@ def find_pending_xref_condition(node: addnodes.pending_xref, condition: str) ->


def make_refnode(builder: "Builder", fromdocname: str, todocname: str, targetid: str,
child: Node, title: str = None) -> nodes.reference:
child: Union[Node, List[Node]], title: str = None) -> nodes.reference:
"""Shortcut to create a reference node."""
node = nodes.reference('', '', internal=True)
if fromdocname == todocname and targetid:
Expand All @@ -562,7 +562,7 @@ def make_refnode(builder: "Builder", fromdocname: str, todocname: str, targetid:
node['refuri'] = builder.get_relative_uri(fromdocname, todocname)
if title:
node['reftitle'] = title
node.append(child)
node += child
return node


Expand Down
@@ -0,0 +1 @@
python_use_unqualified_type_names = True
@@ -0,0 +1,8 @@
domain-py-smart_reference
=========================

.. py:class:: Name
:module: foo


.. py:function:: hello(name: foo.Name, age: foo.Age)
19 changes: 19 additions & 0 deletions tests/test_domain_py.py
Expand Up @@ -906,6 +906,25 @@ def test_noindexentry(app):
assert_node(doctree[2], addnodes.index, entries=[])


@pytest.mark.sphinx('html', testroot='domain-py-python_use_unqualified_type_names')
def test_python_python_use_unqualified_type_names(app, status, warning):
app.build()
content = (app.outdir / 'index.html').read_text()
assert ('<span class="n"><a class="reference internal" href="#foo.Name" title="foo.Name">'
'Name</a></span>' in content)
assert '<span class="n">foo.Age</span>' in content


@pytest.mark.sphinx('html', testroot='domain-py-python_use_unqualified_type_names',
confoverrides={'python_use_unqualified_type_names': False})
def test_python_python_use_unqualified_type_names_disabled(app, status, warning):
app.build()
content = (app.outdir / 'index.html').read_text()
assert ('<span class="n"><a class="reference internal" href="#foo.Name" title="foo.Name">'
'foo.Name</a></span>' in content)
assert '<span class="n">foo.Age</span>' in content


@pytest.mark.sphinx('dummy', testroot='domain-py-xref-warning')
def test_warn_missing_reference(app, status, warning):
app.build()
Expand Down

0 comments on commit e6674ec

Please sign in to comment.