refactor: Add Optional to type annotations

This commit is contained in:
Takeshi KOMIYA 2021-05-03 23:17:30 +09:00
parent b88187de34
commit 2ee634bfda
19 changed files with 81 additions and 77 deletions

View File

@ -141,9 +141,9 @@ class Sphinx:
self.phase = BuildPhase.INITIALIZATION
self.verbosity = verbosity
self.extensions: Dict[str, Extension] = {}
self.builder: Builder = None
self.env: BuildEnvironment = None
self.project: Project = None
self.builder: Optional[Builder] = None
self.env: Optional[BuildEnvironment] = None
self.project: Optional[Project] = None
self.registry = SphinxComponentRegistry()
self.html_themes: Dict[str, str] = {}
@ -174,7 +174,7 @@ class Sphinx:
if status is None:
self._status: IO = StringIO()
self.quiet = True
self.quiet: bool = True
else:
self._status = status
self.quiet = False

View File

@ -11,7 +11,8 @@
import pickle
import time
from os import path
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Sequence, Set, Tuple, Type, Union
from typing import (TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Sequence, Set, Tuple,
Type, Union)
from docutils import nodes
from docutils.nodes import Node
@ -88,7 +89,7 @@ class Builder:
ensuredir(self.doctreedir)
self.app: Sphinx = app
self.env: BuildEnvironment = None
self.env: Optional[BuildEnvironment] = None
self.events: EventManager = app.events
self.config: Config = app.config
self.tags: Tags = app.tags
@ -225,7 +226,7 @@ class Builder:
self.compile_catalogs(set(repo.catalogs), message)
def compile_specific_catalogs(self, specified_files: List[str]) -> None:
def to_domain(fpath: str) -> str:
def to_domain(fpath: str) -> Optional[str]:
docname = self.env.path2doc(path.abspath(fpath))
if docname:
return docname_to_domain(docname, self.config.gettext_compact)

View File

@ -11,8 +11,8 @@
import copy
from abc import ABC, abstractmethod
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, List, NamedTuple, Tuple,
Type, Union, cast)
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, List, NamedTuple, Optional,
Tuple, Type, Union, cast)
from docutils import nodes
from docutils.nodes import Element, Node, system_message
@ -196,7 +196,7 @@ class Domain:
#: data value for a fresh environment
initial_data: Dict = {}
#: data value
data: Dict = None
data: Dict
#: data version, bump this when the format of `self.data` changes
data_version = 0
@ -251,7 +251,7 @@ class Domain:
for role in objtype.roles:
self._role2type.setdefault(role, []).append(name)
def role(self, name: str) -> RoleFunction:
def role(self, name: str) -> Optional[RoleFunction]:
"""Return a role adapter function that always gives the registered
role its full name ('domain:name') as the first argument.
"""
@ -269,7 +269,7 @@ class Domain:
self._role_cache[name] = role_adapter
return role_adapter
def directive(self, name: str) -> Callable:
def directive(self, name: str) -> Optional[Callable]:
"""Return a directive adapter class that always gives the registered
directive its full name ('domain:name') as ``self.name``.
"""
@ -318,7 +318,7 @@ class Domain:
def resolve_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder",
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
) -> Optional[Element]:
"""Resolve the pending_xref *node* with the given *typ* and *target*.
This method should return a new node, to replace the xref node,
@ -393,11 +393,11 @@ class Domain:
return type.lname
return _('%s %s') % (self.label, type.lname)
def get_enumerable_node_type(self, node: Node) -> str:
def get_enumerable_node_type(self, node: Node) -> Optional[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: Element) -> str:
def get_full_qualified_name(self, node: Element) -> Optional[str]:
"""Return full qualified name for given node."""
return None

View File

@ -9,7 +9,8 @@
"""
import re
from typing import Any, Callable, Dict, Generator, Iterator, List, Tuple, TypeVar, Union, cast
from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, TypeVar,
Union, cast)
from docutils import nodes
from docutils.nodes import Element, Node, TextElement, system_message
@ -3807,7 +3808,7 @@ class CDomain(Domain):
def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref,
contnode: Element) -> Tuple[Element, str]:
contnode: Element) -> Tuple[Optional[Element], Optional[str]]:
parser = DefinitionParser(target, location=node, config=env.config)
try:
name = parser.parse_xref_object()
@ -3844,7 +3845,7 @@ class CDomain(Domain):
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref,
contnode: Element) -> Element:
contnode: Element) -> Optional[Element]:
return self._resolve_xref_inner(env, fromdocname, builder, typ,
target, node, contnode)[0]

