diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2019-07-06 12:37:27 +0900 |
---|---|---|
committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2019-07-06 12:37:27 +0900 |
commit | fe06eebfb5c2a24f8a0e297aef2e7a5ec82b062c (patch) | |
tree | f9761849901806750991b3480deb32d23817ce2a | |
parent | 3fbc9c9e045c298060be96c1c85c421ae08f9277 (diff) | |
parent | 847a642b414871dd0b9df4b8913f9e04516b5757 (diff) | |
download | sphinx-git-fe06eebfb5c2a24f8a0e297aef2e7a5ec82b062c.tar.gz |
Merge branch '2.0'
-rw-r--r-- | sphinx/ext/autosectionlabel.py | 16 | ||||
-rw-r--r-- | sphinx/ext/autosummary/__init__.py | 106 | ||||
-rw-r--r-- | sphinx/ext/autosummary/generate.py | 69 | ||||
-rw-r--r-- | sphinx/ext/doctest.py | 99 | ||||
-rw-r--r-- | sphinx/ext/ifconfig.py | 18 | ||||
-rw-r--r-- | sphinx/ext/imgmath.py | 54 | ||||
-rw-r--r-- | sphinx/ext/inheritance_diagram.py | 81 | ||||
-rw-r--r-- | sphinx/ext/jsmath.py | 10 | ||||
-rw-r--r-- | sphinx/ext/napoleon/__init__.py | 23 | ||||
-rw-r--r-- | sphinx/ext/napoleon/docstring.py | 209 | ||||
-rw-r--r-- | sphinx/ext/napoleon/iterators.py | 32 | ||||
-rw-r--r-- | sphinx/ext/todo.py | 76 | ||||
-rw-r--r-- | sphinx/ext/viewcode.py | 30 |
13 files changed, 309 insertions, 514 deletions
diff --git a/sphinx/ext/autosectionlabel.py b/sphinx/ext/autosectionlabel.py index 3d55ad749..9173fecf0 100644 --- a/sphinx/ext/autosectionlabel.py +++ b/sphinx/ext/autosectionlabel.py @@ -8,24 +8,22 @@ :license: BSD, see LICENSE for details. """ +from typing import Any, Dict from typing import cast from docutils import nodes +from docutils.nodes import Node +from sphinx.application import Sphinx from sphinx.locale import __ from sphinx.util import logging from sphinx.util.nodes import clean_astext -if False: - # For type annotation - from typing import Any, Dict # NOQA - from sphinx.application import Sphinx # NOQA - logger = logging.getLogger(__name__) -def get_node_depth(node): +def get_node_depth(node: Node) -> int: i = 0 cur_node = node while cur_node.parent != node.document: @@ -34,8 +32,7 @@ def get_node_depth(node): return i -def register_sections_as_label(app, document): - # type: (Sphinx, nodes.Node) -> None +def register_sections_as_label(app: Sphinx, document: Node) -> None: labels = app.env.domaindata['std']['labels'] anonlabels = app.env.domaindata['std']['anonlabels'] for node in document.traverse(nodes.section): @@ -61,8 +58,7 @@ def register_sections_as_label(app, document): labels[name] = docname, labelid, sectname -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('autosectionlabel_prefix_document', False, 'env') app.add_config_value('autosectionlabel_maxdepth', None, 'env') app.connect('doctree-read', register_sections_as_label) diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index de9d6dcd3..7c92bb8b5 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -60,18 +60,22 @@ import sys import warnings from os import path from types import ModuleType -from typing import List, cast +from typing import Any, Dict, List, Tuple, Type +from typing import cast from docutils import nodes +from docutils.nodes import Element, Node, system_message from docutils.parsers.rst import directives -from docutils.parsers.rst.states import RSTStateMachine, Struct, state_classes +from docutils.parsers.rst.states import Inliner, RSTStateMachine, Struct, state_classes from docutils.statemachine import StringList import sphinx from sphinx import addnodes +from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.environment import BuildEnvironment from sphinx.environment.adapters.toctree import TocTree -from sphinx.ext.autodoc import get_documenters +from sphinx.ext.autodoc import Documenter, get_documenters from sphinx.ext.autodoc.directive import DocumenterBridge, Options from sphinx.ext.autodoc.importer import import_module from sphinx.ext.autodoc.mock import mock @@ -82,15 +86,8 @@ from sphinx.util.docutils import ( NullReporter, SphinxDirective, SphinxRole, new_document, switch_source_input ) from sphinx.util.matching import Matcher +from sphinx.writers.html import HTMLTranslator -if False: - # For type annotation - from typing import Any, Dict, Tuple, Type # NOQA - from docutils.parsers.rst.states import Inliner # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA - from sphinx.ext.autodoc import Documenter # NOQA - from sphinx.writers.html import HTMLTranslator # NOQA logger = logging.getLogger(__name__) @@ -105,16 +102,14 @@ class autosummary_toc(nodes.comment): pass -def process_autosummary_toc(app, doctree): - # type: (Sphinx, nodes.document) -> None +def process_autosummary_toc(app: Sphinx, doctree: nodes.document) -> None: """Insert items described in autosummary:: to the TOC tree, but do not generate the toctree:: list. """ env = app.builder.env crawled = {} - def crawl_toc(node, depth=1): - # type: (nodes.Element, int) -> None + def crawl_toc(node: Element, depth: int = 1) -> None: crawled[node] = True for j, subnode in enumerate(node): try: @@ -131,14 +126,12 @@ def process_autosummary_toc(app, doctree): crawl_toc(doctree) -def autosummary_toc_visit_html(self, node): - # type: (nodes.NodeVisitor, autosummary_toc) -> None +def autosummary_toc_visit_html(self: nodes.NodeVisitor, node: autosummary_toc) -> None: """Hide autosummary toctree list in HTML output.""" raise nodes.SkipNode -def autosummary_noop(self, node): - # type: (nodes.NodeVisitor, nodes.Node) -> None +def autosummary_noop(self: nodes.NodeVisitor, node: Node) -> None: pass @@ -148,8 +141,7 @@ class autosummary_table(nodes.comment): pass -def autosummary_table_visit_html(self, node): - # type: (HTMLTranslator, autosummary_table) -> None +def autosummary_table_visit_html(self: HTMLTranslator, node: autosummary_table) -> None: """Make the first column of the table non-breaking.""" try: table = cast(nodes.table, node[0]) @@ -174,16 +166,14 @@ _app = None # type: Sphinx class FakeDirective(DocumenterBridge): - def __init__(self): - # type: () -> None + def __init__(self) -> None: settings = Struct(tab_width=8) document = Struct(settings=settings) state = Struct(document=document) super().__init__({}, None, Options(), 0, state) # type: ignore -def get_documenter(app, obj, parent): - # type: (Sphinx, Any, Any) -> Type[Documenter] +def get_documenter(app: Sphinx, obj: Any, parent: Any) -> Type[Documenter]: """Get an autodoc.Documenter class suitable for documenting the given object. @@ -237,8 +227,7 @@ class Autosummary(SphinxDirective): 'template': directives.unchanged, } - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: self.bridge = DocumenterBridge(self.env, self.state.document.reporter, Options(), self.lineno, self.state) @@ -280,8 +269,7 @@ class Autosummary(SphinxDirective): return nodes - def get_items(self, names): - # type: (List[str]) -> List[Tuple[str, str, str, str]] + def get_items(self, names: List[str]) -> List[Tuple[str, str, str, str]]: """Try to import the given names, and return a list of ``[(name, signature, summary_string, real_name), ...]``. """ @@ -361,8 +349,7 @@ class Autosummary(SphinxDirective): return items - def get_table(self, items): - # type: (List[Tuple[str, str, str, str]]) -> List[nodes.Node] + def get_table(self, items: List[Tuple[str, str, str, str]]) -> List[Node]: """Generate a proper list of table nodes for autosummary:: directive. *items* is a list produced by :meth:`get_items`. @@ -380,8 +367,7 @@ class Autosummary(SphinxDirective): body = nodes.tbody('') group.append(body) - def append_row(*column_texts): - # type: (str) -> None + def append_row(*column_texts: str) -> None: row = nodes.row('') source, line = self.state_machine.get_source_and_line() for text in column_texts: @@ -409,42 +395,36 @@ class Autosummary(SphinxDirective): return [table_spec, table] - def warn(self, msg): - # type: (str) -> None + def warn(self, msg: str) -> None: warnings.warn('Autosummary.warn() is deprecated', RemovedInSphinx40Warning, stacklevel=2) logger.warning(msg) @property - def genopt(self): - # type: () -> Options + def genopt(self) -> Options: warnings.warn('Autosummary.genopt is deprecated', RemovedInSphinx40Warning, stacklevel=2) return self.bridge.genopt @property - def warnings(self): - # type: () -> List[nodes.Node] + def warnings(self) -> List[Node]: warnings.warn('Autosummary.warnings is deprecated', RemovedInSphinx40Warning, stacklevel=2) return [] @property - def result(self): - # type: () -> StringList + def result(self) -> StringList: warnings.warn('Autosummary.result is deprecated', RemovedInSphinx40Warning, stacklevel=2) return self.bridge.result -def strip_arg_typehint(s): - # type: (str) -> str +def strip_arg_typehint(s: str) -> str: """Strip a type hint from argument definition.""" return s.split(':')[0].strip() -def mangle_signature(sig, max_chars=30): - # type: (str, int) -> str +def mangle_signature(sig: str, max_chars: int = 30) -> str: """Reformat a function signature to a more compact form.""" # Strip return type annotation s = re.sub(r"\)\s*->\s.*$", ")", sig) @@ -501,8 +481,7 @@ def mangle_signature(sig, max_chars=30): return "(%s)" % sig -def extract_summary(doc, document): - # type: (List[str], Any) -> str +def extract_summary(doc: List[str], document: Any) -> str: """Extract summary from docstring.""" # Skip a blank lines at the top @@ -550,8 +529,8 @@ def extract_summary(doc, document): return summary -def limited_join(sep, items, max_chars=30, overflow_marker="..."): - # type: (str, List[str], int, str) -> str +def limited_join(sep: str, items: List[str], max_chars: int = 30, + overflow_marker: str = "...") -> str: """Join a number of strings to one, limiting the length to *max_chars*. If the string overflows this limit, replace the last fitting item by @@ -577,8 +556,7 @@ def limited_join(sep, items, max_chars=30, overflow_marker="..."): # -- Importing items ----------------------------------------------------------- -def get_import_prefixes_from_env(env): - # type: (BuildEnvironment) -> List[str] +def get_import_prefixes_from_env(env: BuildEnvironment) -> List[str]: """ Obtain current Python import prefixes (for `import_by_name`) from ``document.env`` @@ -599,8 +577,7 @@ def get_import_prefixes_from_env(env): return prefixes -def import_by_name(name, prefixes=[None]): - # type: (str, List[str]) -> Tuple[str, Any, Any, str] +def import_by_name(name: str, prefixes: List[str] = [None]) -> Tuple[str, Any, Any, str]: """Import a Python object that has the given *name*, under one of the *prefixes*. The first name that succeeds is used. """ @@ -618,8 +595,7 @@ def import_by_name(name, prefixes=[None]): raise ImportError('no module named %s' % ' or '.join(tried)) -def _import_by_name(name): - # type: (str) -> Tuple[Any, Any, str] +def _import_by_name(name: str) -> Tuple[Any, Any, str]: """Import a Python object given its full name.""" try: name_parts = name.split('.') @@ -662,8 +638,9 @@ def _import_by_name(name): # -- :autolink: (smart default role) ------------------------------------------- -def autolink_role(typ, rawtext, etext, lineno, inliner, options={}, content=[]): - # type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA +def autolink_role(typ: str, rawtext: str, etext: str, lineno: int, inliner: Inliner, + options: Dict = {}, content: List[str] = [] + ) -> Tuple[List[Node], List[system_message]]: """Smart linking role. Expands to ':obj:`text`' if `text` is an object that can be imported; @@ -694,8 +671,7 @@ class AutoLink(SphinxRole): Expands to ':obj:`text`' if `text` is an object that can be imported; otherwise expands to '*text*'. """ - def run(self): - # type: () -> Tuple[List[nodes.Node], List[nodes.system_message]] + def run(self) -> Tuple[List[Node], List[system_message]]: pyobj_role = self.env.get_domain('py').role('obj') objects, errors = pyobj_role('obj', self.rawtext, self.text, self.lineno, self.inliner, self.options, self.content) @@ -716,10 +692,8 @@ class AutoLink(SphinxRole): return objects, errors -def get_rst_suffix(app): - # type: (Sphinx) -> str - def get_supported_format(suffix): - # type: (str) -> Tuple[str, ...] +def get_rst_suffix(app: Sphinx) -> str: + def get_supported_format(suffix: str) -> Tuple[str, ...]: parser_class = app.registry.get_source_parsers().get(suffix) if parser_class is None: return ('restructuredtext',) @@ -735,8 +709,7 @@ def get_rst_suffix(app): return None -def process_generate_options(app): - # type: (Sphinx) -> None +def process_generate_options(app: Sphinx) -> None: genfiles = app.config.autosummary_generate if genfiles is True: @@ -771,8 +744,7 @@ def process_generate_options(app): app=app, imported_members=imported_members) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: # I need autodoc app.setup_extension('sphinx.ext.autodoc') app.add_node(autosummary_toc, diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 5419e41df..2a23f1289 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -24,6 +24,7 @@ import pydoc import re import sys import warnings +from typing import Any, Callable, Dict, List, Set, Tuple, Type from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound from jinja2.sandbox import SandboxedEnvironment @@ -31,7 +32,9 @@ from jinja2.sandbox import SandboxedEnvironment import sphinx.locale from sphinx import __display_version__ from sphinx import package_dir +from sphinx.builders import Builder from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.ext.autodoc import Documenter from sphinx.ext.autosummary import import_by_name, get_documenter from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.locale import __ @@ -41,12 +44,6 @@ from sphinx.util import rst from sphinx.util.inspect import safe_getattr from sphinx.util.osutil import ensuredir -if False: - # For type annotation - from typing import Any, Callable, Dict, List, Set, Tuple, Type, Union # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.ext.autodoc import Documenter # NOQA - logger = logging.getLogger(__name__) @@ -54,15 +51,13 @@ logger = logging.getLogger(__name__) class DummyApplication: """Dummy Application class for sphinx-autogen command.""" - def __init__(self): - # type: () -> None + def __init__(self) -> None: self.registry = SphinxComponentRegistry() self.messagelog = [] # type: List[str] self.verbosity = 0 -def setup_documenters(app): - # type: (Any) -> None +def setup_documenters(app: Any) -> None: from sphinx.ext.autodoc import ( ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, FunctionDocumenter, MethodDocumenter, AttributeDocumenter, @@ -79,18 +74,15 @@ def setup_documenters(app): app.registry.add_documenter(documenter.objtype, documenter) -def _simple_info(msg): - # type: (str) -> None +def _simple_info(msg: str) -> None: print(msg) -def _simple_warn(msg): - # type: (str) -> None +def _simple_warn(msg: str) -> None: print('WARNING: ' + msg, file=sys.stderr) -def _underline(title, line='='): - # type: (str, str) -> str +def _underline(title: str, line: str = '=') -> str: if '\n' in title: raise ValueError('Can only underline single lines') return title + '\n' + line * len(title) @@ -99,8 +91,7 @@ def _underline(title, line='='): class AutosummaryRenderer: """A helper class for rendering.""" - def __init__(self, builder, template_dir): - # type: (Builder, str) -> None + def __init__(self, builder: Builder, template_dir: str) -> None: loader = None # type: BaseLoader template_dirs = [os.path.join(package_dir, 'ext', 'autosummary', 'templates')] if builder is None: @@ -117,8 +108,7 @@ class AutosummaryRenderer: self.env.filters['e'] = rst.escape self.env.filters['underline'] = _underline - def exists(self, template_name): - # type: (str) -> bool + def exists(self, template_name: str) -> bool: """Check if template file exists.""" try: self.env.get_template(template_name) @@ -126,8 +116,7 @@ class AutosummaryRenderer: except TemplateNotFound: return False - def render(self, template_name, context): - # type: (str, Dict) -> str + def render(self, template_name: str, context: Dict) -> str: """Render a template file.""" return self.env.get_template(template_name).render(context) @@ -135,9 +124,9 @@ class AutosummaryRenderer: # -- Generating output --------------------------------------------------------- -def generate_autosummary_content(name, obj, parent, template, template_name, - imported_members, app): - # type: (str, Any, Any, AutosummaryRenderer, str, bool, Any) -> str +def generate_autosummary_content(name: str, obj: Any, parent: Any, + template: AutosummaryRenderer, template_name: str, + imported_members: bool, app: Any) -> str: doc = get_documenter(app, obj, parent) if template_name is None: @@ -145,8 +134,8 @@ def generate_autosummary_content(name, obj, parent, template, template_name, if not template.exists(template_name): template_name = 'autosummary/base.rst' - def get_members(obj, types, include_public=[], imported=True): - # type: (Any, Set[str], List[str], bool) -> Tuple[List[str], List[str]] # NOQA + def get_members(obj: Any, types: Set[str], include_public: List[str] = [], + imported: bool = True) -> Tuple[List[str], List[str]]: items = [] # type: List[str] for name in dir(obj): try: @@ -201,10 +190,11 @@ def generate_autosummary_content(name, obj, parent, template, template_name, return template.render(template_name, ns) -def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', - warn=None, info=None, base_path=None, builder=None, - template_dir=None, imported_members=False, app=None): - # type: (List[str], str, str, Callable, Callable, str, Builder, str, bool, Any) -> None +def generate_autosummary_docs(sources: List[str], output_dir: str = None, + suffix: str = '.rst', warn: Callable = None, + info: Callable = None, base_path: str = None, + builder: Builder = None, template_dir: str = None, + imported_members: bool = False, app: Any = None) -> None: if info: warnings.warn('info argument for generate_autosummary_docs() is deprecated.', RemovedInSphinx40Warning) @@ -279,8 +269,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', # -- Finding documented entries in files --------------------------------------- -def find_autosummary_in_files(filenames): - # type: (List[str]) -> List[Tuple[str, str, str]] +def find_autosummary_in_files(filenames: List[str]) -> List[Tuple[str, str, str]]: """Find out what items are documented in source/*.rst. See `find_autosummary_in_lines`. @@ -293,8 +282,8 @@ def find_autosummary_in_files(filenames): return documented -def find_autosummary_in_docstring(name, module=None, filename=None): - # type: (str, Any, str) -> List[Tuple[str, str, str]] +def find_autosummary_in_docstring(name: str, module: Any = None, filename: str = None + ) -> List[Tuple[str, str, str]]: """Find out what items are documented in the given object's docstring. See `find_autosummary_in_lines`. @@ -313,8 +302,8 @@ def find_autosummary_in_docstring(name, module=None, filename=None): return [] -def find_autosummary_in_lines(lines, module=None, filename=None): - # type: (List[str], Any, str) -> List[Tuple[str, str, str]] +def find_autosummary_in_lines(lines: List[str], module: Any = None, filename: str = None + ) -> List[Tuple[str, str, str]]: """Find out what items appear in autosummary:: directives in the given lines. @@ -400,8 +389,7 @@ def find_autosummary_in_lines(lines, module=None, filename=None): return documented -def get_parser(): - # type: () -> argparse.ArgumentParser +def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( usage='%(prog)s [OPTIONS] <SOURCE_FILE>...', epilog=__('For more information, visit <http://sphinx-doc.org/>.'), @@ -443,8 +431,7 @@ The format of the autosummary directive is documented in the return parser -def main(argv=sys.argv[1:]): - # type: (List[str]) -> None +def main(argv: List[str] = sys.argv[1:]) -> None: sphinx.locale.setlocale(locale.LC_ALL, '') sphinx.locale.init_console(os.path.join(package_dir, 'locale'), 'sphinx') diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index 01ab38efe..68df253d5 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -16,8 +16,10 @@ import time import warnings from io import StringIO from os import path +from typing import Any, Callable, Dict, Iterable, List, Sequence, Set, Tuple, Type from docutils import nodes +from docutils.nodes import Element, Node, TextElement from docutils.parsers.rst import directives from packaging.specifiers import SpecifierSet, InvalidSpecifier from packaging.version import Version @@ -33,8 +35,8 @@ from sphinx.util.osutil import relpath if False: # For type annotation - from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Type # NOQA - from sphinx.application import Sphinx # NOQA + from sphinx.application import Sphinx + logger = logging.getLogger(__name__) @@ -42,15 +44,13 @@ blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE) doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE) -def doctest_encode(text, encoding): - # type: (str, str) -> str +def doctest_encode(text: str, encoding: str) -> str: warnings.warn('doctest_encode() is deprecated.', RemovedInSphinx40Warning) return text -def is_allowed_version(spec, version): - # type: (str, str) -> bool +def is_allowed_version(spec: str, version: str) -> bool: """Check `spec` satisfies `version` or not. This obeys PEP-440 specifiers: @@ -80,8 +80,7 @@ class TestDirective(SphinxDirective): optional_arguments = 1 final_argument_whitespace = True - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: # use ordinary docutils nodes for test code: they get special attributes # so that our builder recognizes them, and the other builders are happy. code = '\n'.join(self.content) @@ -95,7 +94,7 @@ class TestDirective(SphinxDirective): if not test: test = code code = doctestopt_re.sub('', code) - nodetype = nodes.literal_block # type: Type[nodes.TextElement] + nodetype = nodes.literal_block # type: Type[TextElement] if self.name in ('testsetup', 'testcleanup') or 'hide' in self.options: nodetype = nodes.comment if self.arguments: @@ -194,15 +193,13 @@ parser = doctest.DocTestParser() # helper classes class TestGroup: - def __init__(self, name): - # type: (str) -> None + def __init__(self, name: str) -> None: self.name = name self.setup = [] # type: List[TestCode] self.tests = [] # type: List[List[TestCode]] self.cleanup = [] # type: List[TestCode] - def add_code(self, code, prepend=False): - # type: (TestCode, bool) -> None + def add_code(self, code: "TestCode", prepend: bool = False) -> None: if code.type == 'testsetup': if prepend: self.setup.insert(0, code) @@ -220,30 +217,28 @@ class TestGroup: else: raise RuntimeError(__('invalid TestCode type')) - def __repr__(self): - # type: () -> str + def __repr__(self) -> str: return 'TestGroup(name=%r, setup=%r, cleanup=%r, tests=%r)' % ( self.name, self.setup, self.cleanup, self.tests) class TestCode: - def __init__(self, code, type, filename, lineno, options=None): - # type: (str, str, Optional[str], int, Optional[Dict]) -> None + def __init__(self, code: str, type: str, filename: str, + lineno: int, options: Dict = None) -> None: self.code = code self.type = type self.filename = filename self.lineno = lineno self.options = options or {} - def __repr__(self): - # type: () -> str + def __repr__(self) -> str: return 'TestCode(%r, %r, filename=%r, lineno=%r, options=%r)' % ( self.code, self.type, self.filename, self.lineno, self.options) class SphinxDocTestRunner(doctest.DocTestRunner): - def summarize(self, out, verbose=None): # type: ignore - # type: (Callable, bool) -> Tuple[int, int] + def summarize(self, out: Callable, verbose: bool = None # type: ignore + ) -> Tuple[int, int]: string_io = StringIO() old_stdout = sys.stdout sys.stdout = string_io @@ -254,9 +249,8 @@ class SphinxDocTestRunner(doctest.DocTestRunner): out(string_io.getvalue()) return res - def _DocTestRunner__patched_linecache_getlines(self, filename, - module_globals=None): - # type: (str, Any) -> Any + def _DocTestRunner__patched_linecache_getlines(self, filename: str, + module_globals: Any = None) -> Any: # this is overridden from DocTestRunner adding the try-except below m = self._DocTestRunner__LINECACHE_FILENAME_RE.match(filename) # type: ignore if m and m.group('name') == self.test.name: @@ -282,8 +276,7 @@ class DocTestBuilder(Builder): epilog = __('Testing of doctests in the sources finished, look at the ' 'results in %(outdir)s/output.txt.') - def init(self): - # type: () -> None + def init(self) -> None: # default options self.opt = self.config.doctest_default_flags @@ -312,32 +305,26 @@ class DocTestBuilder(Builder): '==================================%s\n') % (date, '=' * len(date))) - def _out(self, text): - # type: (str) -> None + def _out(self, text: str) -> None: logger.info(text, nonl=True) self.outfile.write(text) - def _warn_out(self, text): - # type: (str) -> None + def _warn_out(self, text: str) -> None: if self.app.quiet or self.app.warningiserror: logger.warning(text) else: logger.info(text, nonl=True) self.outfile.write(text) - def get_target_uri(self, docname, typ=None): - # type: (str, str) -> str + def get_target_uri(self, docname: str, typ: str = None) -> str: return '' - def get_outdated_docs(self): - # type: () -> Set[str] + def get_outdated_docs(self) -> Set[str]: return self.env.found_docs - def finish(self): - # type: () -> None + def finish(self) -> None: # write executive summary - def s(v): - # type: (int) -> str + def s(v: int) -> str: return v != 1 and 's' or '' repl = (self.total_tries, s(self.total_tries), self.total_failures, s(self.total_failures), @@ -356,8 +343,8 @@ Doctest summary if self.total_failures or self.setup_failures or self.cleanup_failures: self.app.statuscode = 1 - def write(self, build_docnames, updated_docnames, method='update'): - # type: (Iterable[str], Sequence[str], str) -> None + def write(self, build_docnames: Iterable[str], updated_docnames: Sequence[str], + method: str = 'update') -> None: if build_docnames is None: build_docnames = sorted(self.env.all_docs) @@ -367,8 +354,7 @@ Doctest summary doctree = self.env.get_doctree(docname) self.test_doc(docname, doctree) - def get_filename_for_node(self, node, docname): - # type: (nodes.Node, str) -> str + def get_filename_for_node(self, node: Node, docname: str) -> str: """Try to get the file which actually contains the doctest, not the filename of the document it's included in.""" try: @@ -379,8 +365,7 @@ Doctest summary return filename @staticmethod - def get_line_number(node): - # type: (nodes.Node) -> Optional[int] + def get_line_number(node: Node) -> int: """Get the real line number or admit we don't know.""" # TODO: Work out how to store or calculate real (file-relative) # line numbers for doctest blocks in docstrings. @@ -395,8 +380,7 @@ Doctest summary return node.line - 1 return None - def skipped(self, node): - # type: (nodes.Element) -> bool + def skipped(self, node: Element) -> bool: if 'skipif' not in node: return False else: @@ -409,8 +393,7 @@ Doctest summary exec(self.config.doctest_global_cleanup, context) return should_skip - def test_doc(self, docname, doctree): - # type: (str, nodes.Node) -> None + def test_doc(self, docname: str, doctree: Node) -> None: groups = {} # type: Dict[str, TestGroup] add_to_all_groups = [] self.setup_runner = SphinxDocTestRunner(verbose=False, @@ -424,17 +407,15 @@ Doctest summary self.cleanup_runner._fakeout = self.setup_runner._fakeout # type: ignore if self.config.doctest_test_doctest_blocks: - def condition(node): - # type: (nodes.Node) -> bool + def condition(node: Node) -> bool: return (isinstance(node, (nodes.literal_block, nodes.comment)) and 'testnodetype' in node) or \ isinstance(node, nodes.doctest_block) else: - def condition(node): - # type: (nodes.Node) -> bool + def condition(node: Node) -> bool: return isinstance(node, (nodes.literal_block, nodes.comment)) \ and 'testnodetype' in node - for node in doctree.traverse(condition): # type: nodes.Element + for node in doctree.traverse(condition): # type: Element if self.skipped(node): continue @@ -490,16 +471,13 @@ Doctest summary self.cleanup_failures += res_f self.cleanup_tries += res_t - def compile(self, code, name, type, flags, dont_inherit): - # type: (str, str, str, Any, bool) -> Any + def compile(self, code: str, name: str, type: str, flags: Any, dont_inherit: bool) -> Any: return compile(code, name, self.type, flags, dont_inherit) - def test_group(self, group): - # type: (TestGroup) -> None + def test_group(self, group: TestGroup) -> None: ns = {} # type: Dict - def run_setup_cleanup(runner, testcodes, what): - # type: (Any, List[TestCode], Any) -> bool + def run_setup_cleanup(runner: Any, testcodes: List[TestCode], what: Any) -> bool: examples = [] for testcode in testcodes: example = doctest.Example(testcode.code, '', lineno=testcode.lineno) @@ -568,8 +546,7 @@ Doctest summary run_setup_cleanup(self.cleanup_runner, group.cleanup, 'cleanup') -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: "Sphinx") -> Dict[str, Any]: app.add_directive('testsetup', TestsetupDirective) app.add_directive('testcleanup', TestcleanupDirective) app.add_directive('doctest', DoctestDirective) diff --git a/sphinx/ext/ifconfig.py b/sphinx/ext/ifconfig.py index 1768acf18..a6d3f78e8 100644 --- a/sphinx/ext/ifconfig.py +++ b/sphinx/ext/ifconfig.py @@ -19,17 +19,16 @@ :license: BSD, see LICENSE for details. """ +from typing import Any, Dict, List + from docutils import nodes +from docutils.nodes import Node import sphinx +from sphinx.application import Sphinx from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import nested_parse_with_titles -if False: - # For type annotation - from typing import Any, Dict, List # NOQA - from sphinx.application import Sphinx # NOQA - class ifconfig(nodes.Element): pass @@ -43,8 +42,7 @@ class IfConfig(SphinxDirective): final_argument_whitespace = True option_spec = {} # type: Dict - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: node = ifconfig() node.document = self.state.document self.set_source_info(node) @@ -53,8 +51,7 @@ class IfConfig(SphinxDirective): return [node] -def process_ifconfig_nodes(app, doctree, docname): - # type: (Sphinx, nodes.document, str) -> None +def process_ifconfig_nodes(app: Sphinx, doctree: nodes.document, docname: str) -> None: ns = {confval.name: confval.value for confval in app.config} ns.update(app.config.__dict__.copy()) ns['builder'] = app.builder.name @@ -76,8 +73,7 @@ def process_ifconfig_nodes(app, doctree, docname): node.replace_self(node.children) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_node(ifconfig) app.add_directive('ifconfig', IfConfig) app.connect('doctree-resolved', process_ifconfig_nodes) diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py index 3efbf4b25..992be7e95 100644 --- a/sphinx/ext/imgmath.py +++ b/sphinx/ext/imgmath.py @@ -17,11 +17,16 @@ import tempfile from hashlib import sha1 from os import path from subprocess import CalledProcessError, PIPE +from typing import Any, Dict, List, Tuple from docutils import nodes +from docutils.nodes import Element import sphinx from sphinx import package_dir +from sphinx.application import Sphinx +from sphinx.builders import Builder +from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.errors import SphinxError from sphinx.locale import _, __ @@ -30,14 +35,7 @@ from sphinx.util.math import get_node_equation_number, wrap_displaymath from sphinx.util.osutil import ensuredir from sphinx.util.png import read_png_depth, write_png_depth from sphinx.util.template import LaTeXRenderer - -if False: - # For type annotation - from typing import Any, Dict, List, Tuple, Union # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.config import Config # NOQA - from sphinx.writers.html import HTMLTranslator # NOQA +from sphinx.writers.html import HTMLTranslator logger = logging.getLogger(__name__) @@ -47,8 +45,7 @@ templates_path = path.join(package_dir, 'templates', 'imgmath') class MathExtError(SphinxError): category = 'Math extension error' - def __init__(self, msg, stderr=None, stdout=None): - # type: (str, bytes, bytes) -> None + def __init__(self, msg: str, stderr: bytes = None, stdout: bytes = None) -> None: if stderr: msg += '\n[stderr]\n' + stderr.decode(sys.getdefaultencoding(), 'replace') if stdout: @@ -116,8 +113,8 @@ def write_svg_depth(filename, depth): f.write('\n<!-- DEPTH=%s -->' % depth) -def generate_latex_macro(image_format, math, config, confdir=''): - # type: (str, str, Config, str) -> str +def generate_latex_macro(image_format: str, math: str, + config: Config, confdir: str = '') -> str: """Generate LaTeX macro.""" variables = { 'fontsize': config.imgmath_font_size, @@ -140,8 +137,7 @@ def generate_latex_macro(image_format, math, config, confdir=''): return LaTeXRenderer(templates_path).render(template_name, variables) -def ensure_tempdir(builder): - # type: (Builder) -> str +def ensure_tempdir(builder: Builder) -> str: """Create temporary directory. use only one tempdir per build -- the use of a directory is cleaner @@ -154,8 +150,7 @@ def ensure_tempdir(builder): return builder._imgmath_tempdir # type: ignore -def compile_math(latex, builder): - # type: (str, Builder) -> str +def compile_math(latex: str, builder: Builder) -> str: """Compile LaTeX macros for math to DVI.""" tempdir = ensure_tempdir(builder) filename = path.join(tempdir, 'math.tex') @@ -182,8 +177,7 @@ def compile_math(latex, builder): raise MathExtError('latex exited with error', exc.stderr, exc.stdout) -def convert_dvi_to_image(command, name): - # type: (List[str], str) -> Tuple[bytes, bytes] +def convert_dvi_to_image(command: List[str], name: str) -> Tuple[bytes, bytes]: """Convert DVI file to specific image format.""" try: ret = subprocess.run(command, stdout=PIPE, stderr=PIPE, check=True) @@ -197,8 +191,7 @@ def convert_dvi_to_image(command, name): raise MathExtError('%s exited with error' % name, exc.stderr, exc.stdout) -def convert_dvi_to_png(dvipath, builder): - # type: (str, Builder) -> Tuple[str, int] +def convert_dvi_to_png(dvipath: str, builder: Builder) -> Tuple[str, int]: """Convert DVI file to PNG image.""" tempdir = ensure_tempdir(builder) filename = path.join(tempdir, 'math.png') @@ -224,8 +217,7 @@ def convert_dvi_to_png(dvipath, builder): return filename, depth -def convert_dvi_to_svg(dvipath, builder): - # type: (str, Builder) -> Tuple[str, int] +def convert_dvi_to_svg(dvipath: str, builder: Builder) -> Tuple[str, int]: """Convert DVI file to SVG image.""" tempdir = ensure_tempdir(builder) filename = path.join(tempdir, 'math.svg') @@ -249,8 +241,7 @@ def convert_dvi_to_svg(dvipath, builder): return filename, depth -def render_math(self, math): - # type: (HTMLTranslator, str) -> Tuple[str, int] +def render_math(self: HTMLTranslator, math: str) -> Tuple[str, int]: """Render the LaTeX math expression *math* using latex and dvipng or dvisvgm. @@ -312,8 +303,7 @@ def render_math(self, math): return relfn, depth -def cleanup_tempdir(app, exc): - # type: (Sphinx, Exception) -> None +def cleanup_tempdir(app: Sphinx, exc: Exception) -> None: if exc: return if not hasattr(app.builder, '_imgmath_tempdir'): @@ -324,15 +314,13 @@ def cleanup_tempdir(app, exc): pass -def get_tooltip(self, node): - # type: (HTMLTranslator, Union[nodes.math, nodes.math_block]) -> str +def get_tooltip(self: HTMLTranslator, node: Element) -> str: if self.builder.config.imgmath_add_tooltips: return ' alt="%s"' % self.encode(node.astext()).strip() return '' -def html_visit_math(self, node): - # type: (HTMLTranslator, nodes.math) -> None +def html_visit_math(self: HTMLTranslator, node: nodes.math) -> None: try: fname, depth = render_math(self, '$' + node.astext() + '$') except MathExtError as exc: @@ -354,8 +342,7 @@ def html_visit_math(self, node): raise nodes.SkipNode -def html_visit_displaymath(self, node): - # type: (HTMLTranslator, nodes.math_block) -> None +def html_visit_displaymath(self: HTMLTranslator, node: nodes.math_block) -> None: if node['nowrap']: latex = node.astext() else: @@ -395,8 +382,7 @@ deprecated_alias('sphinx.ext.imgmath', RemovedInSphinx40Warning) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_html_math_renderer('imgmath', (html_visit_math, None), (html_visit_displaymath, None)) diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index df3ff01ed..f52a990bf 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -40,27 +40,25 @@ import inspect import re import sys from hashlib import md5 -from typing import Iterable, cast +from typing import Any, Dict, Iterable, List, Tuple +from typing import cast from docutils import nodes +from docutils.nodes import Node from docutils.parsers.rst import directives import sphinx from sphinx import addnodes +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment from sphinx.ext.graphviz import ( graphviz, figure_wrapper, render_dot_html, render_dot_latex, render_dot_texinfo ) from sphinx.util.docutils import SphinxDirective - -if False: - # For type annotation - from typing import Any, Dict, List, Optional, Tuple # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA - from sphinx.writers.html import HTMLTranslator # NOQA - from sphinx.writers.latex import LaTeXTranslator # NOQA - from sphinx.writers.texinfo import TexinfoTranslator # NOQA +from sphinx.writers.html import HTMLTranslator +from sphinx.writers.latex import LaTeXTranslator +from sphinx.writers.texinfo import TexinfoTranslator module_sig_re = re.compile(r'''^(?:([\w.]*)\.)? # module names @@ -68,8 +66,7 @@ module_sig_re = re.compile(r'''^(?:([\w.]*)\.)? # module names ''', re.VERBOSE) -def try_import(objname): - # type: (str) -> Any +def try_import(objname: str) -> Any: """Import a object or module using *name* and *currentmodule*. *name* should be a relative name from *currentmodule* or a fully-qualified name. @@ -96,8 +93,7 @@ def try_import(objname): return None -def import_classes(name, currmodule): - # type: (str, str) -> Any +def import_classes(name: str, currmodule: str) -> Any: """Import a class using its fully-qualified *name*.""" target = None @@ -138,9 +134,9 @@ class InheritanceGraph: from all the way to the root "object", and then is able to generate a graphviz dot graph from them. """ - def __init__(self, class_names, currmodule, show_builtins=False, - private_bases=False, parts=0, aliases=None, top_classes=[]): - # type: (List[str], str, bool, bool, int, Optional[Dict[str, str]], List[Any]) -> None + def __init__(self, class_names: List[str], currmodule: str, show_builtins: bool = False, + private_bases: bool = False, parts: int = 0, aliases: Dict[str, str] = None, + top_classes: List[Any] = []) -> None: """*class_names* is a list of child classes to show bases from. If *show_builtins* is True, then Python builtins will be shown @@ -154,16 +150,16 @@ class InheritanceGraph: raise InheritanceException('No classes found for ' 'inheritance diagram') - def _import_classes(self, class_names, currmodule): - # type: (List[str], str) -> List[Any] + def _import_classes(self, class_names: List[str], currmodule: str) -> List[Any]: """Import a list of classes.""" classes = [] # type: List[Any] for name in class_names: classes.extend(import_classes(name, currmodule)) return classes - def _class_info(self, classes, show_builtins, private_bases, parts, aliases, top_classes): - # type: (List[Any], bool, bool, int, Optional[Dict[str, str]], List[Any]) -> List[Tuple[str, str, List[str], str]] # NOQA + def _class_info(self, classes: List[Any], show_builtins: bool, private_bases: bool, + parts: int, aliases: Dict[str, str], top_classes: List[Any] + ) -> List[Tuple[str, str, List[str], str]]: """Return name and bases for all classes that are ancestors of *classes*. @@ -182,8 +178,7 @@ class InheritanceGraph: all_classes = {} py_builtins = vars(builtins).values() - def recurse(cls): - # type: (Any) -> None + def recurse(cls: Any) -> None: if not show_builtins and cls in py_builtins: return if not private_bases and cls.__name__.startswith('_'): @@ -222,8 +217,7 @@ class InheritanceGraph: return list(all_classes.values()) - def class_name(self, cls, parts=0, aliases=None): - # type: (Any, int, Optional[Dict[str, str]]) -> str + def class_name(self, cls: Any, parts: int = 0, aliases: Dict[str, str] = None) -> str: """Given a class object, return a fully-qualified name. This works for things I've tested in matplotlib so far, but may not be @@ -243,8 +237,7 @@ class InheritanceGraph: return aliases[result] return result - def get_all_class_names(self): - # type: () -> List[str] + def get_all_class_names(self) -> List[str]: """Get all of the class names involved in the graph.""" return [fullname for (_, fullname, _, _) in self.class_info] @@ -266,17 +259,15 @@ class InheritanceGraph: 'style': '"setlinewidth(0.5)"', } - def _format_node_attrs(self, attrs): - # type: (Dict) -> str + def _format_node_attrs(self, attrs: Dict) -> str: return ','.join(['%s=%s' % x for x in sorted(attrs.items())]) - def _format_graph_attrs(self, attrs): - # type: (Dict) -> str + def _format_graph_attrs(self, attrs: Dict) -> str: return ''.join(['%s=%s;\n' % x for x in sorted(attrs.items())]) - def generate_dot(self, name, urls={}, env=None, - graph_attrs={}, node_attrs={}, edge_attrs={}): - # type: (str, Dict, BuildEnvironment, Dict, Dict, Dict) -> str + def generate_dot(self, name: str, urls: Dict = {}, env: BuildEnvironment = None, + graph_attrs: Dict = {}, node_attrs: Dict = {}, edge_attrs: Dict = {} + ) -> str: """Generate a graphviz dot graph from the classes that were passed in to __init__. @@ -344,8 +335,7 @@ class InheritanceDiagram(SphinxDirective): 'top-classes': directives.unchanged_required, } - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: node = inheritance_diagram() node.document = self.state.document class_names = self.arguments[0].split() @@ -391,14 +381,12 @@ class InheritanceDiagram(SphinxDirective): return [figure] -def get_graph_hash(node): - # type: (inheritance_diagram) -> str +def get_graph_hash(node: inheritance_diagram) -> str: encoded = (node['content'] + str(node['parts'])).encode() return md5(encoded).hexdigest()[-10:] -def html_visit_inheritance_diagram(self, node): - # type: (HTMLTranslator, inheritance_diagram) -> None +def html_visit_inheritance_diagram(self: HTMLTranslator, node: inheritance_diagram) -> None: """ Output the graph for HTML. This will insert a PNG with clickable image map. @@ -431,8 +419,7 @@ def html_visit_inheritance_diagram(self, node): raise nodes.SkipNode -def latex_visit_inheritance_diagram(self, node): - # type: (LaTeXTranslator, inheritance_diagram) -> None +def latex_visit_inheritance_diagram(self: LaTeXTranslator, node: inheritance_diagram) -> None: """ Output the graph for LaTeX. This will insert a PDF. """ @@ -447,8 +434,8 @@ def latex_visit_inheritance_diagram(self, node): raise nodes.SkipNode -def texinfo_visit_inheritance_diagram(self, node): - # type: (TexinfoTranslator, inheritance_diagram) -> None +def texinfo_visit_inheritance_diagram(self: TexinfoTranslator, node: inheritance_diagram + ) -> None: """ Output the graph for Texinfo. This will insert a PNG. """ @@ -463,13 +450,11 @@ def texinfo_visit_inheritance_diagram(self, node): raise nodes.SkipNode -def skip(self, node): - # type: (nodes.NodeVisitor, inheritance_diagram) -> None +def skip(self: nodes.NodeVisitor, node: inheritance_diagram) -> None: raise nodes.SkipNode -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.setup_extension('sphinx.ext.graphviz') app.add_node( inheritance_diagram, diff --git a/sphinx/ext/jsmath.py b/sphinx/ext/jsmath.py index 47e1b1836..84f191a5e 100644 --- a/sphinx/ext/jsmath.py +++ b/sphinx/ext/jsmath.py @@ -10,6 +10,7 @@ """ import warnings +from typing import Any, Dict from sphinxcontrib.jsmath import ( # NOQA html_visit_math, @@ -18,16 +19,11 @@ from sphinxcontrib.jsmath import ( # NOQA ) import sphinx +from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning -if False: - # For type annotation - from typing import Any, Dict # NOQA - from sphinx.application import Sphinx # NOQA - -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: warnings.warn('sphinx.ext.jsmath has been moved to sphinxcontrib-jsmath.', RemovedInSphinx40Warning) diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py index b475dadef..d211a050e 100644 --- a/sphinx/ext/napoleon/__init__.py +++ b/sphinx/ext/napoleon/__init__.py @@ -8,14 +8,12 @@ :license: BSD, see LICENSE for details. """ +from typing import Any, Dict, List + from sphinx import __display_version__ as __version__ from sphinx.application import Sphinx from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring -if False: - # For type annotation - from typing import Any, Dict, List # NOQA - class Config: """Sphinx napoleon extension settings in `conf.py`. @@ -267,16 +265,14 @@ class Config: 'napoleon_custom_sections': (None, 'env') } - def __init__(self, **settings): - # type: (Any) -> None + def __init__(self, **settings) -> None: for name, (default, rebuild) in self._config_values.items(): setattr(self, name, default) for name, value in settings.items(): setattr(self, name, value) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: """Sphinx extension setup function. When the extension is loaded, Sphinx imports this module and executes @@ -313,8 +309,7 @@ def setup(app): return {'version': __version__, 'parallel_read_safe': True} -def _patch_python_domain(): - # type: () -> None +def _patch_python_domain() -> None: try: from sphinx.domains.python import PyTypedField except ImportError: @@ -333,8 +328,8 @@ def _patch_python_domain(): can_collapse=True)) -def _process_docstring(app, what, name, obj, options, lines): - # type: (Sphinx, str, str, Any, Any, List[str]) -> None +def _process_docstring(app: Sphinx, what: str, name: str, obj: Any, + options: Any, lines: List[str]) -> None: """Process the docstring for a given python object. Called when autodoc has read and processed a docstring. `lines` is a list @@ -383,8 +378,8 @@ def _process_docstring(app, what, name, obj, options, lines): lines[:] = result_lines[:] -def _skip_member(app, what, name, obj, skip, options): - # type: (Sphinx, str, str, Any, bool, Any) -> bool +def _skip_member(app: Sphinx, what: str, name: str, obj: Any, + skip: bool, options: Any) -> bool: """Determine if private and special class members are included in docs. The following settings in conf.py determine if private and special class diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py index 7ff184961..097c00e29 100644 --- a/sphinx/ext/napoleon/docstring.py +++ b/sphinx/ext/napoleon/docstring.py @@ -13,16 +13,13 @@ import inspect import re from functools import partial +from typing import Any, Callable, Dict, List, Tuple, Type, Union +from sphinx.application import Sphinx +from sphinx.config import Config as SphinxConfig from sphinx.ext.napoleon.iterators import modify_iter from sphinx.locale import _ -if False: - # For type annotation - from typing import Any, Callable, Dict, List, Tuple, Type, Union # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.config import Config as SphinxConfig # NOQA - _directive_regex = re.compile(r'\.\. \S+::') _google_section_regex = re.compile(r'^(\s|\w)+:\s*$') @@ -103,9 +100,9 @@ class GoogleDocstring: _name_rgx = re.compile(r"^\s*((?::(?P<role>\S+):)?`(?P<name>[a-zA-Z0-9_.-]+)`|" r" (?P<name2>[a-zA-Z0-9_.-]+))\s*", re.X) - def __init__(self, docstring, config=None, app=None, what='', name='', - obj=None, options=None): - # type: (Union[str, List[str]], SphinxConfig, Sphinx, str, str, Any, Any) -> None + def __init__(self, docstring: Union[str, List[str]], config: SphinxConfig = None, + app: Sphinx = None, what: str = '', name: str = '', + obj: Any = None, options: Any = None) -> None: self._config = config self._app = app @@ -175,8 +172,7 @@ class GoogleDocstring: self._parse() - def __str__(self): - # type: () -> str + def __str__(self) -> str: """Return the parsed docstring in reStructuredText format. Returns @@ -187,8 +183,7 @@ class GoogleDocstring: """ return '\n'.join(self.lines()) - def lines(self): - # type: () -> List[str] + def lines(self) -> List[str]: """Return the parsed lines of the docstring in reStructuredText format. Returns @@ -199,8 +194,7 @@ class GoogleDocstring: """ return self._parsed_lines - def _consume_indented_block(self, indent=1): - # type: (int) -> List[str] + def _consume_indented_block(self, indent: int = 1) -> List[str]: lines = [] line = self._line_iter.peek() while(not self._is_section_break() and @@ -209,8 +203,7 @@ class GoogleDocstring: line = self._line_iter.peek() return lines - def _consume_contiguous(self): - # type: () -> List[str] + def _consume_contiguous(self) -> List[str]: lines = [] while (self._line_iter.has_next() and self._line_iter.peek() and @@ -218,8 +211,7 @@ class GoogleDocstring: lines.append(next(self._line_iter)) return lines - def _consume_empty(self): - # type: () -> List[str] + def _consume_empty(self) -> List[str]: lines = [] line = self._line_iter.peek() while self._line_iter.has_next() and not line: @@ -227,8 +219,8 @@ class GoogleDocstring: line = self._line_iter.peek() return lines - def _consume_field(self, parse_type=True, prefer_type=False): - # type: (bool, bool) -> Tuple[str, str, List[str]] + def _consume_field(self, parse_type: bool = True, prefer_type: bool = False + ) -> Tuple[str, str, List[str]]: line = next(self._line_iter) before, colon, after = self._partition_field_on_colon(line) @@ -249,8 +241,8 @@ class GoogleDocstring: _descs = self.__class__(_descs, self._config).lines() return _name, _type, _descs - def _consume_fields(self, parse_type=True, prefer_type=False): - # type: (bool, bool) -> List[Tuple[str, str, List[str]]] + def _consume_fields(self, parse_type: bool = True, prefer_type: bool = False + ) -> List[Tuple[str, str, List[str]]]: self._consume_empty() fields = [] while not self._is_section_break(): @@ -259,8 +251,7 @@ class GoogleDocstring: fields.append((_name, _type, _desc,)) return fields - def _consume_inline_attribute(self): - # type: () -> Tuple[str, List[str]] + def _consume_inline_attribute(self) -> Tuple[str, List[str]]: line = next(self._line_iter) _type, colon, _desc = self._partition_field_on_colon(line) if not colon or not _desc: @@ -270,8 +261,7 @@ class GoogleDocstring: _descs = self.__class__(_descs, self._config).lines() return _type, _descs - def _consume_returns_section(self): - # type: () -> List[Tuple[str, str, List[str]]] + def _consume_returns_section(self) -> List[Tuple[str, str, List[str]]]: lines = self._dedent(self._consume_to_next_section()) if lines: before, colon, after = self._partition_field_on_colon(lines[0]) @@ -290,44 +280,38 @@ class GoogleDocstring: else: return [] - def _consume_usage_section(self): - # type: () -> List[str] + def _consume_usage_section(self) -> List[str]: lines = self._dedent(self._consume_to_next_section()) return lines - def _consume_section_header(self): - # type: () -> str + def _consume_section_header(self) -> str: section = next(self._line_iter) stripped_section = section.strip(':') if stripped_section.lower() in self._sections: section = stripped_section return section - def _consume_to_end(self): - # type: () -> List[str] + def _consume_to_end(self) -> List[str]: lines = [] while self._line_iter.has_next(): lines.append(next(self._line_iter)) return lines - def _consume_to_next_section(self): - # type: () -> List[str] + def _consume_to_next_section(self) -> List[str]: self._consume_empty() lines = [] while not self._is_section_break(): lines.append(next(self._line_iter)) return lines + self._consume_empty() - def _dedent(self, lines, full=False): - # type: (List[str], bool) -> List[str] + def _dedent(self, lines: List[str], full: bool = False) -> List[str]: if full: return [line.lstrip() for line in lines] else: min_indent = self._get_min_indent(lines) return [line[min_indent:] for line in lines] - def _escape_args_and_kwargs(self, name): - # type: (str) -> str + def _escape_args_and_kwargs(self, name: str) -> str: if name.endswith('_'): name = name[:-1] + r'\_' @@ -338,8 +322,7 @@ class GoogleDocstring: else: return name - def _fix_field_desc(self, desc): - # type: (List[str]) -> List[str] + def _fix_field_desc(self, desc: List[str]) -> List[str]: if self._is_list(desc): desc = [''] + desc elif desc[0].endswith('::'): @@ -352,8 +335,7 @@ class GoogleDocstring: desc = ['', desc[0]] + self._indent(desc_block, 4) return desc - def _format_admonition(self, admonition, lines): - # type: (str, List[str]) -> List[str] + def _format_admonition(self, admonition: str, lines: List[str]) -> List[str]: lines = self._strip_empty(lines) if len(lines) == 1: return ['.. %s:: %s' % (admonition, lines[0].strip()), ''] @@ -363,8 +345,7 @@ class GoogleDocstring: else: return ['.. %s::' % admonition, ''] - def _format_block(self, prefix, lines, padding=None): - # type: (str, List[str], str) -> List[str] + def _format_block(self, prefix: str, lines: List[str], padding: str = None) -> List[str]: if lines: if padding is None: padding = ' ' * len(prefix) @@ -380,9 +361,9 @@ class GoogleDocstring: else: return [prefix] - def _format_docutils_params(self, fields, field_role='param', - type_role='type'): - # type: (List[Tuple[str, str, List[str]]], str, str) -> List[str] + def _format_docutils_params(self, fields: List[Tuple[str, str, List[str]]], + field_role: str = 'param', type_role: str = 'type' + ) -> List[str]: lines = [] for _name, _type, _desc in fields: _desc = self._strip_empty(_desc) @@ -397,8 +378,7 @@ class GoogleDocstring: lines.append(':%s %s: %s' % (type_role, _name, _type)) return lines + [''] - def _format_field(self, _name, _type, _desc): - # type: (str, str, List[str]) -> List[str] + def _format_field(self, _name: str, _type: str, _desc: List[str]) -> List[str]: _desc = self._strip_empty(_desc) has_desc = any(_desc) separator = has_desc and ' -- ' or '' @@ -427,8 +407,8 @@ class GoogleDocstring: else: return [field] - def _format_fields(self, field_type, fields): - # type: (str, List[Tuple[str, str, List[str]]]) -> List[str] + def _format_fields(self, field_type: str, fields: List[Tuple[str, str, List[str]]] + ) -> List[str]: field_type = ':%s:' % field_type.strip() padding = ' ' * len(field_type) multi = len(fields) > 1 @@ -446,8 +426,7 @@ class GoogleDocstring: lines.append('') return lines - def _get_current_indent(self, peek_ahead=0): - # type: (int) -> int + def _get_current_indent(self, peek_ahead: int = 0) -> int: line = self._line_iter.peek(peek_ahead + 1)[peek_ahead] while line != self._line_iter.sentinel: if line: @@ -456,22 +435,19 @@ class GoogleDocstring: line = self._line_iter.peek(peek_ahead + 1)[peek_ahead] return 0 - def _get_indent(self, line): - # type: (str) -> int + def _get_indent(self, line: str) -> int: for i, s in enumerate(line): if not s.isspace(): return i return len(line) - def _get_initial_indent(self, lines): - # type: (List[str]) -> int + def _get_initial_indent(self, lines: List[str]) -> int: for line in lines: if line: return self._get_indent(line) return 0 - def _get_min_indent(self, lines): - # type: (List[str]) -> int + def _get_min_indent(self, lines: List[str]) -> int: min_indent = None for line in lines: if line: @@ -482,12 +458,10 @@ class GoogleDocstring: min_indent = indent return min_indent or 0 - def _indent(self, lines, n=4): - # type: (List[str], int) -> List[str] + def _indent(self, lines: List[str], n: int = 4) -> List[str]: return [(' ' * n) + line for line in lines] - def _is_indented(self, line, indent=1): - # type: (str, int) -> bool + def _is_indented(self, line: str, indent: int = 1) -> bool: for i, s in enumerate(line): if i >= indent: return True @@ -495,8 +469,7 @@ class GoogleDocstring: return False return False - def _is_list(self, lines): - # type: (List[str]) -> bool + def _is_list(self, lines: List[str]) -> bool: if not lines: return False if _bullet_list_regex.match(lines[0]): @@ -513,8 +486,7 @@ class GoogleDocstring: break return next_indent > indent - def _is_section_header(self): - # type: () -> bool + def _is_section_header(self) -> bool: section = self._line_iter.peek().lower() match = _google_section_regex.match(section) if match and section.strip(':') in self._sections: @@ -528,8 +500,7 @@ class GoogleDocstring: return True return False - def _is_section_break(self): - # type: () -> bool + def _is_section_break(self) -> bool: line = self._line_iter.peek() return (not self._line_iter.has_next() or self._is_section_header() or @@ -537,9 +508,7 @@ class GoogleDocstring: line and not self._is_indented(line, self._section_indent))) - def _load_custom_sections(self): - # type: () -> None - + def _load_custom_sections(self) -> None: if self._config.napoleon_custom_sections is not None: for entry in self._config.napoleon_custom_sections: if isinstance(entry, str): @@ -554,8 +523,7 @@ class GoogleDocstring: self._sections.get(entry[1].lower(), self._parse_custom_generic_section) - def _parse(self): - # type: () -> None + def _parse(self) -> None: self._parsed_lines = self._consume_empty() if self._name and self._what in ('attribute', 'data', 'property'): @@ -594,16 +562,14 @@ class GoogleDocstring: lines = self._consume_to_next_section() return self._format_admonition(admonition, lines) - def _parse_attribute_docstring(self): - # type: () -> List[str] + def _parse_attribute_docstring(self) -> List[str]: _type, _desc = self._consume_inline_attribute() lines = self._format_field('', '', _desc) if _type: lines.extend(['', ':type: %s' % _type]) return lines - def _parse_attributes_section(self, section): - # type: (str) -> List[str] + def _parse_attributes_section(self, section: str) -> List[str]: lines = [] for _name, _type, _desc in self._consume_fields(): if self._config.napoleon_use_ivar: @@ -624,8 +590,7 @@ class GoogleDocstring: lines.append('') return lines - def _parse_examples_section(self, section): - # type: (str) -> List[str] + def _parse_examples_section(self, section: str) -> List[str]: labels = { 'example': _('Example'), 'examples': _('Examples'), @@ -638,16 +603,14 @@ class GoogleDocstring: # for now, no admonition for simple custom sections return self._parse_generic_section(section, False) - def _parse_usage_section(self, section): - # type: (str) -> List[str] + def _parse_usage_section(self, section: str) -> List[str]: header = ['.. rubric:: Usage:', ''] block = ['.. code-block:: python', ''] lines = self._consume_usage_section() lines = self._indent(lines, 3) return header + block + lines + [''] - def _parse_generic_section(self, section, use_admonition): - # type: (str, bool) -> List[str] + def _parse_generic_section(self, section: str, use_admonition: bool) -> List[str]: lines = self._strip_empty(self._consume_to_next_section()) lines = self._dedent(lines) if use_admonition: @@ -660,8 +623,7 @@ class GoogleDocstring: else: return [header, ''] - def _parse_keyword_arguments_section(self, section): - # type: (str) -> List[str] + def _parse_keyword_arguments_section(self, section: str) -> List[str]: fields = self._consume_fields() if self._config.napoleon_use_keyword: return self._format_docutils_params( @@ -671,8 +633,7 @@ class GoogleDocstring: else: return self._format_fields(_('Keyword Arguments'), fields) - def _parse_methods_section(self, section): - # type: (str) -> List[str] + def _parse_methods_section(self, section: str) -> List[str]: lines = [] # type: List[str] for _name, _type, _desc in self._consume_fields(parse_type=False): lines.append('.. method:: %s' % _name) @@ -681,25 +642,21 @@ class GoogleDocstring: lines.append('') return lines - def _parse_notes_section(self, section): - # type: (str) -> List[str] + def _parse_notes_section(self, section: str) -> List[str]: use_admonition = self._config.napoleon_use_admonition_for_notes return self._parse_generic_section(_('Notes'), use_admonition) - def _parse_other_parameters_section(self, section): - # type: (str) -> List[str] + def _parse_other_parameters_section(self, section: str) -> List[str]: return self._format_fields(_('Other Parameters'), self._consume_fields()) - def _parse_parameters_section(self, section): - # type: (str) -> List[str] + def _parse_parameters_section(self, section: str) -> List[str]: fields = self._consume_fields() if self._config.napoleon_use_param: return self._format_docutils_params(fields) else: return self._format_fields(_('Parameters'), fields) - def _parse_raises_section(self, section): - # type: (str) -> List[str] + def _parse_raises_section(self, section: str) -> List[str]: fields = self._consume_fields(parse_type=False, prefer_type=True) lines = [] # type: List[str] for _name, _type, _desc in fields: @@ -714,13 +671,11 @@ class GoogleDocstring: lines.append('') return lines - def _parse_references_section(self, section): - # type: (str) -> List[str] + def _parse_references_section(self, section: str) -> List[str]: use_admonition = self._config.napoleon_use_admonition_for_references return self._parse_generic_section(_('References'), use_admonition) - def _parse_returns_section(self, section): - # type: (str) -> List[str] + def _parse_returns_section(self, section: str) -> List[str]: fields = self._consume_returns_section() multi = len(fields) > 1 if multi: @@ -748,21 +703,17 @@ class GoogleDocstring: lines.append('') return lines - def _parse_see_also_section(self, section): - # type (str) -> List[str] + def _parse_see_also_section(self, section: str) -> List[str]: return self._parse_admonition('seealso', section) - def _parse_warns_section(self, section): - # type: (str) -> List[str] + def _parse_warns_section(self, section: str) -> List[str]: return self._format_fields(_('Warns'), self._consume_fields()) - def _parse_yields_section(self, section): - # type: (str) -> List[str] + def _parse_yields_section(self, section: str) -> List[str]: fields = self._consume_returns_section() return self._format_fields(_('Yields'), fields) - def _partition_field_on_colon(self, line): - # type: (str) -> Tuple[str, str, str] + def _partition_field_on_colon(self, line: str) -> Tuple[str, str, str]: before_colon = [] after_colon = [] colon = '' @@ -784,8 +735,7 @@ class GoogleDocstring: colon, "".join(after_colon).strip()) - def _qualify_name(self, attr_name, klass): - # type: (str, Type) -> str + def _qualify_name(self, attr_name: str, klass: Type) -> str: if klass and '.' not in attr_name: if attr_name.startswith('~'): attr_name = attr_name[1:] @@ -796,8 +746,7 @@ class GoogleDocstring: return '~%s.%s' % (q, attr_name) return attr_name - def _strip_empty(self, lines): - # type: (List[str]) -> List[str] + def _strip_empty(self, lines: List[str]) -> List[str]: if lines: start = -1 for i, line in enumerate(lines): @@ -910,14 +859,14 @@ class NumpyDocstring(GoogleDocstring): The lines of the docstring in a list. """ - def __init__(self, docstring, config=None, app=None, what='', name='', - obj=None, options=None): - # type: (Union[str, List[str]], SphinxConfig, Sphinx, str, str, Any, Any) -> None + def __init__(self, docstring: Union[str, List[str]], config: SphinxConfig = None, + app: Sphinx = None, what: str = '', name: str = '', + obj: Any = None, options: Any = None) -> None: self._directive_sections = ['.. index::'] super().__init__(docstring, config, app, what, name, obj, options) - def _consume_field(self, parse_type=True, prefer_type=False): - # type: (bool, bool) -> Tuple[str, str, List[str]] + def _consume_field(self, parse_type: bool = True, prefer_type: bool = False + ) -> Tuple[str, str, List[str]]: line = next(self._line_iter) if parse_type: _name, _, _type = self._partition_field_on_colon(line) @@ -933,20 +882,17 @@ class NumpyDocstring(GoogleDocstring): _desc = self.__class__(_desc, self._config).lines() return _name, _type, _desc - def _consume_returns_section(self): - # type: () -> List[Tuple[str, str, List[str]]] + def _consume_returns_section(self) -> List[Tuple[str, str, List[str]]]: return self._consume_fields(prefer_type=True) - def _consume_section_header(self): - # type: () -> str + def _consume_section_header(self) -> str: section = next(self._line_iter) if not _directive_regex.match(section): # Consume the header underline next(self._line_iter) return section - def _is_section_break(self): - # type: () -> bool + def _is_section_break(self) -> bool: line1, line2 = self._line_iter.peek(2) return (not self._line_iter.has_next() or self._is_section_header() or @@ -955,8 +901,7 @@ class NumpyDocstring(GoogleDocstring): line1 and not self._is_indented(line1, self._section_indent))) - def _is_section_header(self): - # type: () -> bool + def _is_section_header(self) -> bool: section, underline = self._line_iter.peek(2) section = section.lower() if section in self._sections and isinstance(underline, str): @@ -968,16 +913,14 @@ class NumpyDocstring(GoogleDocstring): return True return False - def _parse_see_also_section(self, section): - # type: (str) -> List[str] + def _parse_see_also_section(self, section: str) -> List[str]: lines = self._consume_to_next_section() try: return self._parse_numpydoc_see_also_section(lines) except ValueError: return self._format_admonition('seealso', lines) - def _parse_numpydoc_see_also_section(self, content): - # type: (List[str]) -> List[str] + def _parse_numpydoc_see_also_section(self, content: List[str]) -> List[str]: """ Derived from the NumpyDoc implementation of _parse_see_also. @@ -991,8 +934,7 @@ class NumpyDocstring(GoogleDocstring): """ items = [] - def parse_item_name(text): - # type: (str) -> Tuple[str, str] + def parse_item_name(text: str) -> Tuple[str, str]: """Match ':role:`name`' or 'name'""" m = self._name_rgx.match(text) if m: @@ -1003,8 +945,7 @@ class NumpyDocstring(GoogleDocstring): return g[2], g[1] raise ValueError("%s is not a item name" % text) - def push_item(name, rest): - # type: (str, List[str]) -> None + def push_item(name: str, rest: List[str]) -> None: if not name: return name, role = parse_item_name(name) diff --git a/sphinx/ext/napoleon/iterators.py b/sphinx/ext/napoleon/iterators.py index d9de4fb80..3aa728e44 100644 --- a/sphinx/ext/napoleon/iterators.py +++ b/sphinx/ext/napoleon/iterators.py @@ -11,10 +11,7 @@ """ import collections - -if False: - # For type annotation - from typing import Any, Iterable # NOQA +from typing import Any, Iterable class peek_iter: @@ -50,8 +47,7 @@ class peek_iter: be set to a new object instance: ``object()``. """ - def __init__(self, *args): - # type: (Any) -> None + def __init__(self, *args) -> None: """__init__(o, sentinel=None)""" self._iterable = iter(*args) # type: Iterable self._cache = collections.deque() # type: collections.deque @@ -60,18 +56,15 @@ class peek_iter: else: self.sentinel = object() - def __iter__(self): - # type: () -> peek_iter + def __iter__(self) -> "peek_iter": return self - def __next__(self, n=None): - # type: (int) -> Any + def __next__(self, n: int = None) -> Any: # note: prevent 2to3 to transform self.next() in next(self) which # causes an infinite loop ! return getattr(self, 'next')(n) - def _fillcache(self, n): - # type: (int) -> None + def _fillcache(self, n: int) -> None: """Cache `n` items. If `n` is 0 or None, then 1 item is cached.""" if not n: n = 1 @@ -82,8 +75,7 @@ class peek_iter: while len(self._cache) < n: self._cache.append(self.sentinel) - def has_next(self): - # type: () -> bool + def has_next(self) -> bool: """Determine if iterator is exhausted. Returns @@ -98,8 +90,7 @@ class peek_iter: """ return self.peek() != self.sentinel - def next(self, n=None): - # type: (int) -> Any + def next(self, n: int = None) -> Any: """Get the next item or `n` items of the iterator. Parameters @@ -134,8 +125,7 @@ class peek_iter: result = [self._cache.popleft() for i in range(n)] return result - def peek(self, n=None): - # type: (int) -> Any + def peek(self, n: int = None) -> Any: """Preview the next item or `n` items of the iterator. The iterator is not advanced when peek is called. @@ -218,8 +208,7 @@ class modify_iter(peek_iter): "whitespace." """ - def __init__(self, *args, **kwargs): - # type: (Any, Any) -> None + def __init__(self, *args, **kwargs) -> None: """__init__(o, sentinel=None, modifier=lambda x: x)""" if 'modifier' in kwargs: self.modifier = kwargs['modifier'] @@ -233,8 +222,7 @@ class modify_iter(peek_iter): 'modifier must be callable') super().__init__(*args) - def _fillcache(self, n): - # type: (int) -> None + def _fillcache(self, n: int) -> None: """Cache `n` modified items. If `n` is 0 or None, 1 item is cached. Each item returned by the iterator is passed through the diff --git a/sphinx/ext/todo.py b/sphinx/ext/todo.py index 2da27700b..49cd5019e 100644 --- a/sphinx/ext/todo.py +++ b/sphinx/ext/todo.py @@ -12,29 +12,27 @@ """ import warnings +from typing import Any, Dict, Iterable, List, Tuple from typing import cast from docutils import nodes +from docutils.nodes import Element, Node from docutils.parsers.rst import directives from docutils.parsers.rst.directives.admonitions import BaseAdmonition import sphinx +from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.domains import Domain +from sphinx.environment import BuildEnvironment from sphinx.errors import NoUri from sphinx.locale import _, __ from sphinx.util import logging from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import make_refnode from sphinx.util.texescape import tex_escape_map - -if False: - # For type annotation - from typing import Any, Dict, Iterable, List, Tuple # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA - from sphinx.writers.html import HTMLTranslator # NOQA - from sphinx.writers.latex import LaTeXTranslator # NOQA +from sphinx.writers.html import HTMLTranslator +from sphinx.writers.latex import LaTeXTranslator logger = logging.getLogger(__name__) @@ -62,12 +60,11 @@ class Todo(BaseAdmonition, SphinxDirective): 'name': directives.unchanged, } - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: if not self.options.get('class'): self.options['class'] = ['admonition-todo'] - (todo,) = super().run() # type: Tuple[nodes.Node] + (todo,) = super().run() # type: Tuple[Node] if isinstance(todo, nodes.system_message): return [todo] elif isinstance(todo, todo_node): @@ -86,21 +83,18 @@ class TodoDomain(Domain): label = 'todo' @property - def todos(self): - # type: () -> Dict[str, List[todo_node]] + def todos(self) -> Dict[str, List[todo_node]]: return self.data.setdefault('todos', {}) - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: self.todos.pop(docname, None) - def merge_domaindata(self, docnames, otherdata): - # type: (List[str], Dict) -> None + def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None: for docname in docnames: self.todos[docname] = otherdata['todos'][docname] - def process_doc(self, env, docname, document): - # type: (BuildEnvironment, str, nodes.document) -> None + def process_doc(self, env: BuildEnvironment, docname: str, + document: nodes.document) -> None: todos = self.todos.setdefault(docname, []) for todo in document.traverse(todo_node): env.app.emit('todo-defined', todo) @@ -111,8 +105,7 @@ class TodoDomain(Domain): location=todo) -def process_todos(app, doctree): - # type: (Sphinx, nodes.document) -> None +def process_todos(app: Sphinx, doctree: nodes.document) -> None: warnings.warn('process_todos() is deprecated.', RemovedInSphinx40Warning) # collect all todos in the environment # this is not done in the directive itself because it some transformations @@ -150,16 +143,14 @@ class TodoList(SphinxDirective): final_argument_whitespace = False option_spec = {} # type: Dict - def run(self): - # type: () -> List[nodes.Node] + def run(self) -> List[Node]: # Simply insert an empty todolist node which will be replaced later # when process_todo_nodes is called return [todolist('')] class TodoListProcessor: - def __init__(self, app, doctree, docname): - # type: (Sphinx, nodes.document, str) -> None + def __init__(self, app: Sphinx, doctree: nodes.document, docname: str) -> None: self.builder = app.builder self.config = app.config self.env = app.env @@ -167,8 +158,7 @@ class TodoListProcessor: self.process(doctree, docname) - def process(self, doctree, docname): - # type: (nodes.document, str) -> None + def process(self, doctree: nodes.document, docname: str) -> None: todos = sum(self.domain.todos.values(), []) for node in doctree.traverse(todolist): if not self.config.todo_include_todos: @@ -176,7 +166,7 @@ class TodoListProcessor: continue if node.get('ids'): - content = [nodes.target()] # type: List[nodes.Element] + content = [nodes.target()] # type: List[Element] else: content = [] @@ -194,8 +184,7 @@ class TodoListProcessor: node.replace_self(content) - def create_todo_reference(self, todo, docname): - # type: (todo_node, str) -> nodes.paragraph + def create_todo_reference(self, todo: todo_node, docname: str) -> nodes.paragraph: if self.config.todo_link_only: description = _('<<original entry>>') else: @@ -224,8 +213,7 @@ class TodoListProcessor: return para -def process_todo_nodes(app, doctree, fromdocname): - # type: (Sphinx, nodes.document, str) -> None +def process_todo_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str) -> None: """Replace all todolist nodes with a list of the collected todos. Augment each todo with a backlink to the original location. """ @@ -236,7 +224,7 @@ def process_todo_nodes(app, doctree, fromdocname): for node in doctree.traverse(todolist): if node.get('ids'): - content = [nodes.target()] # type: List[nodes.Element] + content = [nodes.target()] # type: List[Element] else: content = [] @@ -280,8 +268,7 @@ def process_todo_nodes(app, doctree, fromdocname): node.replace_self(content) -def purge_todos(app, env, docname): - # type: (Sphinx, BuildEnvironment, str) -> None +def purge_todos(app: Sphinx, env: BuildEnvironment, docname: str) -> None: warnings.warn('purge_todos() is deprecated.', RemovedInSphinx40Warning) if not hasattr(env, 'todo_all_todos'): return @@ -289,8 +276,8 @@ def purge_todos(app, env, docname): if todo['docname'] != docname] -def merge_info(app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Iterable[str], BuildEnvironment) -> None +def merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], + other: BuildEnvironment) -> None: warnings.warn('merge_info() is deprecated.', RemovedInSphinx40Warning) if not hasattr(other, 'todo_all_todos'): return @@ -299,21 +286,18 @@ def merge_info(app, env, docnames, other): env.todo_all_todos.extend(other.todo_all_todos) # type: ignore -def visit_todo_node(self, node): - # type: (HTMLTranslator, todo_node) -> None +def visit_todo_node(self: HTMLTranslator, node: todo_node) -> None: if self.config.todo_include_todos: self.visit_admonition(node) else: raise nodes.SkipNode -def depart_todo_node(self, node): - # type: (HTMLTranslator, todo_node) -> None +def depart_todo_node(self: HTMLTranslator, node: todo_node) -> None: self.depart_admonition(node) -def latex_visit_todo_node(self, node): - # type: (LaTeXTranslator, todo_node) -> None +def latex_visit_todo_node(self: LaTeXTranslator, node: todo_node) -> None: if self.config.todo_include_todos: self.body.append('\n\\begin{sphinxadmonition}{note}{') self.body.append(self.hypertarget_to(node)) @@ -324,13 +308,11 @@ def latex_visit_todo_node(self, node): raise nodes.SkipNode -def latex_depart_todo_node(self, node): - # type: (LaTeXTranslator, todo_node) -> None +def latex_depart_todo_node(self: LaTeXTranslator, node: todo_node) -> None: self.body.append('\\end{sphinxadmonition}\n') -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_event('todo-defined') app.add_config_value('todo_include_todos', False, 'html') app.add_config_value('todo_link_only', False, 'html') diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 5de8f7f5e..5bbec60a9 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -9,28 +9,25 @@ """ import traceback +from typing import Any, Dict, Iterable, Iterator, Set, Tuple from docutils import nodes +from docutils.nodes import Element, Node import sphinx from sphinx import addnodes +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzer from sphinx.util import get_full_modname, logging, status_iterator from sphinx.util.nodes import make_refnode -if False: - # For type annotation - from typing import Any, Dict, Iterable, Iterator, Set, Tuple # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.config import Config # NOQA - from sphinx.environment import BuildEnvironment # NOQA logger = logging.getLogger(__name__) -def _get_full_modname(app, modname, attribute): - # type: (Sphinx, str, str) -> str +def _get_full_modname(app: Sphinx, modname: str, attribute: str) -> str: try: return get_full_modname(modname, attribute) except AttributeError: @@ -48,8 +45,7 @@ def _get_full_modname(app, modname, attribute): return None -def doctree_read(app, doctree): - # type: (Sphinx, nodes.Node) -> None +def doctree_read(app: Sphinx, doctree: Node) -> None: env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} # type: ignore @@ -120,8 +116,8 @@ def doctree_read(app, doctree): signode += onlynode -def env_merge_info(app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Iterable[str], BuildEnvironment) -> None +def env_merge_info(app: Sphinx, env: BuildEnvironment, docnames: Iterable[str], + other: BuildEnvironment) -> None: if not hasattr(other, '_viewcode_modules'): return # create a _viewcode_modules dict on the main environment @@ -131,8 +127,8 @@ def env_merge_info(app, env, docnames, other): env._viewcode_modules.update(other._viewcode_modules) # type: ignore -def missing_reference(app, env, node, contnode): - # type: (Sphinx, BuildEnvironment, nodes.Element, nodes.Node) -> nodes.Node +def missing_reference(app: Sphinx, env: BuildEnvironment, node: Element, contnode: Node + ) -> Node: # resolve our "viewcode" reference nodes -- they need special treatment if node['reftype'] == 'viewcode': return make_refnode(app.builder, node['refdoc'], node['reftarget'], @@ -141,8 +137,7 @@ def missing_reference(app, env, node, contnode): return None -def collect_pages(app): - # type: (Sphinx) -> Iterator[Tuple[str, Dict[str, Any], str]] +def collect_pages(app: Sphinx) -> Iterator[Tuple[str, Dict[str, Any], str]]: env = app.builder.env if not hasattr(env, '_viewcode_modules'): return @@ -236,8 +231,7 @@ def collect_pages(app): yield ('_modules/index', context, 'page.html') -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value('viewcode_import', None, False) app.add_config_value('viewcode_enable_epub', False, False) app.add_config_value('viewcode_follow_imported_members', True, False) |