From 0ddccf3ee04694a06660b95b7d34ac0c7d6e7197 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 28 Nov 2021 14:46:34 +0900 Subject: [PATCH] Fix #9899: py domain: Allows cross-reference specifier to :type: option --- CHANGES | 2 ++ sphinx/domains/python.py | 18 +++++++++++++++--- tests/test_domain_py.py | 23 +++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 87cc9ab823..cd8f83ac4d 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,8 @@ Features added ``__all__`` attribute if :confval:`autosummary_ignore_module_all` is set to ``False``. The default behaviour is unchanged. Autogen also now supports this behavior with the ``--respect-module-all`` switch. +* #9899: py domain: Allows to specify cross-reference specifier (``.`` and + ``~``) as ``:type:`` option Bugs fixed ---------- diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index b932a9ea5c..bcf312d7e8 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -80,9 +80,9 @@ class ModuleEntry(NamedTuple): deprecated: bool -def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xref: +def type_to_xref(target: str, env: BuildEnvironment = None) -> addnodes.pending_xref: """Convert a type string to a cross reference node.""" - if text == 'None': + if target == 'None': reftype = 'obj' else: reftype = 'class' @@ -93,6 +93,17 @@ def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xr else: kwargs = {} + refspecific = False + if target.startswith('.'): + target = target[1:] + text = target + refspecific = True + elif target.startswith('~'): + target = target[1:] + text = target.split('.')[-1] + else: + text = target + if env.config.python_use_unqualified_type_names: # Note: It would be better to use qualname to describe the object to support support # nested classes. But python domain can't access the real python object because this @@ -104,7 +115,8 @@ def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xr contnodes = [nodes.Text(text)] return pending_xref('', *contnodes, - refdomain='py', reftype=reftype, reftarget=text, **kwargs) + refdomain='py', reftype=reftype, reftarget=target, + refspecific=refspecific, **kwargs) def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Node]: diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index e34218dfa4..842a0eb63b 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -1170,6 +1170,29 @@ def test_info_field_list_var(app): refdomain="py", reftype="class", reftarget="int", **{"py:class": "Class"}) +def test_type_field(app): + text = (".. py:data:: var1\n" + " :type: .int\n" + ".. py:data:: var2\n" + " :type: ~builtins.int\n") + domain = app.env.get_domain('py') + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, + [desc, ([desc_signature, ([desc_name, "var1"], + [desc_annotation, ([desc_sig_punctuation, ':'], + desc_sig_space, + [pending_xref, "int"])])], + [desc_content, ()])], + addnodes.index, + [desc, ([desc_signature, ([desc_name, "var2"], + [desc_annotation, ([desc_sig_punctuation, ':'], + desc_sig_space, + [pending_xref, "int"])])], + [desc_content, ()])])) + assert_node(doctree[1][0][1][2], pending_xref, reftarget='int', refspecific=True) + assert_node(doctree[3][0][1][2], pending_xref, reftarget='builtins.int', refspecific=False) + + @pytest.mark.sphinx(freshenv=True) def test_module_index(app): text = (".. py:module:: docutils\n"