View File

@ -8,7 +8,7 @@
:license: BSD, see LICENSE for details.
"""
from typing import TYPE_CHECKING, Any, Dict, List, Set, Tuple, cast
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple, cast
from docutils import nodes
from docutils.nodes import Element
@ -88,7 +88,7 @@ class CitationDomain(Domain):
def resolve_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder",
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
) -> Optional[Element]:
docname, labelid, lineno = self.citations.get(target, ('', '', 0))
if not docname:
return None

View File

@ -7594,7 +7594,7 @@ class CPPDomain(Domain):
def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref,
contnode: Element) -> Tuple[Element, str]:
contnode: Element) -> Tuple[Optional[Element], Optional[str]]:
# add parens again for those that could be functions
if typ == 'any' or typ == 'func':
target += '()'
@ -7743,7 +7743,7 @@ class CPPDomain(Domain):
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
) -> Optional[Element]:
return self._resolve_xref_inner(env, fromdocname, builder, typ,
target, node, contnode)[0]

View File

@ -8,7 +8,7 @@
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict, Iterator, List, Tuple, cast
from typing import Any, Dict, Iterator, List, Optional, Tuple, cast
from docutils import nodes
from docutils.nodes import Element, Node
@ -413,7 +413,7 @@ class JavaScriptDomain(Domain):
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
) -> Optional[Element]:
mod_name = node.get('js:module')
prefix = node.get('js:object')
searchorder = 1 if node.hasattr('refspecific') else 0

View File

@ -8,7 +8,7 @@
:license: BSD, see LICENSE for details.
"""
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Tuple
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple
from docutils import nodes
from docutils.nodes import Element, Node, make_id, system_message
@ -97,7 +97,7 @@ class MathDomain(Domain):
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: "Builder",
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
) -> Optional[Element]:
assert typ in ('eq', 'numref')
docname, number = self.equations.get(target, (None, None))
if docname:

View File

@ -15,7 +15,7 @@ import sys
import typing
import warnings
from inspect import Parameter
from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Tuple, Type, cast
from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Optional, Tuple, Type, cast
from docutils import nodes
from docutils.nodes import Element, Node
@ -1246,7 +1246,7 @@ class PythonDomain(Domain):
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
type: str, target: str, node: pending_xref, contnode: Element
) -> Element:
) -> Optional[Element]:
modname = node.get('py:module')
clsname = node.get('py:class')
searchmode = 1 if node.hasattr('refspecific') else 0
@ -1340,7 +1340,7 @@ class PythonDomain(Domain):
else:
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, 1)
def get_full_qualified_name(self, node: Element) -> str:
def get_full_qualified_name(self, node: Element) -> Optional[str]:
modname = node.get('py:module')
clsname = node.get('py:class')
target = node.get('reftarget')

View File

