diff options
Diffstat (limited to 'sphinx/domains/python.py')
| -rw-r--r-- | sphinx/domains/python.py | 63 |
1 files changed, 40 insertions, 23 deletions
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 7d39d80ed..d79de154e 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -20,6 +20,7 @@ from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Optional, Tu from docutils import nodes from docutils.nodes import Element, Node from docutils.parsers.rst import directives +from docutils.parsers.rst.states import Inliner from sphinx import addnodes from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition @@ -129,10 +130,14 @@ def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Nod return unparse(node.value) elif isinstance(node, ast.List): result = [addnodes.desc_sig_punctuation('', '[')] - for elem in node.elts: - result.extend(unparse(elem)) - result.append(addnodes.desc_sig_punctuation('', ', ')) - result.pop() + if node.elts: + # check if there are elements in node.elts to only pop the + # last element of result if the for-loop was run at least + # once + for elem in node.elts: + result.extend(unparse(elem)) + result.append(addnodes.desc_sig_punctuation('', ', ')) + result.pop() result.append(addnodes.desc_sig_punctuation('', ']')) return result elif isinstance(node, ast.Module): @@ -284,9 +289,13 @@ def _pseudo_parse_arglist(signode: desc_signature, arglist: str) -> None: class PyXrefMixin: def make_xref(self, rolename: str, domain: str, target: str, innernode: Type[TextlikeNode] = nodes.emphasis, - contnode: Node = None, env: BuildEnvironment = None) -> Node: + contnode: Node = None, env: BuildEnvironment = None, + inliner: Inliner = None, location: Node = None) -> Node: + # we use inliner=None to make sure we get the old behaviour with a single + # pending_xref node result = super().make_xref(rolename, domain, target, # type: ignore - innernode, contnode, env) + innernode, contnode, + env, inliner=None, location=None) result['refspecific'] = True result['py:module'] = env.ref_context.get('py:module') result['py:class'] = env.ref_context.get('py:class') @@ -299,12 +308,23 @@ class PyXrefMixin: for node in result.traverse(nodes.Text): node.parent[node.parent.index(node)] = nodes.Text(text) break + elif isinstance(result, pending_xref) and env.config.python_use_unqualified_type_names: + children = result.children + result.clear() + + shortname = target.split('.')[-1] + textnode = innernode('', shortname) + contnodes = [pending_xref_condition('', '', textnode, condition='resolved'), + pending_xref_condition('', '', *children, condition='*')] + result.extend(contnodes) + return result def make_xrefs(self, rolename: str, domain: str, target: str, innernode: Type[TextlikeNode] = nodes.emphasis, - contnode: Node = None, env: BuildEnvironment = None) -> List[Node]: - delims = r'(\s*[\[\]\(\),](?:\s*or\s)?\s*|\s+or\s+|\.\.\.)' + contnode: Node = None, env: BuildEnvironment = None, + inliner: Inliner = None, location: Node = None) -> List[Node]: + delims = r'(\s*[\[\]\(\),](?:\s*or\s)?\s*|\s+or\s+|\s*\|\s*|\.\.\.)' delims_re = re.compile(delims) sub_targets = re.split(delims, target) @@ -319,7 +339,7 @@ class PyXrefMixin: results.append(contnode or innernode(sub_target, sub_target)) else: results.append(self.make_xref(rolename, domain, sub_target, - innernode, contnode, env)) + innernode, contnode, env, inliner, location)) return results @@ -327,12 +347,14 @@ class PyXrefMixin: class PyField(PyXrefMixin, Field): def make_xref(self, rolename: str, domain: str, target: str, innernode: Type[TextlikeNode] = nodes.emphasis, - contnode: Node = None, env: BuildEnvironment = None) -> Node: + contnode: Node = None, env: BuildEnvironment = None, + inliner: Inliner = None, location: Node = None) -> Node: if rolename == 'class' and target == 'None': # None is not a type, so use obj role instead. rolename = 'obj' - return super().make_xref(rolename, domain, target, innernode, contnode, env) + return super().make_xref(rolename, domain, target, innernode, contnode, + env, inliner, location) class PyGroupedField(PyXrefMixin, GroupedField): @@ -342,12 +364,14 @@ class PyGroupedField(PyXrefMixin, GroupedField): class PyTypedField(PyXrefMixin, TypedField): def make_xref(self, rolename: str, domain: str, target: str, innernode: Type[TextlikeNode] = nodes.emphasis, - contnode: Node = None, env: BuildEnvironment = None) -> Node: + contnode: Node = None, env: BuildEnvironment = None, + inliner: Inliner = None, location: Node = None) -> Node: if rolename == 'class' and target == 'None': # None is not a type, so use obj role instead. rolename = 'obj' - return super().make_xref(rolename, domain, target, innernode, contnode, env) + return super().make_xref(rolename, domain, target, innernode, contnode, + env, inliner, location) class PyObject(ObjectDescription[Tuple[str, str]]): @@ -448,12 +472,9 @@ class PyObject(ObjectDescription[Tuple[str, str]]): if prefix: signode += addnodes.desc_addname(prefix, prefix) - elif add_module and self.env.config.add_module_names: - if modname and modname != 'exceptions': - # exceptions are a special case, since they are documented in the - # 'exceptions' module. - nodetext = modname + '.' - signode += addnodes.desc_addname(nodetext, nodetext) + elif modname and add_module and self.env.config.add_module_names: + nodetext = modname + '.' + signode += addnodes.desc_addname(nodetext, nodetext) signode += addnodes.desc_name(name, name) if arglist: @@ -1363,10 +1384,6 @@ def builtin_resolver(app: Sphinx, env: BuildEnvironment, return s in typing.__all__ # type: ignore - content = find_pending_xref_condition(node, 'resolved') - if content: - contnode = content.children[0] # type: ignore - if node.get('refdomain') != 'py': return None elif node.get('reftype') in ('class', 'obj') and node.get('reftarget') == 'None': |
