summaryrefslogtreecommitdiff
path: root/sphinx/domains/python.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/domains/python.py')
-rw-r--r--sphinx/domains/python.py143
1 files changed, 71 insertions, 72 deletions
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index 427c86aa9..150067e99 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""
sphinx.domains.python
~~~~~~~~~~~~~~~~~~~~~
@@ -13,12 +12,11 @@ import re
from docutils import nodes
from docutils.parsers.rst import directives
-from six import iteritems
from sphinx import addnodes, locale
from sphinx.deprecation import DeprecatedDict, RemovedInSphinx30Warning
from sphinx.directives import ObjectDescription
-from sphinx.domains import Domain, ObjType, Index
+from sphinx.domains import Domain, ObjType, Index, IndexEntry
from sphinx.locale import _, __
from sphinx.roles import XRefRole
from sphinx.util import logging
@@ -28,10 +26,11 @@ from sphinx.util.nodes import make_refnode
if False:
# For type annotation
- from typing import Any, Dict, Iterable, Iterator, List, Tuple, Union # NOQA
+ from typing import Any, Dict, Iterable, Iterator, List, Tuple, Type, Union # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
+ from sphinx.util.typing import TextlikeNode # NOQA
logger = logging.getLogger(__name__)
@@ -54,7 +53,7 @@ pairindextypes = {
'exception': _('exception'),
'statement': _('statement'),
'builtin': _('built-in function'),
-} # Dict[unicode, unicode]
+}
locale.pairindextypes = DeprecatedDict(
pairindextypes,
@@ -65,7 +64,7 @@ locale.pairindextypes = DeprecatedDict(
def _pseudo_parse_arglist(signode, arglist):
- # type: (addnodes.desc_signature, unicode) -> None
+ # type: (addnodes.desc_signature, str) -> None
""""Parse" a list of arguments separated by commas.
Arguments can have "optional" annotations given by enclosing them in
@@ -73,7 +72,7 @@ def _pseudo_parse_arglist(signode, arglist):
string literal (e.g. default argument value).
"""
paramlist = addnodes.desc_parameterlist()
- stack = [paramlist]
+ stack = [paramlist] # type: List[nodes.Element]
try:
for argument in arglist.split(','):
argument = argument.strip()
@@ -106,26 +105,27 @@ def _pseudo_parse_arglist(signode, arglist):
# if there are too few or too many elements on the stack, just give up
# and treat the whole argument list as one argument, discarding the
# already partially populated paramlist node
- signode += addnodes.desc_parameterlist()
- signode[-1] += addnodes.desc_parameter(arglist, arglist)
+ paramlist = addnodes.desc_parameterlist()
+ paramlist += addnodes.desc_parameter(arglist, arglist)
+ signode += paramlist
else:
signode += paramlist
# This override allows our inline type specifiers to behave like :class: link
# when it comes to handling "." and "~" prefixes.
-class PyXrefMixin(object):
+class PyXrefMixin:
def make_xref(self,
- rolename, # type: unicode
- domain, # type: unicode
- target, # type: unicode
- innernode=nodes.emphasis, # type: nodes.Node
+ rolename, # type: str
+ domain, # type: str
+ target, # type: str
+ innernode=nodes.emphasis, # type: Type[TextlikeNode]
contnode=None, # type: nodes.Node
env=None, # type: BuildEnvironment
):
# type: (...) -> nodes.Node
- result = super(PyXrefMixin, self).make_xref(rolename, domain, target, # type: ignore
- innernode, contnode, env)
+ result = super().make_xref(rolename, domain, target, # type: ignore
+ innernode, contnode, env)
result['refspecific'] = True
if target.startswith(('.', '~')):
prefix, result['reftarget'] = target[0], target[1:]
@@ -139,10 +139,10 @@ class PyXrefMixin(object):
return result
def make_xrefs(self,
- rolename, # type: unicode
- domain, # type: unicode
- target, # type: unicode
- innernode=nodes.emphasis, # type: nodes.Node
+ rolename, # type: str
+ domain, # type: str
+ target, # type: str
+ innernode=nodes.emphasis, # type: Type[TextlikeNode]
contnode=None, # type: nodes.Node
env=None, # type: BuildEnvironment
):
@@ -151,7 +151,7 @@ class PyXrefMixin(object):
delims_re = re.compile(delims)
sub_targets = re.split(delims, target)
- split_contnode = bool(contnode and contnode.astext() == target)
+ split_contnode = bool(contnode and contnode.astext() == target) # type: ignore
results = []
for sub_target in filter(None, sub_targets):
@@ -170,13 +170,12 @@ class PyXrefMixin(object):
class PyField(PyXrefMixin, Field):
def make_xref(self, rolename, domain, target,
innernode=nodes.emphasis, contnode=None, env=None):
- # type: (unicode, unicode, unicode, nodes.Node, nodes.Node, BuildEnvironment) -> nodes.Node # NOQA
+ # type: (str, str, str, Type[TextlikeNode], nodes.Node, BuildEnvironment) -> nodes.Node # NOQA
if rolename == 'class' and target == 'None':
# None is not a type, so use obj role instead.
rolename = 'obj'
- return super(PyField, self).make_xref(rolename, domain, target,
- innernode, contnode, env)
+ return super().make_xref(rolename, domain, target, innernode, contnode, env)
class PyGroupedField(PyXrefMixin, GroupedField):
@@ -186,13 +185,12 @@ class PyGroupedField(PyXrefMixin, GroupedField):
class PyTypedField(PyXrefMixin, TypedField):
def make_xref(self, rolename, domain, target,
innernode=nodes.emphasis, contnode=None, env=None):
- # type: (unicode, unicode, unicode, nodes.Node, nodes.Node, BuildEnvironment) -> nodes.Node # NOQA
+ # type: (str, str, str, Type[TextlikeNode], nodes.Node, BuildEnvironment) -> nodes.Node # NOQA
if rolename == 'class' and target == 'None':
# None is not a type, so use obj role instead.
rolename = 'obj'
- return super(PyTypedField, self).make_xref(rolename, domain, target,
- innernode, contnode, env)
+ return super().make_xref(rolename, domain, target, innernode, contnode, env)
class PyObject(ObjectDescription):
@@ -230,7 +228,7 @@ class PyObject(ObjectDescription):
allow_nesting = False
def get_signature_prefix(self, sig):
- # type: (unicode) -> unicode
+ # type: (str) -> str
"""May return a prefix to put before the object name in the
signature.
"""
@@ -244,7 +242,7 @@ class PyObject(ObjectDescription):
return False
def handle_signature(self, sig, signode):
- # type: (unicode, addnodes.desc_signature) -> Tuple[unicode, unicode]
+ # type: (str, addnodes.desc_signature) -> Tuple[str, str]
"""Transform a Python signature into RST nodes.
Return (fully qualified name of the thing, classname if any).
@@ -324,12 +322,12 @@ class PyObject(ObjectDescription):
return fullname, name_prefix
def get_index_text(self, modname, name):
- # type: (unicode, unicode) -> unicode
+ # type: (str, str) -> str
"""Return the text for the index entry of the object."""
raise NotImplementedError('must be implemented in subclasses')
def add_target_and_index(self, name_cls, sig, signode):
- # type: (unicode, unicode, addnodes.desc_signature) -> None
+ # type: (str, str, addnodes.desc_signature) -> None
modname = self.options.get(
'module', self.env.ref_context.get('py:module'))
fullname = (modname and modname + '.' or '') + name_cls[0]
@@ -425,7 +423,7 @@ class PyModulelevel(PyObject):
return self.objtype == 'function'
def get_index_text(self, modname, name_cls):
- # type: (unicode, unicode) -> unicode
+ # type: (str, str) -> str
if self.objtype == 'function':
if not modname:
return _('%s() (built-in function)') % name_cls[0]
@@ -446,11 +444,11 @@ class PyClasslike(PyObject):
allow_nesting = True
def get_signature_prefix(self, sig):
- # type: (unicode) -> unicode
+ # type: (str) -> str
return self.objtype + ' '
def get_index_text(self, modname, name_cls):
- # type: (unicode, unicode) -> unicode
+ # type: (str, str) -> str
if self.objtype == 'class':
if not modname:
return _('%s (built-in class)') % name_cls[0]
@@ -471,7 +469,7 @@ class PyClassmember(PyObject):
return self.objtype.endswith('method')
def get_signature_prefix(self, sig):
- # type: (unicode) -> unicode
+ # type: (str) -> str
if self.objtype == 'staticmethod':
return 'static '
elif self.objtype == 'classmethod':
@@ -479,7 +477,7 @@ class PyClassmember(PyObject):
return ''
def get_index_text(self, modname, name_cls):
- # type: (unicode, unicode) -> unicode
+ # type: (str, str) -> str
name, cls = name_cls
add_modules = self.env.config.add_module_names
if self.objtype == 'method':
@@ -536,13 +534,13 @@ class PyClassmember(PyObject):
return ''
-class PyDecoratorMixin(object):
+class PyDecoratorMixin:
"""
Mixin for decorator directives.
"""
def handle_signature(self, sig, signode):
- # type: (unicode, addnodes.desc_signature) -> Tuple[unicode, unicode]
- ret = super(PyDecoratorMixin, self).handle_signature(sig, signode) # type: ignore
+ # type: (str, addnodes.desc_signature) -> Tuple[str, str]
+ ret = super().handle_signature(sig, signode) # type: ignore
signode.insert(0, addnodes.desc_addname('@', '@'))
return ret
@@ -559,7 +557,7 @@ class PyDecoratorFunction(PyDecoratorMixin, PyModulelevel):
# type: () -> List[nodes.Node]
# a decorator function is a function after all
self.name = 'py:function'
- return PyModulelevel.run(self)
+ return super().run()
class PyDecoratorMethod(PyDecoratorMixin, PyClassmember):
@@ -569,7 +567,7 @@ class PyDecoratorMethod(PyDecoratorMixin, PyClassmember):
def run(self):
# type: () -> List[nodes.Node]
self.name = 'py:method'
- return PyClassmember.run(self)
+ return super().run()
class PyModule(SphinxDirective):
@@ -593,7 +591,7 @@ class PyModule(SphinxDirective):
modname = self.arguments[0].strip()
noindex = 'noindex' in self.options
self.env.ref_context['py:module'] = modname
- ret = []
+ ret = [] # type: List[nodes.Node]
if not noindex:
self.env.domaindata['py']['modules'][modname] = (self.env.docname,
self.options.get('synopsis', ''),
@@ -639,7 +637,7 @@ class PyCurrentModule(SphinxDirective):
class PyXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target):
- # type: (BuildEnvironment, nodes.Node, bool, unicode, unicode) -> Tuple[unicode, unicode] # NOQA
+ # type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str]
refnode['py:module'] = env.ref_context.get('py:module')
refnode['py:class'] = env.ref_context.get('py:class')
if not has_explicit_title:
@@ -670,14 +668,14 @@ class PythonModuleIndex(Index):
shortname = _('modules')
def generate(self, docnames=None):
- # type: (Iterable[unicode]) -> Tuple[List[Tuple[unicode, List[List[Union[unicode, int]]]]], bool] # NOQA
- content = {} # type: Dict[unicode, List]
+ # type: (Iterable[str]) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]
+ content = {} # type: Dict[str, List[IndexEntry]]
# list of prefixes to ignore
- ignores = None # type: List[unicode]
+ ignores = None # type: List[str]
ignores = self.domain.env.config['modindex_common_prefix'] # type: ignore
ignores = sorted(ignores, key=len, reverse=True)
# list of all modules, sorted by module name
- modules = sorted(iteritems(self.domain.data['modules']),
+ modules = sorted(self.domain.data['modules'].items(),
key=lambda x: x[0].lower())
# sort out collapsable modules
prev_modname = ''
@@ -706,19 +704,22 @@ class PythonModuleIndex(Index):
if prev_modname == package:
# first submodule - make parent a group head
if entries:
- entries[-1][1] = 1
+ last = entries[-1]
+ entries[-1] = IndexEntry(last[0], 1, last[2], last[3],
+ last[4], last[5], last[6])
+ entries.append(IndexEntry(stripped + package, 1, '', '', '', '', ''))
elif not prev_modname.startswith(package):
# submodule without parent in list, add dummy entry
- entries.append([stripped + package, 1, '', '', '', '', ''])
+ entries.append(IndexEntry(stripped + package, 1, '', '', '', '', ''))
subtype = 2
else:
num_toplevels += 1
subtype = 0
qualifier = deprecated and _('Deprecated') or ''
- entries.append([stripped + modname, subtype, docname,
- 'module-' + stripped + modname, platforms,
- qualifier, synopsis])
+ entries.append(IndexEntry(stripped + modname, subtype, docname,
+ 'module-' + stripped + modname, platforms,
+ qualifier, synopsis))
prev_modname = modname
# apply heuristics when to collapse modindex at page load:
@@ -727,7 +728,7 @@ class PythonModuleIndex(Index):
collapse = len(modules) - num_toplevels < num_toplevels
# sort by first letter
- sorted_content = sorted(iteritems(content))
+ sorted_content = sorted(content.items())
return sorted_content, collapse
@@ -746,7 +747,7 @@ class PythonDomain(Domain):
'staticmethod': ObjType(_('static method'), 'meth', 'obj'),
'attribute': ObjType(_('attribute'), 'attr', 'obj'),
'module': ObjType(_('module'), 'mod', 'obj'),
- } # type: Dict[unicode, ObjType]
+ } # type: Dict[str, ObjType]
directives = {
'function': PyModulelevel,
@@ -776,13 +777,13 @@ class PythonDomain(Domain):
initial_data = {
'objects': {}, # fullname -> docname, objtype
'modules': {}, # modname -> docname, synopsis, platform, deprecated
- } # type: Dict[unicode, Dict[unicode, Tuple[Any]]]
+ } # type: Dict[str, Dict[str, Tuple[Any]]]
indices = [
PythonModuleIndex,
]
def clear_doc(self, docname):
- # type: (unicode) -> None
+ # type: (str) -> None
for fullname, (fn, _l) in list(self.data['objects'].items()):
if fn == docname:
del self.data['objects'][fullname]
@@ -791,7 +792,7 @@ class PythonDomain(Domain):
del self.data['modules'][modname]
def merge_domaindata(self, docnames, otherdata):
- # type: (List[unicode], Dict) -> None
+ # type: (List[str], Dict) -> None
# XXX check duplicates?
for fullname, (fn, objtype) in otherdata['objects'].items():
if fn in docnames:
@@ -801,7 +802,7 @@ class PythonDomain(Domain):
self.data['modules'][modname] = data
def find_obj(self, env, modname, classname, name, type, searchmode=0):
- # type: (BuildEnvironment, unicode, unicode, unicode, unicode, int) -> List[Tuple[unicode, Any]] # NOQA
+ # type: (BuildEnvironment, str, str, str, str, int) -> List[Tuple[str, Any]]
"""Find a Python object for "name", perhaps using the given module
and/or classname. Returns a list of (name, object entry) tuples.
"""
@@ -813,7 +814,7 @@ class PythonDomain(Domain):
return []
objects = self.data['objects']
- matches = [] # type: List[Tuple[unicode, Any]]
+ matches = [] # type: List[Tuple[str, Any]]
newname = None
if searchmode == 1:
@@ -866,7 +867,7 @@ class PythonDomain(Domain):
def resolve_xref(self, env, fromdocname, builder,
type, target, node, contnode):
- # type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA
+ # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA
modname = node.get('py:module')
clsname = node.get('py:class')
searchmode = node.hasattr('refspecific') and 1 or 0
@@ -881,18 +882,16 @@ class PythonDomain(Domain):
name, obj = matches[0]
if obj[1] == 'module':
- return self._make_module_refnode(builder, fromdocname, name,
- contnode)
+ return self._make_module_refnode(builder, fromdocname, name, contnode)
else:
- return make_refnode(builder, fromdocname, obj[0], name,
- contnode, name)
+ return make_refnode(builder, fromdocname, obj[0], name, contnode, name)
def resolve_any_xref(self, env, fromdocname, builder, target,
node, contnode):
- # type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[Tuple[unicode, nodes.Node]] # NOQA
+ # type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA
modname = node.get('py:module')
clsname = node.get('py:class')
- results = [] # type: List[Tuple[unicode, nodes.Node]]
+ results = [] # type: List[Tuple[str, nodes.Element]]
# always search in "refspecific" mode with the :any: role
matches = self.find_obj(env, modname, clsname, target, None, 1)
@@ -908,7 +907,7 @@ class PythonDomain(Domain):
return results
def _make_module_refnode(self, builder, fromdocname, name, contnode):
- # type: (Builder, unicode, unicode, nodes.Node) -> nodes.Node
+ # type: (Builder, str, str, nodes.Node) -> nodes.Element
# get additional info for modules
docname, synopsis, platform, deprecated = self.data['modules'][name]
title = name
@@ -922,15 +921,15 @@ class PythonDomain(Domain):
'module-' + name, contnode, title)
def get_objects(self):
- # type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]]
- for modname, info in iteritems(self.data['modules']):
+ # type: () -> Iterator[Tuple[str, str, str, str, str, int]]
+ for modname, info in self.data['modules'].items():
yield (modname, modname, 'module', info[0], 'module-' + modname, 0)
- for refname, (docname, type) in iteritems(self.data['objects']):
+ for refname, (docname, type) in self.data['objects'].items():
if type != 'module': # modules are already handled
yield (refname, refname, type, docname, refname, 1)
def get_full_qualified_name(self, node):
- # type: (nodes.Node) -> unicode
+ # type: (nodes.Element) -> str
modname = node.get('py:module')
clsname = node.get('py:class')
target = node.get('reftarget')
@@ -941,7 +940,7 @@ class PythonDomain(Domain):
def setup(app):
- # type: (Sphinx) -> Dict[unicode, Any]
+ # type: (Sphinx) -> Dict[str, Any]
app.add_domain(PythonDomain)
return {