From 116d3fba119836fd478376d6cffe2884789fc701 Mon Sep 17 00:00:00 2001 From: Viktor Haag Date: Fri, 28 Jun 2019 14:48:58 -0400 Subject: [PATCH 01/11] Force last update datetime value to always be UTC - If SOURCE_DATE_EPOCH is set in the environment, then the build date will use UTC as the timezone. - If it's not set in the environment, we should do the same thing and use UTC as the timezone for the build date. - `datetime.now()` produces a naive system-time datetime object; `datetime.utcnow()` produces the aware, UTC-oriented datetime object. --- sphinx/util/i18n.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index 8638d4058..1e721da4e 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -286,7 +286,7 @@ def format_date(format, date=None, language=None): if source_date_epoch is not None: date = datetime.utcfromtimestamp(float(source_date_epoch)) else: - date = datetime.now() + date = datetime.utcnow() result = [] tokens = date_format_re.split(format) From 828beb12e06dee86f478a31c5d1cb091ed2e224e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 29 Jun 2019 18:43:30 +0900 Subject: [PATCH 02/11] doc: Update document for :annotation: option (refs: #6495) --- doc/usage/extensions/autodoc.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/usage/extensions/autodoc.rst b/doc/usage/extensions/autodoc.rst index 8fdee214b..74c0b609d 100644 --- a/doc/usage/extensions/autodoc.rst +++ b/doc/usage/extensions/autodoc.rst @@ -243,21 +243,23 @@ inserting them into the page source under a suitable :rst:dir:`py:module`, These work exactly like :rst:dir:`autoclass` etc., but do not offer the options used for automatic member documentation. - :rst:dir:`autodata` and :rst:dir:`autoattribute` support - the ``annotation`` option. - Without this option, the representation of the object - will be shown in the documentation. - When the option is given without arguments, - only the name of the object will be printed:: + :rst:dir:`autodata` and :rst:dir:`autoattribute` support the ``annotation`` + option. The option controls how the value of variable is shown. If specified + without arguments, only the name of the variable will be printed, and its value + is not shown:: .. autodata:: CD_DRIVE :annotation: - You can tell sphinx what should be printed after the name:: + If the option specified with arguments, it is printed after the name as a value + of the variable:: .. autodata:: CD_DRIVE :annotation: = your CD device name + By default, without ``annotation`` option, Sphinx tries to obtain the value of + the variable and print it after the name. + For module data members and class attributes, documentation can either be put into a comment with special formatting (using a ``#:`` to start the comment instead of just ``#``), or in a docstring *after* the definition. Comments From 320661ee945bb74ce1433f710f5da6728416bd2b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 10 Jun 2019 23:13:08 +0900 Subject: [PATCH 03/11] Migrate to py3 style type annotation: sphinx.domains.citation --- sphinx/domains/citation.py | 62 +++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/sphinx/domains/citation.py b/sphinx/domains/citation.py index 2bb49def9..0b512c365 100644 --- a/sphinx/domains/citation.py +++ b/sphinx/domains/citation.py @@ -8,11 +8,13 @@ :license: BSD, see LICENSE for details. """ +from typing import Any, Dict, List, Set, Tuple from typing import cast from docutils import nodes +from docutils.nodes import Element -from sphinx import addnodes +from sphinx.addnodes import pending_xref from sphinx.domains import Domain from sphinx.locale import __ from sphinx.transforms import SphinxTransform @@ -21,10 +23,10 @@ from sphinx.util.nodes import copy_source_info, make_refnode if False: # For type annotation - from typing import Any, Dict, List, Set, Tuple, Union # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA + from sphinx.application import Sphinx + from sphinx.builders import Builder + from sphinx.environment import BuildEnvironment + logger = logging.getLogger(__name__) @@ -40,17 +42,14 @@ class CitationDomain(Domain): } @property - def citations(self): - # type: () -> Dict[str, Tuple[str, str, int]] + def citations(self) -> Dict[str, Tuple[str, str, int]]: return self.data.setdefault('citations', {}) @property - def citation_refs(self): - # type: () -> Dict[str, Set[str]] + def citation_refs(self) -> Dict[str, Set[str]]: return self.data.setdefault('citation_refs', {}) - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: for key, (fn, _l, lineno) in list(self.citations.items()): if fn == docname: del self.citations[key] @@ -60,8 +59,7 @@ class CitationDomain(Domain): elif docname in docnames: docnames.remove(docname) - def merge_domaindata(self, docnames, otherdata): - # type: (List[str], Dict) -> None + def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: # XXX duplicates? for key, data in otherdata['citations'].items(): if data[0] in docnames: @@ -72,8 +70,7 @@ class CitationDomain(Domain): if docname in docnames: citation_refs.add(docname) - def note_citation(self, node): - # type: (nodes.citation) -> None + def note_citation(self, node: nodes.citation) -> None: label = node[0].astext() if label in self.citations: path = self.env.doc2path(self.citations[label][0]) @@ -81,20 +78,19 @@ class CitationDomain(Domain): location=node, type='ref', subtype='citation') self.citations[label] = (node['docname'], node['ids'][0], node.line) - def note_citation_reference(self, node): - # type: (addnodes.pending_xref) -> None + def note_citation_reference(self, node: pending_xref) -> None: docnames = self.citation_refs.setdefault(node['reftarget'], set()) docnames.add(self.env.docname) - def check_consistency(self): - # type: () -> None + def check_consistency(self) -> None: for name, (docname, labelid, lineno) in self.citations.items(): if name not in self.citation_refs: logger.warning(__('Citation [%s] is not referenced.'), name, type='ref', subtype='citation', location=(docname, lineno)) - def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def resolve_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder", + typ: str, target: str, node: pending_xref, contnode: Element + ) -> Element: docname, labelid, lineno = self.citations.get(target, ('', '', 0)) if not docname: return None @@ -102,8 +98,9 @@ class CitationDomain(Domain): return make_refnode(builder, fromdocname, docname, labelid, contnode) - def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA + def resolve_any_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder", + target: str, node: pending_xref, contnode: Element + ) -> List[Tuple[str, Element]]: refnode = self.resolve_xref(env, fromdocname, builder, 'ref', target, node, contnode) if refnode is None: return [] @@ -115,8 +112,7 @@ class CitationDefinitionTransform(SphinxTransform): """Mark citation definition labels as not smartquoted.""" default_priority = 619 - def apply(self, **kwargs): - # type: (Any) -> None + def apply(self, **kwargs) -> None: domain = cast(CitationDomain, self.env.get_domain('citation')) for node in self.document.traverse(nodes.citation): # register citation node to domain @@ -135,16 +131,15 @@ class CitationReferenceTransform(SphinxTransform): """ default_priority = 619 - def apply(self, **kwargs): - # type: (Any) -> None + def apply(self, **kwargs) -> None: domain = cast(CitationDomain, self.env.get_domain('citation')) for node in self.document.traverse(nodes.citation_reference): target = node.astext() - ref = addnodes.pending_xref(target, refdomain='citation', reftype='ref', - reftarget=target, refwarn=True, - support_smartquotes=False, - ids=node["ids"], - classes=node.get('classes', [])) + ref = pending_xref(target, refdomain='citation', reftype='ref', + reftarget=target, refwarn=True, + support_smartquotes=False, + ids=node["ids"], + classes=node.get('classes', [])) ref += nodes.inline(target, '[%s]' % target) copy_source_info(node, ref) node.replace_self(ref) @@ -153,8 +148,7 @@ class CitationReferenceTransform(SphinxTransform): domain.note_citation_reference(ref) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: "Sphinx") -> Dict[str, Any]: app.add_domain(CitationDomain) app.add_transform(CitationDefinitionTransform) app.add_transform(CitationReferenceTransform) From 62e5f6935b85db66113c23491a3cf261d7af4ef4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 4 Jun 2019 12:07:35 +0900 Subject: [PATCH 04/11] Migrate to py3 style type annotation: sphinx.domains.std --- sphinx/domains/std.py | 185 ++++++++++++++++++------------------------ 1 file changed, 81 insertions(+), 104 deletions(-) diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index 45516ebd9..971589367 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -12,13 +12,16 @@ import re import unicodedata import warnings from copy import copy +from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Type, Union from typing import cast from docutils import nodes -from docutils.parsers.rst import directives +from docutils.nodes import Element, Node, system_message +from docutils.parsers.rst import Directive, directives from docutils.statemachine import StringList from sphinx import addnodes +from sphinx.addnodes import desc_signature, pending_xref from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType @@ -28,15 +31,13 @@ from sphinx.roles import XRefRole from sphinx.util import ws_re, logging, docname_join from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import clean_astext, make_refnode +from sphinx.util.typing import RoleFunction if False: # For type annotation - from typing import Any, Callable, Dict, Iterable, Iterator, List, Tuple, Type, Union # NOQA - from docutils.parsers.rst import Directive # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA - from sphinx.util.typing import RoleFunction # NOQA + from sphinx.application import Sphinx + from sphinx.builders import Builder + from sphinx.environment import BuildEnvironment logger = logging.getLogger(__name__) @@ -52,10 +53,9 @@ class GenericObject(ObjectDescription): A generic x-ref directive registered with Sphinx.add_object_type(). """ indextemplate = '' - parse_node = None # type: Callable[[GenericObject, BuildEnvironment, str, addnodes.desc_signature], str] # NOQA + parse_node = None # type: Callable[[GenericObject, BuildEnvironment, str, desc_signature], str] # NOQA - def handle_signature(self, sig, signode): - # type: (str, addnodes.desc_signature) -> str + def handle_signature(self, sig: str, signode: desc_signature) -> str: if self.parse_node: name = self.parse_node(self.env, sig, signode) else: @@ -65,8 +65,7 @@ class GenericObject(ObjectDescription): name = ws_re.sub('', sig) return name - def add_target_and_index(self, name, sig, signode): - # type: (str, str, addnodes.desc_signature) -> None + def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None: targetname = '%s-%s' % (self.objtype, name) signode['ids'].append(targetname) self.state.document.note_explicit_target(signode) @@ -94,8 +93,8 @@ class EnvVarXRefRole(XRefRole): Cross-referencing role for environment variables (adds an index entry). """ - def result_nodes(self, document, env, node, is_ref): - # type: (nodes.document, BuildEnvironment, nodes.Element, bool) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA + def result_nodes(self, document: nodes.document, env: "BuildEnvironment", node: Element, + is_ref: bool) -> Tuple[List[Node], List[system_message]]: if not is_ref: return [node], [] varname = node['reftarget'] @@ -122,8 +121,7 @@ class Target(SphinxDirective): final_argument_whitespace = True option_spec = {} # type: Dict - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: # normalize whitespace in fullname like XRefRole does fullname = ws_re.sub(' ', self.arguments[0].strip()) targetname = '%s-%s' % (self.name, fullname) @@ -155,8 +153,7 @@ class Cmdoption(ObjectDescription): Description of a command-line option (.. option). """ - def handle_signature(self, sig, signode): - # type: (str, addnodes.desc_signature) -> str + def handle_signature(self, sig: str, signode: desc_signature) -> str: """Transform an option description into RST nodes.""" count = 0 firstname = '' @@ -184,8 +181,7 @@ class Cmdoption(ObjectDescription): raise ValueError return firstname - def add_target_and_index(self, firstname, sig, signode): - # type: (str, str, addnodes.desc_signature) -> None + def add_target_and_index(self, firstname: str, sig: str, signode: desc_signature) -> None: currprogram = self.env.ref_context.get('std:program') for optname in signode.get('allnames', []): targetname = optname.replace('/', '-') @@ -221,8 +217,7 @@ class Program(SphinxDirective): final_argument_whitespace = True option_spec = {} # type: Dict - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: program = ws_re.sub('-', self.arguments[0].strip()) if program == 'None': self.env.ref_context.pop('std:program', None) @@ -232,21 +227,20 @@ class Program(SphinxDirective): class OptionXRefRole(XRefRole): - def process_link(self, env, refnode, has_explicit_title, title, target): - # type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str] + def process_link(self, env: "BuildEnvironment", refnode: Element, has_explicit_title: bool, + title: str, target: str) -> Tuple[str, str]: refnode['std:program'] = env.ref_context.get('std:program') return title, target -def split_term_classifiers(line): - # type: (str) -> List[Union[str, None]] +def split_term_classifiers(line: str) -> List[Optional[str]]: # split line into a term and classifiers. if no classifier, None is used.. parts = re.split(' +: +', line) + [None] return parts -def make_glossary_term(env, textnodes, index_key, source, lineno, new_id=None): - # type: (BuildEnvironment, Iterable[nodes.Node], str, str, int, str) -> nodes.term +def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index_key: str, + source: str, lineno: int, new_id: str = None) -> nodes.term: # get a text-only representation of the term and register it # as a cross-reference target term = nodes.term('', '', *textnodes) @@ -292,8 +286,7 @@ class Glossary(SphinxDirective): 'sorted': directives.flag, } - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: node = addnodes.glossary() node.document = self.state.document @@ -399,16 +392,15 @@ class Glossary(SphinxDirective): return messages + [node] -def token_xrefs(text): - # type: (str) -> List[nodes.Node] +def token_xrefs(text: str) -> List[Node]: retnodes = [] # type: List[nodes.Node] pos = 0 for m in token_re.finditer(text): if m.start() > pos: txt = text[pos:m.start()] retnodes.append(nodes.Text(txt, txt)) - refnode = addnodes.pending_xref( - m.group(1), reftype='token', refdomain='std', reftarget=m.group(1)) + refnode = pending_xref(m.group(1), reftype='token', refdomain='std', + reftarget=m.group(1)) refnode += nodes.literal(m.group(1), m.group(1), classes=['xref']) retnodes.append(refnode) pos = m.end() @@ -428,8 +420,7 @@ class ProductionList(SphinxDirective): final_argument_whitespace = True option_spec = {} # type: Dict - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: domain = cast(StandardDomain, self.env.get_domain('std')) node = addnodes.productionlist() # type: nodes.Element i = 0 @@ -534,8 +525,7 @@ class StandardDomain(Domain): nodes.container: ('code-block', None), } # type: Dict[Type[nodes.Node], Tuple[str, Callable]] - def __init__(self, env): - # type: (BuildEnvironment) -> None + def __init__(self, env: "BuildEnvironment") -> None: super().__init__(env) # set up enumerable nodes @@ -544,27 +534,22 @@ class StandardDomain(Domain): self.enumerable_nodes[node] = settings @property - def objects(self): - # type: () -> Dict[Tuple[str, str], Tuple[str, str]] + def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]: return self.data.setdefault('objects', {}) # (objtype, name) -> docname, labelid @property - def progoptions(self): - # type: () -> Dict[Tuple[str, str], Tuple[str, str]] + def progoptions(self) -> Dict[Tuple[str, str], Tuple[str, str]]: return self.data.setdefault('progoptions', {}) # (program, name) -> docname, labelid @property - def labels(self): - # type: () -> Dict[str, Tuple[str, str, str]] + def labels(self) -> Dict[str, Tuple[str, str, str]]: return self.data.setdefault('labels', {}) # labelname -> docname, labelid, sectionname @property - def anonlabels(self): - # type: () -> Dict[str, Tuple[str, str]] + def anonlabels(self) -> Dict[str, Tuple[str, str]]: return self.data.setdefault('anonlabels', {}) # labelname -> docname, labelid - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: key = None # type: Any for key, (fn, _l) in list(self.progoptions.items()): if fn == docname: @@ -579,8 +564,7 @@ class StandardDomain(Domain): if fn == docname: del self.anonlabels[key] - def merge_domaindata(self, docnames, otherdata): - # type: (List[str], Dict) -> None + def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: # XXX duplicates? for key, data in otherdata['progoptions'].items(): if data[0] in docnames: @@ -595,8 +579,7 @@ class StandardDomain(Domain): if data[0] in docnames: self.anonlabels[key] = data - def process_doc(self, env, docname, document): - # type: (BuildEnvironment, str, nodes.document) -> None + def process_doc(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA for name, explicit in document.nametypes.items(): if not explicit: continue @@ -637,17 +620,15 @@ class StandardDomain(Domain): continue self.labels[name] = docname, labelid, sectname - def add_object(self, objtype, name, docname, labelid): - # type: (str, str, str, str) -> None + def add_object(self, objtype: str, name: str, docname: str, labelid: str) -> None: self.objects[objtype, name] = (docname, labelid) - def add_program_option(self, program, name, docname, labelid): - # type: (str, str, str, str) -> None + def add_program_option(self, program: str, name: str, docname: str, labelid: str) -> None: self.progoptions[program, name] = (docname, labelid) - def build_reference_node(self, fromdocname, builder, docname, labelid, - sectname, rolename, **options): - # type: (str, Builder, str, str, str, str, Any) -> nodes.Element + def build_reference_node(self, fromdocname: str, builder: "Builder", docname: str, + labelid: str, sectname: str, rolename: str, **options + ) -> Element: nodeclass = options.pop('nodeclass', nodes.reference) newnode = nodeclass('', '', internal=True, **options) innernode = nodes.inline(sectname, sectname) @@ -660,7 +641,7 @@ class StandardDomain(Domain): # set more info in contnode; in case the # get_relative_uri call raises NoUri, # the builder will then have to resolve these - contnode = addnodes.pending_xref('') + contnode = pending_xref('') contnode['refdocname'] = docname contnode['refsectname'] = sectname newnode['refuri'] = builder.get_relative_uri( @@ -670,8 +651,8 @@ class StandardDomain(Domain): newnode.append(innernode) return newnode - def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def resolve_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder", + typ: str, target: str, node: pending_xref, contnode: Element) -> Element: if typ == 'ref': resolver = self._resolve_ref_xref elif typ == 'numref': @@ -692,8 +673,9 @@ class StandardDomain(Domain): return resolver(env, fromdocname, builder, typ, target, node, contnode) - def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def _resolve_ref_xref(self, env: "BuildEnvironment", fromdocname: str, + builder: "Builder", typ: str, target: str, node: pending_xref, + contnode: Element) -> Element: if node['refexplicit']: # reference to anonymous label; the reference uses # the supplied link caption @@ -709,8 +691,9 @@ class StandardDomain(Domain): return self.build_reference_node(fromdocname, builder, docname, labelid, sectname, 'ref') - def _resolve_numref_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def _resolve_numref_xref(self, env: "BuildEnvironment", fromdocname: str, + builder: "Builder", typ: str, target: str, + node: pending_xref, contnode: Element) -> Element: if target in self.labels: docname, labelid, figname = self.labels.get(target, ('', '', '')) else: @@ -770,8 +753,9 @@ class StandardDomain(Domain): nodeclass=addnodes.number_reference, title=title) - def _resolve_keyword_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def _resolve_keyword_xref(self, env: "BuildEnvironment", fromdocname: str, + builder: "Builder", typ: str, target: str, + node: pending_xref, contnode: Element) -> Element: # keywords are oddballs: they are referenced by named labels docname, labelid, _ = self.labels.get(target, ('', '', '')) if not docname: @@ -779,8 +763,9 @@ class StandardDomain(Domain): return make_refnode(builder, fromdocname, docname, labelid, contnode) - def _resolve_doc_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def _resolve_doc_xref(self, env: "BuildEnvironment", fromdocname: str, + builder: "Builder", typ: str, target: str, + node: pending_xref, contnode: Element) -> Element: # directly reference to document by source name; can be absolute or relative refdoc = node.get('refdoc', fromdocname) docname = docname_join(refdoc, node['reftarget']) @@ -795,8 +780,9 @@ class StandardDomain(Domain): innernode = nodes.inline(caption, caption, classes=['doc']) return make_refnode(builder, fromdocname, docname, None, innernode) - def _resolve_option_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def _resolve_option_xref(self, env: "BuildEnvironment", fromdocname: str, + builder: "Builder", typ: str, target: str, + node: pending_xref, contnode: Element) -> Element: progname = node.get('std:program') target = target.strip() docname, labelid = self.progoptions.get((progname, target), ('', '')) @@ -816,8 +802,9 @@ class StandardDomain(Domain): return make_refnode(builder, fromdocname, docname, labelid, contnode) - def _resolve_citation_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def _resolve_citation_xref(self, env: "BuildEnvironment", fromdocname: str, + builder: "Builder", typ: str, target: str, + node: pending_xref, contnode: Element) -> Element: warnings.warn('StandardDomain._resolve_citation_xref() is deprecated.', RemovedInSphinx30Warning) docname, labelid, lineno = self.data['citations'].get(target, ('', '', 0)) @@ -839,8 +826,9 @@ class StandardDomain(Domain): del node['ids'][:] raise - def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def _resolve_obj_xref(self, env: "BuildEnvironment", fromdocname: str, + builder: "Builder", typ: str, target: str, + node: pending_xref, contnode: Element) -> Element: objtypes = self.objtypes_for_role(typ) or [] for objtype in objtypes: if (objtype, target) in self.objects: @@ -853,8 +841,9 @@ class StandardDomain(Domain): return make_refnode(builder, fromdocname, docname, labelid, contnode) - def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA + def resolve_any_xref(self, env: "BuildEnvironment", fromdocname: str, + builder: "Builder", target: str, node: pending_xref, + contnode: Element) -> List[Tuple[str, Element]]: results = [] # type: List[Tuple[str, nodes.Element]] ltarget = target.lower() # :ref: lowercases its target automatically for role in ('ref', 'option'): # do not try "keyword" @@ -875,8 +864,7 @@ class StandardDomain(Domain): labelid, contnode))) return results - def get_objects(self): - # type: () -> Iterator[Tuple[str, str, str, str, str, int]] + def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]: # handle the special 'doc' reference here for doc in self.env.all_docs: yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1) @@ -897,17 +885,14 @@ class StandardDomain(Domain): if name not in non_anon_labels: yield (name, name, 'label', docname, labelid, -1) - def get_type_name(self, type, primary=False): - # type: (ObjType, bool) -> str + def get_type_name(self, type: ObjType, primary: bool = False) -> str: # never prepend "Default" return type.lname - def is_enumerable_node(self, node): - # type: (nodes.Node) -> bool + def is_enumerable_node(self, node: Node) -> bool: return node.__class__ in self.enumerable_nodes - def get_numfig_title(self, node): - # type: (nodes.Node) -> str + def get_numfig_title(self, node: Node) -> str: """Get the title of enumerable nodes to refer them using its title""" if self.is_enumerable_node(node): elem = cast(nodes.Element, node) @@ -921,11 +906,9 @@ class StandardDomain(Domain): return None - def get_enumerable_node_type(self, node): - # type: (nodes.Node) -> str + def get_enumerable_node_type(self, node: Node) -> str: """Get type of enumerable nodes.""" - def has_child(node, cls): - # type: (nodes.Element, Type) -> bool + def has_child(node: Element, cls: Type) -> bool: return any(isinstance(child, cls) for child in node) if isinstance(node, nodes.section): @@ -939,8 +922,7 @@ class StandardDomain(Domain): figtype, _ = self.enumerable_nodes.get(node.__class__, (None, None)) return figtype - def get_figtype(self, node): - # type: (nodes.Node) -> str + def get_figtype(self, node: Node) -> str: """Get figure type of nodes. .. deprecated:: 1.8 @@ -950,8 +932,8 @@ class StandardDomain(Domain): RemovedInSphinx30Warning, stacklevel=2) return self.get_enumerable_node_type(node) - def get_fignumber(self, env, builder, figtype, docname, target_node): - # type: (BuildEnvironment, Builder, str, str, nodes.Element) -> Tuple[int, ...] + def get_fignumber(self, env: "BuildEnvironment", builder: "Builder", + figtype: str, docname: str, target_node: Element) -> Tuple[int, ...]: if figtype == 'section': if builder.name == 'latex': return tuple() @@ -973,8 +955,7 @@ class StandardDomain(Domain): # Maybe it is defined in orphaned document. raise ValueError - def get_full_qualified_name(self, node): - # type: (nodes.Element) -> str + def get_full_qualified_name(self, node: Element) -> str: if node.get('reftype') == 'option': progname = node.get('std:program') command = ws_re.split(node.get('reftarget')) @@ -988,24 +969,20 @@ class StandardDomain(Domain): else: return None - def note_citations(self, env, docname, document): - # type: (BuildEnvironment, str, nodes.document) -> None + def note_citations(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA warnings.warn('StandardDomain.note_citations() is deprecated.', RemovedInSphinx40Warning) - def note_citation_refs(self, env, docname, document): - # type: (BuildEnvironment, str, nodes.document) -> None + def note_citation_refs(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA warnings.warn('StandardDomain.note_citation_refs() is deprecated.', RemovedInSphinx40Warning) - def note_labels(self, env, docname, document): - # type: (BuildEnvironment, str, nodes.document) -> None + def note_labels(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA warnings.warn('StandardDomain.note_labels() is deprecated.', RemovedInSphinx40Warning) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: "Sphinx") -> Dict[str, Any]: app.add_domain(StandardDomain) return { From 6c47f7d4a2ff5cbd26d632e2dfc5e426f6500341 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 4 Jun 2019 12:25:31 +0900 Subject: [PATCH 05/11] Migrate to py3 style type annotation: sphinx.domains.changeset --- sphinx/domains/changeset.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/sphinx/domains/changeset.py b/sphinx/domains/changeset.py index aeea645c1..8ff9e90fc 100644 --- a/sphinx/domains/changeset.py +++ b/sphinx/domains/changeset.py @@ -9,9 +9,11 @@ """ from collections import namedtuple +from typing import Any, Dict, List from typing import cast from docutils import nodes +from docutils.nodes import Node from sphinx import addnodes from sphinx import locale @@ -23,9 +25,8 @@ from sphinx.util.docutils import SphinxDirective if False: # For type annotation - from typing import Any, Dict, List # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA + from sphinx.application import Sphinx + from sphinx.environment import BuildEnvironment versionlabels = { @@ -63,8 +64,7 @@ class VersionChange(SphinxDirective): final_argument_whitespace = True option_spec = {} # type: Dict - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: node = addnodes.versionmodified() node.document = self.state.document self.set_source_info(node) @@ -102,7 +102,7 @@ class VersionChange(SphinxDirective): domain = cast(ChangeSetDomain, self.env.get_domain('changeset')) domain.note_changeset(node) - ret = [node] # type: List[nodes.Node] + ret = [node] # type: List[Node] ret += messages return ret @@ -117,15 +117,13 @@ class ChangeSetDomain(Domain): 'changes': {}, # version -> list of ChangeSet } # type: Dict - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: for version, changes in self.data['changes'].items(): for changeset in changes[:]: if changeset.docname == docname: changes.remove(changeset) - def merge_domaindata(self, docnames, otherdata): - # type: (List[str], Dict) -> None + def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: # XXX duplicates? for version, otherchanges in otherdata['changes'].items(): changes = self.data['changes'].setdefault(version, []) @@ -133,12 +131,10 @@ class ChangeSetDomain(Domain): if changeset.docname in docnames: changes.append(changeset) - def process_doc(self, env, docname, document): - # type: (BuildEnvironment, str, nodes.document) -> None + def process_doc(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA pass # nothing to do here. All changesets are registered on calling directive. - def note_changeset(self, node): - # type: (addnodes.versionmodified) -> None + def note_changeset(self, node: addnodes.versionmodified) -> None: version = node['version'] module = self.env.ref_context.get('py:module') objname = self.env.temp_data.get('object') @@ -146,13 +142,11 @@ class ChangeSetDomain(Domain): module, objname, node.astext()) self.data['changes'].setdefault(version, []).append(changeset) - def get_changesets_for(self, version): - # type: (str) -> List[ChangeSet] + def get_changesets_for(self, version: str) -> List[ChangeSet]: return self.data['changes'].get(version, []) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: "Sphinx") -> Dict[str, Any]: app.add_domain(ChangeSetDomain) app.add_directive('deprecated', VersionChange) app.add_directive('versionadded', VersionChange) From 3a81e0ad7d4f2db4326fbb3f8346a08fa3e09051 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 29 Jun 2019 23:33:15 +0900 Subject: [PATCH 06/11] Migrate to py3 style type annotation: sphinx.domains.c --- sphinx/domains/c.py | 67 ++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index ec311cfc7..a0ca0873c 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -10,24 +10,23 @@ import re import string +from typing import Any, Dict, Iterator, List, Tuple from docutils import nodes +from docutils.nodes import Element from sphinx import addnodes +from sphinx.addnodes import pending_xref, desc_signature +from sphinx.application import Sphinx +from sphinx.builders import Builder from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType +from sphinx.environment import BuildEnvironment from sphinx.locale import _ from sphinx.roles import XRefRole from sphinx.util.docfields import Field, TypedField from sphinx.util.nodes import make_refnode -if False: - # For type annotation - from typing import Any, Dict, Iterator, List, Tuple # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA - # RE to split at word boundaries wsplit_re = re.compile(r'(\W+)') @@ -79,23 +78,20 @@ class CObject(ObjectDescription): 'struct', '_Bool', } - def _parse_type(self, node, ctype): - # type: (nodes.Element, str) -> None + def _parse_type(self, node: Element, ctype: str) -> None: # add cross-ref nodes for all words for part in [_f for _f in wsplit_re.split(ctype) if _f]: tnode = nodes.Text(part, part) if part[0] in string.ascii_letters + '_' and \ part not in self.stopwords: - pnode = addnodes.pending_xref( - '', refdomain='c', reftype='type', reftarget=part, - modname=None, classname=None) + pnode = pending_xref('', refdomain='c', reftype='type', reftarget=part, + modname=None, classname=None) pnode += tnode node += pnode else: node += tnode - def _parse_arglist(self, arglist): - # type: (str) -> Iterator[str] + def _parse_arglist(self, arglist: str) -> Iterator[str]: while True: m = c_funcptr_arg_sig_re.match(arglist) if m: @@ -113,8 +109,7 @@ class CObject(ObjectDescription): yield arglist break - def handle_signature(self, sig, signode): - # type: (str, addnodes.desc_signature) -> str + def handle_signature(self, sig: str, signode: desc_signature) -> str: """Transform a C signature into RST nodes.""" # first try the function pointer signature regex, it's more specific m = c_funcptr_sig_re.match(sig) @@ -183,8 +178,7 @@ class CObject(ObjectDescription): signode += addnodes.desc_addname(const, const) return fullname - def get_index_text(self, name): - # type: (str) -> str + def get_index_text(self, name: str) -> str: if self.objtype == 'function': return _('%s (C function)') % name elif self.objtype == 'member': @@ -198,8 +192,7 @@ class CObject(ObjectDescription): else: return '' - def add_target_and_index(self, name, sig, signode): - # type: (str, str, addnodes.desc_signature) -> None + def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None: # for C API items we add a prefix since names are usually not qualified # by a module name and so easily clash with e.g. section titles targetname = 'c.' + name @@ -221,23 +214,21 @@ class CObject(ObjectDescription): self.indexnode['entries'].append(('single', indextext, targetname, '', None)) - def before_content(self): - # type: () -> None + def before_content(self) -> None: self.typename_set = False if self.name == 'c:type': if self.names: self.env.ref_context['c:type'] = self.names[0] self.typename_set = True - def after_content(self): - # type: () -> None + def after_content(self) -> None: if self.typename_set: self.env.ref_context.pop('c:type', None) class CXRefRole(XRefRole): - def process_link(self, env, refnode, has_explicit_title, title, target): - # type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str] + def process_link(self, env: BuildEnvironment, refnode: Element, + has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]: if not has_explicit_title: target = target.lstrip('~') # only has a meaning for the title # if the first character is a tilde, don't display the module/class @@ -280,22 +271,20 @@ class CDomain(Domain): 'objects': {}, # fullname -> docname, objtype } # type: Dict[str, Dict[str, Tuple[str, Any]]] - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: for fullname, (fn, _l) in list(self.data['objects'].items()): if fn == docname: del self.data['objects'][fullname] - def merge_domaindata(self, docnames, otherdata): - # type: (List[str], Dict) -> None + def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: # XXX check duplicates for fullname, (fn, objtype) in otherdata['objects'].items(): if fn in docnames: self.data['objects'][fullname] = (fn, objtype) - def resolve_xref(self, env, fromdocname, builder, - typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, + typ: str, target: str, node: pending_xref, contnode: Element + ) -> Element: # strip pointer asterisk target = target.rstrip(' *') # becase TypedField can generate xrefs @@ -307,9 +296,9 @@ class CDomain(Domain): return make_refnode(builder, fromdocname, obj[0], 'c.' + target, contnode, target) - def resolve_any_xref(self, env, fromdocname, builder, target, - node, contnode): - # type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA + def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, + target: str, node: pending_xref, contnode: Element + ) -> List[Tuple[str, Element]]: # strip pointer asterisk target = target.rstrip(' *') if target not in self.data['objects']: @@ -319,14 +308,12 @@ class CDomain(Domain): make_refnode(builder, fromdocname, obj[0], 'c.' + target, contnode, target))] - def get_objects(self): - # type: () -> Iterator[Tuple[str, str, str, str, str, int]] + def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]: for refname, (docname, type) in list(self.data['objects'].items()): yield (refname, refname, type, docname, 'c.' + refname, 1) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_domain(CDomain) return { From ee6e44a04f40c7f88d6cb9624068c352de8149db Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 29 Jun 2019 23:45:57 +0900 Subject: [PATCH 07/11] Migrate to py3 style type annotation: sphinx.domains.python --- sphinx/domains/python.py | 211 +++++++++++++++------------------------ 1 file changed, 79 insertions(+), 132 deletions(-) diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 2a9a120ef..b70481198 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -10,31 +10,31 @@ import re import warnings +from typing import Any, Dict, Iterable, Iterator, List, Tuple, Type from typing import cast from docutils import nodes +from docutils.nodes import Element, Node from docutils.parsers.rst import directives from sphinx import addnodes, locale +from sphinx.addnodes import pending_xref, desc_signature +from sphinx.application import Sphinx +from sphinx.builders import Builder from sphinx.deprecation import ( DeprecatedDict, RemovedInSphinx30Warning, RemovedInSphinx40Warning ) from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType, Index, IndexEntry +from sphinx.environment import BuildEnvironment from sphinx.locale import _, __ from sphinx.roles import XRefRole from sphinx.util import logging from sphinx.util.docfields import Field, GroupedField, TypedField from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import make_refnode +from sphinx.util.typing import TextlikeNode -if False: - # For type annotation - from typing import Any, Dict, Iterable, Iterator, List, Tuple, Type # 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__) @@ -67,8 +67,7 @@ locale.pairindextypes = DeprecatedDict( ) -def _pseudo_parse_arglist(signode, arglist): - # type: (addnodes.desc_signature, str) -> None +def _pseudo_parse_arglist(signode: desc_signature, arglist: str) -> None: """"Parse" a list of arguments separated by commas. Arguments can have "optional" annotations given by enclosing them in @@ -76,7 +75,7 @@ def _pseudo_parse_arglist(signode, arglist): string literal (e.g. default argument value). """ paramlist = addnodes.desc_parameterlist() - stack = [paramlist] # type: List[nodes.Element] + stack = [paramlist] # type: List[Element] try: for argument in arglist.split(','): argument = argument.strip() @@ -119,15 +118,9 @@ def _pseudo_parse_arglist(signode, arglist): # This override allows our inline type specifiers to behave like :class: link # when it comes to handling "." and "~" prefixes. class PyXrefMixin: - def make_xref(self, - 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 + def make_xref(self, rolename: str, domain: str, target: str, + innernode: Type[TextlikeNode] = nodes.emphasis, + contnode: Node = None, env: BuildEnvironment = None) -> Node: result = super().make_xref(rolename, domain, target, # type: ignore innernode, contnode, env) result['refspecific'] = True @@ -142,15 +135,9 @@ class PyXrefMixin: break return result - def make_xrefs(self, - 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: (...) -> List[nodes.Node] + 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+)' delims_re = re.compile(delims) sub_targets = re.split(delims, target) @@ -172,9 +159,9 @@ class PyXrefMixin: class PyField(PyXrefMixin, Field): - def make_xref(self, rolename, domain, target, - innernode=nodes.emphasis, contnode=None, env=None): - # type: (str, str, str, Type[TextlikeNode], nodes.Node, BuildEnvironment) -> nodes.Node # NOQA + def make_xref(self, rolename: str, domain: str, target: str, + innernode: Type[TextlikeNode] = nodes.emphasis, + contnode: Node = None, env: BuildEnvironment = None) -> Node: if rolename == 'class' and target == 'None': # None is not a type, so use obj role instead. rolename = 'obj' @@ -187,9 +174,9 @@ class PyGroupedField(PyXrefMixin, GroupedField): class PyTypedField(PyXrefMixin, TypedField): - def make_xref(self, rolename, domain, target, - innernode=nodes.emphasis, contnode=None, env=None): - # type: (str, str, str, Type[TextlikeNode], nodes.Node, BuildEnvironment) -> nodes.Node # NOQA + def make_xref(self, rolename: str, domain: str, target: str, + innernode: Type[TextlikeNode] = nodes.emphasis, + contnode: Node = None, env: BuildEnvironment = None) -> Node: if rolename == 'class' and target == 'None': # None is not a type, so use obj role instead. rolename = 'obj' @@ -231,22 +218,19 @@ class PyObject(ObjectDescription): allow_nesting = False - def get_signature_prefix(self, sig): - # type: (str) -> str + def get_signature_prefix(self, sig: str) -> str: """May return a prefix to put before the object name in the signature. """ return '' - def needs_arglist(self): - # type: () -> bool + def needs_arglist(self) -> bool: """May return true if an empty argument list is to be generated even if the document contains none. """ return False - def handle_signature(self, sig, signode): - # type: (str, addnodes.desc_signature) -> Tuple[str, str] + def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]: """Transform a Python signature into RST nodes. Return (fully qualified name of the thing, classname if any). @@ -320,13 +304,12 @@ class PyObject(ObjectDescription): return fullname, prefix - def get_index_text(self, modname, name): - # type: (str, Tuple[str, str]) -> str + def get_index_text(self, modname: str, name: Tuple[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: (Tuple[str, str], str, addnodes.desc_signature) -> None + def add_target_and_index(self, name_cls: Tuple[str, str], sig: str, + signode: desc_signature) -> None: modname = self.options.get('module', self.env.ref_context.get('py:module')) fullname = (modname and modname + '.' or '') + name_cls[0] # note target @@ -345,8 +328,7 @@ class PyObject(ObjectDescription): self.indexnode['entries'].append(('single', indextext, fullname, '', None)) - def before_content(self): - # type: () -> None + def before_content(self) -> None: """Handle object nesting before content :py:class:`PyObject` represents Python language constructs. For @@ -379,8 +361,7 @@ class PyObject(ObjectDescription): modules.append(self.env.ref_context.get('py:module')) self.env.ref_context['py:module'] = self.options['module'] - def after_content(self): - # type: () -> None + def after_content(self) -> None: """Handle object de-nesting after content If this class is a nestable object, removing the last nested class prefix @@ -411,19 +392,16 @@ class PyModulelevel(PyObject): Description of an object on module level (functions, data). """ - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: warnings.warn('PyClassmember is deprecated.', RemovedInSphinx40Warning) return super().run() - def needs_arglist(self): - # type: () -> bool + def needs_arglist(self) -> bool: return self.objtype == 'function' - def get_index_text(self, modname, name_cls): - # type: (str, Tuple[str, str]) -> str + def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: if self.objtype == 'function': if not modname: return _('%s() (built-in function)') % name_cls[0] @@ -444,19 +422,16 @@ class PyFunction(PyObject): 'async': directives.flag, }) - def get_signature_prefix(self, sig): - # type: (str) -> str + def get_signature_prefix(self, sig: str) -> str: if 'async' in self.options: return 'async ' else: return '' - def needs_arglist(self): - # type: () -> bool + def needs_arglist(self) -> bool: return True - def get_index_text(self, modname, name_cls): - # type: (str, Tuple[str, str]) -> str + def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: name, cls = name_cls if modname: return _('%s() (in module %s)') % (name, modname) @@ -467,8 +442,7 @@ class PyFunction(PyObject): class PyVariable(PyObject): """Description of a variable.""" - def get_index_text(self, modname, name_cls): - # type: (str, Tuple[str, str]) -> str + def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: name, cls = name_cls if modname: return _('%s (in module %s)') % (name, modname) @@ -483,12 +457,10 @@ class PyClasslike(PyObject): allow_nesting = True - def get_signature_prefix(self, sig): - # type: (str) -> str + def get_signature_prefix(self, sig: str) -> str: return self.objtype + ' ' - def get_index_text(self, modname, name_cls): - # type: (str, Tuple[str, str]) -> str + def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: if self.objtype == 'class': if not modname: return _('%s (built-in class)') % name_cls[0] @@ -504,27 +476,23 @@ class PyClassmember(PyObject): Description of a class member (methods, attributes). """ - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: warnings.warn('PyClassmember is deprecated.', RemovedInSphinx40Warning) return super().run() - def needs_arglist(self): - # type: () -> bool + def needs_arglist(self) -> bool: return self.objtype.endswith('method') - def get_signature_prefix(self, sig): - # type: (str) -> str + def get_signature_prefix(self, sig: str) -> str: if self.objtype == 'staticmethod': return 'static ' elif self.objtype == 'classmethod': return 'classmethod ' return '' - def get_index_text(self, modname, name_cls): - # type: (str, Tuple[str, str]) -> str + def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: name, cls = name_cls add_modules = self.env.config.add_module_names if self.objtype == 'method': @@ -593,15 +561,13 @@ class PyMethod(PyObject): 'staticmethod': directives.flag, }) - def needs_arglist(self): - # type: () -> bool + def needs_arglist(self) -> bool: if 'property' in self.options: return False else: return True - def get_signature_prefix(self, sig): - # type: (str) -> str + def get_signature_prefix(self, sig: str) -> str: prefix = [] if 'abstractmethod' in self.options: prefix.append('abstract') @@ -619,8 +585,7 @@ class PyMethod(PyObject): else: return '' - def get_index_text(self, modname, name_cls): - # type: (str, Tuple[str, str]) -> str + def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: name, cls = name_cls try: clsname, methname = name.rsplit('.', 1) @@ -647,8 +612,7 @@ class PyClassMethod(PyMethod): option_spec = PyObject.option_spec.copy() - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: self.name = 'py:method' self.options['classmethod'] = True @@ -660,8 +624,7 @@ class PyStaticMethod(PyMethod): option_spec = PyObject.option_spec.copy() - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: self.name = 'py:method' self.options['staticmethod'] = True @@ -671,8 +634,7 @@ class PyStaticMethod(PyMethod): class PyAttribute(PyObject): """Description of an attribute.""" - def get_index_text(self, modname, name_cls): - # type: (str, Tuple[str, str]) -> str + def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: name, cls = name_cls try: clsname, attrname = name.rsplit('.', 1) @@ -691,14 +653,12 @@ class PyDecoratorMixin: """ Mixin for decorator directives. """ - def handle_signature(self, sig, signode): - # type: (str, addnodes.desc_signature) -> Tuple[str, str] + def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]: ret = super().handle_signature(sig, signode) # type: ignore signode.insert(0, addnodes.desc_addname('@', '@')) return ret - def needs_arglist(self): - # type: () -> bool + def needs_arglist(self) -> bool: return False @@ -706,8 +666,7 @@ class PyDecoratorFunction(PyDecoratorMixin, PyModulelevel): """ Directive to mark functions meant to be used as decorators. """ - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: # a decorator function is a function after all self.name = 'py:function' return super().run() @@ -717,8 +676,7 @@ class PyDecoratorMethod(PyDecoratorMixin, PyClassmember): """ Directive to mark methods meant to be used as decorators. """ - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: self.name = 'py:method' return super().run() @@ -739,14 +697,13 @@ class PyModule(SphinxDirective): 'deprecated': directives.flag, } - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: domain = cast(PythonDomain, self.env.get_domain('py')) modname = self.arguments[0].strip() noindex = 'noindex' in self.options self.env.ref_context['py:module'] = modname - ret = [] # type: List[nodes.Node] + ret = [] # type: List[Node] if not noindex: # note module to the domain domain.note_module(modname, @@ -780,8 +737,7 @@ class PyCurrentModule(SphinxDirective): final_argument_whitespace = False option_spec = {} # type: Dict - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: modname = self.arguments[0].strip() if modname == 'None': self.env.ref_context.pop('py:module', None) @@ -791,8 +747,8 @@ class PyCurrentModule(SphinxDirective): class PyXRefRole(XRefRole): - def process_link(self, env, refnode, has_explicit_title, title, target): - # type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str] + def process_link(self, env: BuildEnvironment, refnode: Element, + has_explicit_title: bool, title: str, target: 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: @@ -822,8 +778,8 @@ class PythonModuleIndex(Index): localname = _('Python Module Index') shortname = _('modules') - def generate(self, docnames=None): - # type: (Iterable[str]) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool] + def generate(self, docnames: Iterable[str] = None + ) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]: content = {} # type: Dict[str, List[IndexEntry]] # list of prefixes to ignore ignores = None # type: List[str] @@ -937,12 +893,10 @@ class PythonDomain(Domain): ] @property - def objects(self): - # type: () -> Dict[str, Tuple[str, str]] + def objects(self) -> Dict[str, Tuple[str, str]]: return self.data.setdefault('objects', {}) # fullname -> docname, objtype - def note_object(self, name, objtype, location=None): - # type: (str, str, Any) -> None + def note_object(self, name: str, objtype: str, location: Any = None) -> None: """Note a python object for cross reference. .. versionadded:: 2.1 @@ -955,20 +909,17 @@ class PythonDomain(Domain): self.objects[name] = (self.env.docname, objtype) @property - def modules(self): - # type: () -> Dict[str, Tuple[str, str, str, bool]] + def modules(self) -> Dict[str, Tuple[str, str, str, bool]]: return self.data.setdefault('modules', {}) # modname -> docname, synopsis, platform, deprecated # NOQA - def note_module(self, name, synopsis, platform, deprecated): - # type: (str, str, str, bool) -> None + def note_module(self, name: str, synopsis: str, platform: str, deprecated: bool) -> None: """Note a python module for cross reference. .. versionadded:: 2.1 """ self.modules[name] = (self.env.docname, synopsis, platform, deprecated) - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: for fullname, (fn, _l) in list(self.objects.items()): if fn == docname: del self.objects[fullname] @@ -976,8 +927,7 @@ class PythonDomain(Domain): if fn == docname: del self.modules[modname] - def merge_domaindata(self, docnames, otherdata): - # type: (List[str], Dict) -> None + def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: # XXX check duplicates? for fullname, (fn, objtype) in otherdata['objects'].items(): if fn in docnames: @@ -986,8 +936,8 @@ class PythonDomain(Domain): if data[0] in docnames: self.modules[modname] = data - def find_obj(self, env, modname, classname, name, type, searchmode=0): - # type: (BuildEnvironment, str, str, str, str, int) -> List[Tuple[str, Any]] + def find_obj(self, env: BuildEnvironment, modname: str, classname: str, + name: str, type: str, searchmode: int = 0) -> 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. """ @@ -1049,9 +999,9 @@ class PythonDomain(Domain): matches.append((newname, self.objects[newname])) return matches - def resolve_xref(self, env, fromdocname, builder, - type, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, + type: str, target: str, node: pending_xref, contnode: Element + ) -> Element: modname = node.get('py:module') clsname = node.get('py:class') searchmode = node.hasattr('refspecific') and 1 or 0 @@ -1070,12 +1020,12 @@ class PythonDomain(Domain): else: return make_refnode(builder, fromdocname, obj[0], name, contnode, name) - def resolve_any_xref(self, env, fromdocname, builder, target, - node, contnode): - # type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA + def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, + target: str, node: pending_xref, contnode: Element + ) -> List[Tuple[str, Element]]: modname = node.get('py:module') clsname = node.get('py:class') - results = [] # type: List[Tuple[str, nodes.Element]] + results = [] # type: List[Tuple[str, Element]] # always search in "refspecific" mode with the :any: role matches = self.find_obj(env, modname, clsname, target, None, 1) @@ -1090,8 +1040,8 @@ class PythonDomain(Domain): contnode, name))) return results - def _make_module_refnode(self, builder, fromdocname, name, contnode): - # type: (Builder, str, str, nodes.Node) -> nodes.Element + def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str, + contnode: Node) -> Element: # get additional info for modules docname, synopsis, platform, deprecated = self.modules[name] title = name @@ -1104,16 +1054,14 @@ class PythonDomain(Domain): return make_refnode(builder, fromdocname, docname, 'module-' + name, contnode, title) - def get_objects(self): - # type: () -> Iterator[Tuple[str, str, str, str, str, int]] + def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]: for modname, info in self.modules.items(): yield (modname, modname, 'module', info[0], 'module-' + modname, 0) for refname, (docname, type) in self.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.Element) -> str + def get_full_qualified_name(self, node: Element) -> str: modname = node.get('py:module') clsname = node.get('py:class') target = node.get('reftarget') @@ -1123,8 +1071,7 @@ class PythonDomain(Domain): return '.'.join(filter(None, [modname, clsname, target])) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_domain(PythonDomain) return { From f6d0cb8f3ad5a29e5e5c4f0c85f5736904291703 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 29 Jun 2019 23:51:12 +0900 Subject: [PATCH 08/11] Migrate to py3 style type annotation: sphinx.domains.rst --- sphinx/domains/rst.py | 80 +++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index 349043294..85f10e15c 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -9,26 +9,24 @@ """ import re +from typing import Any, Dict, Iterator, List, Tuple from typing import cast +from docutils.nodes import Element from docutils.parsers.rst import directives from sphinx import addnodes +from sphinx.addnodes import desc_signature, pending_xref +from sphinx.application import Sphinx +from sphinx.builders import Builder from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType +from sphinx.environment import BuildEnvironment from sphinx.locale import _, __ from sphinx.roles import XRefRole from sphinx.util import logging from sphinx.util.nodes import make_refnode -if False: - # For type annotation - from typing import Any, Dict, Iterator, List, Tuple # NOQA - from docutils import nodes # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA - logger = logging.getLogger(__name__) @@ -40,8 +38,7 @@ class ReSTMarkup(ObjectDescription): Description of generic reST markup. """ - def add_target_and_index(self, name, sig, signode): - # type: (str, str, addnodes.desc_signature) -> None + def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None: targetname = self.objtype + '-' + name if targetname not in self.state.document.ids: signode['names'].append(targetname) @@ -57,13 +54,11 @@ class ReSTMarkup(ObjectDescription): self.indexnode['entries'].append(('single', indextext, targetname, '', None)) - def get_index_text(self, objectname, name): - # type: (str, str) -> str + def get_index_text(self, objectname: str, name: str) -> str: return '' -def parse_directive(d): - # type: (str) -> Tuple[str, str] +def parse_directive(d: str) -> Tuple[str, str]: """Parse a directive signature. Returns (directive, arguments) string tuple. If no arguments are given, @@ -87,8 +82,7 @@ class ReSTDirective(ReSTMarkup): """ Description of a reST directive. """ - def handle_signature(self, sig, signode): - # type: (str, addnodes.desc_signature) -> str + def handle_signature(self, sig: str, signode: desc_signature) -> str: name, args = parse_directive(sig) desc_name = '.. %s::' % name signode += addnodes.desc_name(desc_name, desc_name) @@ -96,18 +90,15 @@ class ReSTDirective(ReSTMarkup): signode += addnodes.desc_addname(args, args) return name - def get_index_text(self, objectname, name): - # type: (str, str) -> str + def get_index_text(self, objectname: str, name: str) -> str: return _('%s (directive)') % name - def before_content(self): - # type: () -> None + def before_content(self) -> None: if self.names: directives = self.env.ref_context.setdefault('rst:directives', []) directives.append(self.names[0]) - def after_content(self): - # type: () -> None + def after_content(self) -> None: directives = self.env.ref_context.setdefault('rst:directives', []) if directives: directives.pop() @@ -122,8 +113,7 @@ class ReSTDirectiveOption(ReSTMarkup): 'type': directives.unchanged, }) - def handle_signature(self, sig, signode): - # type: (str, addnodes.desc_signature) -> str + def handle_signature(self, sig: str, signode: desc_signature) -> str: try: name, argument = re.split(r'\s*:\s+', sig.strip(), 1) except ValueError: @@ -137,8 +127,7 @@ class ReSTDirectiveOption(ReSTMarkup): signode += addnodes.desc_annotation(text, text) return name - def add_target_and_index(self, name, sig, signode): - # type: (str, str, addnodes.desc_signature) -> None + def add_target_and_index(self, name: str, sig: str, signode: desc_signature) -> None: directive_name = self.current_directive targetname = '-'.join([self.objtype, self.current_directive, name]) if targetname not in self.state.document.ids: @@ -162,8 +151,7 @@ class ReSTDirectiveOption(ReSTMarkup): self.indexnode['entries'].append(('single', text, targetname, '', key)) @property - def current_directive(self): - # type: () -> str + def current_directive(self) -> str: directives = self.env.ref_context.get('rst:directives') if directives: return directives[-1] @@ -175,13 +163,11 @@ class ReSTRole(ReSTMarkup): """ Description of a reST role. """ - def handle_signature(self, sig, signode): - # type: (str, addnodes.desc_signature) -> str + def handle_signature(self, sig: str, signode: desc_signature) -> str: signode += addnodes.desc_name(':%s:' % sig, ':%s:' % sig) return sig - def get_index_text(self, objectname, name): - # type: (str, str) -> str + def get_index_text(self, objectname: str, name: str) -> str: return _('%s (role)') % name @@ -209,12 +195,10 @@ class ReSTDomain(Domain): } # type: Dict[str, Dict[Tuple[str, str], str]] @property - def objects(self): - # type: () -> Dict[Tuple[str, str], str] + def objects(self) -> Dict[Tuple[str, str], str]: return self.data.setdefault('objects', {}) # (objtype, fullname) -> docname - def note_object(self, objtype, name, location=None): - # type: (str, str, Any) -> None + def note_object(self, objtype: str, name: str, location: Any = None) -> None: if (objtype, name) in self.objects: docname = self.objects[objtype, name] logger.warning(__('duplicate description of %s %s, other instance in %s') % @@ -222,21 +206,20 @@ class ReSTDomain(Domain): self.objects[objtype, name] = self.env.docname - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: for (typ, name), doc in list(self.objects.items()): if doc == docname: del self.objects[typ, name] - def merge_domaindata(self, docnames, otherdata): - # type: (List[str], Dict) -> None + def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: # XXX check duplicates for (typ, name), doc in otherdata['objects'].items(): if doc in docnames: self.objects[typ, name] = doc - def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, + typ: str, target: str, node: pending_xref, contnode: Element + ) -> Element: objtypes = self.objtypes_for_role(typ) for objtype in objtypes: todocname = self.objects.get((objtype, target)) @@ -246,9 +229,10 @@ class ReSTDomain(Domain): contnode, target + ' ' + objtype) return None - def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA - results = [] # type: List[Tuple[str, nodes.Element]] + def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, + target: str, node: pending_xref, contnode: Element + ) -> List[Tuple[str, Element]]: + results = [] # type: List[Tuple[str, Element]] for objtype in self.object_types: todocname = self.objects.get((objtype, target)) if todocname: @@ -258,14 +242,12 @@ class ReSTDomain(Domain): contnode, target + ' ' + objtype))) return results - def get_objects(self): - # type: () -> Iterator[Tuple[str, str, str, str, str, int]] + def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]: for (typ, name), docname in self.data['objects'].items(): yield name, name, typ, docname, typ + '-' + name, 1 -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_domain(ReSTDomain) return { From f5620910fcad6ff7db708d809a7a8e1f1961fe90 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 29 Jun 2019 23:56:40 +0900 Subject: [PATCH 09/11] Migrate to py3 style type annotation: sphinx.domains.math --- sphinx/domains/math.py | 63 +++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/sphinx/domains/math.py b/sphinx/domains/math.py index 45e33ea6f..d3cacc5ba 100644 --- a/sphinx/domains/math.py +++ b/sphinx/domains/math.py @@ -9,13 +9,17 @@ """ import warnings +from typing import Any, Dict, Iterable, List, Tuple from docutils import nodes +from docutils.nodes import Element, Node, system_message from docutils.nodes import make_id from sphinx.addnodes import math_block as displaymath +from sphinx.addnodes import pending_xref from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.domains import Domain +from sphinx.environment import BuildEnvironment from sphinx.locale import __ from sphinx.roles import XRefRole from sphinx.util import logging @@ -23,18 +27,16 @@ from sphinx.util.nodes import make_refnode if False: # For type annotation - from typing import Any, Dict, Iterable, List, Tuple # NOQA - from sphinx import addnodes # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA + from sphinx.application import Sphinx + from sphinx.builders import Builder + logger = logging.getLogger(__name__) class MathReferenceRole(XRefRole): - def result_nodes(self, document, env, node, is_ref): - # type: (nodes.document, BuildEnvironment, nodes.Element, bool) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA + def result_nodes(self, document: nodes.document, env: BuildEnvironment, node: Element, + is_ref: bool) -> Tuple[List[Node], List[system_message]]: node['refdomain'] = 'math' return [node], [] @@ -60,12 +62,10 @@ class MathDomain(Domain): } @property - def equations(self): - # type: () -> Dict[str, Tuple[str, int]] + def equations(self) -> Dict[str, Tuple[str, int]]: return self.data.setdefault('objects', {}) # labelid -> (docname, eqno) - def note_equation(self, docname, labelid, location=None): - # type: (str, str, Any) -> None + def note_equation(self, docname: str, labelid: str, location: Any = None) -> None: if labelid in self.equations: other = self.equations[labelid][0] logger.warning(__('duplicate label of equation %s, other instance in %s') % @@ -73,31 +73,27 @@ class MathDomain(Domain): self.equations[labelid] = (docname, self.env.new_serialno('eqno') + 1) - def get_equation_number_for(self, labelid): - # type: (str) -> int + def get_equation_number_for(self, labelid: str) -> int: if labelid in self.equations: return self.equations[labelid][1] else: return None - def process_doc(self, env, docname, document): - # type: (BuildEnvironment, str, nodes.document) -> None - def math_node(node): - # type: (nodes.Node) -> bool + def process_doc(self, env: BuildEnvironment, docname: str, + document: nodes.document) -> None: + def math_node(node: Node) -> bool: return isinstance(node, (nodes.math, nodes.math_block)) self.data['has_equations'][docname] = any(document.traverse(math_node)) - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: for equation_id, (doc, eqno) in list(self.equations.items()): if doc == docname: del self.equations[equation_id] self.data['has_equations'].pop(docname, None) - def merge_domaindata(self, docnames, otherdata): - # type: (Iterable[str], Dict) -> None + def merge_domaindata(self, docnames: Iterable[str], otherdata: Dict) -> None: for labelid, (doc, eqno) in otherdata['objects'].items(): if doc in docnames: self.equations[labelid] = (doc, eqno) @@ -105,8 +101,9 @@ class MathDomain(Domain): for docname in docnames: self.data['has_equations'][docname] = otherdata['has_equations'][docname] - def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: "Builder", + typ: str, target: str, node: pending_xref, contnode: Element + ) -> Element: assert typ in ('eq', 'numref') docname, number = self.equations.get(target, (None, None)) if docname: @@ -133,20 +130,19 @@ class MathDomain(Domain): else: return None - def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA + def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: "Builder", + target: str, node: pending_xref, contnode: Element + ) -> List[Tuple[str, Element]]: refnode = self.resolve_xref(env, fromdocname, builder, 'eq', target, node, contnode) if refnode is None: return [] else: return [('eq', refnode)] - def get_objects(self): - # type: () -> List + def get_objects(self) -> List: return [] - def add_equation(self, env, docname, labelid): - # type: (BuildEnvironment, str, str) -> int + def add_equation(self, env: BuildEnvironment, docname: str, labelid: str) -> int: warnings.warn('MathDomain.add_equation() is deprecated.', RemovedInSphinx40Warning) if labelid in self.equations: @@ -158,20 +154,17 @@ class MathDomain(Domain): self.equations[labelid] = (docname, eqno) return eqno - def get_next_equation_number(self, docname): - # type: (str) -> int + def get_next_equation_number(self, docname: str) -> int: warnings.warn('MathDomain.get_next_equation_number() is deprecated.', RemovedInSphinx40Warning) targets = [eq for eq in self.equations.values() if eq[0] == docname] return len(targets) + 1 - def has_equations(self): - # type: () -> bool + def has_equations(self) -> bool: return any(self.data['has_equations'].values()) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: "Sphinx") -> Dict[str, Any]: app.add_domain(MathDomain) app.add_role('eq', MathReferenceRole(warn_dangling=True)) From 1b597dc4509b393cf7b0107738beb9ee8c440a1d Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 30 Jun 2019 00:10:15 +0900 Subject: [PATCH 10/11] Migrate to py3 style type annotation: sphinx.domains.javascript --- sphinx/domains/javascript.py | 70 ++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index 5d8b4f1e0..8181ea525 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -8,26 +8,26 @@ :license: BSD, see LICENSE for details. """ +from typing import Any, Dict, Iterator, List, Tuple + from docutils import nodes +from docutils.nodes import Element, Node from docutils.parsers.rst import directives from sphinx import addnodes +from sphinx.addnodes import desc_signature, pending_xref +from sphinx.application import Sphinx +from sphinx.builders import Builder from sphinx.directives import ObjectDescription from sphinx.domains import Domain, ObjType from sphinx.domains.python import _pseudo_parse_arglist +from sphinx.environment import BuildEnvironment from sphinx.locale import _ from sphinx.roles import XRefRole from sphinx.util.docfields import Field, GroupedField, TypedField from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import make_refnode -if False: - # For type annotation - from typing import Any, Dict, Iterator, List, Tuple # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA - class JSObject(ObjectDescription): """ @@ -44,8 +44,7 @@ class JSObject(ObjectDescription): #: based on directive nesting allow_nesting = False - def handle_signature(self, sig, signode): - # type: (str, addnodes.desc_signature) -> Tuple[str, str] + def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]: """Breaks down construct signatures Parses out prefix and argument list from construct definition. The @@ -98,8 +97,8 @@ class JSObject(ObjectDescription): _pseudo_parse_arglist(signode, arglist) return fullname, prefix - def add_target_and_index(self, name_obj, sig, signode): - # type: (Tuple[str, str], str, addnodes.desc_signature) -> None + def add_target_and_index(self, name_obj: Tuple[str, str], sig: str, + signode: desc_signature) -> None: mod_name = self.env.ref_context.get('js:module') fullname = (mod_name and mod_name + '.' or '') + name_obj[0] if fullname not in self.state.document.ids: @@ -122,8 +121,7 @@ class JSObject(ObjectDescription): fullname.replace('$', '_S_'), '', None)) - def get_index_text(self, objectname, name_obj): - # type: (str, Tuple[str, str]) -> str + def get_index_text(self, objectname: str, name_obj: Tuple[str, str]) -> str: name, obj = name_obj if self.objtype == 'function': if not obj: @@ -137,8 +135,7 @@ class JSObject(ObjectDescription): return _('%s (%s attribute)') % (name, obj) return '' - def before_content(self): - # type: () -> None + def before_content(self) -> None: """Handle object nesting before content :py:class:`JSObject` represents JavaScript language constructs. For @@ -174,8 +171,7 @@ class JSObject(ObjectDescription): objects = self.env.ref_context.setdefault('js:objects', []) objects.append(prefix) - def after_content(self): - # type: () -> None + def after_content(self) -> None: """Handle object de-nesting after content If this class is a nestable object, removing the last nested class prefix @@ -246,12 +242,11 @@ class JSModule(SphinxDirective): 'noindex': directives.flag } - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: mod_name = self.arguments[0].strip() self.env.ref_context['js:module'] = mod_name noindex = 'noindex' in self.options - ret = [] # type: List[nodes.Node] + ret = [] # type: List[Node] if not noindex: self.env.domaindata['js']['modules'][mod_name] = self.env.docname # Make a duplicate entry in 'objects' to facilitate searching for @@ -269,8 +264,8 @@ class JSModule(SphinxDirective): class JSXRefRole(XRefRole): - def process_link(self, env, refnode, has_explicit_title, title, target): - # type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str] + def process_link(self, env: BuildEnvironment, refnode: Element, + has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]: # basically what sphinx.domains.python.PyXRefRole does refnode['js:object'] = env.ref_context.get('js:object') refnode['js:module'] = env.ref_context.get('js:module') @@ -322,8 +317,7 @@ class JavaScriptDomain(Domain): 'modules': {}, # mod_name -> docname } # type: Dict[str, Dict[str, Tuple[str, str]]] - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: for fullname, (pkg_docname, _l) in list(self.data['objects'].items()): if pkg_docname == docname: del self.data['objects'][fullname] @@ -331,8 +325,7 @@ class JavaScriptDomain(Domain): if pkg_docname == docname: del self.data['modules'][mod_name] - def merge_domaindata(self, docnames, otherdata): - # type: (List[str], Dict) -> None + def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: # XXX check duplicates for fullname, (fn, objtype) in otherdata['objects'].items(): if fn in docnames: @@ -341,8 +334,8 @@ class JavaScriptDomain(Domain): if pkg_docname in docnames: self.data['modules'][mod_name] = pkg_docname - def find_obj(self, env, mod_name, prefix, name, typ, searchorder=0): - # type: (BuildEnvironment, str, str, str, str, int) -> Tuple[str, Tuple[str, str]] + def find_obj(self, env: BuildEnvironment, mod_name: str, prefix: str, name: str, + typ: str, searchorder: int = 0) -> Tuple[str, Tuple[str, str]]: if name[-2:] == '()': name = name[:-2] objects = self.data['objects'] @@ -366,9 +359,9 @@ class JavaScriptDomain(Domain): return newname, objects.get(newname) - def resolve_xref(self, env, fromdocname, builder, typ, target, node, - contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, + typ: str, target: str, node: pending_xref, contnode: Element + ) -> Element: mod_name = node.get('js:module') prefix = node.get('js:object') searchorder = node.hasattr('refspecific') and 1 or 0 @@ -378,9 +371,9 @@ class JavaScriptDomain(Domain): return make_refnode(builder, fromdocname, obj[0], name.replace('$', '_S_'), contnode, name) - def resolve_any_xref(self, env, fromdocname, builder, target, node, - contnode): - # type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA + def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, + target: str, node: pending_xref, contnode: Element + ) -> List[Tuple[str, Element]]: mod_name = node.get('js:module') prefix = node.get('js:object') name, obj = self.find_obj(env, mod_name, prefix, target, None, 1) @@ -390,14 +383,12 @@ class JavaScriptDomain(Domain): make_refnode(builder, fromdocname, obj[0], name.replace('$', '_S_'), contnode, name))] - def get_objects(self): - # type: () -> Iterator[Tuple[str, str, str, str, str, int]] + def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]: for refname, (docname, type) in list(self.data['objects'].items()): yield refname, refname, type, docname, \ refname.replace('$', '_S_'), 1 - def get_full_qualified_name(self, node): - # type: (nodes.Element) -> str + def get_full_qualified_name(self, node: Element) -> str: modname = node.get('js:module') prefix = node.get('js:object') target = node.get('reftarget') @@ -407,8 +398,7 @@ class JavaScriptDomain(Domain): return '.'.join(filter(None, [modname, prefix, target])) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_domain(JavaScriptDomain) return { From b93672c4d45f0574e144966d1b4b92a96beb3abb Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 30 Jun 2019 00:19:40 +0900 Subject: [PATCH 11/11] Migrate to py3 style type annotation: sphinx.domains --- sphinx/domains/__init__.py | 90 +++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 07e05568a..1fe98950b 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -10,21 +10,22 @@ """ import copy -from typing import NamedTuple +from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union +from docutils import nodes +from docutils.nodes import Element, Node, system_message +from docutils.parsers.rst.states import Inliner + +from sphinx.addnodes import pending_xref from sphinx.errors import SphinxError from sphinx.locale import _ +from sphinx.roles import XRefRole +from sphinx.util.typing import RoleFunction if False: # For type annotation - from typing import Any, Callable, Dict, Iterable, List, Tuple, Type, Union # NOQA - from docutils import nodes # NOQA - from docutils.parsers.rst.states import Inliner # NOQA - from sphinx import addnodes # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA - from sphinx.roles import XRefRole # NOQA - from sphinx.util.typing import RoleFunction # NOQA + from sphinx.builders import Builder + from sphinx.environment import BuildEnvironment class ObjType: @@ -46,8 +47,7 @@ class ObjType: 'searchprio': 1, } - def __init__(self, lname, *roles, **attrs): - # type: (str, Any, Any) -> None + def __init__(self, lname: str, *roles, **attrs) -> None: self.lname = lname self.roles = roles # type: Tuple self.attrs = self.known_attrs.copy() # type: Dict @@ -82,15 +82,14 @@ class Index: localname = None # type: str shortname = None # type: str - def __init__(self, domain): - # type: (Domain) -> None + def __init__(self, domain: "Domain") -> None: if self.name is None or self.localname is None: raise SphinxError('Index subclass %s has no valid name or localname' % self.__class__.__name__) self.domain = domain - def generate(self, docnames=None): - # type: (Iterable[str]) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool] + def generate(self, docnames: Iterable[str] = None + ) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]: """Get entries for the index. If ``docnames`` is given, restrict to entries referring to these @@ -181,7 +180,7 @@ class Domain: #: role name -> a warning message if reference is missing dangling_warnings = {} # type: Dict[str, str] #: node_class -> (enum_node_type, title_getter) - enumerable_nodes = {} # type: Dict[Type[nodes.Node], Tuple[str, Callable]] + enumerable_nodes = {} # type: Dict[Type[Node], Tuple[str, Callable]] #: data value for a fresh environment initial_data = {} # type: Dict @@ -190,8 +189,7 @@ class Domain: #: data version, bump this when the format of `self.data` changes data_version = 0 - def __init__(self, env): - # type: (BuildEnvironment) -> None + def __init__(self, env: "BuildEnvironment") -> None: self.env = env # type: BuildEnvironment self._role_cache = {} # type: Dict[str, Callable] self._directive_cache = {} # type: Dict[str, Callable] @@ -220,8 +218,7 @@ class Domain: self.objtypes_for_role = self._role2type.get # type: Callable[[str], List[str]] self.role_for_objtype = self._type2role.get # type: Callable[[str], str] - def add_object_type(self, name, objtype): - # type: (str, ObjType) -> None + def add_object_type(self, name: str, objtype: ObjType) -> None: """Add an object type.""" self.object_types[name] = objtype if objtype.roles: @@ -232,8 +229,7 @@ class Domain: for role in objtype.roles: self._role2type.setdefault(role, []).append(name) - def role(self, name): - # type: (str) -> RoleFunction + def role(self, name: str) -> RoleFunction: """Return a role adapter function that always gives the registered role its full name ('domain:name') as the first argument. """ @@ -243,15 +239,15 @@ class Domain: return None fullname = '%s:%s' % (self.name, name) - def role_adapter(typ, rawtext, text, lineno, inliner, options={}, content=[]): - # type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA + def role_adapter(typ: str, rawtext: str, text: str, lineno: int, + inliner: Inliner, options: Dict = {}, content: List[str] = [] + ) -> Tuple[List[Node], List[system_message]]: return self.roles[name](fullname, rawtext, text, lineno, inliner, options, content) self._role_cache[name] = role_adapter return role_adapter - def directive(self, name): - # type: (str) -> Callable + def directive(self, name: str) -> Callable: """Return a directive adapter class that always gives the registered directive its full name ('domain:name') as ``self.name``. """ @@ -263,8 +259,7 @@ class Domain: BaseDirective = self.directives[name] class DirectiveAdapter(BaseDirective): # type: ignore - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: self.name = fullname return super().run() self._directive_cache[name] = DirectiveAdapter @@ -272,13 +267,11 @@ class Domain: # methods that should be overwritten - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: """Remove traces of a document in the domain-specific inventories.""" pass - def merge_domaindata(self, docnames, otherdata): - # type: (List[str], Dict) -> None + def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: """Merge in data regarding *docnames* from a different domaindata inventory (coming from a subprocess in parallel builds). """ @@ -286,26 +279,24 @@ class Domain: 'to be able to do parallel builds!' % self.__class__) - def process_doc(self, env, docname, document): - # type: (BuildEnvironment, str, nodes.document) -> None + def process_doc(self, env: "BuildEnvironment", docname: str, + document: nodes.document) -> None: """Process a document after it is read by the environment.""" pass - def check_consistency(self): - # type: () -> None + def check_consistency(self) -> None: """Do consistency checks (**experimental**).""" pass - def process_field_xref(self, pnode): - # type: (addnodes.pending_xref) -> None + def process_field_xref(self, pnode: pending_xref) -> None: """Process a pending xref created in a doc field. For example, attach information about the current scope. """ pass - def resolve_xref(self, env, fromdocname, builder, - typ, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, str, addnodes.pending_xref, nodes.Element) -> nodes.Element # NOQA + def resolve_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder", + typ: str, target: str, node: pending_xref, contnode: Element + ) -> Element: """Resolve the pending_xref *node* with the given *typ* and *target*. This method should return a new node, to replace the xref node, @@ -321,8 +312,9 @@ class Domain: """ pass - def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): - # type: (BuildEnvironment, str, Builder, str, addnodes.pending_xref, nodes.Element) -> List[Tuple[str, nodes.Element]] # NOQA + def resolve_any_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder", + target: str, node: pending_xref, contnode: Element + ) -> List[Tuple[str, Element]]: """Resolve the pending_xref *node* with the given *target*. The reference comes from an "any" or similar role, which means that we @@ -338,8 +330,7 @@ class Domain: """ raise NotImplementedError - def get_objects(self): - # type: () -> Iterable[Tuple[str, str, str, str, str, int]] + def get_objects(self) -> Iterable[Tuple[str, str, str, str, str, int]]: """Return an iterable of "object descriptions". Object descriptions are tuples with six items: @@ -374,20 +365,17 @@ class Domain: """ return [] - def get_type_name(self, type, primary=False): - # type: (ObjType, bool) -> str + def get_type_name(self, type: ObjType, primary: bool = False) -> str: """Return full name for given ObjType.""" if primary: return type.lname return _('%s %s') % (self.label, type.lname) - def get_enumerable_node_type(self, node): - # type: (nodes.Node) -> str + def get_enumerable_node_type(self, node: Node) -> str: """Get type of enumerable nodes (experimental).""" enum_node_type, _ = self.enumerable_nodes.get(node.__class__, (None, None)) return enum_node_type - def get_full_qualified_name(self, node): - # type: (nodes.Element) -> str + def get_full_qualified_name(self, node: Element) -> str: """Return full qualified name for given node.""" return None