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 Mar 5, 2021
1 parent d991326 commit 24b6814
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Features added
* #8924: autodoc: Support ``bound`` argument for TypeVar
* #4826: py domain: Add ``:canonical:`` option to python directives to describe
the location where the object is defined
* #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)
* #7784: i18n: The alt text for image is translated by default (without
:confval:`gettext_additional_targets` setting)
* #2018: html: :confval:`html_favicon` and :confval:`html_logo` now accept URL
Expand Down
11 changes: 11 additions & 0 deletions doc/usage/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2714,6 +2714,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:: 4.0

.. note:: This configuration is still in experimental

Example of configuration file
=============================
Expand Down
34 changes: 29 additions & 5 deletions sphinx/domains/python.py
Original file line number Diff line number Diff line change
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 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

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -92,7 +92,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 @@ -1209,7 +1216,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 @@ -1226,9 +1241,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 @@ -1295,6 +1318,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
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import re
import unicodedata
from typing import TYPE_CHECKING, Any, Callable, Iterable, List, Set, Tuple, Type, cast
from typing import TYPE_CHECKING, Any, Callable, Iterable, List, Set, Tuple, Type, Union, cast

from docutils import nodes
from docutils.nodes import Element, Node
Expand Down Expand Up @@ -542,7 +542,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 @@ -555,7 +555,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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python_use_unqualified_type_names = True
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,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 24b6814

Please sign in to comment.