@ -9,7 +9,7 @@
"""
import re
from typing import Any, Dict, Iterator, List, Tuple, cast
from typing import Any, Dict, Iterator, List, Optional, Tuple, cast
from docutils.nodes import Element
from docutils.parsers.rst import directives
@ -247,7 +247,7 @@ class ReSTDomain(Domain):
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
typ: str, target: str, node: pending_xref, contnode: Element
) -> Element:
) -> Optional[Element]:
objtypes = self.objtypes_for_role(typ)
for objtype in objtypes:
todocname, node_id = self.objects.get((objtype, target), (None, None))

View File

@ -285,7 +285,7 @@ class OptionXRefRole(XRefRole):
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]
parts: List[Optional[str]] = re.split(' +: +', line) + [None]
return parts
@ -621,7 +621,7 @@ class StandardDomain(Domain):
}
# node_class -> (figtype, title_getter)
enumerable_nodes: Dict[Type[Node], Tuple[str, Callable]] = {
enumerable_nodes: Dict[Type[Node], Tuple[str, Optional[Callable]]] = {
nodes.figure: ('figure', None),
nodes.table: ('table', None),
nodes.container: ('code-block', None),
@ -812,7 +812,8 @@ class StandardDomain(Domain):
return newnode
def resolve_xref(self, env: "BuildEnvironment", fromdocname: str, builder: "Builder",
typ: str, target: str, node: pending_xref, contnode: Element) -> Element:
typ: str, target: str, node: pending_xref, contnode: Element
) -> Optional[Element]:
if typ == 'ref':
resolver = self._resolve_ref_xref
elif typ == 'numref':
@ -832,7 +833,7 @@ class StandardDomain(Domain):
def _resolve_ref_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str, node: pending_xref,
contnode: Element) -> Element:
contnode: Element) -> Optional[Element]:
if node['refexplicit']:
# reference to anonymous label; the reference uses
# the supplied link caption
@ -850,7 +851,7 @@ class StandardDomain(Domain):
def _resolve_numref_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
node: pending_xref, contnode: Element) -> Optional[Element]:
if target in self.labels:
docname, labelid, figname = self.labels.get(target, ('', '', ''))
else:
@ -913,7 +914,7 @@ class StandardDomain(Domain):
def _resolve_keyword_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
node: pending_xref, contnode: Element) -> Optional[Element]:
# keywords are oddballs: they are referenced by named labels
docname, labelid, _ = self.labels.get(target, ('', '', ''))
if not docname:
@ -923,7 +924,7 @@ class StandardDomain(Domain):
def _resolve_doc_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
node: pending_xref, contnode: Element) -> Optional[Element]:
# directly reference to document by source name; can be absolute or relative
refdoc = node.get('refdoc', fromdocname)
docname = docname_join(refdoc, node['reftarget'])
@ -940,7 +941,7 @@ class StandardDomain(Domain):
def _resolve_option_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
node: pending_xref, contnode: Element) -> Optional[Element]:
progname = node.get('std:program')
target = target.strip()
docname, labelid = self.progoptions.get((progname, target), ('', ''))
@ -977,7 +978,7 @@ class StandardDomain(Domain):
def _resolve_obj_xref(self, env: "BuildEnvironment", fromdocname: str,
builder: "Builder", typ: str, target: str,
node: pending_xref, contnode: Element) -> Element:
node: pending_xref, contnode: Element) -> Optional[Element]:
objtypes = self.objtypes_for_role(typ) or []
for objtype in objtypes:
if (objtype, target) in self.objects:
@ -1041,7 +1042,7 @@ class StandardDomain(Domain):
def is_enumerable_node(self, node: Node) -> bool:
return node.__class__ in self.enumerable_nodes
def get_numfig_title(self, node: Node) -> str:
def get_numfig_title(self, node: Node) -> Optional[str]:
"""Get the title of enumerable nodes to refer them using its title"""
if self.is_enumerable_node(node):
elem = cast(Element, node)
@ -1055,7 +1056,7 @@ class StandardDomain(Domain):
return None
def get_enumerable_node_type(self, node: Node) -> str:
def get_enumerable_node_type(self, node: Node) -> Optional[str]:
"""Get type of enumerable nodes."""
def has_child(node: Element, cls: Type) -> bool:
return any(isinstance(child, cls) for child in node)
@ -1094,7 +1095,7 @@ class StandardDomain(Domain):
# Maybe it is defined in orphaned document.
raise ValueError from exc
def get_full_qualified_name(self, node: Element) -> str:
def get_full_qualified_name(self, node: Element) -> Optional[str]:
if node.get('reftype') == 'option':
progname = node.get('std:program')
command = ws_re.split(node.get('reftarget'))
@ -1109,7 +1110,8 @@ class StandardDomain(Domain):
return None
def warn_missing_reference(app: "Sphinx", domain: Domain, node: pending_xref) -> bool:
def warn_missing_reference(app: "Sphinx", domain: Domain, node: pending_xref
) -> Optional[bool]:
if (domain and domain.name != 'std') or node['reftype'] != 'ref':
return None
else:

View File

@ -14,8 +14,8 @@ from collections import defaultdict
from copy import copy
from datetime import datetime
from os import path
from typing import (TYPE_CHECKING, Any, Callable, Dict, Generator, Iterator, List, Set, Tuple,
Union)
from typing import (TYPE_CHECKING, Any, Callable, Dict, Generator, Iterator, List, Optional,
Set, Tuple, Union)
from docutils import nodes
from docutils.nodes import Node
@ -87,7 +87,7 @@ class BuildEnvironment:
transformations to resolve links to them.
"""
domains: Dict[str, Domain] = None
domains: Dict[str, Domain]
# --------- ENVIRONMENT INITIALIZATION -------------------------------------
@ -266,7 +266,7 @@ class BuildEnvironment:
raise an exception if the user tries to use an environment with an
incompatible versioning method.
"""
condition: Union[bool, Callable] = None
condition: Union[bool, Callable]
if callable(method):
condition = method
else:
@ -309,7 +309,7 @@ class BuildEnvironment:
domain.merge_domaindata(docnames, other.domaindata[domainname])
self.events.emit('env-merge-info', self, docnames, other)
def path2doc(self, filename: str) -> str:
def path2doc(self, filename: str) -> Optional[str]:
"""Return the docname for the filename if the file is document.
*filename* should be absolute or relative to the source directory.
@ -577,7 +577,7 @@ class BuildEnvironment:
# allow custom references to be resolved
self.events.emit('doctree-resolved', doctree, docname)
def collect_relations(self) -> Dict[str, List[str]]:
def collect_relations(self) -> Dict[str, List[Optional[str]]]:
traversed = set()
def traverse_toctree(parent: str, docname: str) -> Iterator[Tuple[str, str]]:

