diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 2ee34cc90..8e2db2b4e 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -14,12 +14,20 @@ import warnings from collections import defaultdict from copy import copy from os import path +from typing import Any, Callable, Dict, Generator, Iterator, List, Set, Tuple, Union + +from docutils import nodes +from docutils.nodes import Node from sphinx import addnodes +from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx40Warning +from sphinx.domains import Domain from sphinx.environment.adapters.toctree import TocTree from sphinx.errors import SphinxError, BuildEnvironmentError, DocumentError, ExtensionError +from sphinx.events import EventManager from sphinx.locale import __ +from sphinx.project import Project from sphinx.transforms import SphinxTransformer from sphinx.util import DownloadFiles, FilenameUniqDict from sphinx.util import logging @@ -29,14 +37,9 @@ from sphinx.util.nodes import is_translatable if False: # For type annotation - from typing import Any, Callable, Dict, IO, Iterator, List, Optional, Set, Tuple, Union # NOQA - from docutils import nodes # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.config import Config # NOQA - from sphinx.event import EventManager # NOQA - from sphinx.domains import Domain # NOQA - from sphinx.project import Project # NOQA + from sphinx.application import Sphinx + from sphinx.builders import Builder + logger = logging.getLogger(__name__) @@ -89,8 +92,7 @@ class BuildEnvironment: # --------- ENVIRONMENT INITIALIZATION ------------------------------------- - def __init__(self, app=None): - # type: (Sphinx) -> None + def __init__(self, app: "Sphinx" = None): self.app = None # type: Sphinx self.doctreedir = None # type: str self.srcdir = None # type: str @@ -188,19 +190,16 @@ class BuildEnvironment: if app: self.setup(app) - def __getstate__(self): - # type: () -> Dict + def __getstate__(self) -> Dict: """Obtains serializable data for pickling.""" __dict__ = self.__dict__.copy() __dict__.update(app=None, domains={}, events=None) # clear unpickable attributes return __dict__ - def __setstate__(self, state): - # type: (Dict) -> None + def __setstate__(self, state: Dict) -> None: self.__dict__.update(state) - def setup(self, app): - # type: (Sphinx) -> None + def setup(self, app: "Sphinx") -> None: """Set up BuildEnvironment object.""" if self.version and self.version != app.registry.get_envversion(app): raise BuildEnvironmentError(__('build environment version not current')) @@ -228,8 +227,7 @@ class BuildEnvironment: # initialie settings self._update_settings(app.config) - def _update_config(self, config): - # type: (Config) -> None + def _update_config(self, config: Config) -> None: """Update configurations by new one.""" self.config_status = CONFIG_OK if self.config is None: @@ -246,8 +244,7 @@ class BuildEnvironment: self.config = config - def _update_settings(self, config): - # type: (Config) -> None + def _update_settings(self, config: Config) -> None: """Update settings by new config.""" self.settings['input_encoding'] = config.source_encoding self.settings['trim_footnote_reference_space'] = config.trim_footnote_reference_space @@ -256,8 +253,7 @@ class BuildEnvironment: # Allow to disable by 3rd party extension (workaround) self.settings.setdefault('smart_quotes', True) - def set_versioning_method(self, method, compare): - # type: (Union[str, Callable], bool) -> None + def set_versioning_method(self, method: Union[str, Callable], compare: bool) -> None: """This sets the doctree versioning method for this environment. Versioning methods are a builder property; only builders with the same @@ -280,8 +276,7 @@ class BuildEnvironment: self.versioning_condition = condition self.versioning_compare = compare - def clear_doc(self, docname): - # type: (str) -> None + def clear_doc(self, docname: str) -> None: """Remove all traces of a source file in the inventory.""" if docname in self.all_docs: self.all_docs.pop(docname, None) @@ -291,8 +286,8 @@ class BuildEnvironment: for domain in self.domains.values(): domain.clear_doc(docname) - def merge_info_from(self, docnames, other, app): - # type: (List[str], BuildEnvironment, Sphinx) -> None + def merge_info_from(self, docnames: List[str], other: "BuildEnvironment", + app: "Sphinx") -> None: """Merge global information gathered about *docnames* while reading them from the *other* environment. @@ -309,16 +304,14 @@ class BuildEnvironment: domain.merge_domaindata(docnames, other.domaindata[domainname]) self.events.emit('env-merge-info', self, docnames, other) - def path2doc(self, filename): - # type: (str) -> Optional[str] + def path2doc(self, filename: str) -> str: """Return the docname for the filename if the file is document. *filename* should be absolute or relative to the source directory. """ return self.project.path2doc(filename) - def doc2path(self, docname, base=True, suffix=None): - # type: (str, Union[bool, str], str) -> str + def doc2path(self, docname: str, base: Union[bool, str] = True, suffix: str = None) -> str: """Return the filename for the document name. If *base* is True, return absolute path under self.srcdir. @@ -341,8 +334,7 @@ class BuildEnvironment: pathname = path.join(base, pathname) # type: ignore return pathname - def relfn2path(self, filename, docname=None): - # type: (str, str) -> Tuple[str, str] + def relfn2path(self, filename: str, docname: str = None) -> Tuple[str, str]: """Return paths to a file referenced from a document, relative to documentation root and absolute. @@ -361,13 +353,11 @@ class BuildEnvironment: return rel_fn, path.abspath(path.join(self.srcdir, rel_fn)) @property - def found_docs(self): - # type: () -> Set[str] + def found_docs(self) -> Set[str]: """contains all existing docnames.""" return self.project.docnames - def find_files(self, config, builder): - # type: (Config, Builder) -> None + def find_files(self, config: Config, builder: "Builder") -> None: """Find all source files in the source dir and put them in self.found_docs. """ @@ -395,8 +385,7 @@ class BuildEnvironment: except OSError as exc: raise DocumentError(__('Failed to scan documents in %s: %r') % (self.srcdir, exc)) - def get_outdated_files(self, config_changed): - # type: (bool) -> Tuple[Set[str], Set[str], Set[str]] + def get_outdated_files(self, config_changed: bool) -> Tuple[Set[str], Set[str], Set[str]]: """Return (added, changed, removed) sets.""" # clear all files no longer present removed = set(self.all_docs) - self.found_docs @@ -446,8 +435,7 @@ class BuildEnvironment: return added, changed, removed - def check_dependents(self, app, already): - # type: (Sphinx, Set[str]) -> Iterator[str] + def check_dependents(self, app: "Sphinx", already: Set[str]) -> Generator[str, None, None]: to_rewrite = [] # type: List[str] for docnames in self.events.emit('env-get-updated', self): to_rewrite.extend(docnames) @@ -457,8 +445,7 @@ class BuildEnvironment: # --------- SINGLE FILE READING -------------------------------------------- - def prepare_settings(self, docname): - # type: (str) -> None + def prepare_settings(self, docname: str) -> None: """Prepare to set up environment for reading.""" self.temp_data['docname'] = docname # defaults to the global default, but can be re-set in a document @@ -469,13 +456,11 @@ class BuildEnvironment: # utilities to use while reading a document @property - def docname(self): - # type: () -> str + def docname(self) -> str: """Returns the docname of the document currently being parsed.""" return self.temp_data['docname'] - def new_serialno(self, category=''): - # type: (str) -> int + def new_serialno(self, category: str = '') -> int: """Return a serial number, e.g. for index entry targets. The number is guaranteed to be unique in the current document. @@ -485,8 +470,7 @@ class BuildEnvironment: self.temp_data[key] = cur + 1 return cur - def note_dependency(self, filename): - # type: (str) -> None + def note_dependency(self, filename: str) -> None: """Add *filename* as a dependency of the current document. This means that the document will be rebuilt if this file changes. @@ -495,8 +479,7 @@ class BuildEnvironment: """ self.dependencies[self.docname].add(filename) - def note_included(self, filename): - # type: (str) -> None + def note_included(self, filename: str) -> None: """Add *filename* as a included from other document. This means the document is not orphaned. @@ -505,15 +488,13 @@ class BuildEnvironment: """ self.included[self.docname].add(self.path2doc(filename)) - def note_reread(self): - # type: () -> None + def note_reread(self) -> None: """Add the current document to the list of documents that will automatically be re-read at the next build. """ self.reread_always.add(self.docname) - def get_domain(self, domainname): - # type: (str) -> Domain + def get_domain(self, domainname: str) -> Domain: """Return the domain instance with the specified name. Raises an ExtensionError if the domain is not registered. @@ -525,8 +506,7 @@ class BuildEnvironment: # --------- RESOLVING REFERENCES AND TOCTREES ------------------------------ - def get_doctree(self, docname): - # type: (str) -> nodes.document + def get_doctree(self, docname: str) -> nodes.document: """Read the doctree for a file from the pickle and return it.""" filename = path.join(self.doctreedir, docname + '.doctree') with open(filename, 'rb') as f: @@ -535,9 +515,9 @@ class BuildEnvironment: doctree.reporter = LoggingReporter(self.doc2path(docname)) return doctree - def get_and_resolve_doctree(self, docname, builder, doctree=None, - prune_toctrees=True, includehidden=False): - # type: (str, Builder, nodes.document, bool, bool) -> nodes.document + def get_and_resolve_doctree(self, docname: str, builder: "Builder", + doctree: nodes.document = None, prune_toctrees: bool = True, + includehidden: bool = False) -> nodes.document: """Read the doctree from the pickle, resolve cross-references and toctrees and return it. """ @@ -559,9 +539,9 @@ class BuildEnvironment: return doctree - def resolve_toctree(self, docname, builder, toctree, prune=True, maxdepth=0, - titles_only=False, collapse=False, includehidden=False): - # type: (str, Builder, addnodes.toctree, bool, int, bool, bool, bool) -> nodes.Node + def resolve_toctree(self, docname: str, builder: "Builder", toctree: addnodes.toctree, + prune: bool = True, maxdepth: int = 0, titles_only: bool = False, + collapse: bool = False, includehidden: bool = False) -> Node: """Resolve a *toctree* node into individual bullet lists with titles as items, returning None (if no containing titles are found) or a new node. @@ -577,12 +557,11 @@ class BuildEnvironment: maxdepth, titles_only, collapse, includehidden) - def resolve_references(self, doctree, fromdocname, builder): - # type: (nodes.document, str, Builder) -> None + def resolve_references(self, doctree: nodes.document, fromdocname: str, + builder: "Builder") -> None: self.apply_post_transforms(doctree, fromdocname) - def apply_post_transforms(self, doctree, docname): - # type: (nodes.document, str) -> None + def apply_post_transforms(self, doctree: nodes.document, docname: str) -> None: """Apply all post-transforms.""" try: # set env.docname during applying post-transforms @@ -599,12 +578,10 @@ class BuildEnvironment: # allow custom references to be resolved self.events.emit('doctree-resolved', doctree, docname) - def collect_relations(self): - # type: () -> Dict[str, List[str]] + def collect_relations(self) -> Dict[str, List[str]]: traversed = set() - def traverse_toctree(parent, docname): - # type: (str, str) -> Iterator[Tuple[str, str]] + def traverse_toctree(parent: str, docname: str) -> Iterator[Tuple[str, str]]: if parent == docname: logger.warning(__('self referenced toctree found. Ignored.'), location=docname) return @@ -633,8 +610,7 @@ class BuildEnvironment: return relations - def check_consistency(self): - # type: () -> None + def check_consistency(self) -> None: """Do consistency checks.""" included = set().union(*self.included.values()) # type: ignore for docname in sorted(self.all_docs): diff --git a/sphinx/environment/adapters/asset.py b/sphinx/environment/adapters/asset.py index b57943967..bc282de0c 100644 --- a/sphinx/environment/adapters/asset.py +++ b/sphinx/environment/adapters/asset.py @@ -8,18 +8,14 @@ :license: BSD, see LICENSE for details. """ -if False: - # For type annotation - from sphinx.environment import BuildEnvironment # NOQA +from sphinx.environment import BuildEnvironment class ImageAdapter: - def __init__(self, env): - # type: (BuildEnvironment) -> None + def __init__(self, env: BuildEnvironment) -> None: self.env = env - def get_original_image_uri(self, name): - # type: (str) -> str + def get_original_image_uri(self, name: str) -> str: """Get the original image URI.""" while name in self.env.original_image_uri: name = self.env.original_image_uri[name] diff --git a/sphinx/environment/adapters/indexentries.py b/sphinx/environment/adapters/indexentries.py index 38d28f0b0..430c3dce2 100644 --- a/sphinx/environment/adapters/indexentries.py +++ b/sphinx/environment/adapters/indexentries.py @@ -11,33 +11,30 @@ import bisect import re import unicodedata from itertools import groupby +from typing import Any, Dict, Pattern, List, Tuple +from sphinx.builders import Builder +from sphinx.environment import BuildEnvironment from sphinx.errors import NoUri from sphinx.locale import _, __ from sphinx.util import split_into, logging -if False: - # For type annotation - from typing import Any, Dict, Pattern, List, Tuple # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA logger = logging.getLogger(__name__) class IndexEntries: - def __init__(self, env): - # type: (BuildEnvironment) -> None + def __init__(self, env: BuildEnvironment) -> None: self.env = env - def create_index(self, builder, group_entries=True, - _fixre=re.compile(r'(.*) ([(][^()]*[)])')): - # type: (Builder, bool, Pattern) -> List[Tuple[str, List[Tuple[str, Any]]]] + def create_index(self, builder: Builder, group_entries: bool = True, + _fixre: Pattern = re.compile(r'(.*) ([(][^()]*[)])') + ) -> List[Tuple[str, List[Tuple[str, Any]]]]: """Create the real index from the collected index entries.""" new = {} # type: Dict[str, List] - def add_entry(word, subword, main, link=True, dic=new, key=None): - # type: (str, str, str, bool, Dict, str) -> None + def add_entry(word: str, subword: str, main: str, link: bool = True, + dic: Dict = new, key: str = None) -> None: # Force the word to be unicode if it's a ASCII bytestring. # This will solve problems with unicode normalization later. # For instance the RFC role will add bytestrings at the moment @@ -91,8 +88,7 @@ class IndexEntries: # sort the index entries; put all symbols at the front, even those # following the letters in ASCII, this is where the chr(127) comes from - def keyfunc(entry): - # type: (Tuple[str, List]) -> Tuple[str, str] + def keyfunc(entry: Tuple[str, List]) -> Tuple[str, str]: key, (void, void, category_key) = entry if category_key: # using specified category key to sort @@ -138,8 +134,7 @@ class IndexEntries: i += 1 # group the entries by letter - def keyfunc2(item): - # type: (Tuple[str, List]) -> str + def keyfunc2(item: Tuple[str, List]) -> str: # hack: mutating the subitems dicts to a list in the keyfunc k, v = item v[1] = sorted((si, se) for (si, (se, void, void)) in v[1].items()) diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py index fe7bd3d0d..d5f827dde 100644 --- a/sphinx/environment/adapters/toctree.py +++ b/sphinx/environment/adapters/toctree.py @@ -8,9 +8,11 @@ :license: BSD, see LICENSE for details. """ -from typing import Iterable, cast +from typing import cast +from typing import Iterable, List from docutils import nodes +from docutils.nodes import Element, Node from sphinx import addnodes from sphinx.locale import __ @@ -20,20 +22,18 @@ from sphinx.util.nodes import clean_astext, process_only_nodes if False: # For type annotation - from typing import Any, Dict, List # NOQA - from sphinx.builders import Builder # NOQA - from sphinx.environment import BuildEnvironment # NOQA + from sphinx.builders import Builder + from sphinx.environment import BuildEnvironment + logger = logging.getLogger(__name__) class TocTree: - def __init__(self, env): - # type: (BuildEnvironment) -> None + def __init__(self, env: "BuildEnvironment") -> None: self.env = env - def note(self, docname, toctreenode): - # type: (str, addnodes.toctree) -> None + def note(self, docname: str, toctreenode: addnodes.toctree) -> None: """Note a TOC tree directive in a document and gather information about file relations from it. """ @@ -48,9 +48,9 @@ class TocTree: self.env.files_to_rebuild.setdefault(includefile, set()).add(docname) self.env.toctree_includes.setdefault(docname, []).extend(includefiles) - def resolve(self, docname, builder, toctree, prune=True, maxdepth=0, - titles_only=False, collapse=False, includehidden=False): - # type: (str, Builder, addnodes.toctree, bool, int, bool, bool, bool) -> nodes.Element + def resolve(self, docname: str, builder: "Builder", toctree: addnodes.toctree, + prune: bool = True, maxdepth: int = 0, titles_only: bool = False, + collapse: bool = False, includehidden: bool = False) -> Element: """Resolve a *toctree* node into individual bullet lists with titles as items, returning None (if no containing titles are found) or a new node. @@ -86,8 +86,7 @@ class TocTree: toctree_ancestors = self.get_toctree_ancestors(docname) excluded = Matcher(self.env.config.exclude_patterns) - def _toctree_add_classes(node, depth): - # type: (nodes.Element, int) -> None + def _toctree_add_classes(node: Element, depth: int) -> None: """Add 'toctree-l%d' and 'current' classes to the toctree.""" for subnode in node.children: if isinstance(subnode, (addnodes.compact_paragraph, @@ -105,7 +104,7 @@ class TocTree: if not subnode['anchorname']: # give the whole branch a 'current' class # (useful for styling it differently) - branchnode = subnode # type: nodes.Element + branchnode = subnode # type: Element while branchnode: branchnode['classes'].append('current') branchnode = branchnode.parent @@ -117,11 +116,12 @@ class TocTree: subnode['iscurrent'] = True subnode = subnode.parent - def _entries_from_toctree(toctreenode, parents, separate=False, subtree=False): - # type: (addnodes.toctree, List[str], bool, bool) -> List[nodes.Element] + def _entries_from_toctree(toctreenode: addnodes.toctree, parents: List[str], + separate: bool = False, subtree: bool = False + ) -> List[Element]: """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] - entries = [] # type: List[nodes.Element] + entries = [] # type: List[Element] for (title, ref) in refs: try: refdoc = None @@ -265,8 +265,7 @@ class TocTree: docname, refnode['refuri']) + refnode['anchorname'] return newnode - def get_toctree_ancestors(self, docname): - # type: (str) -> List[str] + def get_toctree_ancestors(self, docname: str) -> List[str]: parent = {} for p, children in self.env.toctree_includes.items(): for child in children: @@ -278,8 +277,8 @@ class TocTree: d = parent[d] return ancestors - def _toctree_prune(self, node, depth, maxdepth, collapse=False): - # type: (nodes.Element, int, int, bool) -> None + def _toctree_prune(self, node: Element, depth: int, maxdepth: int, collapse: bool = False + ) -> None: """Utility: Cut a TOC at a specified depth.""" for subnode in node.children[:]: if isinstance(subnode, (addnodes.compact_paragraph, @@ -300,8 +299,7 @@ class TocTree: # recurse on visible children self._toctree_prune(subnode, depth + 1, maxdepth, collapse) - def get_toc_for(self, docname, builder): - # type: (str, Builder) -> nodes.Node + def get_toc_for(self, docname: str, builder: "Builder") -> Node: """Return a TOC nodetree -- for use on the same page only!""" tocdepth = self.env.metadata[docname].get('tocdepth', 0) try: @@ -316,11 +314,11 @@ class TocTree: node['refuri'] = node['anchorname'] or '#' return toc - def get_toctree_for(self, docname, builder, collapse, **kwds): - # type: (str, Builder, bool, Any) -> nodes.Element + def get_toctree_for(self, docname: str, builder: "Builder", collapse: bool, **kwds + ) -> Element: """Return the global TOC nodetree.""" doctree = self.env.get_doctree(self.env.config.master_doc) - toctrees = [] # type: List[nodes.Element] + toctrees = [] # type: List[Element] if 'includehidden' not in kwds: kwds['includehidden'] = True if 'maxdepth' not in kwds: diff --git a/sphinx/environment/collectors/__init__.py b/sphinx/environment/collectors/__init__.py index 3f7b9344b..eb16a9f25 100644 --- a/sphinx/environment/collectors/__init__.py +++ b/sphinx/environment/collectors/__init__.py @@ -8,12 +8,12 @@ :license: BSD, see LICENSE for details. """ -if False: - # For type annotation - from typing import Dict, List, Set # NOQA - from docutils import nodes # NOQA - from sphinx.sphinx import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA +from typing import Dict, List, Set + +from docutils import nodes + +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment class EnvironmentCollector: @@ -27,8 +27,7 @@ class EnvironmentCollector: listener_ids = None # type: Dict[str, int] - def enable(self, app): - # type: (Sphinx) -> None + def enable(self, app: Sphinx) -> None: assert self.listener_ids is None self.listener_ids = { 'doctree-read': app.connect('doctree-read', self.process_doc), @@ -38,43 +37,39 @@ class EnvironmentCollector: 'env-get-outdated': app.connect('env-get-outdated', self.get_outdated_docs), } - def disable(self, app): - # type: (Sphinx) -> None + def disable(self, app: Sphinx) -> None: assert self.listener_ids is not None for listener_id in self.listener_ids.values(): app.disconnect(listener_id) self.listener_ids = None - def clear_doc(self, app, env, docname): - # type: (Sphinx, BuildEnvironment, str) -> None + def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: """Remove specified data of a document. This method is called on the removal of the document.""" raise NotImplementedError - def merge_other(self, app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Set[str], BuildEnvironment) -> None + def merge_other(self, app: Sphinx, env: BuildEnvironment, + docnames: Set[str], other: BuildEnvironment) -> None: """Merge in specified data regarding docnames from a different `BuildEnvironment` object which coming from a subprocess in parallel builds.""" raise NotImplementedError - def process_doc(self, app, doctree): - # type: (Sphinx, nodes.document) -> None + def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: """Process a document and gather specific data from it. This method is called after the document is read.""" raise NotImplementedError - def get_updated_docs(self, app, env): - # type: (Sphinx, BuildEnvironment) -> List[str] + def get_updated_docs(self, app: Sphinx, env: BuildEnvironment) -> List[str]: """Return a list of docnames to re-read. This methods is called after reading the whole of documents (experimental). """ return [] - def get_outdated_docs(self, app, env, added, changed, removed): - # type: (Sphinx, BuildEnvironment, str, Set[str], Set[str], Set[str]) -> List[str] + def get_outdated_docs(self, app: Sphinx, env: BuildEnvironment, + added: Set[str], changed: Set[str], removed: Set[str]) -> List[str]: """Return a list of docnames to re-read. This methods is called before reading the documents. diff --git a/sphinx/environment/collectors/asset.py b/sphinx/environment/collectors/asset.py index fed8280c1..e1d3abef1 100644 --- a/sphinx/environment/collectors/asset.py +++ b/sphinx/environment/collectors/asset.py @@ -11,22 +11,21 @@ import os from glob import glob from os import path +from typing import Any, Dict, List, Set from docutils import nodes +from docutils.nodes import Node from docutils.utils import relative_path from sphinx import addnodes +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment from sphinx.environment.collectors import EnvironmentCollector from sphinx.locale import __ from sphinx.util import logging from sphinx.util.i18n import get_image_filename_for_language, search_image_for_language from sphinx.util.images import guess_mimetype -if False: - # For type annotation - from typing import Dict, List, Set # NOQA - from sphinx.sphinx import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA logger = logging.getLogger(__name__) @@ -34,16 +33,14 @@ logger = logging.getLogger(__name__) class ImageCollector(EnvironmentCollector): """Image files collector for sphinx.environment.""" - def clear_doc(self, app, env, docname): - # type: (Sphinx, BuildEnvironment, str) -> None + def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: env.images.purge_doc(docname) - def merge_other(self, app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Set[str], BuildEnvironment) -> None + def merge_other(self, app: Sphinx, env: BuildEnvironment, + docnames: Set[str], other: BuildEnvironment) -> None: env.images.merge_other(docnames, other.images) - def process_doc(self, app, doctree): - # type: (Sphinx, nodes.document) -> None + def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: """Process and rewrite image URIs.""" docname = app.env.docname @@ -92,8 +89,8 @@ class ImageCollector(EnvironmentCollector): continue app.env.images.add_file(docname, imgpath) - def collect_candidates(self, env, imgpath, candidates, node): - # type: (BuildEnvironment, str, Dict[str, str], nodes.Node) -> None + def collect_candidates(self, env: BuildEnvironment, imgpath: str, + candidates: Dict[str, str], node: Node) -> None: globbed = {} # type: Dict[str, List[str]] for filename in glob(imgpath): new_imgpath = relative_path(path.join(env.srcdir, 'dummy'), @@ -115,16 +112,14 @@ class ImageCollector(EnvironmentCollector): class DownloadFileCollector(EnvironmentCollector): """Download files collector for sphinx.environment.""" - def clear_doc(self, app, env, docname): - # type: (Sphinx, BuildEnvironment, str) -> None + def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: env.dlfiles.purge_doc(docname) - def merge_other(self, app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Set[str], BuildEnvironment) -> None + def merge_other(self, app: Sphinx, env: BuildEnvironment, + docnames: Set[str], other: BuildEnvironment) -> None: env.dlfiles.merge_other(docnames, other.dlfiles) - def process_doc(self, app, doctree): - # type: (Sphinx, nodes.document) -> None + def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: """Process downloadable file paths. """ for node in doctree.traverse(addnodes.download_reference): targetname = node['reftarget'] @@ -140,8 +135,7 @@ class DownloadFileCollector(EnvironmentCollector): node['filename'] = app.env.dlfiles.add_file(app.env.docname, rel_filename) -def setup(app): - # type: (Sphinx) -> Dict +def setup(app: Sphinx) -> Dict[str, Any]: app.add_env_collector(ImageCollector) app.add_env_collector(DownloadFileCollector) diff --git a/sphinx/environment/collectors/dependencies.py b/sphinx/environment/collectors/dependencies.py index b091b371d..63ae63e84 100644 --- a/sphinx/environment/collectors/dependencies.py +++ b/sphinx/environment/collectors/dependencies.py @@ -10,35 +10,30 @@ import os from os import path +from typing import Any, Dict, Set +from docutils import nodes from docutils.utils import relative_path +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment from sphinx.environment.collectors import EnvironmentCollector from sphinx.util.osutil import fs_encoding -if False: - # For type annotation - from typing import Dict, Set # NOQA - from docutils import nodes # NOQA - from sphinx.sphinx import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA - class DependenciesCollector(EnvironmentCollector): """dependencies collector for sphinx.environment.""" - def clear_doc(self, app, env, docname): - # type: (Sphinx, BuildEnvironment, str) -> None + def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: env.dependencies.pop(docname, None) - def merge_other(self, app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Set[str], BuildEnvironment) -> None + def merge_other(self, app: Sphinx, env: BuildEnvironment, + docnames: Set[str], other: BuildEnvironment) -> None: for docname in docnames: if docname in other.dependencies: env.dependencies[docname] = other.dependencies[docname] - def process_doc(self, app, doctree): - # type: (Sphinx, nodes.document) -> None + def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: """Process docutils-generated dependency info.""" cwd = os.getcwd() frompath = path.join(path.normpath(app.srcdir), 'dummy') @@ -55,8 +50,7 @@ class DependenciesCollector(EnvironmentCollector): app.env.dependencies[app.env.docname].add(relpath) -def setup(app): - # type: (Sphinx) -> Dict +def setup(app: Sphinx) -> Dict[str, Any]: app.add_env_collector(DependenciesCollector) return { diff --git a/sphinx/environment/collectors/indexentries.py b/sphinx/environment/collectors/indexentries.py index 2d8af7887..9c86779fc 100644 --- a/sphinx/environment/collectors/indexentries.py +++ b/sphinx/environment/collectors/indexentries.py @@ -8,34 +8,31 @@ :license: BSD, see LICENSE for details. """ +from typing import Any, Dict, Set + +from docutils import nodes + from sphinx import addnodes +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment from sphinx.environment.collectors import EnvironmentCollector from sphinx.util import split_index_msg, logging -if False: - # For type annotation - from typing import Dict, Set # NOQA - from docutils import nodes # NOQA - from sphinx.applicatin import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA - logger = logging.getLogger(__name__) class IndexEntriesCollector(EnvironmentCollector): name = 'indices' - def clear_doc(self, app, env, docname): - # type: (Sphinx, BuildEnvironment, str) -> None + def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: env.indexentries.pop(docname, None) - def merge_other(self, app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Set[str], BuildEnvironment) -> None + def merge_other(self, app: Sphinx, env: BuildEnvironment, + docnames: Set[str], other: BuildEnvironment) -> None: for docname in docnames: env.indexentries[docname] = other.indexentries[docname] - def process_doc(self, app, doctree): - # type: (Sphinx, nodes.document) -> None + def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: docname = app.env.docname entries = app.env.indexentries[docname] = [] for node in doctree.traverse(addnodes.index): @@ -50,8 +47,7 @@ class IndexEntriesCollector(EnvironmentCollector): entries.append(entry) -def setup(app): - # type: (Sphinx) -> Dict +def setup(app: Sphinx) -> Dict[str, Any]: app.add_env_collector(IndexEntriesCollector) return { diff --git a/sphinx/environment/collectors/metadata.py b/sphinx/environment/collectors/metadata.py index 9168e7840..a547d2551 100644 --- a/sphinx/environment/collectors/metadata.py +++ b/sphinx/environment/collectors/metadata.py @@ -8,33 +8,28 @@ :license: BSD, see LICENSE for details. """ -from typing import List, cast +from typing import Any, Dict, List, Set +from typing import cast from docutils import nodes +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment from sphinx.environment.collectors import EnvironmentCollector -if False: - # For type annotation - from typing import Dict, Set # NOQA - from sphinx.sphinx import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA - class MetadataCollector(EnvironmentCollector): """metadata collector for sphinx.environment.""" - def clear_doc(self, app, env, docname): - # type: (Sphinx, BuildEnvironment, str) -> None + def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: env.metadata.pop(docname, None) - def merge_other(self, app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Set[str], BuildEnvironment) -> None + def merge_other(self, app: Sphinx, env: BuildEnvironment, + docnames: Set[str], other: BuildEnvironment) -> None: for docname in docnames: env.metadata[docname] = other.metadata[docname] - def process_doc(self, app, doctree): - # type: (Sphinx, nodes.document) -> None + def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: """Process the docinfo part of the doctree as metadata. Keep processing minimal -- just return what docutils says. @@ -67,8 +62,7 @@ class MetadataCollector(EnvironmentCollector): doctree.pop(0) -def setup(app): - # type: (Sphinx) -> Dict +def setup(app: Sphinx) -> Dict[str, Any]: app.add_env_collector(MetadataCollector) return { diff --git a/sphinx/environment/collectors/title.py b/sphinx/environment/collectors/title.py index 0f43eb0af..7d464f874 100644 --- a/sphinx/environment/collectors/title.py +++ b/sphinx/environment/collectors/title.py @@ -8,34 +8,30 @@ :license: BSD, see LICENSE for details. """ +from typing import Any, Dict, Set + from docutils import nodes +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment from sphinx.environment.collectors import EnvironmentCollector from sphinx.transforms import SphinxContentsFilter -if False: - # For type annotation - from typing import Dict, Set # NOQA - from sphinx.sphinx import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA - class TitleCollector(EnvironmentCollector): """title collector for sphinx.environment.""" - def clear_doc(self, app, env, docname): - # type: (Sphinx, BuildEnvironment, str) -> None + def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: env.titles.pop(docname, None) env.longtitles.pop(docname, None) - def merge_other(self, app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Set[str], BuildEnvironment) -> None + def merge_other(self, app: Sphinx, env: BuildEnvironment, + docnames: Set[str], other: BuildEnvironment) -> None: for docname in docnames: env.titles[docname] = other.titles[docname] env.longtitles[docname] = other.longtitles[docname] - def process_doc(self, app, doctree): - # type: (Sphinx, nodes.document) -> None + def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: """Add a title node to the document (just copy the first section title), and store that title in the environment. """ @@ -59,8 +55,7 @@ class TitleCollector(EnvironmentCollector): app.env.longtitles[app.env.docname] = longtitlenode -def setup(app): - # type: (Sphinx) -> Dict +def setup(app: Sphinx) -> Dict[str, Any]: app.add_env_collector(TitleCollector) return { diff --git a/sphinx/environment/collectors/toctree.py b/sphinx/environment/collectors/toctree.py index 53009c753..d1e211d2c 100644 --- a/sphinx/environment/collectors/toctree.py +++ b/sphinx/environment/collectors/toctree.py @@ -8,31 +8,29 @@ :license: BSD, see LICENSE for details. """ +from typing import Any, Dict, List, Set, Tuple, Type, TypeVar from typing import cast from docutils import nodes +from docutils.nodes import Element, Node from sphinx import addnodes +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment from sphinx.environment.adapters.toctree import TocTree from sphinx.environment.collectors import EnvironmentCollector from sphinx.locale import __ from sphinx.transforms import SphinxContentsFilter from sphinx.util import url_re, logging -if False: - # For type annotation - from typing import Dict, List, Set, Tuple, Type, TypeVar # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.environment import BuildEnvironment # NOQA - N = TypeVar('N') +N = TypeVar('N') logger = logging.getLogger(__name__) class TocTreeCollector(EnvironmentCollector): - def clear_doc(self, app, env, docname): - # type: (Sphinx, BuildEnvironment, str) -> None + def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None: env.tocs.pop(docname, None) env.toc_secnumbers.pop(docname, None) env.toc_fignumbers.pop(docname, None) @@ -46,8 +44,8 @@ class TocTreeCollector(EnvironmentCollector): if not fnset: del env.files_to_rebuild[subfn] - def merge_other(self, app, env, docnames, other): - # type: (Sphinx, BuildEnvironment, Set[str], BuildEnvironment) -> None + def merge_other(self, app: Sphinx, env: BuildEnvironment, docnames: Set[str], + other: BuildEnvironment) -> None: for docname in docnames: env.tocs[docname] = other.tocs[docname] env.toc_num_entries[docname] = other.toc_num_entries[docname] @@ -61,14 +59,12 @@ class TocTreeCollector(EnvironmentCollector): for subfn, fnset in other.files_to_rebuild.items(): env.files_to_rebuild.setdefault(subfn, set()).update(fnset & set(docnames)) - def process_doc(self, app, doctree): - # type: (Sphinx, nodes.document) -> None + def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: """Build a TOC from the doctree and store it in the inventory.""" docname = app.env.docname numentries = [0] # nonlocal again... - def traverse_in_section(node, cls): - # type: (nodes.Element, Type[N]) -> List[N] + def traverse_in_section(node: Element, cls: Type[N]) -> List[N]: """Like traverse(), but stay within the same section.""" result = [] # type: List[N] if isinstance(node, cls): @@ -80,9 +76,8 @@ class TocTreeCollector(EnvironmentCollector): result.extend(traverse_in_section(child, cls)) return result - def build_toc(node, depth=1): - # type: (nodes.Element, int) -> nodes.bullet_list - entries = [] # type: List[nodes.Element] + def build_toc(node: Element, depth: int = 1) -> nodes.bullet_list: + entries = [] # type: List[Element] for sectionnode in node: # find all toctree nodes in this section and add them # to the toc (just copying the toctree node which is then @@ -107,7 +102,7 @@ class TocTreeCollector(EnvironmentCollector): '', '', internal=True, refuri=docname, anchorname=anchorname, *nodetext) para = addnodes.compact_paragraph('', '', reference) - item = nodes.list_item('', para) # type: nodes.Element + item = nodes.list_item('', para) # type: Element sub_item = build_toc(sectionnode, depth + 1) if sub_item: item += sub_item @@ -135,12 +130,10 @@ class TocTreeCollector(EnvironmentCollector): app.env.tocs[docname] = nodes.bullet_list('') app.env.toc_num_entries[docname] = numentries[0] - def get_updated_docs(self, app, env): - # type: (Sphinx, BuildEnvironment) -> List[str] + def get_updated_docs(self, app: Sphinx, env: BuildEnvironment) -> List[str]: return self.assign_section_numbers(env) + self.assign_figure_numbers(env) - def assign_section_numbers(self, env): - # type: (BuildEnvironment) -> List[str] + def assign_section_numbers(self, env: BuildEnvironment) -> List[str]: """Assign a section number to each heading under a numbered toctree.""" # a list of all docnames whose section numbers changed rewrite_needed = [] @@ -149,8 +142,7 @@ class TocTreeCollector(EnvironmentCollector): old_secnumbers = env.toc_secnumbers env.toc_secnumbers = {} - def _walk_toc(node, secnums, depth, titlenode=None): - # type: (nodes.Element, Dict, int, nodes.title) -> None + def _walk_toc(node: Element, secnums: Dict, depth: int, titlenode: nodes.title = None) -> None: # NOQA # titlenode is the title of the document, it will get assigned a # secnumber too, so that it shows up in next/prev/parent rellinks for subnode in node.children: @@ -184,8 +176,7 @@ class TocTreeCollector(EnvironmentCollector): elif isinstance(subnode, addnodes.toctree): _walk_toctree(subnode, depth) - def _walk_toctree(toctreenode, depth): - # type: (addnodes.toctree, int) -> None + def _walk_toctree(toctreenode: addnodes.toctree, depth: int) -> None: if depth == 0: return for (title, ref) in toctreenode['entries']: @@ -216,8 +207,7 @@ class TocTreeCollector(EnvironmentCollector): return rewrite_needed - def assign_figure_numbers(self, env): - # type: (BuildEnvironment) -> List[str] + def assign_figure_numbers(self, env: BuildEnvironment) -> List[str]: """Assign a figure number to each figure under a numbered toctree.""" rewrite_needed = [] @@ -227,8 +217,7 @@ class TocTreeCollector(EnvironmentCollector): env.toc_fignumbers = {} fignum_counter = {} # type: Dict[str, Dict[Tuple[int, ...], int]] - def get_figtype(node): - # type: (nodes.Node) -> str + def get_figtype(node: Node) -> str: for domain in env.domains.values(): figtype = domain.get_enumerable_node_type(node) if figtype: @@ -236,8 +225,7 @@ class TocTreeCollector(EnvironmentCollector): return None - def get_section_number(docname, section): - # type: (str, nodes.section) -> Tuple[int, ...] + def get_section_number(docname: str, section: nodes.section) -> Tuple[int, ...]: anchorname = '#' + section['ids'][0] secnumbers = env.toc_secnumbers.get(docname, {}) if anchorname in secnumbers: @@ -247,24 +235,22 @@ class TocTreeCollector(EnvironmentCollector): return secnum or tuple() - def get_next_fignumber(figtype, secnum): - # type: (str, Tuple[int, ...]) -> Tuple[int, ...] + def get_next_fignumber(figtype: str, secnum: Tuple[int, ...]) -> Tuple[int, ...]: counter = fignum_counter.setdefault(figtype, {}) secnum = secnum[:env.config.numfig_secnum_depth] counter[secnum] = counter.get(secnum, 0) + 1 return secnum + (counter[secnum],) - def register_fignumber(docname, secnum, figtype, fignode): - # type: (str, Tuple[int, ...], str, nodes.Element) -> None + def register_fignumber(docname: str, secnum: Tuple[int, ...], + figtype: str, fignode: Element) -> None: env.toc_fignumbers.setdefault(docname, {}) fignumbers = env.toc_fignumbers[docname].setdefault(figtype, {}) figure_id = fignode['ids'][0] fignumbers[figure_id] = get_next_fignumber(figtype, secnum) - def _walk_doctree(docname, doctree, secnum): - # type: (str, nodes.Element, Tuple[int, ...]) -> None + def _walk_doctree(docname: str, doctree: Element, secnum: Tuple[int, ...]) -> None: for subnode in doctree.children: if isinstance(subnode, nodes.section): next_secnum = get_section_number(docname, subnode) @@ -286,8 +272,7 @@ class TocTreeCollector(EnvironmentCollector): _walk_doctree(docname, subnode, secnum) - def _walk_doc(docname, secnum): - # type: (str, Tuple[int, ...]) -> None + def _walk_doc(docname: str, secnum: Tuple[int, ...]) -> None: if docname not in assigned: assigned.add(docname) doctree = env.get_doctree(docname) @@ -302,8 +287,7 @@ class TocTreeCollector(EnvironmentCollector): return rewrite_needed -def setup(app): - # type: (Sphinx) -> Dict +def setup(app: Sphinx) -> Dict[str, Any]: app.add_env_collector(TocTreeCollector) return { diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index d7dd6d95f..7bfb3ad3e 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -166,7 +166,7 @@ class DownloadFiles(dict): Hence don't hack this directly. """ - def add_file(self, docname: str, filename: str) -> None: + def add_file(self, docname: str, filename: str) -> str: if filename not in self: digest = md5(filename.encode()).hexdigest() dest = '%s/%s' % (digest, os.path.basename(filename))