From 17e26bf29fa6d8f2f40b9da47b1131c30680cd80 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 3 Jun 2019 22:23:55 +0900 Subject: [PATCH 01/12] Migrate to py3 style type annotation: sphinx.util.requests --- sphinx/util/requests.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/sphinx/util/requests.py b/sphinx/util/requests.py index dee52e281..a279b4eb4 100644 --- a/sphinx/util/requests.py +++ b/sphinx/util/requests.py @@ -10,11 +10,14 @@ import warnings from contextlib import contextmanager +from typing import Generator, Union from urllib.parse import urlsplit import pkg_resources import requests +from sphinx.config import Config + try: from requests.packages.urllib3.exceptions import SSLError except ImportError: @@ -54,17 +57,12 @@ else: pkg_resources.VersionConflict): pass # ignored -if False: - # For type annotation - from typing import Any, Generator, Union # NOQA - from sphinx.config import Config # NOQA useragent_header = [('User-Agent', 'Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0')] -def is_ssl_error(exc): - # type: (Exception) -> bool +def is_ssl_error(exc: Exception) -> bool: """Check an exception is SSLError.""" if isinstance(exc, SSLError): return True @@ -77,8 +75,7 @@ def is_ssl_error(exc): @contextmanager -def ignore_insecure_warning(**kwargs): - # type: (Any) -> Generator +def ignore_insecure_warning(**kwargs) -> Generator[None, None, None]: with warnings.catch_warnings(): if not kwargs.get('verify') and InsecureRequestWarning: # ignore InsecureRequestWarning if verify=False @@ -86,8 +83,7 @@ def ignore_insecure_warning(**kwargs): yield -def _get_tls_cacert(url, config): - # type: (str, Config) -> Union[str, bool] +def _get_tls_cacert(url: str, config: Config) -> Union[str, bool]: """Get additional CA cert for a specific URL. This also returns ``False`` if verification is disabled. @@ -109,8 +105,7 @@ def _get_tls_cacert(url, config): return certs.get(hostname, True) -def get(url, **kwargs): - # type: (str, Any) -> requests.Response +def get(url: str, **kwargs) -> requests.Response: """Sends a GET request like requests.get(). This sets up User-Agent header and TLS verification automatically.""" @@ -123,8 +118,7 @@ def get(url, **kwargs): return requests.get(url, **kwargs) -def head(url, **kwargs): - # type: (str, Any) -> requests.Response +def head(url: str, **kwargs) -> requests.Response: """Sends a HEAD request like requests.head(). This sets up User-Agent header and TLS verification automatically.""" From a3c9edfbe6d50b486ea28876e47b7d6e27379916 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 4 Jun 2019 01:00:15 +0900 Subject: [PATCH 02/12] Migrate to py3 style type annotation: sphinx.util.osutil --- sphinx/util/osutil.py | 75 +++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 50 deletions(-) diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py index 2b3fe51b0..3751fcc08 100644 --- a/sphinx/util/osutil.py +++ b/sphinx/util/osutil.py @@ -19,14 +19,11 @@ import time import warnings from io import StringIO from os import path +from typing import Any, Generator, Iterator, List, Tuple, Type from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning from sphinx.testing.path import path as Path -if False: - # For type annotation - from typing import Any, Iterator, List, Tuple # NOQA - # Errnos that we need. EEXIST = getattr(errno, 'EEXIST', 0) # RemovedInSphinx40Warning ENOENT = getattr(errno, 'ENOENT', 0) # RemovedInSphinx40Warning @@ -41,19 +38,16 @@ EINVAL = getattr(errno, 'EINVAL', 0) # RemovedInSphinx40Warning SEP = "/" -def os_path(canonicalpath): - # type: (str) -> str +def os_path(canonicalpath: str) -> str: return canonicalpath.replace(SEP, path.sep) -def canon_path(nativepath): - # type: (str) -> str +def canon_path(nativepath: str) -> str: """Return path in OS-independent form""" return nativepath.replace(path.sep, SEP) -def relative_uri(base, to): - # type: (str, str) -> str +def relative_uri(base: str, to: str) -> str: """Return a relative URL from ``base`` to ``to``.""" if to.startswith(SEP): return to @@ -76,22 +70,19 @@ def relative_uri(base, to): return ('..' + SEP) * (len(b2) - 1) + SEP.join(t2) -def ensuredir(path): - # type: (str) -> None +def ensuredir(path: str) -> None: """Ensure that a path exists.""" os.makedirs(path, exist_ok=True) -def walk(top, topdown=True, followlinks=False): - # type: (str, bool, bool) -> Iterator[Tuple[str, List[str], List[str]]] +def walk(top: str, topdown: bool = True, followlinks: bool = False) -> Iterator[Tuple[str, List[str], List[str]]]: # NOQA warnings.warn('sphinx.util.osutil.walk() is deprecated for removal. ' 'Please use os.walk() instead.', RemovedInSphinx40Warning) return os.walk(top, topdown=topdown, followlinks=followlinks) -def mtimes_of_files(dirnames, suffix): - # type: (List[str], str) -> Iterator[float] +def mtimes_of_files(dirnames: List[str], suffix: str) -> Iterator[float]: for dirname in dirnames: for root, dirs, files in os.walk(dirname): for sfile in files: @@ -102,8 +93,7 @@ def mtimes_of_files(dirnames, suffix): pass -def movefile(source, dest): - # type: (str, str) -> None +def movefile(source: str, dest: str) -> None: """Move a file, removing the destination if it exists.""" if os.path.exists(dest): try: @@ -113,16 +103,14 @@ def movefile(source, dest): os.rename(source, dest) -def copytimes(source, dest): - # type: (str, str) -> None +def copytimes(source: str, dest: str) -> None: """Copy a file's modification times.""" st = os.stat(source) if hasattr(os, 'utime'): os.utime(dest, (st.st_atime, st.st_mtime)) -def copyfile(source, dest): - # type: (str, str) -> None +def copyfile(source: str, dest: str) -> None: """Copy a file and its modification times, if possible. Note: ``copyfile`` skips copying if the file has not been changed""" @@ -139,18 +127,15 @@ no_fn_re = re.compile(r'[^a-zA-Z0-9_-]') project_suffix_re = re.compile(' Documentation$') -def make_filename(string): - # type: (str) -> str +def make_filename(string: str) -> str: return no_fn_re.sub('', string) or 'sphinx' -def make_filename_from_project(project): - # type: (str) -> str +def make_filename_from_project(project: str) -> str: return make_filename(project_suffix_re.sub('', project)).lower() -def ustrftime(format, *args): - # type: (str, Any) -> str +def ustrftime(format: str, *args) -> str: """[DEPRECATED] strftime for unicode strings.""" warnings.warn('sphinx.util.osutil.ustrtime is deprecated for removal', RemovedInSphinx30Warning, stacklevel=2) @@ -171,8 +156,7 @@ def ustrftime(format, *args): return r.encode().decode('unicode-escape') -def relpath(path, start=os.curdir): - # type: (str, str) -> str +def relpath(path: str, start: str = os.curdir) -> str: """Return a relative filepath to *path* either from the current directory or from an optional *start* directory. @@ -189,8 +173,7 @@ safe_relpath = relpath # for compatibility fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() -def abspath(pathdir): - # type: (str) -> str +def abspath(pathdir: str) -> str: if isinstance(pathdir, Path): return pathdir.abspath() else: @@ -205,8 +188,7 @@ def abspath(pathdir): return pathdir -def getcwd(): - # type: () -> str +def getcwd() -> str: warnings.warn('sphinx.util.osutil.getcwd() is deprecated. ' 'Please use os.getcwd() instead.', RemovedInSphinx40Warning) @@ -214,8 +196,7 @@ def getcwd(): @contextlib.contextmanager -def cd(target_dir): - # type: (str) -> Iterator[None] +def cd(target_dir: str) -> Generator[None, None, None]: cwd = os.getcwd() try: os.chdir(target_dir) @@ -236,19 +217,16 @@ class FileAvoidWrite: Objects can be used as context managers. """ - def __init__(self, path): - # type: (str) -> None + def __init__(self, path: str) -> None: self._path = path self._io = None # type: StringIO - def write(self, data): - # type: (str) -> None + def write(self, data: str) -> None: if not self._io: self._io = StringIO() self._io.write(data) - def close(self): - # type: () -> None + def close(self) -> None: """Stop accepting writes and write file, if needed.""" if not self._io: raise Exception('FileAvoidWrite does not support empty files.') @@ -267,16 +245,14 @@ class FileAvoidWrite: with open(self._path, 'w') as f: f.write(buf) - def __enter__(self): - # type: () -> FileAvoidWrite + def __enter__(self) -> "FileAvoidWrite": return self - def __exit__(self, type, value, traceback): - # type: (str, str, str) -> None + def __exit__(self, exc_type: Type[Exception], exc_value: Exception, traceback: Any) -> bool: # NOQA self.close() + return True - def __getattr__(self, name): - # type: (str) -> Any + def __getattr__(self, name: str) -> Any: # Proxy to _io instance. if not self._io: raise Exception('Must write to FileAvoidWrite before other ' @@ -285,8 +261,7 @@ class FileAvoidWrite: return getattr(self._io, name) -def rmtree(path): - # type: (str) -> None +def rmtree(path: str) -> None: if os.path.isdir(path): shutil.rmtree(path) else: From 073b92d45a59eb5065d304fbaf0fc2d2ff88c5e8 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 4 Jun 2019 01:00:45 +0900 Subject: [PATCH 03/12] Migrate to py3 style type annotation: sphinx.util.rst --- sphinx/util/rst.py | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/sphinx/util/rst.py b/sphinx/util/rst.py index c897b075a..0824e413f 100644 --- a/sphinx/util/rst.py +++ b/sphinx/util/rst.py @@ -11,23 +11,20 @@ import re from collections import defaultdict from contextlib import contextmanager +from typing import Dict, Generator from unicodedata import east_asian_width from docutils.parsers.rst import roles from docutils.parsers.rst.languages import en as english +from docutils.statemachine import StringList from docutils.utils import Reporter +from jinja2 import Environment from jinja2 import environmentfilter from sphinx.locale import __ from sphinx.util import docutils from sphinx.util import logging -if False: - # For type annotation - from typing import Callable, Dict, Generator # NOQA - from docutils.statemachine import StringList # NOQA - from jinja2 import Environment # NOQA - logger = logging.getLogger(__name__) docinfo_re = re.compile(':\\w+:.*?') @@ -40,18 +37,15 @@ WIDECHARS = defaultdict(lambda: "WF") # type: Dict[str, str] WIDECHARS["ja"] = "WFA" # In Japanese, Ambiguous characters also have double width -def escape(text): - # type: (str) -> str +def escape(text: str) -> str: text = symbols_re.sub(r'\\\1', text) text = re.sub(r'^\.', r'\.', text) # escape a dot at top return text -def textwidth(text, widechars='WF'): - # type: (str, str) -> int +def textwidth(text: str, widechars: str = 'WF') -> int: """Get width of text.""" - def charwidth(char, widechars): - # type: (str, str) -> int + def charwidth(char: str, widechars: str) -> int: if east_asian_width(char) in widechars: return 2 else: @@ -61,8 +55,7 @@ def textwidth(text, widechars='WF'): @environmentfilter -def heading(env, text, level=1): - # type: (Environment, str, int) -> str +def heading(env: Environment, text: str, level: int = 1) -> str: """Create a heading for *level*.""" assert level <= 3 width = textwidth(text, WIDECHARS[env.language]) # type: ignore @@ -71,8 +64,7 @@ def heading(env, text, level=1): @contextmanager -def default_role(docname, name): - # type: (str, str) -> Generator +def default_role(docname: str, name: str) -> Generator[None, None, None]: if name: dummy_reporter = Reporter('', 4, 4) role_fn, _ = roles.role(name, english, 0, dummy_reporter) @@ -86,8 +78,7 @@ def default_role(docname, name): docutils.unregister_role('') -def prepend_prolog(content, prolog): - # type: (StringList, str) -> None +def prepend_prolog(content: StringList, prolog: str) -> None: """Prepend a string to content body as prolog.""" if prolog: pos = 0 @@ -109,8 +100,7 @@ def prepend_prolog(content, prolog): content.insert(pos + lineno + 1, '', '', 0) -def append_epilog(content, epilog): - # type: (StringList, str) -> None +def append_epilog(content: StringList, epilog: str) -> None: """Append a string to content body as epilog.""" if epilog: content.append('', '', 0) From 1e70267cc8a3a31dbadea4e72971bec4c60cb255 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 4 Jun 2019 01:02:02 +0900 Subject: [PATCH 04/12] Migrate to py3 style type annotation: sphinx.util.template --- sphinx/util/template.py | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/sphinx/util/template.py b/sphinx/util/template.py index b521c5c79..636767d41 100644 --- a/sphinx/util/template.py +++ b/sphinx/util/template.py @@ -9,7 +9,9 @@ """ import os +from typing import Dict +from jinja2.loaders import BaseLoader from jinja2.sandbox import SandboxedEnvironment from sphinx import package_dir @@ -17,58 +19,45 @@ from sphinx.jinja2glue import SphinxFileSystemLoader from sphinx.locale import get_translator from sphinx.util import rst, texescape -if False: - # For type annotation - from typing import Dict # NOQA - from jinja2.loaders import BaseLoader # NOQA - class BaseRenderer: - def __init__(self, loader=None): - # type: (BaseLoader) -> None + def __init__(self, loader: BaseLoader = None) -> None: self.env = SandboxedEnvironment(loader=loader, extensions=['jinja2.ext.i18n']) self.env.filters['repr'] = repr self.env.install_gettext_translations(get_translator()) # type: ignore - def render(self, template_name, context): - # type: (str, Dict) -> str + def render(self, template_name: str, context: Dict) -> str: return self.env.get_template(template_name).render(context) - def render_string(self, source, context): - # type: (str, Dict) -> str + def render_string(self, source: str, context: Dict) -> str: return self.env.from_string(source).render(context) class FileRenderer(BaseRenderer): - def __init__(self, search_path): - # type: (str) -> None + def __init__(self, search_path: str) -> None: loader = SphinxFileSystemLoader(search_path) super().__init__(loader) @classmethod - def render_from_file(cls, filename, context): - # type: (str, Dict) -> str + def render_from_file(cls, filename: str, context: Dict) -> str: dirname = os.path.dirname(filename) basename = os.path.basename(filename) return cls(dirname).render(basename, context) class SphinxRenderer(FileRenderer): - def __init__(self, template_path=None): - # type: (str) -> None + def __init__(self, template_path: str = None) -> None: if template_path is None: template_path = os.path.join(package_dir, 'templates') super().__init__(template_path) @classmethod - def render_from_file(cls, filename, context): - # type: (str, Dict) -> str + def render_from_file(cls, filename: str, context: Dict) -> str: return FileRenderer.render_from_file(filename, context) class LaTeXRenderer(SphinxRenderer): - def __init__(self, template_path=None): - # type: (str) -> None + def __init__(self, template_path: str = None) -> None: if template_path is None: template_path = os.path.join(package_dir, 'templates', 'latex') super().__init__(template_path) @@ -87,8 +76,7 @@ class LaTeXRenderer(SphinxRenderer): class ReSTRenderer(SphinxRenderer): - def __init__(self, template_path=None, language=None): - # type: (str, str) -> None + def __init__(self, template_path: str = None, language: str = None) -> None: super().__init__(template_path) # add language to environment From 8aa04eb85537e6607718fad35b70758747258248 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 4 Jun 2019 01:02:23 +0900 Subject: [PATCH 05/12] Migrate to py3 style type annotation: sphinx.util.nodes --- sphinx/util/nodes.py | 98 +++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 60 deletions(-) diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index 58c6a6698..e0aaaa14e 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -10,9 +10,14 @@ import re import warnings -from typing import Any, cast +from typing import Any, Callable, Iterable, List, Set, Tuple, Type +from typing import cast from docutils import nodes +from docutils.nodes import Element, Node +from docutils.parsers.rst import Directive +from docutils.parsers.rst.states import Inliner +from docutils.statemachine import StringList from sphinx import addnodes from sphinx.deprecation import RemovedInSphinx40Warning @@ -21,11 +26,8 @@ from sphinx.util import logging if False: # For type annotation - from typing import Callable, Iterable, List, Optional, Set, Tuple, Type # NOQA - from docutils.parsers.rst.states import Inliner # NOQA - from docutils.statemachine import StringList # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.utils.tags import Tags # NOQA + from sphinx.builders import Builder + from sphinx.utils.tags import Tags logger = logging.getLogger(__name__) @@ -57,13 +59,11 @@ class NodeMatcher: # => [, , ...] """ - def __init__(self, *classes, **attrs): - # type: (Type[nodes.Node], Any) -> None + def __init__(self, *classes: Type[Node], **attrs) -> None: self.classes = classes self.attrs = attrs - def match(self, node): - # type: (nodes.Node) -> bool + def match(self, node: Node) -> bool: try: if self.classes and not isinstance(node, self.classes): return False @@ -85,13 +85,11 @@ class NodeMatcher: # for non-Element nodes return False - def __call__(self, node): - # type: (nodes.Node) -> bool + def __call__(self, node: Node) -> bool: return self.match(node) -def get_full_module_name(node): - # type: (nodes.Node) -> str +def get_full_module_name(node: Node) -> str: """ return full module dotted path like: 'docutils.nodes.paragraph' @@ -101,8 +99,7 @@ def get_full_module_name(node): return '{}.{}'.format(node.__module__, node.__class__.__name__) -def repr_domxml(node, length=80): - # type: (nodes.Node, Optional[int]) -> str +def repr_domxml(node: Node, length: int = 80) -> str: """ return DOM XML representation of the specified node like: 'New in version...' @@ -122,8 +119,7 @@ def repr_domxml(node, length=80): return text -def apply_source_workaround(node): - # type: (nodes.Element) -> None +def apply_source_workaround(node: Element) -> None: # workaround: nodes.term have wrong rawsource if classifier is specified. # The behavior of docutils-0.11, 0.12 is: # * when ``term text : classifier1 : classifier2`` is specified, @@ -186,8 +182,7 @@ IGNORED_NODES = ( ) -def is_pending_meta(node): - # type: (nodes.Node) -> bool +def is_pending_meta(node: Node) -> bool: if (isinstance(node, nodes.pending) and isinstance(node.details.get('nodes', [None])[0], addnodes.meta)): return True @@ -195,8 +190,7 @@ def is_pending_meta(node): return False -def is_translatable(node): - # type: (nodes.Node) -> bool +def is_translatable(node: Node) -> bool: if isinstance(node, addnodes.translatable): return True @@ -251,8 +245,7 @@ META_TYPE_NODES = ( ) -def extract_messages(doctree): - # type: (nodes.Element) -> Iterable[Tuple[nodes.Element, str]] +def extract_messages(doctree: Element) -> Iterable[Tuple[Element, str]]: """Extract translatable messages from a document tree.""" for node in doctree.traverse(is_translatable): # type: nodes.Element if isinstance(node, addnodes.translatable): @@ -279,39 +272,34 @@ def extract_messages(doctree): yield node, msg -def find_source_node(node): - # type: (nodes.Element) -> str +def find_source_node(node: Element) -> str: warnings.warn('find_source_node() is deprecated.', RemovedInSphinx40Warning) return get_node_source(node) -def get_node_source(node): - # type: (nodes.Element) -> str +def get_node_source(node: Element) -> str: for pnode in traverse_parent(node): if pnode.source: return pnode.source return None -def get_node_line(node): - # type: (nodes.Element) -> int +def get_node_line(node: Element) -> int: for pnode in traverse_parent(node): if pnode.line: return pnode.line return None -def traverse_parent(node, cls=None): - # type: (nodes.Element, Any) -> Iterable[nodes.Element] +def traverse_parent(node: Element, cls: Any = None) -> Iterable[Element]: while node: if cls is None or isinstance(node, cls): yield node node = node.parent -def get_prev_node(node): - # type: (nodes.Node) -> nodes.Node +def get_prev_node(node: Node) -> Node: pos = node.parent.index(node) if pos > 0: return node.parent[pos - 1] @@ -319,8 +307,7 @@ def get_prev_node(node): return None -def traverse_translatable_index(doctree): - # type: (nodes.Element) -> Iterable[Tuple[nodes.Element, List[str]]] +def traverse_translatable_index(doctree: Element) -> Iterable[Tuple[Element, List[str]]]: """Traverse translatable index node from a document tree.""" for node in doctree.traverse(NodeMatcher(addnodes.index, inline=False)): # type: addnodes.index # NOQA if 'raw_entries' in node: @@ -330,8 +317,7 @@ def traverse_translatable_index(doctree): yield node, entries -def nested_parse_with_titles(state, content, node): - # type: (Any, StringList, nodes.Node) -> str +def nested_parse_with_titles(state: Any, content: StringList, node: Node) -> str: """Version of state.nested_parse() that allows titles and does not require titles to have the same decoration as the calling document. @@ -350,8 +336,7 @@ def nested_parse_with_titles(state, content, node): state.memo.section_level = surrounding_section_level -def clean_astext(node): - # type: (nodes.Element) -> str +def clean_astext(node: Element) -> str: """Like node.astext(), but ignore images.""" node = node.deepcopy() for img in node.traverse(nodes.image): @@ -361,8 +346,7 @@ def clean_astext(node): return node.astext() -def split_explicit_title(text): - # type: (str) -> Tuple[bool, str, str] +def split_explicit_title(text: str) -> Tuple[bool, str, str]: """Split role content into title and target, if given.""" match = explicit_title_re.match(text) if match: @@ -375,8 +359,7 @@ indextypes = [ ] -def process_index_entry(entry, targetid): - # type: (str, str) -> List[Tuple[str, str, str, str, str]] +def process_index_entry(entry: str, targetid: str) -> List[Tuple[str, str, str, str, str]]: from sphinx.domains.python import pairindextypes indexentries = [] # type: List[Tuple[str, str, str, str, str]] @@ -414,8 +397,9 @@ def process_index_entry(entry, targetid): return indexentries -def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc, traversed): - # type: (Builder, Set[str], str, nodes.document, Callable, List[str]) -> nodes.document +def inline_all_toctrees(builder: "Builder", docnameset: Set[str], docname: str, + tree: nodes.document, colorfunc: Callable, traversed: List[str] + ) -> nodes.document: """Inline all toctrees in the *tree*. Record all docnames in *docnameset*, and output docnames with *colorfunc*. @@ -447,8 +431,8 @@ def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc, traversed return tree -def make_refnode(builder, fromdocname, todocname, targetid, child, title=None): - # type: (Builder, str, str, str, nodes.Node, str) -> nodes.reference +def make_refnode(builder: "Builder", fromdocname: str, todocname: str, targetid: str, + child: Node, title: str = None) -> nodes.reference: """Shortcut to create a reference node.""" node = nodes.reference('', '', internal=True) if fromdocname == todocname and targetid: @@ -465,19 +449,16 @@ def make_refnode(builder, fromdocname, todocname, targetid, child, title=None): return node -def set_source_info(directive, node): - # type: (Any, nodes.Node) -> None +def set_source_info(directive: Directive, node: Node) -> None: node.source, node.line = \ directive.state_machine.get_source_and_line(directive.lineno) -def set_role_source_info(inliner, lineno, node): - # type: (Inliner, int, nodes.Node) -> None +def set_role_source_info(inliner: Inliner, lineno: int, node: Node) -> None: node.source, node.line = inliner.reporter.get_source_and_line(lineno) # type: ignore -def copy_source_info(src, dst): - # type: (nodes.Element, nodes.Element) -> None +def copy_source_info(src: Element, dst: Element) -> None: dst.source = get_node_source(src) dst.line = get_node_line(src) @@ -493,8 +474,7 @@ NON_SMARTQUOTABLE_PARENT_NODES = ( ) -def is_smartquotable(node): - # type: (nodes.Node) -> bool +def is_smartquotable(node: Node) -> bool: """Check the node is smart-quotable or not.""" if isinstance(node.parent, NON_SMARTQUOTABLE_PARENT_NODES): return False @@ -506,8 +486,7 @@ def is_smartquotable(node): return True -def process_only_nodes(document, tags): - # type: (nodes.Node, Tags) -> None +def process_only_nodes(document: Node, tags: "Tags") -> None: """Filter ``only`` nodes which does not match *tags*.""" for node in document.traverse(addnodes.only): try: @@ -530,8 +509,7 @@ def process_only_nodes(document, tags): # monkey-patch Element.copy to copy the rawsource and line # for docutils-0.14 or older versions. -def _new_copy(self): - # type: (nodes.Element) -> nodes.Element +def _new_copy(self: Element) -> Element: newnode = self.__class__(self.rawsource, **self.attributes) if isinstance(self, nodes.Element): newnode.source = self.source From 086e46bdf212063e5cde6964ab02a24d6f6fe5fc Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 5 Jun 2019 01:30:23 +0900 Subject: [PATCH 06/12] Migrate to py3 style type annotation: sphinx.util.math --- sphinx/util/math.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sphinx/util/math.py b/sphinx/util/math.py index d296a3fe0..2af4e4db6 100644 --- a/sphinx/util/math.py +++ b/sphinx/util/math.py @@ -8,15 +8,12 @@ :license: BSD, see LICENSE for details. """ +from docutils import nodes -if False: - # For type annotation - from docutils import nodes # NOQA - from sphinx.builders.html import HTMLTranslator # NOQA +from sphinx.builders.html import HTMLTranslator -def get_node_equation_number(writer, node): - # type: (HTMLTranslator, nodes.math_block) -> str +def get_node_equation_number(writer: HTMLTranslator, node: nodes.math_block) -> str: if writer.builder.config.math_numfig and writer.builder.config.numfig: figtype = 'displaymath' if writer.builder.name == 'singlehtml': @@ -31,10 +28,8 @@ def get_node_equation_number(writer, node): return node['number'] -def wrap_displaymath(text, label, numbering): - # type: (str, str, bool) -> str - def is_equation(part): - # type: (str) -> str +def wrap_displaymath(text: str, label: str, numbering: bool) -> str: + def is_equation(part: str) -> str: return part.strip() if label is None: From 09d8526ee772f10cd04eb579a8b40e540a99fdc5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 5 Jun 2019 01:31:10 +0900 Subject: [PATCH 07/12] Migrate to py3 style type annotation: sphinx.util.parallel --- sphinx/util/parallel.py | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/sphinx/util/parallel.py b/sphinx/util/parallel.py index 013dc3071..2d519a8d3 100644 --- a/sphinx/util/parallel.py +++ b/sphinx/util/parallel.py @@ -12,6 +12,7 @@ import os import time import traceback from math import sqrt +from typing import Any, Callable, Dict, List, Sequence try: import multiprocessing @@ -21,10 +22,6 @@ except ImportError: from sphinx.errors import SphinxParallelError from sphinx.util import logging -if False: - # For type annotation - from typing import Any, Callable, Dict, List, Sequence # NOQA - logger = logging.getLogger(__name__) @@ -35,12 +32,10 @@ parallel_available = multiprocessing and (os.name == 'posix') class SerialTasks: """Has the same interface as ParallelTasks, but executes tasks directly.""" - def __init__(self, nproc=1): - # type: (int) -> None + def __init__(self, nproc: int = 1) -> None: pass - def add_task(self, task_func, arg=None, result_func=None): - # type: (Callable, Any, Callable) -> None + def add_task(self, task_func: Callable, arg: Any = None, result_func: Callable = None) -> None: # NOQA if arg is not None: res = task_func(arg) else: @@ -48,16 +43,14 @@ class SerialTasks: if result_func: result_func(res) - def join(self): - # type: () -> None + def join(self) -> None: pass class ParallelTasks: """Executes *nproc* tasks in parallel after forking.""" - def __init__(self, nproc): - # type: (int) -> None + def __init__(self, nproc: int) -> None: self.nproc = nproc # (optional) function performed by each task on the result of main task self._result_funcs = {} # type: Dict[int, Callable] @@ -74,8 +67,7 @@ class ParallelTasks: # task number of each subprocess self._taskid = 0 - def _process(self, pipe, func, arg): - # type: (Any, Callable, Any) -> None + def _process(self, pipe: Any, func: Callable, arg: Any) -> None: try: collector = logging.LogCollector() with collector.collect(): @@ -91,8 +83,7 @@ class ParallelTasks: logging.convert_serializable(collector.logs) pipe.send((failed, collector.logs, ret)) - def add_task(self, task_func, arg=None, result_func=None): - # type: (Callable, Any, Callable) -> None + def add_task(self, task_func: Callable, arg: Any = None, result_func: Callable = None) -> None: # NOQA tid = self._taskid self._taskid += 1 self._result_funcs[tid] = result_func or (lambda arg, result: None) @@ -104,13 +95,11 @@ class ParallelTasks: self._precvsWaiting[tid] = precv self._join_one() - def join(self): - # type: () -> None + def join(self) -> None: while self._pworking: self._join_one() - def _join_one(self): - # type: () -> None + def _join_one(self) -> None: for tid, pipe in self._precvs.items(): if pipe.poll(): exc, logs, result = pipe.recv() @@ -132,8 +121,7 @@ class ParallelTasks: self._pworking += 1 -def make_chunks(arguments, nproc, maxbatch=10): - # type: (Sequence[str], int, int) -> List[Any] +def make_chunks(arguments: Sequence[str], nproc: int, maxbatch: int = 10) -> List[Any]: # determine how many documents to read in one go nargs = len(arguments) chunksize = nargs // nproc From ffe5e129c3bcb4a0ecd80e5863c92d94910ecffd Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 5 Jun 2019 01:50:22 +0900 Subject: [PATCH 09/12] Migrate to py3 style type annotation: sphinx.util.stemmer --- sphinx/util/stemmer/__init__.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sphinx/util/stemmer/__init__.py b/sphinx/util/stemmer/__init__.py index 047aac708..bda5d2bc2 100644 --- a/sphinx/util/stemmer/__init__.py +++ b/sphinx/util/stemmer/__init__.py @@ -18,18 +18,15 @@ except ImportError: class BaseStemmer: - def stem(self, word): - # type: (str) -> str + def stem(self, word: str) -> str: raise NotImplementedError() class PyStemmer(BaseStemmer): - def __init__(self): - # type: () -> None + def __init__(self) -> None: self.stemmer = _PyStemmer('porter') - def stem(self, word): - # type: (str) -> str + def stem(self, word: str) -> str: return self.stemmer.stemWord(word) @@ -37,13 +34,11 @@ class StandardStemmer(PorterStemmer, BaseStemmer): # type: ignore """All those porter stemmer implementations look hideous; make at least the stem method nicer. """ - def stem(self, word): # type: ignore - # type: (str) -> str + def stem(self, word: str) -> str: # type: ignore return super().stem(word, 0, len(word) - 1) -def get_stemmer(): - # type: () -> BaseStemmer +def get_stemmer() -> BaseStemmer: if PYSTEMMER: return PyStemmer() else: From d141fbf054cf3885538820363460e9e729e3cef0 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 5 Jun 2019 01:49:51 +0900 Subject: [PATCH 10/12] Migrate to py3 style type annotation: sphinx.util.stemmer.porter --- sphinx/util/stemmer/porter.py | 48 ++++++++++++----------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/sphinx/util/stemmer/porter.py b/sphinx/util/stemmer/porter.py index 51c132c2c..1f979624a 100644 --- a/sphinx/util/stemmer/porter.py +++ b/sphinx/util/stemmer/porter.py @@ -30,8 +30,7 @@ class PorterStemmer: - def __init__(self): - # type: () -> None + def __init__(self) -> None: """The main part of the stemming algorithm starts here. b is a buffer holding a word to be stemmed. The letters are in b[k0], b[k0+1] ... ending at b[k]. In fact k0 = 0 in this demo program. k is @@ -47,8 +46,7 @@ class PorterStemmer: self.k0 = 0 self.j = 0 # j is a general offset into the string - def cons(self, i): - # type: (int) -> int + def cons(self, i: int) -> int: """cons(i) is TRUE <=> b[i] is a consonant.""" if self.b[i] == 'a' or self.b[i] == 'e' or self.b[i] == 'i' \ or self.b[i] == 'o' or self.b[i] == 'u': @@ -60,8 +58,7 @@ class PorterStemmer: return (not self.cons(i - 1)) return 1 - def m(self): - # type: () -> int + def m(self) -> int: """m() measures the number of consonant sequences between k0 and j. if c is a consonant sequence and v a vowel sequence, and <..> indicates arbitrary presence, @@ -98,16 +95,14 @@ class PorterStemmer: i = i + 1 i = i + 1 - def vowelinstem(self): - # type: () -> int + def vowelinstem(self) -> int: """vowelinstem() is TRUE <=> k0,...j contains a vowel""" for i in range(self.k0, self.j + 1): if not self.cons(i): return 1 return 0 - def doublec(self, j): - # type: (int) -> int + def doublec(self, j: int) -> int: """doublec(j) is TRUE <=> j,(j-1) contain a double consonant.""" if j < (self.k0 + 1): return 0 @@ -115,8 +110,7 @@ class PorterStemmer: return 0 return self.cons(j) - def cvc(self, i): - # type: (int) -> int + def cvc(self, i: int) -> int: """cvc(i) is TRUE <=> i-2,i-1,i has the form consonant - vowel - consonant and also if the second c is not w,x or y. this is used when trying to @@ -133,8 +127,7 @@ class PorterStemmer: return 0 return 1 - def ends(self, s): - # type: (str) -> int + def ends(self, s: str) -> int: """ends(s) is TRUE <=> k0,...k ends with the string s.""" length = len(s) if s[length - 1] != self.b[self.k]: # tiny speed-up @@ -146,22 +139,19 @@ class PorterStemmer: self.j = self.k - length return 1 - def setto(self, s): - # type: (str) -> None + def setto(self, s: str) -> None: """setto(s) sets (j+1),...k to the characters in the string s, readjusting k.""" length = len(s) self.b = self.b[:self.j + 1] + s + self.b[self.j + length + 1:] self.k = self.j + length - def r(self, s): - # type: (str) -> None + def r(self, s: str) -> None: """r(s) is used further down.""" if self.m() > 0: self.setto(s) - def step1ab(self): - # type: () -> None + def step1ab(self) -> None: """step1ab() gets rid of plurals and -ed or -ing. e.g. caresses -> caress @@ -208,15 +198,13 @@ class PorterStemmer: elif (self.m() == 1 and self.cvc(self.k)): self.setto("e") - def step1c(self): - # type: () -> None + def step1c(self) -> None: """step1c() turns terminal y to i when there is another vowel in the stem.""" if (self.ends("y") and self.vowelinstem()): self.b = self.b[:self.k] + 'i' + self.b[self.k + 1:] - def step2(self): - # type: () -> None + def step2(self) -> None: """step2() maps double suffices to single ones. so -ization ( = -ize plus -ation) maps to -ize etc. note that the string before the suffix must give m() > 0. @@ -275,8 +263,7 @@ class PorterStemmer: self.r("log") # To match the published algorithm, delete this phrase - def step3(self): - # type: () -> None + def step3(self) -> None: """step3() dels with -ic-, -full, -ness etc. similar strategy to step2.""" if self.b[self.k] == 'e': @@ -298,8 +285,7 @@ class PorterStemmer: if self.ends("ness"): self.r("") - def step4(self): - # type: () -> None + def step4(self) -> None: """step4() takes off -ant, -ence etc., in context vcvc.""" if self.b[self.k - 1] == 'a': if self.ends("al"): @@ -382,8 +368,7 @@ class PorterStemmer: if self.m() > 1: self.k = self.j - def step5(self): - # type: () -> None + def step5(self) -> None: """step5() removes a final -e if m() > 1, and changes -ll to -l if m() > 1. """ @@ -395,8 +380,7 @@ class PorterStemmer: if self.b[self.k] == 'l' and self.doublec(self.k) and self.m() > 1: self.k = self.k - 1 - def stem(self, p, i, j): - # type: (str, int, int) -> str + def stem(self, p: str, i: int, j: int) -> str: """In stem(p,i,j), p is a char pointer, and the string to be stemmed is from p[i] to p[j] inclusive. Typically i is zero and j is the offset to the last character of a string, (p[j+1] == '\0'). The From 60b1cec446ef184adc91bdaaca93980c49312ba7 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 5 Jun 2019 01:51:07 +0900 Subject: [PATCH 11/12] Migrate to py3 style type annotation: sphinx.util.smartypants --- sphinx/util/smartypants.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sphinx/util/smartypants.py b/sphinx/util/smartypants.py index 7450e07b8..47f8b59b2 100644 --- a/sphinx/util/smartypants.py +++ b/sphinx/util/smartypants.py @@ -26,14 +26,12 @@ """ import re +from typing import Generator, Iterable, Tuple from docutils.utils import smartquotes from sphinx.util.docutils import __version_info__ as docutils_version -if False: # For type annotation - from typing import Generator, Iterable, Tuple # NOQA - langquotes = {'af': '“”‘’', 'af-x-altquot': '„”‚’', @@ -125,8 +123,7 @@ langquotes = {'af': '“”‘’', } -def educateQuotes(text, language='en'): - # type: (str, str) -> str +def educateQuotes(text: str, language: str = 'en') -> str: """ Parameter: - text string (unicode or bytes). - language (`BCP 47` language tag.) @@ -240,8 +237,10 @@ def educateQuotes(text, language='en'): return text -def educate_tokens(text_tokens, attr=smartquotes.default_smartypants_attr, language='en'): - # type: (Iterable[Tuple[str, str]], str, str) -> Generator[str, None, None] +def educate_tokens(text_tokens: Iterable[Tuple[str, str]], + attr: str = smartquotes.default_smartypants_attr, + language: str = 'en' + ) -> Generator[str, None, None]: """Return iterator that "educates" the items of `text_tokens`. This is modified to intercept the ``attr='2'`` as it was used by the From 9c5b26756a79ae9bbbe6bf385019687494a85649 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 5 Jun 2019 01:52:15 +0900 Subject: [PATCH 12/12] Migrate to py3 style type annotation: sphinx.util --- sphinx/util/__init__.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 66c53b37e..1fb7bcde6 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -337,15 +337,13 @@ _coding_re = re.compile(r'coding[:=]\s*([-\w.]+)') def detect_encoding(readline: Callable[[], bytes]) -> str: """Like tokenize.detect_encoding() from Py3k, but a bit simplified.""" - def read_or_stop(): - # type: () -> bytes + def read_or_stop() -> bytes: try: return readline() except StopIteration: return None - def get_normal_name(orig_enc): - # type: (str) -> str + def get_normal_name(orig_enc: str) -> str: """Imitates get_normal_name in tokenizer.c.""" # Only care about the first 12 characters. enc = orig_enc[:12].lower().replace('_', '-') @@ -356,8 +354,7 @@ def detect_encoding(readline: Callable[[], bytes]) -> str: return 'iso-8859-1' return orig_enc - def find_cookie(line): - # type: (bytes) -> str + def find_cookie(line: bytes) -> str: try: line_string = line.decode('ascii') except UnicodeDecodeError: