Migrate to py3 style type annotation: sphinx.environment

This commit is contained in:
Takeshi KOMIYA
2019-07-06 12:27:47 +09:00
parent 847a642b41
commit 39ec5e0deb

View File

@@ -15,14 +15,22 @@ from collections import defaultdict
from copy import copy
from io import BytesIO
from os import path
from typing import Any, Callable, Dict, Generator, IO, 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 (
RemovedInSphinx30Warning, RemovedInSphinx40Warning, deprecated_alias
)
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
@@ -32,14 +40,8 @@ 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__)
@@ -92,8 +94,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
@@ -191,19 +192,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'))
@@ -231,8 +229,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:
@@ -249,8 +246,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
@@ -259,8 +255,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
@@ -283,8 +278,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)
@@ -294,8 +288,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.
@@ -312,16 +306,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.
@@ -344,8 +336,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.
@@ -364,13 +355,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.
"""
@@ -398,8 +387,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
@@ -449,8 +437,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)
@@ -460,8 +447,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
@@ -472,13 +458,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.
@@ -488,8 +472,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.
@@ -498,8 +481,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.
@@ -508,15 +490,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.
@@ -528,8 +508,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:
@@ -538,9 +517,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.
"""
@@ -562,9 +541,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.
@@ -580,12 +559,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
@@ -602,12 +580,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
@@ -636,8 +612,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):
@@ -660,48 +635,41 @@ class BuildEnvironment:
# --------- METHODS FOR COMPATIBILITY --------------------------------------
def update(self, config, srcdir, doctreedir):
# type: (Config, str, str) -> List[str]
def update(self, config: Config, srcdir: str, doctreedir: str) -> List[str]:
warnings.warn('env.update() is deprecated. Please use builder.read() instead.',
RemovedInSphinx30Warning, stacklevel=2)
return self.app.builder.read()
def _read_serial(self, docnames, app):
# type: (List[str], Sphinx) -> None
def _read_serial(self, docnames: List[str], app: "Sphinx") -> None:
warnings.warn('env._read_serial() is deprecated. Please use builder.read() instead.',
RemovedInSphinx30Warning, stacklevel=2)
return self.app.builder._read_serial(docnames)
def _read_parallel(self, docnames, app, nproc):
# type: (List[str], Sphinx, int) -> None
def _read_parallel(self, docnames: List[str], app: "Sphinx", nproc: int) -> None:
warnings.warn('env._read_parallel() is deprecated. Please use builder.read() instead.',
RemovedInSphinx30Warning, stacklevel=2)
return self.app.builder._read_parallel(docnames, nproc)
def read_doc(self, docname, app=None):
# type: (str, Sphinx) -> None
def read_doc(self, docname: str, app: "Sphinx" = None) -> None:
warnings.warn('env.read_doc() is deprecated. Please use builder.read_doc() instead.',
RemovedInSphinx30Warning, stacklevel=2)
self.app.builder.read_doc(docname)
def write_doctree(self, docname, doctree):
# type: (str, nodes.document) -> None
def write_doctree(self, docname: str, doctree: nodes.document) -> None:
warnings.warn('env.write_doctree() is deprecated. '
'Please use builder.write_doctree() instead.',
RemovedInSphinx30Warning, stacklevel=2)
self.app.builder.write_doctree(docname, doctree)
@property
def _nitpick_ignore(self):
# type: () -> List[str]
def _nitpick_ignore(self) -> List[str]:
warnings.warn('env._nitpick_ignore is deprecated. '
'Please use config.nitpick_ignore instead.',
RemovedInSphinx30Warning, stacklevel=2)
return self.config.nitpick_ignore
@staticmethod
def load(f, app=None):
# type: (IO, Sphinx) -> BuildEnvironment
def load(f: IO, app: "Sphinx" = None) -> "BuildEnvironment":
warnings.warn('BuildEnvironment.load() is deprecated. '
'Please use pickle.load() instead.',
RemovedInSphinx30Warning, stacklevel=2)
@@ -717,8 +685,7 @@ class BuildEnvironment:
return env
@classmethod
def loads(cls, string, app=None):
# type: (bytes, Sphinx) -> BuildEnvironment
def loads(cls, string: bytes, app: "Sphinx" = None) -> "BuildEnvironment":
warnings.warn('BuildEnvironment.loads() is deprecated. '
'Please use pickle.loads() instead.',
RemovedInSphinx30Warning, stacklevel=2)
@@ -726,8 +693,7 @@ class BuildEnvironment:
return cls.load(io, app)
@classmethod
def frompickle(cls, filename, app):
# type: (str, Sphinx) -> BuildEnvironment
def frompickle(cls, filename: str, app: "Sphinx") -> "BuildEnvironment":
warnings.warn('BuildEnvironment.frompickle() is deprecated. '
'Please use pickle.load() instead.',
RemovedInSphinx30Warning, stacklevel=2)
@@ -735,16 +701,14 @@ class BuildEnvironment:
return cls.load(f, app)
@staticmethod
def dump(env, f):
# type: (BuildEnvironment, IO) -> None
def dump(env: "BuildEnvironment", f: IO) -> None:
warnings.warn('BuildEnvironment.dump() is deprecated. '
'Please use pickle.dump() instead.',
RemovedInSphinx30Warning, stacklevel=2)
pickle.dump(env, f, pickle.HIGHEST_PROTOCOL)
@classmethod
def dumps(cls, env):
# type: (BuildEnvironment) -> bytes
def dumps(cls, env: "BuildEnvironment") -> bytes:
warnings.warn('BuildEnvironment.dumps() is deprecated. '
'Please use pickle.dumps() instead.',
RemovedInSphinx30Warning, stacklevel=2)
@@ -752,8 +716,7 @@ class BuildEnvironment:
cls.dump(env, io)
return io.getvalue()
def topickle(self, filename):
# type: (str) -> None
def topickle(self, filename: str) -> None:
warnings.warn('env.topickle() is deprecated. '
'Please use pickle.dump() instead.',
RemovedInSphinx30Warning, stacklevel=2)
@@ -761,15 +724,14 @@ class BuildEnvironment:
self.dump(self, f)
@property
def versionchanges(self):
# type: () -> Dict[str, List[Tuple[str, str, int, str, str, str]]]
def versionchanges(self) -> Dict[str, List[Tuple[str, str, int, str, str, str]]]:
warnings.warn('env.versionchanges() is deprecated. '
'Please use ChangeSetDomain instead.',
RemovedInSphinx30Warning, stacklevel=2)
return self.domaindata['changeset']['changes']
def note_versionchange(self, type, version, node, lineno):
# type: (str, str, addnodes.versionmodified, int) -> None
def note_versionchange(self, type: str, version: str,
node: addnodes.versionmodified, lineno: int) -> None:
warnings.warn('env.note_versionchange() is deprecated. '
'Please use ChangeSetDomain.note_changeset() instead.',
RemovedInSphinx30Warning, stacklevel=2)