View File

@ -313,7 +313,7 @@ class TocTree:
return toc
def get_toctree_for(self, docname: str, builder: "Builder", collapse: bool,
**kwargs: Any) -> Element:
**kwargs: Any) -> Optional[Element]:
"""Return the global TOC nodetree."""
doctree = self.env.get_doctree(self.env.config.root_doc)
toctrees: List[Element] = []

View File

@ -8,7 +8,7 @@
:license: BSD, see LICENSE for details.
"""
from typing import TYPE_CHECKING, Dict, List, Set
from typing import TYPE_CHECKING, Dict, List, Optional, Set
from docutils import nodes
@ -27,7 +27,7 @@ class EnvironmentCollector:
entries and toctrees, etc.
"""
listener_ids: Dict[str, int] = None
listener_ids: Optional[Dict[str, int]] = None
def enable(self, app: "Sphinx") -> None:
assert self.listener_ids is None

View File

@ -25,6 +25,13 @@ from sphinx.pycode.parser import Parser
class ModuleAnalyzer:
annotations: Dict[Tuple[str, str], str]
attr_docs: Dict[Tuple[str, str], List[str]]
finals: List[str]
overloads: Dict[str, List[Signature]]
tagorder: Dict[str, int]
tags: Dict[str, Tuple[str, int, int]]
# cache for analyzer objects -- caches both by module and file name
cache: Dict[Tuple[str, str], Any] = {}
@ -134,13 +141,6 @@ class ModuleAnalyzer:
# cache the source code as well
self.code = source.read()
# will be filled by analyze()
self.annotations: Dict[Tuple[str, str], str] = None
self.attr_docs: Dict[Tuple[str, str], List[str]] = None
self.finals: List[str] = None
self.overloads: Dict[str, List[Signature]] = None
self.tagorder: Dict[str, int] = None
self.tags: Dict[str, Tuple[str, int, int]] = None
self._analyzed = False
def parse(self) -> None:

View File

