diff options
Diffstat (limited to 'sphinx/domains/python.py')
-rw-r--r-- | sphinx/domains/python.py | 143 |
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 { |