From 20f2845e218ffee6461868a4c92f0ccd98f6b3ba Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jun 2019 21:47:16 +0900 Subject: [PATCH 01/13] Migrate to py3 style type annotation: sphinx.util.inventory --- sphinx/util/inventory.py | 47 +++++++++++++++------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/sphinx/util/inventory.py b/sphinx/util/inventory.py index 0fdc3e833..43a868e95 100644 --- a/sphinx/util/inventory.py +++ b/sphinx/util/inventory.py @@ -10,20 +10,20 @@ import os import re import zlib +from typing import Callable, IO, Iterator from sphinx.util import logging - -if False: - # For type annotation - from typing import Callable, IO, Iterator # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA - from sphinx.util.typing import Inventory # NOQA +from sphinx.util.typing import Inventory BUFSIZE = 16 * 1024 logger = logging.getLogger(__name__) +if False: + # For type annotation + from sphinx.builders import Builder + from sphinx.environment import BuildEnvironment + class InventoryFileReader: """A file reader for inventory file. @@ -31,21 +31,18 @@ class InventoryFileReader: This reader supports mixture of texts and compressed texts. """ - def __init__(self, stream): - # type: (IO) -> None + def __init__(self, stream: IO) -> None: self.stream = stream self.buffer = b'' self.eof = False - def read_buffer(self): - # type: () -> None + def read_buffer(self) -> None: chunk = self.stream.read(BUFSIZE) if chunk == b'': self.eof = True self.buffer += chunk - def readline(self): - # type: () -> str + def readline(self) -> str: pos = self.buffer.find(b'\n') if pos != -1: line = self.buffer[:pos].decode() @@ -59,15 +56,13 @@ class InventoryFileReader: return line - def readlines(self): - # type: () -> Iterator[str] + def readlines(self) -> Iterator[str]: while not self.eof: line = self.readline() if line: yield line - def read_compressed_chunks(self): - # type: () -> Iterator[bytes] + def read_compressed_chunks(self) -> Iterator[bytes]: decompressor = zlib.decompressobj() while not self.eof: self.read_buffer() @@ -75,8 +70,7 @@ class InventoryFileReader: self.buffer = b'' yield decompressor.flush() - def read_compressed_lines(self): - # type: () -> Iterator[str] + def read_compressed_lines(self) -> Iterator[str]: buf = b'' for chunk in self.read_compressed_chunks(): buf += chunk @@ -89,8 +83,7 @@ class InventoryFileReader: class InventoryFile: @classmethod - def load(cls, stream, uri, joinfunc): - # type: (IO, str, Callable) -> Inventory + def load(cls, stream: IO, uri: str, joinfunc: Callable) -> Inventory: reader = InventoryFileReader(stream) line = reader.readline().rstrip() if line == '# Sphinx inventory version 1': @@ -101,8 +94,7 @@ class InventoryFile: raise ValueError('invalid inventory header: %s' % line) @classmethod - def load_v1(cls, stream, uri, join): - # type: (InventoryFileReader, str, Callable) -> Inventory + def load_v1(cls, stream: InventoryFileReader, uri: str, join: Callable) -> Inventory: invdata = {} # type: Inventory projname = stream.readline().rstrip()[11:] version = stream.readline().rstrip()[11:] @@ -120,8 +112,7 @@ class InventoryFile: return invdata @classmethod - def load_v2(cls, stream, uri, join): - # type: (InventoryFileReader, str, Callable) -> Inventory + def load_v2(cls, stream: InventoryFileReader, uri: str, join: Callable) -> Inventory: invdata = {} # type: Inventory projname = stream.readline().rstrip()[11:] version = stream.readline().rstrip()[11:] @@ -150,10 +141,8 @@ class InventoryFile: return invdata @classmethod - def dump(cls, filename, env, builder): - # type: (str, BuildEnvironment, Builder) -> None - def escape(string): - # type: (str) -> str + def dump(cls, filename: str, env: "BuildEnvironment", builder: "Builder") -> None: + def escape(string: str) -> str: return re.sub("\\s+", " ", string) with open(os.path.join(filename), 'wb') as f: From d9469c08ed02634df11cf9dc7a3df3e512cedb8b Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jun 2019 21:49:09 +0900 Subject: [PATCH 02/13] Migrate to py3 style type annotation: sphinx.util.jsdump --- sphinx/util/jsdump.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/sphinx/util/jsdump.py b/sphinx/util/jsdump.py index 0bab2f014..bfdba170b 100644 --- a/sphinx/util/jsdump.py +++ b/sphinx/util/jsdump.py @@ -10,10 +10,7 @@ """ import re - -if False: - # For type annotation - from typing import Any, Dict, IO, List, Match, Union # NOQA +from typing import Any, Dict, IO, List, Match, Union _str_re = re.compile(r'"(\\\\|\\"|[^"])*"') _int_re = re.compile(r'\d+') @@ -35,10 +32,8 @@ ESCAPE_DICT = { ESCAPED = re.compile(r'\\u.{4}|\\.') -def encode_string(s): - # type: (str) -> str - def replace(match): - # type: (Match) -> str +def encode_string(s: str) -> str: + def replace(match: Match) -> str: s = match.group(0) try: return ESCAPE_DICT[s] @@ -55,8 +50,7 @@ def encode_string(s): return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' -def decode_string(s): - # type: (str) -> str +def decode_string(s: str) -> str: return ESCAPED.sub(lambda m: eval('"' + m.group() + '"'), s) @@ -78,8 +72,7 @@ do import static with double in super""".split()) -def dumps(obj, key=False): - # type: (Any, bool) -> str +def dumps(obj: Any, key: bool = False) -> str: if key: if not isinstance(obj, str): obj = str(obj) @@ -107,13 +100,11 @@ def dumps(obj, key=False): raise TypeError(type(obj)) -def dump(obj, f): - # type: (Any, IO) -> None +def dump(obj: Any, f: IO) -> None: f.write(dumps(obj)) -def loads(x): - # type: (str) -> Any +def loads(x: str) -> Any: """Loader that can read the JS subset the indexer produces.""" nothing = object() i = 0 @@ -205,6 +196,5 @@ def loads(x): return obj -def load(f): - # type: (IO) -> Any +def load(f: IO) -> Any: return loads(f.read()) From d59e362f5f7d1df333ad6c3b1c24fabd000230cc Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jun 2019 21:49:21 +0900 Subject: [PATCH 03/13] Migrate to py3 style type annotation: sphinx.util.jsonimpl --- sphinx/util/jsonimpl.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/sphinx/util/jsonimpl.py b/sphinx/util/jsonimpl.py index 4fb8e1f5d..c5336a195 100644 --- a/sphinx/util/jsonimpl.py +++ b/sphinx/util/jsonimpl.py @@ -11,13 +11,10 @@ import json import warnings from collections import UserString +from typing import Any, IO from sphinx.deprecation import RemovedInSphinx40Warning -if False: - # For type annotation - from typing import Any, IO # NOQA - warnings.warn('sphinx.util.jsonimpl is deprecated', RemovedInSphinx40Warning, stacklevel=2) @@ -25,30 +22,25 @@ warnings.warn('sphinx.util.jsonimpl is deprecated', class SphinxJSONEncoder(json.JSONEncoder): """JSONEncoder subclass that forces translation proxies.""" - def default(self, obj): - # type: (Any) -> str + def default(self, obj: Any) -> str: if isinstance(obj, UserString): return str(obj) return super().default(obj) -def dump(obj, fp, *args, **kwds): - # type: (Any, IO, Any, Any) -> None +def dump(obj: Any, fp: IO, *args, **kwds) -> None: kwds['cls'] = SphinxJSONEncoder json.dump(obj, fp, *args, **kwds) -def dumps(obj, *args, **kwds): - # type: (Any, Any, Any) -> str +def dumps(obj: Any, *args, **kwds) -> str: kwds['cls'] = SphinxJSONEncoder return json.dumps(obj, *args, **kwds) -def load(*args, **kwds): - # type: (Any, Any) -> Any +def load(*args, **kwds) -> Any: return json.load(*args, **kwds) -def loads(*args, **kwds): - # type: (Any, Any) -> Any +def loads(*args, **kwds) -> Any: return json.loads(*args, **kwds) From 47d9035bca9e83d6db30a0726a02dc9265bd66b1 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Fri, 19 Apr 2019 13:22:17 +0900 Subject: [PATCH 04/13] Migrate to py3 style type annotation: sphinx.util.logging --- sphinx/util/logging.py | 116 ++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 76 deletions(-) diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index afa4ebd23..d6667dacd 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -12,8 +12,10 @@ import logging import logging.handlers from collections import defaultdict from contextlib import contextmanager +from typing import Any, Dict, Generator, IO, List, Tuple, Type, Union from docutils import nodes +from docutils.nodes import Node from docutils.utils import get_source_line from sphinx.errors import SphinxWarning @@ -21,8 +23,7 @@ from sphinx.util.console import colorize if False: # For type annotation - from typing import Any, Dict, Generator, IO, List, Tuple, Type, Union # NOQA - from sphinx.application import Sphinx # NOQA + from sphinx.application import Sphinx NAMESPACE = 'sphinx' @@ -54,8 +55,7 @@ COLOR_MAP = defaultdict(lambda: 'blue', }) -def getLogger(name): - # type: (str) -> SphinxLoggerAdapter +def getLogger(name: str) -> "SphinxLoggerAdapter": """Get logger wrapped by :class:`sphinx.util.logging.SphinxLoggerAdapter`. Sphinx logger always uses ``sphinx.*`` namespace to be independent from @@ -77,8 +77,7 @@ def getLogger(name): return SphinxLoggerAdapter(logger, {}) -def convert_serializable(records): - # type: (List[logging.LogRecord]) -> None +def convert_serializable(records: List[logging.LogRecord]) -> None: """Convert LogRecord serializable.""" for r in records: # extract arguments to a message and clear them @@ -95,8 +94,7 @@ class SphinxLogRecord(logging.LogRecord): prefix = '' location = None # type: Any - def getMessage(self): - # type: () -> str + def getMessage(self) -> str: message = super().getMessage() location = getattr(self, 'location', None) if location: @@ -120,20 +118,17 @@ class SphinxWarningLogRecord(SphinxLogRecord): class SphinxLoggerAdapter(logging.LoggerAdapter): """LoggerAdapter allowing ``type`` and ``subtype`` keywords.""" - def log(self, level, msg, *args, **kwargs): - # type: (Union[int, str], str, Any, Any) -> None + def log(self, level: Union[int, str], msg: str, *args, **kwargs) -> None: if isinstance(level, int): super().log(level, msg, *args, **kwargs) else: levelno = LEVEL_NAMES[level] super().log(levelno, msg, *args, **kwargs) - def verbose(self, msg, *args, **kwargs): - # type: (str, Any, Any) -> None + def verbose(self, msg: str, *args, **kwargs) -> None: self.log(VERBOSE, msg, *args, **kwargs) - def process(self, msg, kwargs): # type: ignore - # type: (str, Dict) -> Tuple[str, Dict] + def process(self, msg: str, kwargs: Dict) -> Tuple[str, Dict]: # type: ignore extra = kwargs.setdefault('extra', {}) if 'type' in kwargs: extra['type'] = kwargs.pop('type') @@ -148,8 +143,7 @@ class SphinxLoggerAdapter(logging.LoggerAdapter): return msg, kwargs - def handle(self, record): - # type: (logging.LogRecord) -> None + def handle(self, record: logging.LogRecord) -> None: self.logger.handle(record) @@ -161,8 +155,7 @@ class WarningStreamHandler(logging.StreamHandler): class NewLineStreamHandler(logging.StreamHandler): """StreamHandler which switches line terminator by record.nonl flag.""" - def emit(self, record): - # type: (logging.LogRecord) -> None + def emit(self, record: logging.LogRecord) -> None: try: self.acquire() if getattr(record, 'nonl', False): @@ -177,16 +170,13 @@ class NewLineStreamHandler(logging.StreamHandler): class MemoryHandler(logging.handlers.BufferingHandler): """Handler buffering all logs.""" - def __init__(self): - # type: () -> None + def __init__(self) -> None: super().__init__(-1) - def shouldFlush(self, record): - # type: (logging.LogRecord) -> bool + def shouldFlush(self, record: logging.LogRecord) -> bool: return False # never flush - def flushTo(self, logger): - # type: (logging.Logger) -> None + def flushTo(self, logger: logging.Logger) -> None: self.acquire() try: for record in self.buffer: @@ -195,15 +185,13 @@ class MemoryHandler(logging.handlers.BufferingHandler): finally: self.release() - def clear(self): - # type: () -> List[logging.LogRecord] + def clear(self) -> List[logging.LogRecord]: buffer, self.buffer = self.buffer, [] return buffer @contextmanager -def pending_warnings(): - # type: () -> Generator +def pending_warnings() -> Generator[logging.Handler, None, None]: """Contextmanager to pend logging warnings temporary. Similar to :func:`pending_logging`. @@ -231,8 +219,7 @@ def pending_warnings(): @contextmanager -def pending_logging(): - # type: () -> Generator +def pending_logging() -> Generator[MemoryHandler, None, None]: """Contextmanager to pend logging all logs temporary. For example:: @@ -264,8 +251,7 @@ def pending_logging(): @contextmanager -def skip_warningiserror(skip=True): - # type: (bool) -> Generator +def skip_warningiserror(skip: bool = True) -> Generator[None, None, None]: """contextmanager to skip WarningIsErrorFilter for a while.""" logger = logging.getLogger(NAMESPACE) @@ -285,8 +271,7 @@ def skip_warningiserror(skip=True): @contextmanager -def prefixed_warnings(prefix): - # type: (str) -> Generator +def prefixed_warnings(prefix: str) -> Generator[None, None, None]: """Prepend prefix to all records for a while. For example:: @@ -332,13 +317,11 @@ def prefixed_warnings(prefix): class LogCollector: - def __init__(self): - # type: () -> None + def __init__(self) -> None: self.logs = [] # type: List[logging.LogRecord] @contextmanager - def collect(self): - # type: () -> Generator + def collect(self) -> Generator[None, None, None]: with pending_logging() as memhandler: yield @@ -348,16 +331,14 @@ class LogCollector: class InfoFilter(logging.Filter): """Filter error and warning messages.""" - def filter(self, record): - # type: (logging.LogRecord) -> bool + def filter(self, record: logging.LogRecord) -> bool: if record.levelno < logging.WARNING: return True else: return False -def is_suppressed_warning(type, subtype, suppress_warnings): - # type: (str, str, List[str]) -> bool +def is_suppressed_warning(type: str, subtype: str, suppress_warnings: List[str]) -> bool: """Check the warning is suppressed or not.""" if type is None: return False @@ -379,13 +360,11 @@ def is_suppressed_warning(type, subtype, suppress_warnings): class WarningSuppressor(logging.Filter): """Filter logs by `suppress_warnings`.""" - def __init__(self, app): - # type: (Sphinx) -> None + def __init__(self, app: "Sphinx") -> None: self.app = app super().__init__() - def filter(self, record): - # type: (logging.LogRecord) -> bool + def filter(self, record: logging.LogRecord) -> bool: type = getattr(record, 'type', None) subtype = getattr(record, 'subtype', None) @@ -405,13 +384,11 @@ class WarningSuppressor(logging.Filter): class WarningIsErrorFilter(logging.Filter): """Raise exception if warning emitted.""" - def __init__(self, app): - # type: (Sphinx) -> None + def __init__(self, app: "Sphinx") -> None: self.app = app super().__init__() - def filter(self, record): - # type: (logging.LogRecord) -> bool + def filter(self, record: logging.LogRecord) -> bool: if getattr(record, 'skip_warningsiserror', False): # disabled by DisableWarningIsErrorFilter return True @@ -433,8 +410,7 @@ class WarningIsErrorFilter(logging.Filter): class DisableWarningIsErrorFilter(logging.Filter): """Disable WarningIsErrorFilter if this filter installed.""" - def filter(self, record): - # type: (logging.LogRecord) -> bool + def filter(self, record: logging.LogRecord) -> bool: record.skip_warningsiserror = True # type: ignore return True @@ -442,13 +418,11 @@ class DisableWarningIsErrorFilter(logging.Filter): class MessagePrefixFilter(logging.Filter): """Prepend prefix to all records.""" - def __init__(self, prefix): - # type: (str) -> None + def __init__(self, prefix: str) -> None: self.prefix = prefix super().__init__() - def filter(self, record): - # type: (logging.LogRecord) -> bool + def filter(self, record: logging.LogRecord) -> bool: if self.prefix: record.msg = self.prefix + ' ' + record.msg return True @@ -462,13 +436,11 @@ class SphinxLogRecordTranslator(logging.Filter): """ LogRecordClass = None # type: Type[logging.LogRecord] - def __init__(self, app): - # type: (Sphinx) -> None + def __init__(self, app: "Sphinx") -> None: self.app = app super().__init__() - def filter(self, record): # type: ignore - # type: (SphinxWarningLogRecord) -> bool + def filter(self, record: SphinxWarningLogRecord) -> bool: # type: ignore if isinstance(record, logging.LogRecord): # force subclassing to handle location record.__class__ = self.LogRecordClass # type: ignore @@ -500,8 +472,7 @@ class WarningLogRecordTranslator(SphinxLogRecordTranslator): LogRecordClass = SphinxWarningLogRecord -def get_node_location(node): - # type: (nodes.Node) -> str +def get_node_location(node: Node) -> str: (source, line) = get_source_line(node) if source and line: return "%s:%s" % (source, line) @@ -514,8 +485,7 @@ def get_node_location(node): class ColorizeFormatter(logging.Formatter): - def format(self, record): - # type: (logging.LogRecord) -> str + def format(self, record: logging.LogRecord) -> str: message = super().format(record) color = getattr(record, 'color', None) if color is None: @@ -529,13 +499,11 @@ class ColorizeFormatter(logging.Formatter): class SafeEncodingWriter: """Stream writer which ignores UnicodeEncodeError silently""" - def __init__(self, stream): - # type: (IO) -> None + def __init__(self, stream: IO) -> None: self.stream = stream self.encoding = getattr(stream, 'encoding', 'ascii') or 'ascii' - def write(self, data): - # type: (str) -> None + def write(self, data: str) -> None: try: self.stream.write(data) except UnicodeEncodeError: @@ -543,25 +511,21 @@ class SafeEncodingWriter: # non-encodable characters, then decode them. self.stream.write(data.encode(self.encoding, 'replace').decode(self.encoding)) - def flush(self): - # type: () -> None + def flush(self) -> None: if hasattr(self.stream, 'flush'): self.stream.flush() class LastMessagesWriter: """Stream writer which memories last 10 messages to save trackback""" - def __init__(self, app, stream): - # type: (Sphinx, IO) -> None + def __init__(self, app: "Sphinx", stream: IO) -> None: self.app = app - def write(self, data): - # type: (str) -> None + def write(self, data: str) -> None: self.app.messagelog.append(data) -def setup(app, status, warning): - # type: (Sphinx, IO, IO) -> None +def setup(app: "Sphinx", status: IO, warning: IO) -> None: """Setup root logger for Sphinx""" logger = logging.getLogger(NAMESPACE) logger.setLevel(logging.DEBUG) From 24f8a3caf03ee2c11a1746413d68a572cb59f23e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jun 2019 17:00:03 +0900 Subject: [PATCH 05/13] Migrate to py3 style type annotation: sphinx.util.console --- sphinx/util/console.py | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/sphinx/util/console.py b/sphinx/util/console.py index c207d32ac..d73d0563e 100644 --- a/sphinx/util/console.py +++ b/sphinx/util/console.py @@ -11,6 +11,7 @@ import os import re import sys +from typing import Dict try: # check if colorama is installed to support color on Windows @@ -18,23 +19,17 @@ try: except ImportError: colorama = None -if False: - # For type annotation - from typing import Dict # NOQA - _ansi_re = re.compile('\x1b\\[(\\d\\d;){0,2}\\d\\dm') codes = {} # type: Dict[str, str] -def terminal_safe(s): - # type: (str) -> str +def terminal_safe(s: str) -> str: """safely encode a string for printing to the terminal.""" return s.encode('ascii', 'backslashreplace').decode('ascii') -def get_terminal_width(): - # type: () -> int +def get_terminal_width() -> int: """Borrowed from the py lib.""" try: import termios @@ -53,8 +48,7 @@ def get_terminal_width(): _tw = get_terminal_width() -def term_width_line(text): - # type: (str) -> str +def term_width_line(text: str) -> str: if not codes: # if no coloring, don't output fancy backspaces return text + '\n' @@ -63,8 +57,7 @@ def term_width_line(text): return text.ljust(_tw + len(text) - len(_ansi_re.sub('', text))) + '\r' -def color_terminal(): - # type: () -> bool +def color_terminal() -> bool: if sys.platform == 'win32' and colorama is not None: colorama.init() return True @@ -80,21 +73,18 @@ def color_terminal(): return False -def nocolor(): - # type: () -> None +def nocolor() -> None: if sys.platform == 'win32' and colorama is not None: colorama.deinit() codes.clear() -def coloron(): - # type: () -> None +def coloron() -> None: codes.update(_orig_codes) -def colorize(name, text, input_mode=False): - # type: (str, str, bool) -> str - def escseq(name): +def colorize(name: str, text: str, input_mode: bool = False) -> str: + def escseq(name: str) -> str: # Wrap escape sequence with ``\1`` and ``\2`` to let readline know # it is non-printable characters # ref: https://tiswww.case.edu/php/chet/readline/readline.html @@ -109,15 +99,12 @@ def colorize(name, text, input_mode=False): return escseq(name) + text + escseq('reset') -def strip_colors(s): - # type: (str) -> str +def strip_colors(s: str) -> str: return re.compile('\x1b.*?m').sub('', s) -def create_color_func(name): - # type: (str) -> None - def inner(text): - # type: (str) -> str +def create_color_func(name: str) -> None: + def inner(text: str) -> str: return colorize(name, text) globals()[name] = inner From f3e45e485e9caefb9099e0598549b73231401264 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jun 2019 17:01:28 +0900 Subject: [PATCH 06/13] Migrate to py3 style type annotation: sphinx.util.compat --- sphinx/util/compat.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py index 492c313d0..75ef90350 100644 --- a/sphinx/util/compat.py +++ b/sphinx/util/compat.py @@ -10,23 +10,22 @@ import sys import warnings +from typing import Any, Dict from docutils.utils import get_source_line from sphinx import addnodes +from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning from sphinx.transforms import SphinxTransform from sphinx.util import import_object if False: # For type annotation - from typing import Any, Dict # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.config import Config # NOQA + from sphinx.application import Sphinx -def deprecate_source_parsers(app, config): - # type: (Sphinx, Config) -> None +def deprecate_source_parsers(app: "Sphinx", config: Config) -> None: if config.source_parsers: warnings.warn('The config variable "source_parsers" is deprecated. ' 'Please update your extension for the parser and remove the setting.', @@ -37,8 +36,7 @@ def deprecate_source_parsers(app, config): app.add_source_parser(suffix, parser) -def register_application_for_autosummary(app): - # type: (Sphinx) -> None +def register_application_for_autosummary(app: "Sphinx") -> None: """Register application object to autosummary module. Since Sphinx-1.7, documenters and attrgetters are registered into @@ -55,8 +53,7 @@ class IndexEntriesMigrator(SphinxTransform): """Migrating indexentries from old style (4columns) to new style (5columns).""" default_priority = 700 - def apply(self, **kwargs): - # type: (Any) -> None + def apply(self, **kwargs) -> None: for node in self.document.traverse(addnodes.index): for i, entries in enumerate(node['entries']): if len(entries) == 4: @@ -66,8 +63,7 @@ class IndexEntriesMigrator(SphinxTransform): node['entries'][i] = entries + (None,) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: "Sphinx") -> Dict[str, Any]: app.add_transform(IndexEntriesMigrator) app.connect('config-inited', deprecate_source_parsers) app.connect('builder-inited', register_application_for_autosummary) From 39c7ee955b71745d2503f61b5ba488345e1b38a4 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jun 2019 17:46:34 +0900 Subject: [PATCH 07/13] Migrate to py3 style type annotation: sphinx.util.tags --- sphinx/util/tags.py | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/sphinx/util/tags.py b/sphinx/util/tags.py index 193e7ef1e..7e7ba4661 100644 --- a/sphinx/util/tags.py +++ b/sphinx/util/tags.py @@ -6,26 +6,23 @@ :license: BSD, see LICENSE for details. """ -# (ab)use the Jinja parser for parsing our boolean expressions +from typing import Iterator, List + from jinja2 import nodes from jinja2.environment import Environment +from jinja2.nodes import Node from jinja2.parser import Parser env = Environment() -if False: - # For type annotation - from typing import Iterator, List # NOQA - class BooleanParser(Parser): """ Only allow condition exprs and/or/not operations. """ - def parse_compare(self): - # type: () -> nodes.Node - node = None # type: nodes.Node + def parse_compare(self) -> Node: + node = None # type: Node token = self.stream.current if token.type == 'name': if token.value in ('true', 'false', 'True', 'False'): @@ -46,38 +43,31 @@ class BooleanParser(Parser): class Tags: - def __init__(self, tags=None): - # type: (List[str]) -> None + def __init__(self, tags: List[str] = None) -> None: self.tags = dict.fromkeys(tags or [], True) - def has(self, tag): - # type: (str) -> bool + def has(self, tag: str) -> bool: return tag in self.tags __contains__ = has - def __iter__(self): - # type: () -> Iterator[str] + def __iter__(self) -> Iterator[str]: return iter(self.tags) - def add(self, tag): - # type: (str) -> None + def add(self, tag: str) -> None: self.tags[tag] = True - def remove(self, tag): - # type: (str) -> None + def remove(self, tag: str) -> None: self.tags.pop(tag, None) - def eval_condition(self, condition): - # type: (str) -> bool + def eval_condition(self, condition: str) -> bool: # exceptions are handled by the caller parser = BooleanParser(env, condition, state='variable') expr = parser.parse_expression() if not parser.stream.eos: raise ValueError('chunk after expression') - def eval_node(node): - # type: (nodes.Node) -> bool + def eval_node(node: Node) -> bool: if isinstance(node, nodes.CondExpr): if eval_node(node.test): # type: ignore return eval_node(node.expr1) # type: ignore From dd4741c352ab45e28c9b0c4fbd2d366d224be503 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jun 2019 17:47:15 +0900 Subject: [PATCH 08/13] Migrate to py3 style type annotation: sphinx.util.texescape --- sphinx/util/texescape.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sphinx/util/texescape.py b/sphinx/util/texescape.py index cc8c0fe1e..408ec1253 100644 --- a/sphinx/util/texescape.py +++ b/sphinx/util/texescape.py @@ -9,10 +9,7 @@ """ import re - -if False: - # For type annotation - from typing import Dict # NOQA +from typing import Dict tex_replacements = [ # map TeX special chars @@ -78,20 +75,17 @@ tex_replace_map = {} tex_hl_escape_map_new = {} -def escape(s): - # type: (str) -> str +def escape(s: str) -> str: """Escape text for LaTeX output.""" return s.translate(tex_escape_map) -def escape_abbr(text): - # type: (str) -> str +def escape_abbr(text: str) -> str: """Adjust spacing after abbreviations. Works with @ letter or other.""" return re.sub(r'\.(?=\s|$)', r'.\@{}', text) -def init(): - # type: () -> None +def init() -> None: for a, b in tex_replacements: tex_escape_map[ord(a)] = b tex_replace_map[ord(a)] = '_' From 086eac39148af091905d0f81bb484c72055c3c0e Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jun 2019 17:48:07 +0900 Subject: [PATCH 09/13] Migrate to py3 style type annotation: sphinx.util.docutils --- sphinx/util/docutils.py | 152 +++++++++++++++------------------------- 1 file changed, 58 insertions(+), 94 deletions(-) diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index eebfec464..42ff5c4b8 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -16,33 +16,33 @@ from contextlib import contextmanager from copy import copy from distutils.version import LooseVersion from os import path -from typing import IO, cast +from types import ModuleType +from typing import Any, Callable, Dict, Generator, IO, List, Set, Tuple, Type +from typing import cast import docutils from docutils import nodes from docutils.io import FileOutput +from docutils.nodes import Element, Node, system_message from docutils.parsers.rst import Directive, directives, roles, convert_directive_function -from docutils.statemachine import StateMachine +from docutils.parsers.rst.states import Inliner +from docutils.statemachine import StateMachine, State, StringList from docutils.utils import Reporter, unescape from sphinx.deprecation import RemovedInSphinx30Warning from sphinx.errors import ExtensionError, SphinxError from sphinx.locale import __ from sphinx.util import logging +from sphinx.util.typing import RoleFunction logger = logging.getLogger(__name__) report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(\\d+)?\\) ') if False: # For type annotation - from types import ModuleType # NOQA - from typing import Any, Callable, Dict, Generator, List, Set, Tuple, Type # NOQA - from docutils.parsers.rst.states import Inliner # NOQA - from docutils.statemachine import State, StringList # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.config import Config # NOQA - from sphinx.environment import BuildEnvironment # NOQA - from sphinx.util.typing import RoleFunction # NOQA + from sphinx.builders import Builder + from sphinx.config import Config + from sphinx.environment import BuildEnvironment __version_info__ = tuple(LooseVersion(docutils.__version__).version) @@ -50,8 +50,7 @@ additional_nodes = set() # type: Set[Type[nodes.Element]] @contextmanager -def docutils_namespace(): - # type: () -> Generator[None, None, None] +def docutils_namespace() -> Generator[None, None, None]: """Create namespace for reST parsers.""" try: _directives = copy(directives._directives) # type: ignore @@ -67,14 +66,12 @@ def docutils_namespace(): additional_nodes.discard(node) -def is_directive_registered(name): - # type: (str) -> bool +def is_directive_registered(name: str) -> bool: """Check the *name* directive is already registered.""" return name in directives._directives # type: ignore -def register_directive(name, directive): - # type: (str, Type[Directive]) -> None +def register_directive(name: str, directive: Type[Directive]) -> None: """Register a directive to docutils. This modifies global state of docutils. So it is better to use this @@ -83,14 +80,12 @@ def register_directive(name, directive): directives.register_directive(name, directive) -def is_role_registered(name): - # type: (str) -> bool +def is_role_registered(name: str) -> bool: """Check the *name* role is already registered.""" return name in roles._roles # type: ignore -def register_role(name, role): - # type: (str, RoleFunction) -> None +def register_role(name: str, role: RoleFunction) -> None: """Register a role to docutils. This modifies global state of docutils. So it is better to use this @@ -99,20 +94,17 @@ def register_role(name, role): roles.register_local_role(name, role) -def unregister_role(name): - # type: (str) -> None +def unregister_role(name: str) -> None: """Unregister a role from docutils.""" roles._roles.pop(name, None) # type: ignore -def is_node_registered(node): - # type: (Type[nodes.Element]) -> bool +def is_node_registered(node: Type[Element]) -> bool: """Check the *node* is already registered.""" return hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__) -def register_node(node): - # type: (Type[nodes.Element]) -> None +def register_node(node: Type[Element]) -> None: """Register a node to docutils. This modifies global state of some visitors. So it is better to use this @@ -123,8 +115,7 @@ def register_node(node): additional_nodes.add(node) -def unregister_node(node): - # type: (Type[nodes.Element]) -> None +def unregister_node(node: Type[Element]) -> None: """Unregister a node from docutils. This is inverse of ``nodes._add_nodes_class_names()``. @@ -137,8 +128,7 @@ def unregister_node(node): @contextmanager -def patched_get_language(): - # type: () -> Generator[None, None, None] +def patched_get_language() -> Generator[None, None, None]: """Patch docutils.languages.get_language() temporarily. This ignores the second argument ``reporter`` to suppress warnings. @@ -146,8 +136,7 @@ def patched_get_language(): """ from docutils.languages import get_language - def patched_get_language(language_code, reporter=None): - # type: (str, Reporter) -> Any + def patched_get_language(language_code: str, reporter: Reporter = None) -> Any: return get_language(language_code) try: @@ -159,8 +148,7 @@ def patched_get_language(): @contextmanager -def using_user_docutils_conf(confdir): - # type: (str) -> Generator[None, None, None] +def using_user_docutils_conf(confdir: str) -> Generator[None, None, None]: """Let docutils know the location of ``docutils.conf`` for Sphinx.""" try: docutilsconfig = os.environ.get('DOCUTILSCONFIG', None) @@ -176,8 +164,7 @@ def using_user_docutils_conf(confdir): @contextmanager -def patch_docutils(confdir=None): - # type: (str) -> Generator[None, None, None] +def patch_docutils(confdir: str = None) -> Generator[None, None, None]: """Patch to docutils temporarily.""" with patched_get_language(), using_user_docutils_conf(confdir): yield @@ -191,35 +178,30 @@ class sphinx_domains: """Monkey-patch directive and role dispatch, so that domain-specific markup takes precedence. """ - def __init__(self, env): - # type: (BuildEnvironment) -> None + def __init__(self, env: "BuildEnvironment") -> None: self.env = env self.directive_func = None # type: Callable self.roles_func = None # type: Callable - def __enter__(self): - # type: () -> None + def __enter__(self) -> None: self.enable() - 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.disable() + return True - def enable(self): - # type: () -> None + def enable(self) -> None: self.directive_func = directives.directive self.role_func = roles.role directives.directive = self.lookup_directive # type: ignore roles.role = self.lookup_role # type: ignore - def disable(self): - # type: () -> None + def disable(self) -> None: directives.directive = self.directive_func roles.role = self.role_func - def lookup_domain_element(self, type, name): - # type: (str, str) -> Any + def lookup_domain_element(self, type: str, name: str) -> Any: """Lookup a markup element (directive or role), given its name which can be a full name (with domain). """ @@ -247,15 +229,13 @@ class sphinx_domains: raise ElementLookupError - def lookup_directive(self, name, lang_module, document): - # type: (str, ModuleType, nodes.document) -> Tuple[Type[Directive], List[nodes.system_message]] # NOQA + def lookup_directive(self, name: str, lang_module: ModuleType, document: nodes.document) -> Tuple[Type[Directive], List[system_message]]: # NOQA try: return self.lookup_domain_element('directive', name) except ElementLookupError: return self.directive_func(name, lang_module, document) - def lookup_role(self, name, lang_module, lineno, reporter): - # type: (str, ModuleType, int, Reporter) -> Tuple[RoleFunction, List[nodes.system_message]] # NOQA + def lookup_role(self, name: str, lang_module: ModuleType, lineno: int, reporter: Reporter) -> Tuple[RoleFunction, List[system_message]]: # NOQA try: return self.lookup_domain_element('role', name) except ElementLookupError: @@ -263,8 +243,7 @@ class sphinx_domains: class WarningStream: - def write(self, text): - # type: (str) -> None + def write(self, text: str) -> None: matched = report_re.search(text) if not matched: logger.warning(text.rstrip("\r\n")) @@ -276,16 +255,14 @@ class WarningStream: class LoggingReporter(Reporter): @classmethod - def from_reporter(cls, reporter): - # type: (Reporter) -> LoggingReporter + def from_reporter(cls, reporter: Reporter) -> "LoggingReporter": """Create an instance of LoggingReporter from other reporter object.""" return cls(reporter.source, reporter.report_level, reporter.halt_level, reporter.debug_flag, reporter.error_handler) - def __init__(self, source, report_level=Reporter.WARNING_LEVEL, - halt_level=Reporter.SEVERE_LEVEL, debug=False, - error_handler='backslashreplace'): - # type: (str, int, int, bool, str) -> None + def __init__(self, source: str, report_level: int = Reporter.WARNING_LEVEL, + halt_level: int = Reporter.SEVERE_LEVEL, debug: bool = False, + error_handler: str = 'backslashreplace') -> None: stream = cast(IO, WarningStream()) super().__init__(source, report_level, halt_level, stream, debug, error_handler=error_handler) @@ -294,18 +271,15 @@ class LoggingReporter(Reporter): class NullReporter(Reporter): """A dummy reporter; write nothing.""" - def __init__(self): - # type: () -> None + def __init__(self) -> None: super().__init__('', 999, 4) -def is_html5_writer_available(): - # type: () -> bool +def is_html5_writer_available() -> bool: return __version_info__ > (0, 13, 0) -def directive_helper(obj, has_content=None, argument_spec=None, **option_spec): - # type: (Any, bool, Tuple[int, int, bool], Any) -> Any +def directive_helper(obj: Any, has_content: bool = None, argument_spec: Tuple[int, int, bool] = None, **option_spec) -> Any: # NOQA warnings.warn('function based directive support is now deprecated. ' 'Use class based directive instead.', RemovedInSphinx30Warning) @@ -323,8 +297,7 @@ def directive_helper(obj, has_content=None, argument_spec=None, **option_spec): @contextmanager -def switch_source_input(state, content): - # type: (State, StringList) -> Generator[None, None, None] +def switch_source_input(state: State, content: StringList) -> Generator[None, None, None]: """Switch current source input of state temporarily.""" try: # remember the original ``get_source_and_line()`` method @@ -344,13 +317,11 @@ def switch_source_input(state, content): class SphinxFileOutput(FileOutput): """Better FileOutput class for Sphinx.""" - def __init__(self, **kwargs): - # type: (Any) -> None + def __init__(self, **kwargs) -> None: self.overwrite_if_changed = kwargs.pop('overwrite_if_changed', False) super().__init__(**kwargs) - def write(self, data): - # type: (str) -> str + def write(self, data: str) -> str: if (self.destination_path and self.autoclose and 'b' not in self.mode and self.overwrite_if_changed and os.path.exists(self.destination_path)): with open(self.destination_path, encoding=self.encoding) as f: @@ -371,19 +342,16 @@ class SphinxDirective(Directive): """ @property - def env(self): - # type: () -> BuildEnvironment + def env(self) -> "BuildEnvironment": """Reference to the :class:`.BuildEnvironment` object.""" return self.state.document.settings.env @property - def config(self): - # type: () -> Config + def config(self) -> "Config": """Reference to the :class:`.Config` object.""" return self.env.config - def set_source_info(self, node): - # type: (nodes.Node) -> None + def set_source_info(self, node: Node) -> None: """Set source and line number to the node.""" node.source, node.line = self.state_machine.get_source_and_line(self.lineno) @@ -406,8 +374,9 @@ class SphinxRole: content = None #: A list of strings, the directive content for customization #: (from the "role" directive). - def __call__(self, name, 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 __call__(self, name: str, rawtext: str, text: str, lineno: int, + inliner: Inliner, options: Dict = {}, content: List[str] = [] + ) -> Tuple[List[Node], List[system_message]]: self.rawtext = rawtext self.text = unescape(text) self.lineno = lineno @@ -427,24 +396,20 @@ class SphinxRole: return self.run() - def run(self): - # type: () -> Tuple[List[nodes.Node], List[nodes.system_message]] + def run(self) -> Tuple[List[Node], List[system_message]]: raise NotImplementedError @property - def env(self): - # type: () -> BuildEnvironment + def env(self) -> "BuildEnvironment": """Reference to the :class:`.BuildEnvironment` object.""" return self.inliner.document.settings.env @property - def config(self): - # type: () -> Config + def config(self) -> "Config": """Reference to the :class:`.Config` object.""" return self.env.config - def set_source_info(self, node, lineno=None): - # type: (nodes.Node, int) -> None + def set_source_info(self, node: Node, lineno: int = None) -> None: if lineno is None: lineno = self.lineno @@ -466,8 +431,9 @@ class ReferenceRole(SphinxRole): # \x00 means the "<" was backslash-escaped explicit_title_re = re.compile(r'^(.+?)\s*(?$', re.DOTALL) - def __call__(self, name, 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 __call__(self, name: str, rawtext: str, text: str, lineno: int, + inliner: Inliner, options: Dict = {}, content: List[str] = [] + ) -> Tuple[List[Node], List[system_message]]: matched = self.explicit_title_re.match(text) if matched: self.has_explicit_title = True @@ -490,8 +456,7 @@ class SphinxTranslator(nodes.NodeVisitor): This class is strongly coupled with Sphinx. """ - def __init__(self, document, builder): - # type: (nodes.document, Builder) -> None + def __init__(self, document: nodes.document, builder: "Builder") -> None: super().__init__(document) self.builder = builder self.config = builder.config @@ -503,8 +468,7 @@ class SphinxTranslator(nodes.NodeVisitor): __document_cache__ = None # type: nodes.document -def new_document(source_path, settings=None): - # type: (str, Any) -> nodes.document +def new_document(source_path: str, settings: Any = None) -> nodes.document: """Return a new empty document object. This is an alternative of docutils'. This is a simple wrapper for ``docutils.utils.new_document()``. It From 2900179436580a53fcf0a9b2b15e31ef8e259979 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 2 Jun 2019 20:29:48 +0900 Subject: [PATCH 10/13] Migrate to py3 style type annotation: sphinx.util.docfields --- sphinx/util/docfields.py | 99 +++++++++++++--------------------------- 1 file changed, 32 insertions(+), 67 deletions(-) diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index 9b19d229d..f3729c0c9 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -10,23 +10,23 @@ """ import warnings -from typing import List, Tuple, cast +from typing import Any, Dict, List, Tuple, Type, Union +from typing import cast from docutils import nodes +from docutils.nodes import Node from sphinx import addnodes from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.util.typing import TextlikeNode if False: # For type annotation - from typing import Any, Dict, Type, Union # NOQA - from sphinx.directive import ObjectDescription # NOQA - from sphinx.environment import BuildEnvironment # NOQA - from sphinx.util.typing import TextlikeNode # NOQA + from sphinx.environment import BuildEnvironment + from sphinx.directive import ObjectDescription -def _is_single_paragraph(node): - # type: (nodes.field_body) -> bool +def _is_single_paragraph(node: nodes.field_body) -> bool: """True if the node only contains one paragraph (and system messages).""" if len(node) == 0: return False @@ -55,9 +55,8 @@ class Field: is_grouped = False is_typed = False - def __init__(self, name, names=(), label=None, has_arg=True, rolename=None, - bodyrolename=None): - # type: (str, Tuple[str, ...], str, bool, str, str) -> None + def __init__(self, name: str, names: Tuple[str, ...] = (), label: str = None, + has_arg: bool = True, rolename: str = None, bodyrolename: str = None) -> None: self.name = name self.names = names self.label = label @@ -65,15 +64,9 @@ class Field: self.rolename = rolename self.bodyrolename = bodyrolename - def make_xref(self, - rolename, # type: str - domain, # type: str - target, # type: str - innernode=addnodes.literal_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] = addnodes.literal_emphasis, + contnode: Node = None, env: "BuildEnvironment" = None) -> Node: if not rolename: return contnode or innernode(target, target) refnode = addnodes.pending_xref('', refdomain=domain, refexplicit=False, @@ -83,28 +76,16 @@ class Field: env.get_domain(domain).process_field_xref(refnode) return refnode - def make_xrefs(self, - rolename, # type: str - domain, # type: str - target, # type: str - innernode=addnodes.literal_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] = addnodes.literal_emphasis, + contnode: Node = None, env: "BuildEnvironment" = None) -> List[Node]: return [self.make_xref(rolename, domain, target, innernode, contnode, env)] - def make_entry(self, fieldarg, content): - # type: (str, List[nodes.Node]) -> Tuple[str, List[nodes.Node]] + def make_entry(self, fieldarg: str, content: List[Node]) -> Tuple[str, List[Node]]: return (fieldarg, content) - def make_field(self, - types, # type: Dict[str, List[nodes.Node]] - domain, # type: str - item, # type: Tuple - env=None, # type: BuildEnvironment - ): - # type: (...) -> nodes.field + def make_field(self, types: Dict[str, List[Node]], domain: str, + item: Tuple, env: "BuildEnvironment" = None) -> nodes.field: fieldarg, content = item fieldname = nodes.field_name('', self.label) if fieldarg: @@ -138,19 +119,13 @@ class GroupedField(Field): is_grouped = True list_type = nodes.bullet_list - def __init__(self, name, names=(), label=None, rolename=None, - can_collapse=False): - # type: (str, Tuple[str, ...], str, str, bool) -> None + def __init__(self, name: str, names: Tuple[str, ...] = (), label: str = None, + rolename: str = None, can_collapse: bool = False) -> None: super().__init__(name, names, label, True, rolename) self.can_collapse = can_collapse - def make_field(self, - types, # type: Dict[str, List[nodes.Node]] - domain, # type: str - items, # type: Tuple - env=None, # type: BuildEnvironment - ): - # type: (...) -> nodes.field + def make_field(self, types: Dict[str, List[Node]], domain: str, + items: Tuple, env: "BuildEnvironment" = None) -> nodes.field: fieldname = nodes.field_name('', self.label) listnode = self.list_type() for fieldarg, content in items: @@ -191,22 +166,16 @@ class TypedField(GroupedField): """ is_typed = True - def __init__(self, name, names=(), typenames=(), label=None, - rolename=None, typerolename=None, can_collapse=False): - # type: (str, Tuple[str, ...], Tuple[str, ...], str, str, str, bool) -> None + def __init__(self, name: str, names: Tuple[str, ...] = (), typenames: Tuple[str, ...] = (), + label: str = None, rolename: str = None, typerolename: str = None, + can_collapse: bool = False) -> None: super().__init__(name, names, label, rolename, can_collapse) self.typenames = typenames self.typerolename = typerolename - def make_field(self, - types, # type: Dict[str, List[nodes.Node]] - domain, # type: str - items, # type: Tuple - env=None, # type: BuildEnvironment - ): - # type: (...) -> nodes.field - def handle_item(fieldarg, content): - # type: (str, str) -> nodes.paragraph + def make_field(self, types: Dict[str, List[Node]], domain: str, + items: Tuple, env: "BuildEnvironment" = None) -> nodes.field: + def handle_item(fieldarg: str, content: str) -> nodes.paragraph: par = nodes.paragraph() par.extend(self.make_xrefs(self.rolename, domain, fieldarg, addnodes.literal_strong, env=env)) @@ -246,13 +215,11 @@ class DocFieldTransformer: """ typemap = None # type: Dict[str, Tuple[Field, bool]] - def __init__(self, directive): - # type: (ObjectDescription) -> None + def __init__(self, directive: "ObjectDescription") -> None: self.directive = directive self.typemap = directive.get_field_type_map() - def preprocess_fieldtypes(self, types): - # type: (List[Field]) -> Dict[str, Tuple[Field, bool]] + def preprocess_fieldtypes(self, types: List[Field]) -> Dict[str, Tuple[Field, bool]]: warnings.warn('DocFieldTransformer.preprocess_fieldtypes() is deprecated.', RemovedInSphinx40Warning) typemap = {} @@ -265,16 +232,14 @@ class DocFieldTransformer: typemap[name] = typed_field, True return typemap - def transform_all(self, node): - # type: (addnodes.desc_content) -> None + def transform_all(self, node: addnodes.desc_content) -> None: """Transform all field list children of a node.""" # don't traverse, only handle field lists that are immediate children for child in node: if isinstance(child, nodes.field_list): self.transform(child) - def transform(self, node): - # type: (nodes.field_list) -> None + def transform(self, node: nodes.field_list) -> None: """Transform a single field list *node*.""" typemap = self.typemap From b5276b3965388e7b7264a42d1a442b8c734b1877 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 3 Jun 2019 22:06:11 +0900 Subject: [PATCH 11/13] Migrate to py3 style type annotation: sphinx.util.matching --- sphinx/util/matching.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/sphinx/util/matching.py b/sphinx/util/matching.py index b1725cb46..97eeff40f 100644 --- a/sphinx/util/matching.py +++ b/sphinx/util/matching.py @@ -9,16 +9,12 @@ """ import re +from typing import Callable, Dict, List, Match, Pattern from sphinx.util.osutil import canon_path -if False: - # For type annotation - from typing import Callable, Dict, List, Match, Pattern # NOQA - -def _translate_pattern(pat): - # type: (str) -> str +def _translate_pattern(pat: str) -> str: """Translate a shell-style glob pattern to a regular expression. Adapted from the fnmatch module, but enhanced so that single stars don't @@ -64,8 +60,7 @@ def _translate_pattern(pat): return res + '$' -def compile_matchers(patterns): - # type: (List[str]) -> List[Callable[[str], Match[str]]] +def compile_matchers(patterns: List[str]) -> List[Callable[[str], Match[str]]]: return [re.compile(_translate_pattern(pat)).match for pat in patterns] @@ -76,17 +71,14 @@ class Matcher: For example, "**/index.rst" matches with "index.rst" """ - def __init__(self, patterns): - # type: (List[str]) -> None + def __init__(self, patterns: List[str]) -> None: expanded = [pat[3:] for pat in patterns if pat.startswith('**/')] self.patterns = compile_matchers(patterns + expanded) - def __call__(self, string): - # type: (str) -> bool + def __call__(self, string: str) -> bool: return self.match(string) - def match(self, string): - # type: (str) -> bool + def match(self, string: str) -> bool: string = canon_path(string) return any(pat(string) for pat in self.patterns) @@ -97,16 +89,14 @@ DOTFILES = Matcher(['**/.*']) _pat_cache = {} # type: Dict[str, Pattern] -def patmatch(name, pat): - # type: (str, str) -> Match[str] +def patmatch(name: str, pat: str) -> Match[str]: """Return if name matches pat. Adapted from fnmatch module.""" if pat not in _pat_cache: _pat_cache[pat] = re.compile(_translate_pattern(pat)) return _pat_cache[pat].match(name) -def patfilter(names, pat): - # type: (List[str], str) -> List[str] +def patfilter(names: List[str], pat: str) -> List[str]: """Return the subset of the list NAMES that match PAT. Adapted from fnmatch module. From 5115fb0172c3ae42f326ed7c50e2aa10917dfb94 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 3 Jun 2019 22:06:44 +0900 Subject: [PATCH 12/13] Migrate to py3 style type annotation: sphinx.util.png --- sphinx/util/png.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sphinx/util/png.py b/sphinx/util/png.py index 2fb97a901..911547db6 100644 --- a/sphinx/util/png.py +++ b/sphinx/util/png.py @@ -20,8 +20,7 @@ DEPTH_CHUNK_START = b'tEXtDepth\x00' IEND_CHUNK = b'\x00\x00\x00\x00IEND\xAE\x42\x60\x82' -def read_png_depth(filename): - # type: (str) -> int +def read_png_depth(filename: str) -> int: """Read the special tEXt chunk indicating the depth from a PNG file.""" with open(filename, 'rb') as f: f.seek(- (LEN_IEND + LEN_DEPTH), 2) @@ -33,8 +32,7 @@ def read_png_depth(filename): return struct.unpack('!i', depthchunk[14:18])[0] -def write_png_depth(filename, depth): - # type: (str, int) -> None +def write_png_depth(filename: str, depth: int) -> None: """Write the special tEXt chunk indicating the depth to a PNG file. The chunk is placed immediately before the special IEND chunk. From 9ba216223a3b7d6d0888e4588709d3923557f096 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Mon, 3 Jun 2019 22:07:07 +0900 Subject: [PATCH 13/13] Migrate to py3 style type annotation: sphinx.util.pycompat --- sphinx/util/pycompat.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py index dca2849c2..06d3bcc2c 100644 --- a/sphinx/util/pycompat.py +++ b/sphinx/util/pycompat.py @@ -13,6 +13,7 @@ import io import sys import textwrap import warnings +from typing import Any, Callable from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.locale import __ @@ -20,10 +21,6 @@ from sphinx.util import logging from sphinx.util.console import terminal_safe from sphinx.util.typing import NoneType -if False: - # For type annotation - from typing import Any, Callable # NOQA - logger = logging.getLogger(__name__) @@ -33,8 +30,7 @@ logger = logging.getLogger(__name__) # convert_with_2to3(): # support for running 2to3 over config files -def convert_with_2to3(filepath): - # type: (str) -> str +def convert_with_2to3(filepath: str) -> str: from lib2to3.refactor import RefactoringTool, get_fixers_from_package from lib2to3.pgen2.parse import ParseError fixers = get_fixers_from_package('lib2to3.fixes') @@ -62,8 +58,7 @@ class UnicodeMixin: return self.__unicode__() -def execfile_(filepath, _globals, open=open): - # type: (str, Any, Callable) -> None +def execfile_(filepath: str, _globals: Any, open: Callable = open) -> None: from sphinx.util.osutil import fs_encoding with open(filepath, 'rb') as f: source = f.read()