diff --git a/CHANGES b/CHANGES index 2bf062e9b..ed2f3e0f9 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,10 @@ Incompatible changes Deprecated ---------- +* The ``info`` and ``warn`` arguments of + ``sphinx.ext.autosummary.generate.generate_autosummary_docs()`` +* ``sphinx.ext.autosummary.generate._simple_info()`` +* ``sphinx.ext.autosummary.generate._simple_warn()`` * ``sphinx.ext.todo.merge_info()`` * ``sphinx.ext.todo.process_todo_nodes()`` * ``sphinx.ext.todo.process_todos()`` @@ -21,10 +25,15 @@ Features added Bugs fixed ---------- +* py domain: duplicated warning does not point the location of source code +* #1125: html theme: scrollbar is hard to see on classic theme and macOS +* #5502: linkcheck: Consider HTTP 503 response as not an error +* #6439: Make generated download links reproducible + Testing -------- -Release 2.1.1 (in development) +Release 2.1.2 (in development) ============================== Dependencies @@ -45,6 +54,27 @@ Bugs fixed Testing -------- +Release 2.1.1 (released Jun 10, 2019) +===================================== + +Incompatible changes +-------------------- + +* #6447: autodoc: Stop to generate document for undocumented module variables + +Bugs fixed +---------- + +* #6442: LaTeX: admonitions of :rst:dir:`note` type can get separated from + immediately preceding section title by pagebreak +* #6448: autodoc: crashed when autodocumenting classes with ``__slots__ = None`` +* #6451: autodoc: generates docs for "optional import"ed modules as variables +* #6452: autosummary: crashed when generating document of properties +* #6455: napoleon: docstrings for properties are not processed +* #6436: napoleon: "Unknown target name" error if variable name ends with + underscore +* #6440: apidoc: missing blank lines between modules + Release 2.1.0 (released Jun 02, 2019) ===================================== diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 1807d3998..8c74b184a 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -250,7 +250,7 @@ the source and the compiled catalogs. When a new locale is submitted, add a new directory with the ISO 639-1 language identifier and put ``sphinx.po`` in there. Don't forget to update the possible -values for :confval:`language` in ``doc/config.rst``. +values for :confval:`language` in ``doc/usage/configuration.rst``. The Sphinx core messages can also be translated on `Transifex `_. There exists a client tool named ``tx`` in the diff --git a/doc/extdev/deprecated.rst b/doc/extdev/deprecated.rst index f67c94592..f83235b92 100644 --- a/doc/extdev/deprecated.rst +++ b/doc/extdev/deprecated.rst @@ -26,6 +26,22 @@ The following is a list of deprecated interfaces. - (will be) Removed - Alternatives + * - The ``info`` and ``warn`` arguments of + ``sphinx.ext.autosummary.generate.generate_autosummary_docs()`` + - 2.2 + - 4.0 + - ``logging.info()`` and ``logging.warning()`` + + * - ``sphinx.ext.autosummary.generate._simple_info()`` + - 2.2 + - 4.0 + - ``logging.info()`` + + * - ``sphinx.ext.autosummary.generate._simple_warn()`` + - 2.2 + - 4.0 + - ``logging.warning()`` + * - ``sphinx.ext.todo.merge_info()`` - 2.2 - 4.0 diff --git a/setup.cfg b/setup.cfg index c91a31879..1f5bbd1cd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,9 +5,6 @@ license_file = LICENSE tag_build = .dev tag_date = true -[bdist_wheel] -universal = 1 - [aliases] release = egg_info -Db '' upload = upload --sign --identity=36580288 diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 8eaa0e215..546b9b0a8 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -11,22 +11,27 @@ import pickle import time from os import path +from typing import Any, Dict, Iterable, List, Sequence, Set, Tuple, Type, Union from docutils import nodes +from docutils.nodes import Node -from sphinx.environment import CONFIG_OK, CONFIG_CHANGED_REASON +from sphinx.config import Config +from sphinx.environment import BuildEnvironment, CONFIG_OK, CONFIG_CHANGED_REASON from sphinx.environment.adapters.asset import ImageAdapter from sphinx.errors import SphinxError +from sphinx.events import EventManager from sphinx.io import read_doc from sphinx.locale import __ from sphinx.util import import_object, logging, rst, progress_message, status_iterator from sphinx.util.build_phase import BuildPhase from sphinx.util.console import bold # type: ignore from sphinx.util.docutils import sphinx_domains -from sphinx.util.i18n import CatalogRepository, docname_to_domain +from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \ parallel_available +from sphinx.util.tags import Tags # side effect: registers roles and directives from sphinx import roles # noqa @@ -39,13 +44,7 @@ except ImportError: if False: # For type annotation - from typing import Any, Dict, Iterable, List, Sequence, Set, Tuple, Type, Union # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.config import Config # NOQA - from sphinx.environment import BuildEnvironment # NOQA - from sphinx.events import EventManager # NOQA - from sphinx.util.i18n import CatalogInfo # NOQA - from sphinx.util.tags import Tags # NOQA + from sphinx.application import Sphinx logger = logging.getLogger(__name__) @@ -84,8 +83,7 @@ class Builder: #: The builder supports data URIs or not. supported_data_uri_images = False - def __init__(self, app): - # type: (Sphinx) -> None + def __init__(self, app: "Sphinx") -> None: self.srcdir = app.srcdir self.confdir = app.confdir self.outdir = app.outdir @@ -113,20 +111,17 @@ class Builder: self.parallel_ok = False self.finish_tasks = None # type: Any - def set_environment(self, env): - # type: (BuildEnvironment) -> None + def set_environment(self, env: BuildEnvironment) -> None: """Store BuildEnvironment object.""" self.env = env self.env.set_versioning_method(self.versioning_method, self.versioning_compare) - def get_translator_class(self, *args): - # type: (Any) -> Type[nodes.NodeVisitor] + def get_translator_class(self, *args) -> Type[nodes.NodeVisitor]: """Return a class of translator.""" return self.app.registry.get_translator_class(self) - def create_translator(self, *args): - # type: (Any) -> nodes.NodeVisitor + def create_translator(self, *args) -> nodes.NodeVisitor: """Return an instance of translator. This method returns an instance of ``default_translator_class`` by default. @@ -135,15 +130,13 @@ class Builder: return self.app.registry.create_translator(self, *args) # helper methods - def init(self): - # type: () -> None + def init(self) -> None: """Load necessary templates and perform initialization. The default implementation does nothing. """ pass - def create_template_bridge(self): - # type: () -> None + def create_template_bridge(self) -> None: """Return the template bridge configured.""" if self.config.template_bridge: self.templates = import_object(self.config.template_bridge, @@ -152,8 +145,7 @@ class Builder: from sphinx.jinja2glue import BuiltinTemplateLoader self.templates = BuiltinTemplateLoader() - def get_target_uri(self, docname, typ=None): - # type: (str, str) -> str + def get_target_uri(self, docname: str, typ: str = None) -> str: """Return the target URI for a document name. *typ* can be used to qualify the link characteristic for individual @@ -161,8 +153,7 @@ class Builder: """ raise NotImplementedError - def get_relative_uri(self, from_, to, typ=None): - # type: (str, str, str) -> str + def get_relative_uri(self, from_: str, to: str, typ: str = None) -> str: """Return a relative URI between two source filenames. May raise environment.NoUri if there's no way to return a sensible URI. @@ -170,8 +161,7 @@ class Builder: return relative_uri(self.get_target_uri(from_), self.get_target_uri(to, typ)) - def get_outdated_docs(self): - # type: () -> Union[str, Iterable[str]] + def get_outdated_docs(self) -> Union[str, Iterable[str]]: """Return an iterable of output files that are outdated, or a string describing what an update build will build. @@ -181,13 +171,11 @@ class Builder: """ raise NotImplementedError - def get_asset_paths(self): - # type: () -> List[str] + def get_asset_paths(self) -> List[str]: """Return list of paths for assets (ex. templates, CSS, etc.).""" return [] - def post_process_images(self, doctree): - # type: (nodes.Node) -> None + def post_process_images(self, doctree: Node) -> None: """Pick the best candidate for all image URIs.""" images = ImageAdapter(self.env) for node in doctree.traverse(nodes.image): @@ -220,13 +208,11 @@ class Builder: # compile po methods - def compile_catalogs(self, catalogs, message): - # type: (Set[CatalogInfo], str) -> None + def compile_catalogs(self, catalogs: Set[CatalogInfo], message: str) -> None: if not self.config.gettext_auto_build: return - def cat2relpath(cat): - # type: (CatalogInfo) -> str + def cat2relpath(cat: CatalogInfo) -> str: return relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP) logger.info(bold(__('building [mo]: ')) + message) @@ -235,17 +221,14 @@ class Builder: stringify_func=cat2relpath): catalog.write_mo(self.config.language) - def compile_all_catalogs(self): - # type: () -> None + def compile_all_catalogs(self) -> None: repo = CatalogRepository(self.srcdir, self.config.locale_dirs, self.config.language, self.config.source_encoding) message = __('all of %d po files') % len(list(repo.catalogs)) self.compile_catalogs(set(repo.catalogs), message) - def compile_specific_catalogs(self, specified_files): - # type: (List[str]) -> None - def to_domain(fpath): - # type: (str) -> str + def compile_specific_catalogs(self, specified_files: List[str]) -> None: + def to_domain(fpath: str) -> str: docname = self.env.path2doc(path.abspath(fpath)) if docname: return docname_to_domain(docname, self.config.gettext_compact) @@ -262,8 +245,7 @@ class Builder: message = __('targets for %d po files that are specified') % len(catalogs) self.compile_catalogs(catalogs, message) - def compile_update_catalogs(self): - # type: () -> None + def compile_update_catalogs(self) -> None: repo = CatalogRepository(self.srcdir, self.config.locale_dirs, self.config.language, self.config.source_encoding) catalogs = {c for c in repo.catalogs if c.is_outdated()} @@ -272,13 +254,11 @@ class Builder: # build methods - def build_all(self): - # type: () -> None + def build_all(self) -> None: """Build all source files.""" self.build(None, summary=__('all source files'), method='all') - def build_specific(self, filenames): - # type: (List[str]) -> None + def build_specific(self, filenames: List[str]) -> None: """Only rebuild as much as needed for changes in the *filenames*.""" # bring the filenames to the canonical format, that is, # relative to the source directory and without source_suffix. @@ -306,8 +286,7 @@ class Builder: self.build(to_write, method='specific', summary=__('%d source files given on command line') % len(to_write)) - def build_update(self): - # type: () -> None + def build_update(self) -> None: """Only rebuild what was changed or added since last build.""" to_build = self.get_outdated_docs() if isinstance(to_build, str): @@ -318,8 +297,7 @@ class Builder: summary=__('targets for %d source files that are out of date') % len(to_build)) - def build(self, docnames, summary=None, method='update'): - # type: (Iterable[str], str, str) -> None + def build(self, docnames: Iterable[str], summary: str = None, method: str = 'update') -> None: # NOQA """Main build method. First updates the environment, and then calls :meth:`write`. @@ -387,8 +365,7 @@ class Builder: # wait for all tasks self.finish_tasks.join() - def read(self): - # type: () -> List[str] + def read(self) -> List[str]: """(Re-)read all files new or changed since last update. Store all environment docnames in the canonical format (ie using SEP as @@ -450,8 +427,7 @@ class Builder: return sorted(docnames) - def _read_serial(self, docnames): - # type: (List[str]) -> None + def _read_serial(self, docnames: List[str]) -> None: for docname in status_iterator(docnames, __('reading sources... '), "purple", len(docnames), self.app.verbosity): # remove all inventory entries for that file @@ -459,23 +435,20 @@ class Builder: self.env.clear_doc(docname) self.read_doc(docname) - def _read_parallel(self, docnames, nproc): - # type: (List[str], int) -> None + def _read_parallel(self, docnames: List[str], nproc: int) -> None: # clear all outdated docs at once for docname in docnames: self.events.emit('env-purge-doc', self.env, docname) self.env.clear_doc(docname) - def read_process(docs): - # type: (List[str]) -> bytes + def read_process(docs: List[str]) -> bytes: self.env.app = self.app for docname in docs: self.read_doc(docname) # allow pickling self to send it back return pickle.dumps(self.env, pickle.HIGHEST_PROTOCOL) - def merge(docs, otherenv): - # type: (List[str], bytes) -> None + def merge(docs: List[str], otherenv: bytes) -> None: env = pickle.loads(otherenv) self.env.merge_info_from(docs, env, self.app) @@ -490,8 +463,7 @@ class Builder: logger.info(bold(__('waiting for workers...'))) tasks.join() - def read_doc(self, docname): - # type: (str) -> None + def read_doc(self, docname: str) -> None: """Parse a file and add/update inventory entries for the doctree.""" self.env.prepare_settings(docname) @@ -516,8 +488,7 @@ class Builder: self.write_doctree(docname, doctree) - def write_doctree(self, docname, doctree): - # type: (str, nodes.document) -> None + def write_doctree(self, docname: str, doctree: nodes.document) -> None: """Write the doctree to a file.""" # make it picklable doctree.reporter = None @@ -531,8 +502,7 @@ class Builder: with open(doctree_filename, 'wb') as f: pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL) - 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: # NOQA if build_docnames is None or build_docnames == ['__all__']: # build_all build_docnames = self.env.found_docs @@ -561,8 +531,7 @@ class Builder: else: self._write_serial(sorted(docnames)) - def _write_serial(self, docnames): - # type: (Sequence[str]) -> None + def _write_serial(self, docnames: Sequence[str]) -> None: with logging.pending_warnings(): for docname in status_iterator(docnames, __('writing output... '), "darkgreen", len(docnames), self.app.verbosity): @@ -572,10 +541,8 @@ class Builder: self.write_doc_serialized(docname, doctree) self.write_doc(docname, doctree) - def _write_parallel(self, docnames, nproc): - # type: (Sequence[str], int) -> None - def write_process(docs): - # type: (List[Tuple[str, nodes.document]]) -> None + def _write_parallel(self, docnames: Sequence[str], nproc: int) -> None: + def write_process(docs: List[Tuple[str, nodes.document]]) -> None: self.app.phase = BuildPhase.WRITING for docname, doctree in docs: self.write_doc(docname, doctree) @@ -605,41 +572,35 @@ class Builder: logger.info(bold(__('waiting for workers...'))) tasks.join() - def prepare_writing(self, docnames): - # type: (Set[str]) -> None + def prepare_writing(self, docnames: Set[str]) -> None: """A place where you can add logic before :meth:`write_doc` is run""" raise NotImplementedError - def write_doc(self, docname, doctree): - # type: (str, nodes.document) -> None + def write_doc(self, docname: str, doctree: nodes.document) -> None: """Where you actually write something to the filesystem.""" raise NotImplementedError - def write_doc_serialized(self, docname, doctree): - # type: (str, nodes.document) -> None + def write_doc_serialized(self, docname: str, doctree: nodes.document) -> None: """Handle parts of write_doc that must be called in the main process if parallel build is active. """ pass - def finish(self): - # type: () -> None + def finish(self) -> None: """Finish the building process. The default implementation does nothing. """ pass - def cleanup(self): - # type: () -> None + def cleanup(self) -> None: """Cleanup any resources. The default implementation does nothing. """ pass - def get_builder_config(self, option, default): - # type: (str, str) -> Any + def get_builder_config(self, option: str, default: str) -> Any: """Return a builder specific option. This method allows customization of common builder settings by diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py index 140f2748d..75e79936b 100644 --- a/sphinx/builders/_epub_base.py +++ b/sphinx/builders/_epub_base.py @@ -14,9 +14,11 @@ import re import warnings from collections import namedtuple from os import path +from typing import Any, Dict, List, Set, Tuple from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile from docutils import nodes +from docutils.nodes import Element, Node from docutils.utils import smartquotes from sphinx import addnodes @@ -34,10 +36,6 @@ try: except ImportError: Image = None -if False: - # For type annotation - from typing import Any, Dict, List, Set, Tuple # NOQA - logger = logging.getLogger(__name__) @@ -93,8 +91,7 @@ Guide = namedtuple('Guide', ['type', 'title', 'uri']) NavPoint = namedtuple('NavPoint', ['navpoint', 'playorder', 'text', 'refuri', 'children']) -def sphinx_smarty_pants(t, language='en'): - # type: (str, str) -> str +def sphinx_smarty_pants(t: str, language: str = 'en') -> str: t = t.replace('"', '"') t = smartquotes.educateDashesOldSchool(t) t = smartquotes.educateQuotes(t, language) @@ -145,8 +142,7 @@ class EpubBuilder(StandaloneHTMLBuilder): template_dir = "" doctype = "" - def init(self): - # type: () -> None + def init(self) -> None: super().init() # the output files for epub must be .html only self.out_suffix = '.xhtml' @@ -157,17 +153,14 @@ class EpubBuilder(StandaloneHTMLBuilder): self.use_index = self.get_builder_config('use_index', 'epub') self.refnodes = [] # type: List[Dict[str, Any]] - def create_build_info(self): - # type: () -> BuildInfo + def create_build_info(self) -> BuildInfo: return BuildInfo(self.config, self.tags, ['html', 'epub']) - def get_theme_config(self): - # type: () -> Tuple[str, Dict] + def get_theme_config(self) -> Tuple[str, Dict]: return self.config.epub_theme, self.config.epub_theme_options # generic support functions - def make_id(self, name): - # type: (str) -> str + def make_id(self, name: str) -> str: # id_cache is intentionally mutable """Return a unique id for name.""" id = self.id_cache.get(name) @@ -176,8 +169,7 @@ class EpubBuilder(StandaloneHTMLBuilder): self.id_cache[name] = id return id - def esc(self, name): - # type: (str) -> str + def esc(self, name: str) -> str: """Replace all characters not allowed in text an attribute values.""" warnings.warn( '%s.esc() is deprecated. Use html.escape() instead.' % self.__class__.__name__, @@ -189,8 +181,7 @@ class EpubBuilder(StandaloneHTMLBuilder): name = name.replace('\'', ''') return name - def get_refnodes(self, doctree, result): - # type: (nodes.Node, List[Dict[str, Any]]) -> List[Dict[str, Any]] + def get_refnodes(self, doctree: Node, result: List[Dict[str, Any]]) -> List[Dict[str, Any]]: # NOQA """Collect section titles, their depth in the toc and the refuri.""" # XXX: is there a better way than checking the attribute # toctree-l[1-8] on the parent node? @@ -213,8 +204,7 @@ class EpubBuilder(StandaloneHTMLBuilder): result = self.get_refnodes(elem, result) return result - def check_refnodes(self, nodes): - # type: (List[Dict[str, Any]]) -> None + def check_refnodes(self, nodes: List[Dict[str, Any]]) -> None: appeared = set() # type: Set[str] for node in nodes: if node['refuri'] in appeared: @@ -222,8 +212,7 @@ class EpubBuilder(StandaloneHTMLBuilder): else: appeared.add(node['refuri']) - def get_toc(self): - # type: () -> None + def get_toc(self) -> None: """Get the total table of contents, containing the master_doc and pre and post files not managed by sphinx. """ @@ -238,8 +227,7 @@ class EpubBuilder(StandaloneHTMLBuilder): item['refuri'] = master_dir + item['refuri'] self.toc_add_files(self.refnodes) - def toc_add_files(self, refnodes): - # type: (List[Dict[str, Any]]) -> None + def toc_add_files(self, refnodes: List[Dict[str, Any]]) -> None: """Add the master_doc, pre and post files to a list of refnodes. """ refnodes.insert(0, { @@ -261,13 +249,11 @@ class EpubBuilder(StandaloneHTMLBuilder): 'text': ssp(html.escape(text)) }) - def fix_fragment(self, prefix, fragment): - # type: (str, str) -> str + def fix_fragment(self, prefix: str, fragment: str) -> str: """Return a href/id attribute with colons replaced by hyphens.""" return prefix + fragment.replace(':', '-') - def fix_ids(self, tree): - # type: (nodes.document) -> None + def fix_ids(self, tree: nodes.document) -> None: """Replace colons with hyphens in href and id attributes. Some readers crash because they interpret the part as a @@ -286,7 +272,7 @@ class EpubBuilder(StandaloneHTMLBuilder): if ':' in node_id: target['ids'][i] = self.fix_fragment('', node_id) - next_node = target.next_node(siblings=True) # type: nodes.Node + next_node = target.next_node(siblings=True) # type: Node if isinstance(next_node, nodes.Element): for i, node_id in enumerate(next_node['ids']): if ':' in node_id: @@ -299,20 +285,17 @@ class EpubBuilder(StandaloneHTMLBuilder): newids.append(self.fix_fragment('', id)) desc_signature.attributes['ids'] = newids - def add_visible_links(self, tree, show_urls='inline'): - # type: (nodes.document, str) -> None + def add_visible_links(self, tree: nodes.document, show_urls: str = 'inline') -> None: """Add visible link targets for external links""" - def make_footnote_ref(doc, label): - # type: (nodes.document, str) -> nodes.footnote_reference + def make_footnote_ref(doc: nodes.document, label: str) -> nodes.footnote_reference: """Create a footnote_reference node with children""" footnote_ref = nodes.footnote_reference('[#]_') footnote_ref.append(nodes.Text(label)) doc.note_autofootnote_ref(footnote_ref) return footnote_ref - def make_footnote(doc, label, uri): - # type: (nodes.document, str, str) -> nodes.footnote + def make_footnote(doc: nodes.document, label: str, uri: str) -> nodes.footnote: """Create a footnote node with children""" footnote = nodes.footnote(uri) para = nodes.paragraph() @@ -322,8 +305,7 @@ class EpubBuilder(StandaloneHTMLBuilder): doc.note_autofootnote(footnote) return footnote - def footnote_spot(tree): - # type: (nodes.document) -> Tuple[nodes.Element, int] + def footnote_spot(tree: nodes.document) -> Tuple[Element, int]: """Find or create a spot to place footnotes. The function returns the tuple (parent, index).""" @@ -371,8 +353,7 @@ class EpubBuilder(StandaloneHTMLBuilder): footnote.add_backref(footnote_ref['ids'][0]) fn_idx += 1 - def write_doc(self, docname, doctree): - # type: (str, nodes.document) -> None + def write_doc(self, docname: str, doctree: nodes.document) -> None: """Write one document file. This method is overwritten in order to fix fragment identifiers @@ -382,8 +363,7 @@ class EpubBuilder(StandaloneHTMLBuilder): self.add_visible_links(doctree, self.config.epub_show_urls) super().write_doc(docname, doctree) - def fix_genindex(self, tree): - # type: (List[Tuple[str, List[Tuple[str, Any]]]]) -> None + def fix_genindex(self, tree: List[Tuple[str, List[Tuple[str, Any]]]]) -> None: """Fix href attributes for genindex pages.""" # XXX: modifies tree inline # Logic modeled from themes/basic/genindex.html @@ -401,14 +381,12 @@ class EpubBuilder(StandaloneHTMLBuilder): subentrylinks[i] = (ismain, self.fix_fragment(m.group(1), m.group(2))) - def is_vector_graphics(self, filename): - # type: (str) -> bool + def is_vector_graphics(self, filename: str) -> bool: """Does the filename extension indicate a vector graphic format?""" ext = path.splitext(filename)[-1] return ext in VECTOR_GRAPHICS_EXTENSIONS - def copy_image_files_pil(self): - # type: () -> None + def copy_image_files_pil(self) -> None: """Copy images using Pillow, the Python Imaging Libary. The method tries to read and write the files with Pillow, converting the format and resizing the image if necessary/possible. @@ -447,8 +425,7 @@ class EpubBuilder(StandaloneHTMLBuilder): logger.warning(__('cannot write image file %r: %s'), path.join(self.srcdir, src), err) - def copy_image_files(self): - # type: () -> None + def copy_image_files(self) -> None: """Copy image files to destination directory. This overwritten method can use Pillow to convert image files. """ @@ -462,13 +439,11 @@ class EpubBuilder(StandaloneHTMLBuilder): else: super().copy_image_files() - def copy_download_files(self): - # type: () -> None + def copy_download_files(self) -> None: pass - def handle_page(self, pagename, addctx, templatename='page.html', - outfilename=None, event_arg=None): - # type: (str, Dict, str, str, Any) -> None + def handle_page(self, pagename: str, addctx: Dict, templatename: str = 'page.html', + outfilename: str = None, event_arg: Any = None) -> None: """Create a rendered page. This method is overwritten for genindex pages in order to fix href link @@ -481,8 +456,7 @@ class EpubBuilder(StandaloneHTMLBuilder): addctx['doctype'] = self.doctype super().handle_page(pagename, addctx, templatename, outfilename, event_arg) - def build_mimetype(self, outdir=None, outname='mimetype'): - # type: (str, str) -> None + def build_mimetype(self, outdir: str = None, outname: str = 'mimetype') -> None: """Write the metainfo file mimetype.""" if outdir: warnings.warn('The arguments of EpubBuilder.build_mimetype() is deprecated.', @@ -494,8 +468,7 @@ class EpubBuilder(StandaloneHTMLBuilder): copy_asset_file(path.join(self.template_dir, 'mimetype'), path.join(outdir, outname)) - def build_container(self, outdir=None, outname='META-INF/container.xml'): - # type: (str, str) -> None + def build_container(self, outdir: str = None, outname: str = 'META-INF/container.xml') -> None: # NOQA """Write the metainfo file META-INF/container.xml.""" if outdir: warnings.warn('The arguments of EpubBuilder.build_container() is deprecated.', @@ -508,8 +481,7 @@ class EpubBuilder(StandaloneHTMLBuilder): ensuredir(path.dirname(filename)) copy_asset_file(path.join(self.template_dir, 'container.xml'), filename) - def content_metadata(self): - # type: () -> Dict[str, Any] + def content_metadata(self) -> Dict[str, Any]: """Create a dictionary with all metadata for the content.opf file properly escaped. """ @@ -528,8 +500,7 @@ class EpubBuilder(StandaloneHTMLBuilder): metadata['guides'] = [] return metadata - def build_content(self, outdir=None, outname='content.opf'): - # type: (str, str) -> None + def build_content(self, outdir: str = None, outname: str = 'content.opf') -> None: """Write the metainfo file content.opf It contains bibliographic data, a file list and the spine (the reading order). """ @@ -648,8 +619,7 @@ class EpubBuilder(StandaloneHTMLBuilder): path.join(outdir, outname), metadata) - def new_navpoint(self, node, level, incr=True): - # type: (Dict[str, Any], int, bool) -> NavPoint + def new_navpoint(self, node: Dict[str, Any], level: int, incr: bool = True) -> NavPoint: """Create a new entry in the toc from the node at given level.""" # XXX Modifies the node if incr: @@ -658,8 +628,7 @@ class EpubBuilder(StandaloneHTMLBuilder): return NavPoint('navPoint%d' % self.tocid, self.playorder, node['text'], node['refuri'], []) - def build_navpoints(self, nodes): - # type: (List[Dict[str, Any]]) -> List[NavPoint] + def build_navpoints(self, nodes: List[Dict[str, Any]]) -> List[NavPoint]: """Create the toc navigation structure. Subelements of a node are nested inside the navpoint. For nested nodes @@ -703,8 +672,7 @@ class EpubBuilder(StandaloneHTMLBuilder): return navstack[0].children - def toc_metadata(self, level, navpoints): - # type: (int, List[NavPoint]) -> Dict[str, Any] + def toc_metadata(self, level: int, navpoints: List[NavPoint]) -> Dict[str, Any]: """Create a dictionary with all metadata for the toc.ncx file properly escaped. """ @@ -715,8 +683,7 @@ class EpubBuilder(StandaloneHTMLBuilder): metadata['navpoints'] = navpoints return metadata - def build_toc(self, outdir=None, outname='toc.ncx'): - # type: (str, str) -> None + def build_toc(self, outdir: str = None, outname: str = 'toc.ncx') -> None: """Write the metainfo file toc.ncx.""" if outdir: warnings.warn('The arguments of EpubBuilder.build_toc() is deprecated.', @@ -743,8 +710,7 @@ class EpubBuilder(StandaloneHTMLBuilder): path.join(outdir, outname), self.toc_metadata(level, navpoints)) - def build_epub(self, outdir=None, outname=None): - # type: (str, str) -> None + def build_epub(self, outdir: str = None, outname: str = None) -> None: """Write the epub file. It is a zip file with the mimetype file stored uncompressed as the first diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py index 0ee50ff56..d7dd336ca 100644 --- a/sphinx/builders/applehelp.py +++ b/sphinx/builders/applehelp.py @@ -9,6 +9,7 @@ """ import warnings +from typing import Any, Dict from sphinxcontrib.applehelp import ( AppleHelpCodeSigningFailed, @@ -16,13 +17,9 @@ from sphinxcontrib.applehelp import ( AppleHelpBuilder, ) +from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias -if False: - # For type annotation - from typing import Any, Dict # NOQA - from sphinx.application import Sphinx # NOQA - deprecated_alias('sphinx.builders.applehelp', { @@ -33,8 +30,7 @@ deprecated_alias('sphinx.builders.applehelp', RemovedInSphinx40Warning) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: warnings.warn('sphinx.builders.applehelp has been moved to sphinxcontrib-applehelp.', RemovedInSphinx40Warning) app.setup_extension('sphinxcontrib.applehelp') diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py index 3b169e493..a42215fad 100644 --- a/sphinx/builders/changes.py +++ b/sphinx/builders/changes.py @@ -10,9 +10,11 @@ import html from os import path +from typing import Any, Dict, List, Tuple from typing import cast from sphinx import package_dir +from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.domains.changeset import ChangeSetDomain from sphinx.locale import _, __ @@ -22,11 +24,6 @@ from sphinx.util.console import bold # type: ignore from sphinx.util.fileutil import copy_asset_file from sphinx.util.osutil import ensuredir, os_path -if False: - # For type annotation - from typing import Any, Dict, List, Tuple # NOQA - from sphinx.application import Sphinx # NOQA - logger = logging.getLogger(__name__) @@ -38,15 +35,13 @@ class ChangesBuilder(Builder): name = 'changes' epilog = __('The overview file is in %(outdir)s.') - def init(self): - # type: () -> None + def init(self) -> None: self.create_template_bridge() theme_factory = HTMLThemeFactory(self.app) self.theme = theme_factory.create('default') self.templates.init(self, self.theme) - def get_outdated_docs(self): - # type: () -> str + def get_outdated_docs(self) -> str: return self.outdir typemap = { @@ -55,8 +50,7 @@ class ChangesBuilder(Builder): 'deprecated': 'deprecated', } - def write(self, *ignored): - # type: (Any) -> None + def write(self, *ignored) -> None: version = self.config.version domain = cast(ChangeSetDomain, self.env.get_domain('changeset')) libchanges = {} # type: Dict[str, List[Tuple[str, str, int]]] @@ -121,8 +115,7 @@ class ChangesBuilder(Builder): '.. versionchanged:: %s' % version, '.. deprecated:: %s' % version] - def hl(no, line): - # type: (int, str) -> str + def hl(no: int, line: str) -> str: line = ' ' % no + html.escape(line) for x in hltext: if x in line: @@ -155,21 +148,18 @@ class ChangesBuilder(Builder): copy_asset_file(path.join(package_dir, 'themes', 'basic', 'static', 'basic.css'), self.outdir) - def hl(self, text, version): - # type: (str, str) -> str + def hl(self, text: str, version: str) -> str: text = html.escape(text) for directive in ['versionchanged', 'versionadded', 'deprecated']: text = text.replace('.. %s:: %s' % (directive, version), '.. %s:: %s' % (directive, version)) return text - def finish(self): - # type: () -> None + def finish(self) -> None: pass -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(ChangesBuilder) return { diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py index 2306ddee2..17e861777 100644 --- a/sphinx/builders/devhelp.py +++ b/sphinx/builders/devhelp.py @@ -11,18 +11,14 @@ """ import warnings +from typing import Any, Dict from sphinxcontrib.devhelp import DevhelpBuilder +from sphinx.application import Sphinx from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias -if False: - # For type annotation - from typing import Any, Dict # NOQA - from sphinx.application import Sphinx # NOQA - - deprecated_alias('sphinx.builders.devhelp', { 'DevhelpBuilder': DevhelpBuilder, @@ -30,8 +26,7 @@ deprecated_alias('sphinx.builders.devhelp', RemovedInSphinx40Warning) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: warnings.warn('sphinx.builders.devhelp has been moved to sphinxcontrib-devhelp.', RemovedInSphinx40Warning) app.setup_extension('sphinxcontrib.devhelp') diff --git a/sphinx/builders/dirhtml.py b/sphinx/builders/dirhtml.py index d5d61c273..40ec7b11f 100644 --- a/sphinx/builders/dirhtml.py +++ b/sphinx/builders/dirhtml.py @@ -9,17 +9,14 @@ """ from os import path +from typing import Any, Dict, Set +from sphinx.application import Sphinx from sphinx.builders.html import StandaloneHTMLBuilder from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.util import logging from sphinx.util.osutil import SEP, os_path -if False: - # For type annotation - from typing import Any, Dict, Set # NOQA - from sphinx.application import Sphinx # NOQA - logger = logging.getLogger(__name__) @@ -31,16 +28,14 @@ class DirectoryHTMLBuilder(StandaloneHTMLBuilder): """ name = 'dirhtml' - def get_target_uri(self, docname, typ=None): - # type: (str, str) -> str + def get_target_uri(self, docname: str, typ: str = None) -> str: if docname == 'index': return '' if docname.endswith(SEP + 'index'): return docname[:-5] # up to sep return docname + SEP - def get_outfilename(self, pagename): - # type: (str) -> str + def get_outfilename(self, pagename: str) -> str: if pagename == 'index' or pagename.endswith(SEP + 'index'): outfilename = path.join(self.outdir, os_path(pagename) + self.out_suffix) @@ -50,8 +45,7 @@ class DirectoryHTMLBuilder(StandaloneHTMLBuilder): return outfilename - def prepare_writing(self, docnames): - # type: (Set[str]) -> None + def prepare_writing(self, docnames: Set[str]) -> None: super().prepare_writing(docnames) self.globalcontext['no_search_suffix'] = True @@ -64,8 +58,7 @@ deprecated_alias('sphinx.builders.html', RemovedInSphinx40Warning) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.setup_extension('sphinx.builders.html') app.add_builder(DirectoryHTMLBuilder) diff --git a/sphinx/builders/dummy.py b/sphinx/builders/dummy.py index d5ae94a82..33d2506ac 100644 --- a/sphinx/builders/dummy.py +++ b/sphinx/builders/dummy.py @@ -8,16 +8,14 @@ :license: BSD, see LICENSE for details. """ +from typing import Any, Dict, Set +from docutils.nodes import Node + +from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.locale import __ -if False: - # For type annotation - from typing import Any, Dict, Set # NOQA - from docutils import nodes # NOQA - from sphinx.application import Sphinx # NOQA - class DummyBuilder(Builder): name = 'dummy' @@ -25,33 +23,26 @@ class DummyBuilder(Builder): allow_parallel = True - def init(self): - # type: () -> None + def init(self) -> None: pass - def get_outdated_docs(self): - # type: () -> Set[str] + def get_outdated_docs(self) -> Set[str]: return self.env.found_docs - 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 prepare_writing(self, docnames): - # type: (Set[str]) -> None + def prepare_writing(self, docnames: Set[str]) -> None: pass - def write_doc(self, docname, doctree): - # type: (str, nodes.Node) -> None + def write_doc(self, docname: str, doctree: Node) -> None: pass - def finish(self): - # type: () -> None + def finish(self) -> None: pass -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(DummyBuilder) return { diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py index 9b3f58d7a..5d7121fe6 100644 --- a/sphinx/builders/epub3.py +++ b/sphinx/builders/epub3.py @@ -13,10 +13,12 @@ import html import warnings from collections import namedtuple from os import path +from typing import Any, Dict, List, Set, Tuple from sphinx import package_dir +from sphinx.application import Sphinx from sphinx.builders import _epub_base -from sphinx.config import ENUM +from sphinx.config import Config, ENUM from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.locale import __ from sphinx.util import logging, xmlname_checker @@ -24,12 +26,6 @@ from sphinx.util.fileutil import copy_asset_file from sphinx.util.i18n import format_date from sphinx.util.osutil import make_filename -if False: - # For type annotation - from typing import Any, Dict, List, Set, Tuple # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.config import Config # NOQA - logger = logging.getLogger(__name__) @@ -75,8 +71,7 @@ class Epub3Builder(_epub_base.EpubBuilder): use_meta_charset = True # Finish by building the epub file - def handle_finish(self): - # type: () -> None + def handle_finish(self) -> None: """Create the metainfo files and finally the epub.""" self.get_toc() self.build_mimetype() @@ -86,13 +81,11 @@ class Epub3Builder(_epub_base.EpubBuilder): self.build_toc() self.build_epub() - def validate_config_value(self): - # type: () -> None + def validate_config_value(self) -> None: warnings.warn('Epub3Builder.validate_config_value() is deprecated.', RemovedInSphinx40Warning, stacklevel=2) - def content_metadata(self): - # type: () -> Dict + def content_metadata(self) -> Dict: """Create a dictionary with all metadata for the content.opf file properly escaped. """ @@ -108,8 +101,7 @@ class Epub3Builder(_epub_base.EpubBuilder): metadata['epub_version'] = self.config.epub_version return metadata - def prepare_writing(self, docnames): - # type: (Set[str]) -> None + def prepare_writing(self, docnames: Set[str]) -> None: super().prepare_writing(docnames) writing_mode = self.config.epub_writing_mode @@ -118,8 +110,7 @@ class Epub3Builder(_epub_base.EpubBuilder): self.globalcontext['use_meta_charset'] = self.use_meta_charset self.globalcontext['skip_ua_compatible'] = True - def build_navlist(self, navnodes): - # type: (List[Dict[str, Any]]) -> List[NavPoint] + def build_navlist(self, navnodes: List[Dict[str, Any]]) -> List[NavPoint]: """Create the toc navigation structure. This method is almost same as build_navpoints method in epub.py. @@ -161,8 +152,7 @@ class Epub3Builder(_epub_base.EpubBuilder): return navstack[0].children - def navigation_doc_metadata(self, navlist): - # type: (List[NavPoint]) -> Dict + def navigation_doc_metadata(self, navlist: List[NavPoint]) -> Dict: """Create a dictionary with all metadata for the nav.xhtml file properly escaped. """ @@ -172,8 +162,7 @@ class Epub3Builder(_epub_base.EpubBuilder): metadata['navlist'] = navlist return metadata - def build_navigation_doc(self, outdir=None, outname='nav.xhtml'): - # type: (str, str) -> None + def build_navigation_doc(self, outdir: str = None, outname: str = 'nav.xhtml') -> None: """Write the metainfo file nav.xhtml.""" if outdir: warnings.warn('The arguments of Epub3Builder.build_navigation_doc() ' @@ -202,8 +191,7 @@ class Epub3Builder(_epub_base.EpubBuilder): self.files.append(outname) -def validate_config_values(app): - # type: (Sphinx) -> None +def validate_config_values(app: Sphinx) -> None: if app.builder.name != 'epub': return @@ -242,8 +230,7 @@ def validate_config_values(app): logger.warning(__('conf value "version" should not be empty for EPUB3')) -def convert_epub_css_files(app, config): - # type: (Sphinx, Config) -> None +def convert_epub_css_files(app: Sphinx, config: Config) -> None: """This converts string styled epub_css_files to tuple styled one.""" epub_css_files = [] # type: List[Tuple[str, Dict]] for entry in config.epub_css_files: @@ -260,8 +247,7 @@ def convert_epub_css_files(app, config): config.epub_css_files = epub_css_files # type: ignore -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(Epub3Builder) # config values diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py index f26b831da..2beb4a5ce 100644 --- a/sphinx/builders/gettext.py +++ b/sphinx/builders/gettext.py @@ -14,27 +14,25 @@ from datetime import datetime, tzinfo, timedelta from io import StringIO from os import path, walk, getenv from time import time +from typing import Any, DefaultDict, Dict, Iterable, List, Set, Tuple, Union from uuid import uuid4 +from docutils import nodes +from docutils.nodes import Element + from sphinx import addnodes +from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.domains.python import pairindextypes from sphinx.errors import ThemeError from sphinx.locale import __ from sphinx.util import split_index_msg, logging, status_iterator from sphinx.util.console import bold # type: ignore -from sphinx.util.i18n import docname_to_domain +from sphinx.util.i18n import CatalogInfo, docname_to_domain from sphinx.util.nodes import extract_messages, traverse_translatable_index from sphinx.util.osutil import relpath, ensuredir, canon_path from sphinx.util.tags import Tags -if False: - # For type annotation - from typing import Any, DefaultDict, Dict, Iterable, List, Set, Tuple, Union # NOQA - from docutils import nodes # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.util.i18n import CatalogInfo # NOQA - logger = logging.getLogger(__name__) @@ -63,15 +61,13 @@ msgstr "" class Catalog: """Catalog of translatable messages.""" - def __init__(self): - # type: () -> None + def __init__(self) -> None: self.messages = [] # type: List[str] # retain insertion order, a la OrderedDict self.metadata = OrderedDict() # type: Dict[str, List[Tuple[str, int, str]]] # msgid -> file, line, uid - def add(self, msg, origin): - # type: (str, Union[nodes.Element, MsgOrigin]) -> None + def add(self, msg: str, origin: Union[Element, "MsgOrigin"]) -> None: if not hasattr(origin, 'uid'): # Nodes that are replicated like todo don't have a uid, # however i18n is also unnecessary. @@ -87,8 +83,7 @@ class MsgOrigin: Origin holder for Catalog message origin. """ - def __init__(self, source, line): - # type: (str, int) -> None + def __init__(self, source: str, line: int) -> None: self.source = source self.line = line self.uid = uuid4().hex @@ -100,8 +95,7 @@ class I18nTags(Tags): To translate all text inside of only nodes, this class always returns True value even if no tags are defined. """ - def eval_condition(self, condition): - # type: (Any) -> bool + def eval_condition(self, condition: Any) -> bool: return True @@ -115,32 +109,26 @@ class I18nBuilder(Builder): # be set by `gettext_uuid` use_message_catalog = False - def init(self): - # type: () -> None + def init(self) -> None: super().init() self.env.set_versioning_method(self.versioning_method, self.env.config.gettext_uuid) self.tags = I18nTags() self.catalogs = defaultdict(Catalog) # type: DefaultDict[str, Catalog] - 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 prepare_writing(self, docnames): - # type: (Set[str]) -> None + def prepare_writing(self, docnames: Set[str]) -> None: return - def compile_catalogs(self, catalogs, message): - # type: (Set[CatalogInfo], str) -> None + def compile_catalogs(self, catalogs: Set[CatalogInfo], message: str) -> None: return - def write_doc(self, docname, doctree): - # type: (str, nodes.document) -> None + def write_doc(self, docname: str, doctree: nodes.document) -> None: catalog = self.catalogs[docname_to_domain(docname, self.config.gettext_compact)] for toctree in self.env.tocs[docname].traverse(addnodes.toctree): @@ -176,26 +164,21 @@ if source_date_epoch is not None: class LocalTimeZone(tzinfo): - - def __init__(self, *args, **kw): - # type: (Any, Any) -> None + def __init__(self, *args, **kw) -> None: super().__init__(*args, **kw) # type: ignore self.tzdelta = tzdelta - def utcoffset(self, dt): - # type: (datetime) -> timedelta + def utcoffset(self, dt: datetime) -> timedelta: return self.tzdelta - def dst(self, dt): - # type: (datetime) -> timedelta + def dst(self, dt: datetime) -> timedelta: return timedelta(0) ltz = LocalTimeZone() -def should_write(filepath, new_content): - # type: (str, str) -> bool +def should_write(filepath: str, new_content: str): if not path.exists(filepath): return True try: @@ -220,14 +203,12 @@ class MessageCatalogBuilder(I18nBuilder): name = 'gettext' epilog = __('The message catalogs are in %(outdir)s.') - def init(self): - # type: () -> None + def init(self) -> None: super().init() self.create_template_bridge() self.templates.init(self) - def _collect_templates(self): - # type: () -> Set[str] + def _collect_templates(self) -> Set[str]: template_files = set() for template_path in self.config.templates_path: tmpl_abs_path = path.join(self.app.srcdir, template_path) @@ -238,8 +219,7 @@ class MessageCatalogBuilder(I18nBuilder): template_files.add(filename) return template_files - def _extract_from_template(self): - # type: () -> None + def _extract_from_template(self) -> None: files = list(self._collect_templates()) files.sort() logger.info(bold(__('building [%s]: ') % self.name), nonl=True) @@ -258,13 +238,11 @@ class MessageCatalogBuilder(I18nBuilder): except Exception as exc: raise ThemeError('%s: %r' % (template, exc)) - def build(self, docnames, summary=None, method='update'): - # type: (Iterable[str], str, str) -> None + def build(self, docnames: Iterable[str], summary: str = None, method: str = 'update') -> None: # NOQA self._extract_from_template() super().build(docnames, summary, method) - def finish(self): - # type: () -> None + def finish(self) -> None: super().finish() data = { 'version': self.config.version, @@ -310,8 +288,7 @@ class MessageCatalogBuilder(I18nBuilder): pofile.write(content) -def setup(app): - # type: (Sphinx) -> Dict[str, Any] +def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(MessageCatalogBuilder) app.add_config_value('gettext_compact', True, 'gettext') diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 504bbc598..1fd9e6cac 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -15,16 +15,21 @@ import sys import warnings from hashlib import md5 from os import path +from typing import Any, Dict, IO, Iterable, Iterator, List, Set, Type, Tuple from docutils import nodes from docutils.core import publish_parts from docutils.frontend import OptionParser from docutils.io import DocTreeInput, StringOutput +from docutils.nodes import Node from docutils.utils import relative_path from sphinx import package_dir, __display_version__ +from sphinx.application import Sphinx from sphinx.builders import Builder +from sphinx.config import Config from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning +from sphinx.domains import Domain, Index, IndexEntry from sphinx.environment.adapters.asset import ImageAdapter from sphinx.environment.adapters.indexentries import IndexEntries from sphinx.environment.adapters.toctree import TocTree @@ -41,16 +46,9 @@ from sphinx.util.i18n import format_date from sphinx.util.inventory import InventoryFile from sphinx.util.matching import patmatch, Matcher, DOTFILES from sphinx.util.osutil import os_path, relative_uri, ensuredir, movefile, copyfile +from sphinx.util.tags import Tags from sphinx.writers.html import HTMLWriter, HTMLTranslator -if False: - # For type annotation - from typing import Any, Dict, IO, Iterable, Iterator, List, Set, Type, Tuple # NOQA - from sphinx.application import Sphinx # NOQA - from sphinx.config import Config # NOQA - from sphinx.domains import Domain, Index, IndexEntry # NOQA - from sphinx.util.tags import Tags # NOQA - # HTML5 Writer is avialable or not if is_html5_writer_available(): from sphinx.writers.html5 import HTML5Translator @@ -65,8 +63,7 @@ logger = logging.getLogger(__name__) return_codes_re = re.compile('[\r\n]+') -def get_stable_hash(obj): - # type: (Any) -> str +def get_stable_hash(obj: Any) -> str: """ Return a stable hash for a Python data structure. We can't just use the md5 of str(obj) since for example dictionary items are enumerated @@ -89,8 +86,7 @@ class Stylesheet(str): attributes = None # type: Dict[str, str] filename = None # type: str - def __new__(cls, filename, *args, **attributes): - # type: (str, str, str) -> None + def __new__(cls, filename: str, *args: str, **attributes: str) -> None: self = str.__new__(cls, filename) # type: ignore self.filename = filename self.attributes = attributes @@ -105,23 +101,20 @@ class Stylesheet(str): class JSContainer(list): """The container for JavaScript scripts.""" - def insert(self, index, obj): - # type: (int, str) -> None + def insert(self, index: int, obj: str) -> None: warnings.warn('To modify script_files in the theme is deprecated. ' 'Please insert a