@ -129,8 +129,8 @@ class TokenProcessor:
lines = iter(buffers)
self.buffers = buffers
self.tokens = tokenize.generate_tokens(lambda: next(lines))
self.current: Token = None
self.previous: Token = None
self.current: Optional[Token] = None
self.previous: Optional[Token] = None
def get_line(self, lineno: int) -> str:
"""Returns specified line."""
@ -178,7 +178,7 @@ class AfterCommentParser(TokenProcessor):
def __init__(self, lines: List[str]) -> None:
super().__init__(lines)
self.comment: str = None
self.comment: Optional[str] = None
def fetch_rvalue(self) -> List[Token]:
"""Fetch right-hand value of assignment."""
@ -223,16 +223,16 @@ class VariableCommentPicker(ast.NodeVisitor):
self.encoding = encoding
self.context: List[str] = []
self.current_classes: List[str] = []
self.current_function: ast.FunctionDef = None
self.current_function: Optional[ast.FunctionDef] = None
self.comments: Dict[Tuple[str, str], str] = OrderedDict()
self.annotations: Dict[Tuple[str, str], str] = {}
self.previous: ast.AST = None
self.previous: Optional[ast.AST] = None
self.deforders: Dict[str, int] = {}
self.finals: List[str] = []
self.overloads: Dict[str, List[Signature]] = {}
self.typing: str = None
self.typing_final: str = None
self.typing_overload: str = None
self.typing: Optional[str] = None
self.typing_final: Optional[str] = None
self.typing_overload: Optional[str] = None
super().__init__()
def get_qualname_for(self, name: str) -> Optional[List[str]]:
@ -308,7 +308,7 @@ class VariableCommentPicker(ast.NodeVisitor):
return False
def get_self(self) -> ast.arg:
def get_self(self) -> Optional[ast.arg]:
"""Returns the name of first argument if in function."""
if self.current_function and self.current_function.args.args:
return self.current_function.args.args[0]
@ -466,7 +466,7 @@ class DefinitionFinder(TokenProcessor):
def __init__(self, lines: List[str]) -> None:
super().__init__(lines)
self.decorator: Token = None
self.decorator: Optional[Token] = None
self.context: List[str] = []
self.indents: List = []
self.definitions: Dict[str, Tuple[str, int, int]] = {}

View File

@ -12,7 +12,7 @@ import pickle
import re
from importlib import import_module
from os import path
from typing import IO, Any, Dict, Iterable, List, Set, Tuple, Type
from typing import IO, Any, Dict, Iterable, List, Optional, Set, Tuple, Type
from docutils import nodes
from docutils.nodes import Node
@ -440,7 +440,7 @@ class IndexBuilder:
else:
return []
def get_js_stemmer_rawcode(self) -> str:
def get_js_stemmer_rawcode(self) -> Optional[str]:
return None
def get_js_stemmer_code(self) -> str:

View File

@ -10,7 +10,7 @@
from os import path
from textwrap import indent
from typing import TYPE_CHECKING, Any, Dict, List, Tuple, Type, TypeVar
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, TypeVar
from docutils import nodes
from docutils.io import StringInput
@ -416,7 +416,7 @@ class Locale(SphinxTransform):
.format(old_xref_rawsources, new_xref_rawsources),
location=node)
def get_ref_key(node: addnodes.pending_xref) -> Tuple[str, str, str]:
def get_ref_key(node: addnodes.pending_xref) -> Optional[Tuple[str, str, str]]:
case = node["refdomain"], node["reftype"]
if case == ('std', 'term'):
return None

View File

@ -22,8 +22,8 @@ from datetime import datetime
from importlib import import_module
from os import path
from time import mktime, strptime
from typing import (IO, TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Pattern,
Set, Tuple, Type)
from typing import (IO, TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Optional,
Pattern, Set, Tuple, Type)
from urllib.parse import parse_qsl, quote_plus, urlencode, urlsplit, urlunsplit
from sphinx.deprecation import RemovedInSphinx50Warning
@ -408,7 +408,7 @@ def import_object(objname: str, source: str = None) -> Any:
raise ExtensionError('Could not import %s' % objname, exc) from exc
def split_full_qualified_name(name: str) -> Tuple[str, str]:
def split_full_qualified_name(name: str) -> Tuple[Optional[str], str]:
"""Split full qualified name to a pair of modname and qualname.
A qualname is an abbreviation for "Qualified name" introduced at PEP-3155