mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '2.0'
This commit is contained in:
commit
d717f5ae31
10
CHANGES
10
CHANGES
@ -68,7 +68,7 @@ Bugs fixed
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 2.3.1 (in development)
|
||||
Release 2.3.2 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
@ -89,6 +89,14 @@ Bugs fixed
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 2.3.1 (released Dec 22, 2019)
|
||||
=====================================
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #6936: sphinx-autogen: raises AttributeError
|
||||
|
||||
Release 2.3.0 (released Dec 15, 2019)
|
||||
=====================================
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict, List, Sequence
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
@ -16,8 +17,7 @@ from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, List, Sequence # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
class translatable(nodes.Node):
|
||||
@ -34,18 +34,15 @@ class translatable(nodes.Node):
|
||||
Because they are used at final step; extraction.
|
||||
"""
|
||||
|
||||
def preserve_original_messages(self):
|
||||
# type: () -> None
|
||||
def preserve_original_messages(self) -> None:
|
||||
"""Preserve original translatable messages."""
|
||||
raise NotImplementedError
|
||||
|
||||
def apply_translated_message(self, original_message, translated_message):
|
||||
# type: (str, str) -> None
|
||||
def apply_translated_message(self, original_message: str, translated_message: str) -> None:
|
||||
"""Apply translated message."""
|
||||
raise NotImplementedError
|
||||
|
||||
def extract_original_messages(self):
|
||||
# type: () -> Sequence[str]
|
||||
def extract_original_messages(self) -> Sequence[str]:
|
||||
"""Extract translation messages.
|
||||
|
||||
:returns: list of extracted messages or messages generator
|
||||
@ -61,8 +58,7 @@ class not_smartquotable:
|
||||
class toctree(nodes.General, nodes.Element, translatable):
|
||||
"""Node for inserting a "TOC tree"."""
|
||||
|
||||
def preserve_original_messages(self):
|
||||
# type: () -> None
|
||||
def preserve_original_messages(self) -> None:
|
||||
# toctree entries
|
||||
rawentries = self.setdefault('rawentries', [])
|
||||
for title, docname in self['entries']:
|
||||
@ -73,8 +69,7 @@ class toctree(nodes.General, nodes.Element, translatable):
|
||||
if self.get('caption'):
|
||||
self['rawcaption'] = self['caption']
|
||||
|
||||
def apply_translated_message(self, original_message, translated_message):
|
||||
# type: (str, str) -> None
|
||||
def apply_translated_message(self, original_message: str, translated_message: str) -> None:
|
||||
# toctree entries
|
||||
for i, (title, docname) in enumerate(self['entries']):
|
||||
if title == original_message:
|
||||
@ -84,8 +79,7 @@ class toctree(nodes.General, nodes.Element, translatable):
|
||||
if self.get('rawcaption') == original_message:
|
||||
self['caption'] = translated_message
|
||||
|
||||
def extract_original_messages(self):
|
||||
# type: () -> List[str]
|
||||
def extract_original_messages(self) -> List[str]:
|
||||
messages = [] # type: List[str]
|
||||
|
||||
# toctree entries
|
||||
@ -143,8 +137,7 @@ class desc_type(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
|
||||
class desc_returns(desc_type):
|
||||
"""Node for a "returns" annotation (a la -> in Python)."""
|
||||
def astext(self):
|
||||
# type: () -> str
|
||||
def astext(self) -> str:
|
||||
return ' -> ' + super().astext()
|
||||
|
||||
|
||||
@ -165,8 +158,7 @@ class desc_optional(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for marking optional parts of the parameter list."""
|
||||
child_text_separator = ', '
|
||||
|
||||
def astext(self):
|
||||
# type: () -> str
|
||||
def astext(self) -> str:
|
||||
return '[' + super().astext() + ']'
|
||||
|
||||
|
||||
@ -313,8 +305,7 @@ class abbreviation(nodes.abbreviation):
|
||||
.. deprecated:: 2.0
|
||||
"""
|
||||
|
||||
def __init__(self, rawsource='', text='', *children, **attributes):
|
||||
# type: (str, str, *nodes.Node, **Any) -> None
|
||||
def __init__(self, rawsource: str = '', text: str = '', *children, **attributes) -> None:
|
||||
warnings.warn("abbrevition node for Sphinx was replaced by docutils'.",
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
@ -325,8 +316,7 @@ class manpage(nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for references to manpages."""
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[str, Any]
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
app.add_node(toctree)
|
||||
app.add_node(desc)
|
||||
app.add_node(desc_signature)
|
||||
|
@ -18,8 +18,12 @@ import warnings
|
||||
from collections import deque
|
||||
from io import StringIO
|
||||
from os import path
|
||||
from typing import Any, Callable, Dict, IO, List, Tuple, Union
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, TextElement
|
||||
from docutils.parsers.rst import Directive, roles
|
||||
from docutils.transforms import Transform
|
||||
from pygments.lexer import Lexer
|
||||
|
||||
import sphinx
|
||||
@ -27,12 +31,16 @@ from sphinx import package_dir, locale
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.environment.collectors import EnvironmentCollector
|
||||
from sphinx.errors import ApplicationError, ConfigError, VersionRequirementError
|
||||
from sphinx.events import EventManager
|
||||
from sphinx.extension import Extension
|
||||
from sphinx.highlighting import lexer_classes, lexers
|
||||
from sphinx.locale import __
|
||||
from sphinx.project import Project
|
||||
from sphinx.registry import SphinxComponentRegistry
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.theming import Theme
|
||||
from sphinx.util import docutils
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import progress_message
|
||||
@ -42,21 +50,14 @@ from sphinx.util.i18n import CatalogRepository
|
||||
from sphinx.util.logging import prefixed_warnings
|
||||
from sphinx.util.osutil import abspath, ensuredir, relpath
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.util.typing import RoleFunction, TitleGetter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Callable, Dict, IO, Iterable, Iterator, List, Tuple, Union # NOQA
|
||||
from docutils.nodes import Node # NOQA
|
||||
from typing import Type # for python3.5.1
|
||||
from docutils import nodes # NOQA
|
||||
from docutils.parsers import Parser # NOQA
|
||||
from docutils.transforms import Transform # NOQA
|
||||
from sphinx.builders import Builder # NOQA
|
||||
from sphinx.domains import Domain, Index # NOQA
|
||||
from sphinx.environment.collectors import EnvironmentCollector # NOQA
|
||||
from sphinx.extension import Extension # NOQA
|
||||
from sphinx.roles import XRefRole # NOQA
|
||||
from sphinx.theming import Theme # NOQA
|
||||
from sphinx.util.typing import RoleFunction, TitleGetter # NOQA
|
||||
from sphinx.builders import Builder
|
||||
|
||||
|
||||
builtin_extensions = (
|
||||
'sphinx.addnodes',
|
||||
@ -132,11 +133,11 @@ class Sphinx:
|
||||
:ivar outdir: Directory for storing build documents.
|
||||
"""
|
||||
|
||||
def __init__(self, srcdir, confdir, outdir, doctreedir, buildername,
|
||||
confoverrides=None, status=sys.stdout, warning=sys.stderr,
|
||||
freshenv=False, warningiserror=False, tags=None, verbosity=0,
|
||||
parallel=0, keep_going=False):
|
||||
# type: (str, str, str, str, str, Dict, IO, IO, bool, bool, List[str], int, int, bool) -> None # NOQA
|
||||
def __init__(self, srcdir: str, confdir: str, outdir: str, doctreedir: str,
|
||||
buildername: str, confoverrides: Dict = None,
|
||||
status: IO = sys.stdout, warning: IO = sys.stderr,
|
||||
freshenv: bool = False, warningiserror: bool = False, tags: List[str] = None,
|
||||
verbosity: int = 0, parallel: int = 0, keep_going: bool = False) -> None:
|
||||
self.phase = BuildPhase.INITIALIZATION
|
||||
self.verbosity = verbosity
|
||||
self.extensions = {} # type: Dict[str, Extension]
|
||||
@ -270,8 +271,7 @@ class Sphinx:
|
||||
# set up the builder
|
||||
self._init_builder()
|
||||
|
||||
def _init_i18n(self):
|
||||
# type: () -> None
|
||||
def _init_i18n(self) -> None:
|
||||
"""Load translated strings from the configured localedirs if enabled in
|
||||
the configuration.
|
||||
"""
|
||||
@ -296,8 +296,7 @@ class Sphinx:
|
||||
else:
|
||||
logger.info(__('not available for built-in messages'))
|
||||
|
||||
def _init_env(self, freshenv):
|
||||
# type: (bool) -> None
|
||||
def _init_env(self, freshenv: bool) -> None:
|
||||
filename = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
|
||||
if freshenv or not os.path.exists(filename):
|
||||
self.env = BuildEnvironment()
|
||||
@ -313,28 +312,24 @@ class Sphinx:
|
||||
logger.info(__('failed: %s'), err)
|
||||
self._init_env(freshenv=True)
|
||||
|
||||
def preload_builder(self, name):
|
||||
# type: (str) -> None
|
||||
def preload_builder(self, name: str) -> None:
|
||||
self.registry.preload_builder(self, name)
|
||||
|
||||
def create_builder(self, name):
|
||||
# type: (str) -> Builder
|
||||
def create_builder(self, name: str) -> "Builder":
|
||||
if name is None:
|
||||
logger.info(__('No builder selected, using default: html'))
|
||||
name = 'html'
|
||||
|
||||
return self.registry.create_builder(self, name)
|
||||
|
||||
def _init_builder(self):
|
||||
# type: () -> None
|
||||
def _init_builder(self) -> None:
|
||||
self.builder.set_environment(self.env)
|
||||
self.builder.init()
|
||||
self.events.emit('builder-inited')
|
||||
|
||||
# ---- main "build" method -------------------------------------------------
|
||||
|
||||
def build(self, force_all=False, filenames=None):
|
||||
# type: (bool, List[str]) -> None
|
||||
def build(self, force_all: bool = False, filenames: List[str] = None) -> None:
|
||||
self.phase = BuildPhase.READING
|
||||
try:
|
||||
if force_all:
|
||||
@ -385,8 +380,7 @@ class Sphinx:
|
||||
|
||||
# ---- general extensibility interface -------------------------------------
|
||||
|
||||
def setup_extension(self, extname):
|
||||
# type: (str) -> None
|
||||
def setup_extension(self, extname: str) -> None:
|
||||
"""Import and setup a Sphinx extension module.
|
||||
|
||||
Load the extension given by the module *name*. Use this if your
|
||||
@ -396,8 +390,7 @@ class Sphinx:
|
||||
logger.debug('[app] setting up extension: %r', extname)
|
||||
self.registry.load_extension(self, extname)
|
||||
|
||||
def require_sphinx(self, version):
|
||||
# type: (str) -> None
|
||||
def require_sphinx(self, version: str) -> None:
|
||||
"""Check the Sphinx version if requested.
|
||||
|
||||
Compare *version* (which must be a ``major.minor`` version string, e.g.
|
||||
@ -410,8 +403,7 @@ class Sphinx:
|
||||
raise VersionRequirementError(version)
|
||||
|
||||
# event interface
|
||||
def connect(self, event, callback):
|
||||
# type: (str, Callable) -> int
|
||||
def connect(self, event: str, callback: Callable) -> int:
|
||||
"""Register *callback* to be called when *event* is emitted.
|
||||
|
||||
For details on available core events and the arguments of callback
|
||||
@ -424,14 +416,12 @@ class Sphinx:
|
||||
logger.debug('[app] connecting event %r: %r [id=%s]', event, callback, listener_id)
|
||||
return listener_id
|
||||
|
||||
def disconnect(self, listener_id):
|
||||
# type: (int) -> None
|
||||
def disconnect(self, listener_id: int) -> None:
|
||||
"""Unregister callback by *listener_id*."""
|
||||
logger.debug('[app] disconnecting event: [id=%s]', listener_id)
|
||||
self.events.disconnect(listener_id)
|
||||
|
||||
def emit(self, event, *args):
|
||||
# type: (str, Any) -> List
|
||||
def emit(self, event: str, *args) -> List:
|
||||
"""Emit *event* and pass *arguments* to the callback functions.
|
||||
|
||||
Return the return values of all callbacks as a list. Do not emit core
|
||||
@ -439,8 +429,7 @@ class Sphinx:
|
||||
"""
|
||||
return self.events.emit(event, *args)
|
||||
|
||||
def emit_firstresult(self, event, *args):
|
||||
# type: (str, Any) -> Any
|
||||
def emit_firstresult(self, event: str, *args) -> Any:
|
||||
"""Emit *event* and pass *arguments* to the callback functions.
|
||||
|
||||
Return the result of the first callback that doesn't return ``None``.
|
||||
@ -451,8 +440,7 @@ class Sphinx:
|
||||
|
||||
# registering addon parts
|
||||
|
||||
def add_builder(self, builder, override=False):
|
||||
# type: (Type[Builder], bool) -> None
|
||||
def add_builder(self, builder: "Type[Builder]", override: bool = False) -> None:
|
||||
"""Register a new builder.
|
||||
|
||||
*builder* must be a class that inherits from
|
||||
@ -464,8 +452,8 @@ class Sphinx:
|
||||
self.registry.add_builder(builder, override=override)
|
||||
|
||||
# TODO(stephenfin): Describe 'types' parameter
|
||||
def add_config_value(self, name, default, rebuild, types=()):
|
||||
# type: (str, Any, Union[bool, str], Any) -> None
|
||||
def add_config_value(self, name: str, default: Any, rebuild: Union[bool, str],
|
||||
types: Any = ()) -> None:
|
||||
"""Register a configuration value.
|
||||
|
||||
This is necessary for Sphinx to recognize new values and set default
|
||||
@ -497,8 +485,7 @@ class Sphinx:
|
||||
rebuild = 'env' if rebuild else ''
|
||||
self.config.add(name, default, rebuild, types)
|
||||
|
||||
def add_event(self, name):
|
||||
# type: (str) -> None
|
||||
def add_event(self, name: str) -> None:
|
||||
"""Register an event called *name*.
|
||||
|
||||
This is needed to be able to emit it.
|
||||
@ -506,8 +493,8 @@ class Sphinx:
|
||||
logger.debug('[app] adding event: %r', name)
|
||||
self.events.add(name)
|
||||
|
||||
def set_translator(self, name, translator_class, override=False):
|
||||
# type: (str, Type[nodes.NodeVisitor], bool) -> None
|
||||
def set_translator(self, name: str, translator_class: "Type[nodes.NodeVisitor]",
|
||||
override: bool = False) -> None:
|
||||
"""Register or override a Docutils translator class.
|
||||
|
||||
This is used to register a custom output translator or to replace a
|
||||
@ -520,8 +507,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_translator(name, translator_class, override=override)
|
||||
|
||||
def add_node(self, node, override=False, **kwds):
|
||||
# type: (Type[nodes.Element], bool, Any) -> None
|
||||
def add_node(self, node: "Type[Element]", override: bool = False, **kwds) -> None:
|
||||
"""Register a Docutils node class.
|
||||
|
||||
This is necessary for Docutils internals. It may also be used in the
|
||||
@ -559,8 +545,9 @@ class Sphinx:
|
||||
docutils.register_node(node)
|
||||
self.registry.add_translation_handlers(node, **kwds)
|
||||
|
||||
def add_enumerable_node(self, node, figtype, title_getter=None, override=False, **kwds):
|
||||
# type: (Type[nodes.Element], str, TitleGetter, bool, Any) -> None
|
||||
def add_enumerable_node(self, node: "Type[Element]", figtype: str,
|
||||
title_getter: TitleGetter = None, override: bool = False,
|
||||
**kwds) -> None:
|
||||
"""Register a Docutils node class as a numfig target.
|
||||
|
||||
Sphinx numbers the node automatically. And then the users can refer it
|
||||
@ -587,8 +574,7 @@ class Sphinx:
|
||||
self.registry.add_enumerable_node(node, figtype, title_getter, override=override)
|
||||
self.add_node(node, override=override, **kwds)
|
||||
|
||||
def add_directive(self, name, cls, override=False):
|
||||
# type: (str, Type[Directive], bool) -> None
|
||||
def add_directive(self, name: str, cls: "Type[Directive]", override: bool = False):
|
||||
"""Register a Docutils directive.
|
||||
|
||||
*name* must be the prospective directive name. *cls* is a directive
|
||||
@ -632,8 +618,7 @@ class Sphinx:
|
||||
|
||||
docutils.register_directive(name, cls)
|
||||
|
||||
def add_role(self, name, role, override=False):
|
||||
# type: (str, Any, bool) -> None
|
||||
def add_role(self, name: str, role: Any, override: bool = False) -> None:
|
||||
"""Register a Docutils role.
|
||||
|
||||
*name* must be the role name that occurs in the source, *role* the role
|
||||
@ -650,8 +635,7 @@ class Sphinx:
|
||||
name, type='app', subtype='add_role')
|
||||
docutils.register_role(name, role)
|
||||
|
||||
def add_generic_role(self, name, nodeclass, override=False):
|
||||
# type: (str, Any, bool) -> None
|
||||
def add_generic_role(self, name: str, nodeclass: Any, override: bool = False) -> None:
|
||||
"""Register a generic Docutils role.
|
||||
|
||||
Register a Docutils role that does nothing but wrap its contents in the
|
||||
@ -670,8 +654,7 @@ class Sphinx:
|
||||
role = roles.GenericRole(name, nodeclass)
|
||||
docutils.register_role(name, role)
|
||||
|
||||
def add_domain(self, domain, override=False):
|
||||
# type: (Type[Domain], bool) -> None
|
||||
def add_domain(self, domain: "Type[Domain]", override: bool = False) -> None:
|
||||
"""Register a domain.
|
||||
|
||||
Make the given *domain* (which must be a class; more precisely, a
|
||||
@ -683,8 +666,8 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_domain(domain, override=override)
|
||||
|
||||
def add_directive_to_domain(self, domain, name, cls, override=False):
|
||||
# type: (str, str, Type[Directive], bool) -> None
|
||||
def add_directive_to_domain(self, domain: str, name: str,
|
||||
cls: "Type[Directive]", override: bool = False) -> None:
|
||||
"""Register a Docutils directive in a domain.
|
||||
|
||||
Like :meth:`add_directive`, but the directive is added to the domain
|
||||
@ -696,8 +679,8 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_directive_to_domain(domain, name, cls, override=override)
|
||||
|
||||
def add_role_to_domain(self, domain, name, role, override=False):
|
||||
# type: (str, str, Union[RoleFunction, XRefRole], bool) -> None
|
||||
def add_role_to_domain(self, domain: str, name: str, role: Union[RoleFunction, XRefRole],
|
||||
override: bool = False) -> None:
|
||||
"""Register a Docutils role in a domain.
|
||||
|
||||
Like :meth:`add_role`, but the role is added to the domain named
|
||||
@ -709,8 +692,8 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_role_to_domain(domain, name, role, override=override)
|
||||
|
||||
def add_index_to_domain(self, domain, index, override=False):
|
||||
# type: (str, Type[Index], bool) -> None
|
||||
def add_index_to_domain(self, domain: str, index: "Type[Index]", override: bool = False
|
||||
) -> None:
|
||||
"""Register a custom index for a domain.
|
||||
|
||||
Add a custom *index* class to the domain named *domain*. *index* must
|
||||
@ -722,10 +705,10 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_index_to_domain(domain, index)
|
||||
|
||||
def add_object_type(self, directivename, rolename, indextemplate='',
|
||||
parse_node=None, ref_nodeclass=None, objname='',
|
||||
doc_field_types=[], override=False):
|
||||
# type: (str, str, str, Callable, Type[nodes.TextElement], str, List, bool) -> None
|
||||
def add_object_type(self, directivename: str, rolename: str, indextemplate: str = '',
|
||||
parse_node: Callable = None, ref_nodeclass: "Type[TextElement]" = None,
|
||||
objname: str = '', doc_field_types: List = [], override: bool = False
|
||||
) -> None:
|
||||
"""Register a new object type.
|
||||
|
||||
This method is a very convenient way to add a new :term:`object` type
|
||||
@ -786,9 +769,9 @@ class Sphinx:
|
||||
ref_nodeclass, objname, doc_field_types,
|
||||
override=override)
|
||||
|
||||
def add_crossref_type(self, directivename, rolename, indextemplate='',
|
||||
ref_nodeclass=None, objname='', override=False):
|
||||
# type: (str, str, str, Type[nodes.TextElement], str, bool) -> None
|
||||
def add_crossref_type(self, directivename: str, rolename: str, indextemplate: str = '',
|
||||
ref_nodeclass: "Type[TextElement]" = None, objname: str = '',
|
||||
override: bool = False) -> None:
|
||||
"""Register a new crossref object type.
|
||||
|
||||
This method is very similar to :meth:`add_object_type` except that the
|
||||
@ -822,8 +805,7 @@ class Sphinx:
|
||||
indextemplate, ref_nodeclass, objname,
|
||||
override=override)
|
||||
|
||||
def add_transform(self, transform):
|
||||
# type: (Type[Transform]) -> None
|
||||
def add_transform(self, transform: "Type[Transform]") -> None:
|
||||
"""Register a Docutils transform to be applied after parsing.
|
||||
|
||||
Add the standard docutils :class:`Transform` subclass *transform* to
|
||||
@ -856,8 +838,7 @@ class Sphinx:
|
||||
""" # NOQA
|
||||
self.registry.add_transform(transform)
|
||||
|
||||
def add_post_transform(self, transform):
|
||||
# type: (Type[Transform]) -> None
|
||||
def add_post_transform(self, transform: "Type[Transform]") -> None:
|
||||
"""Register a Docutils transform to be applied before writing.
|
||||
|
||||
Add the standard docutils :class:`Transform` subclass *transform* to
|
||||
@ -866,16 +847,14 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_post_transform(transform)
|
||||
|
||||
def add_javascript(self, filename, **kwargs):
|
||||
# type: (str, **str) -> None
|
||||
def add_javascript(self, filename: str, **kwargs: str) -> None:
|
||||
"""An alias of :meth:`add_js_file`."""
|
||||
warnings.warn('The app.add_javascript() is deprecated. '
|
||||
'Please use app.add_js_file() instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
self.add_js_file(filename, **kwargs)
|
||||
|
||||
def add_js_file(self, filename, **kwargs):
|
||||
# type: (str, **str) -> None
|
||||
def add_js_file(self, filename: str, **kwargs: str) -> None:
|
||||
"""Register a JavaScript file to include in the HTML output.
|
||||
|
||||
Add *filename* to the list of JavaScript files that the default HTML
|
||||
@ -901,8 +880,7 @@ class Sphinx:
|
||||
if hasattr(self.builder, 'add_js_file'):
|
||||
self.builder.add_js_file(filename, **kwargs) # type: ignore
|
||||
|
||||
def add_css_file(self, filename, **kwargs):
|
||||
# type: (str, **str) -> None
|
||||
def add_css_file(self, filename: str, **kwargs: str) -> None:
|
||||
"""Register a stylesheet to include in the HTML output.
|
||||
|
||||
Add *filename* to the list of CSS files that the default HTML template
|
||||
@ -941,8 +919,8 @@ class Sphinx:
|
||||
if hasattr(self.builder, 'add_css_file'):
|
||||
self.builder.add_css_file(filename, **kwargs) # type: ignore
|
||||
|
||||
def add_stylesheet(self, filename, alternate=False, title=None):
|
||||
# type: (str, bool, str) -> None
|
||||
def add_stylesheet(self, filename: str, alternate: bool = False, title: str = None
|
||||
) -> None:
|
||||
"""An alias of :meth:`add_css_file`."""
|
||||
warnings.warn('The app.add_stylesheet() is deprecated. '
|
||||
'Please use app.add_css_file() instead.',
|
||||
@ -959,8 +937,7 @@ class Sphinx:
|
||||
|
||||
self.add_css_file(filename, **attributes)
|
||||
|
||||
def add_latex_package(self, packagename, options=None):
|
||||
# type: (str, str) -> None
|
||||
def add_latex_package(self, packagename: str, options: str = None) -> None:
|
||||
r"""Register a package to include in the LaTeX source code.
|
||||
|
||||
Add *packagename* to the list of packages that LaTeX source code will
|
||||
@ -978,8 +955,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_latex_package(packagename, options)
|
||||
|
||||
def add_lexer(self, alias, lexer):
|
||||
# type: (str, Union[Lexer, Type[Lexer]]) -> None
|
||||
def add_lexer(self, alias: str, lexer: Union[Lexer, "Type[Lexer]"]) -> None:
|
||||
"""Register a new lexer for source code.
|
||||
|
||||
Use *lexer* to highlight code blocks with the given language *alias*.
|
||||
@ -998,8 +974,7 @@ class Sphinx:
|
||||
else:
|
||||
lexer_classes[alias] = lexer
|
||||
|
||||
def add_autodocumenter(self, cls, override=False):
|
||||
# type: (Any, bool) -> None
|
||||
def add_autodocumenter(self, cls: Any, override: bool = False) -> None:
|
||||
"""Register a new documenter class for the autodoc extension.
|
||||
|
||||
Add *cls* as a new documenter class for the :mod:`sphinx.ext.autodoc`
|
||||
@ -1019,8 +994,8 @@ class Sphinx:
|
||||
self.registry.add_documenter(cls.objtype, cls)
|
||||
self.add_directive('auto' + cls.objtype, AutodocDirective, override=override)
|
||||
|
||||
def add_autodoc_attrgetter(self, typ, getter):
|
||||
# type: (Type, Callable[[Any, str, Any], Any]) -> None
|
||||
def add_autodoc_attrgetter(self, typ: "Type", getter: Callable[[Any, str, Any], Any]
|
||||
) -> None:
|
||||
"""Register a new ``getattr``-like function for the autodoc extension.
|
||||
|
||||
Add *getter*, which must be a function with an interface compatible to
|
||||
@ -1034,8 +1009,7 @@ class Sphinx:
|
||||
logger.debug('[app] adding autodoc attrgetter: %r', (typ, getter))
|
||||
self.registry.add_autodoc_attrgetter(typ, getter)
|
||||
|
||||
def add_search_language(self, cls):
|
||||
# type: (Any) -> None
|
||||
def add_search_language(self, cls: Any) -> None:
|
||||
"""Register a new language for the HTML search index.
|
||||
|
||||
Add *cls*, which must be a subclass of
|
||||
@ -1051,8 +1025,7 @@ class Sphinx:
|
||||
assert issubclass(cls, SearchLanguage)
|
||||
languages[cls.lang] = cls
|
||||
|
||||
def add_source_suffix(self, suffix, filetype, override=False):
|
||||
# type: (str, str, bool) -> None
|
||||
def add_source_suffix(self, suffix: str, filetype: str, override: bool = False) -> None:
|
||||
"""Register a suffix of source files.
|
||||
|
||||
Same as :confval:`source_suffix`. The users can override this
|
||||
@ -1062,8 +1035,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_source_suffix(suffix, filetype, override=override)
|
||||
|
||||
def add_source_parser(self, *args, **kwargs):
|
||||
# type: (Any, Any) -> None
|
||||
def add_source_parser(self, *args, **kwargs) -> None:
|
||||
"""Register a parser class.
|
||||
|
||||
.. versionadded:: 1.4
|
||||
@ -1075,8 +1047,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_source_parser(*args, **kwargs)
|
||||
|
||||
def add_env_collector(self, collector):
|
||||
# type: (Type[EnvironmentCollector]) -> None
|
||||
def add_env_collector(self, collector: "Type[EnvironmentCollector]") -> None:
|
||||
"""Register an environment collector class.
|
||||
|
||||
Refer to :ref:`collector-api`.
|
||||
@ -1086,8 +1057,7 @@ class Sphinx:
|
||||
logger.debug('[app] adding environment collector: %r', collector)
|
||||
collector().enable(self)
|
||||
|
||||
def add_html_theme(self, name, theme_path):
|
||||
# type: (str, str) -> None
|
||||
def add_html_theme(self, name: str, theme_path: str) -> None:
|
||||
"""Register a HTML Theme.
|
||||
|
||||
The *name* is a name of theme, and *path* is a full path to the theme
|
||||
@ -1098,8 +1068,9 @@ class Sphinx:
|
||||
logger.debug('[app] adding HTML theme: %r, %r', name, theme_path)
|
||||
self.html_themes[name] = theme_path
|
||||
|
||||
def add_html_math_renderer(self, name, inline_renderers=None, block_renderers=None):
|
||||
# type: (str, Tuple[Callable, Callable], Tuple[Callable, Callable]) -> None
|
||||
def add_html_math_renderer(self, name: str,
|
||||
inline_renderers: Tuple[Callable, Callable] = None,
|
||||
block_renderers: Tuple[Callable, Callable] = None) -> None:
|
||||
"""Register a math renderer for HTML.
|
||||
|
||||
The *name* is a name of math renderer. Both *inline_renderers* and
|
||||
@ -1113,8 +1084,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_html_math_renderer(name, inline_renderers, block_renderers)
|
||||
|
||||
def add_message_catalog(self, catalog, locale_dir):
|
||||
# type: (str, str) -> None
|
||||
def add_message_catalog(self, catalog: str, locale_dir: str) -> None:
|
||||
"""Register a message catalog.
|
||||
|
||||
The *catalog* is a name of catalog, and *locale_dir* is a base path
|
||||
@ -1127,8 +1097,7 @@ class Sphinx:
|
||||
locale.init_console(locale_dir, catalog)
|
||||
|
||||
# ---- other methods -------------------------------------------------
|
||||
def is_parallel_allowed(self, typ):
|
||||
# type: (str) -> bool
|
||||
def is_parallel_allowed(self, typ: str) -> bool:
|
||||
"""Check parallel processing is allowed or not.
|
||||
|
||||
``typ`` is a type of processing; ``'read'`` or ``'write'``.
|
||||
@ -1170,8 +1139,7 @@ class TemplateBridge:
|
||||
that renders templates given a template name and a context.
|
||||
"""
|
||||
|
||||
def init(self, builder, theme=None, dirs=None):
|
||||
# type: (Builder, Theme, List[str]) -> None
|
||||
def init(self, builder: "Builder", theme: Theme = None, dirs: List[str] = None) -> None:
|
||||
"""Called by the builder to initialize the template system.
|
||||
|
||||
*builder* is the builder object; you'll probably want to look at the
|
||||
@ -1182,23 +1150,20 @@ class TemplateBridge:
|
||||
"""
|
||||
raise NotImplementedError('must be implemented in subclasses')
|
||||
|
||||
def newest_template_mtime(self):
|
||||
# type: () -> float
|
||||
def newest_template_mtime(self) -> float:
|
||||
"""Called by the builder to determine if output files are outdated
|
||||
because of template changes. Return the mtime of the newest template
|
||||
file that was changed. The default implementation returns ``0``.
|
||||
"""
|
||||
return 0
|
||||
|
||||
def render(self, template, context):
|
||||
# type: (str, Dict) -> None
|
||||
def render(self, template: str, context: Dict) -> None:
|
||||
"""Called by the builder to render a template given as a filename with
|
||||
a specified context (a Python dictionary).
|
||||
"""
|
||||
raise NotImplementedError('must be implemented in subclasses')
|
||||
|
||||
def render_string(self, template, context):
|
||||
# type: (str, Dict) -> str
|
||||
def render_string(self, template: str, context: Dict) -> str:
|
||||
"""Called by the builder to render a template given as a string with a
|
||||
specified context (a Python dictionary).
|
||||
"""
|
||||
|
@ -14,7 +14,9 @@ import types
|
||||
import warnings
|
||||
from collections import OrderedDict
|
||||
from os import path, getenv
|
||||
from typing import Any, NamedTuple, Union
|
||||
from typing import (
|
||||
Any, Callable, Dict, Generator, Iterator, List, NamedTuple, Set, Tuple, Union
|
||||
)
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.errors import ConfigError, ExtensionError
|
||||
@ -23,14 +25,13 @@ from sphinx.util import logging
|
||||
from sphinx.util.i18n import format_date
|
||||
from sphinx.util.osutil import cd
|
||||
from sphinx.util.pycompat import execfile_
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.util.typing import NoneType
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Callable, Dict, Generator, Iterator, List, Set, Tuple # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
from sphinx.util.tags import Tags # NOQA
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -43,8 +44,7 @@ ConfigValue = NamedTuple('ConfigValue', [('name', str),
|
||||
('rebuild', Union[bool, str])])
|
||||
|
||||
|
||||
def is_serializable(obj):
|
||||
# type: (Any) -> bool
|
||||
def is_serializable(obj: Any) -> bool:
|
||||
"""Check if object is serializable or not."""
|
||||
if isinstance(obj, UNSERIALIZABLE_TYPES):
|
||||
return False
|
||||
@ -64,12 +64,10 @@ class ENUM:
|
||||
Example:
|
||||
app.add_config_value('latex_show_urls', 'no', None, ENUM('no', 'footnote', 'inline'))
|
||||
"""
|
||||
def __init__(self, *candidates):
|
||||
# type: (str) -> None
|
||||
def __init__(self, *candidates: str) -> None:
|
||||
self.candidates = candidates
|
||||
|
||||
def match(self, value):
|
||||
# type: (Union[str, List, Tuple]) -> bool
|
||||
def match(self, value: Union[str, List, Tuple]) -> bool:
|
||||
if isinstance(value, (list, tuple)):
|
||||
return all(item in self.candidates for item in value)
|
||||
else:
|
||||
@ -156,8 +154,7 @@ class Config:
|
||||
'env', []),
|
||||
} # type: Dict[str, Tuple]
|
||||
|
||||
def __init__(self, config={}, overrides={}):
|
||||
# type: (Dict[str, Any], Dict[str, Any]) -> None
|
||||
def __init__(self, config: Dict[str, Any] = {}, overrides: Dict[str, Any] = {}) -> None:
|
||||
self.overrides = dict(overrides)
|
||||
self.values = Config.config_values.copy()
|
||||
self._raw_config = config
|
||||
@ -171,15 +168,13 @@ class Config:
|
||||
self.extensions = config.get('extensions', []) # type: List[str]
|
||||
|
||||
@classmethod
|
||||
def read(cls, confdir, overrides=None, tags=None):
|
||||
# type: (str, Dict, Tags) -> Config
|
||||
def read(cls, confdir: str, overrides: Dict = None, tags: Tags = None) -> "Config":
|
||||
"""Create a Config object from configuration file."""
|
||||
filename = path.join(confdir, CONFIG_FILENAME)
|
||||
namespace = eval_config_file(filename, tags)
|
||||
return cls(namespace, overrides or {})
|
||||
|
||||
def convert_overrides(self, name, value):
|
||||
# type: (str, Any) -> Any
|
||||
def convert_overrides(self, name: str, value: Any) -> Any:
|
||||
if not isinstance(value, str):
|
||||
return value
|
||||
else:
|
||||
@ -212,8 +207,7 @@ class Config:
|
||||
else:
|
||||
return value
|
||||
|
||||
def pre_init_values(self):
|
||||
# type: () -> None
|
||||
def pre_init_values(self) -> None:
|
||||
"""
|
||||
Initialize some limited config variables before initialize i18n and loading extensions
|
||||
"""
|
||||
@ -227,8 +221,7 @@ class Config:
|
||||
except ValueError as exc:
|
||||
logger.warning("%s", exc)
|
||||
|
||||
def init_values(self):
|
||||
# type: () -> None
|
||||
def init_values(self) -> None:
|
||||
config = self._raw_config
|
||||
for valname, value in self.overrides.items():
|
||||
try:
|
||||
@ -250,8 +243,7 @@ class Config:
|
||||
if name in self.values:
|
||||
self.__dict__[name] = config[name]
|
||||
|
||||
def __getattr__(self, name):
|
||||
# type: (str) -> Any
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
if name.startswith('_'):
|
||||
raise AttributeError(name)
|
||||
if name not in self.values:
|
||||
@ -261,42 +253,34 @@ class Config:
|
||||
return default(self)
|
||||
return default
|
||||
|
||||
def __getitem__(self, name):
|
||||
# type: (str) -> str
|
||||
def __getitem__(self, name: str) -> str:
|
||||
return getattr(self, name)
|
||||
|
||||
def __setitem__(self, name, value):
|
||||
# type: (str, Any) -> None
|
||||
def __setitem__(self, name: str, value: Any) -> None:
|
||||
setattr(self, name, value)
|
||||
|
||||
def __delitem__(self, name):
|
||||
# type: (str) -> None
|
||||
def __delitem__(self, name: str) -> None:
|
||||
delattr(self, name)
|
||||
|
||||
def __contains__(self, name):
|
||||
# type: (str) -> bool
|
||||
def __contains__(self, name: str) -> bool:
|
||||
return name in self.values
|
||||
|
||||
def __iter__(self):
|
||||
# type: () -> Generator[ConfigValue, None, None]
|
||||
def __iter__(self) -> Generator[ConfigValue, None, None]:
|
||||
for name, value in self.values.items():
|
||||
yield ConfigValue(name, getattr(self, name), value[1])
|
||||
|
||||
def add(self, name, default, rebuild, types):
|
||||
# type: (str, Any, Union[bool, str], Any) -> None
|
||||
def add(self, name: str, default: Any, rebuild: Union[bool, str], types: Any) -> None:
|
||||
if name in self.values:
|
||||
raise ExtensionError(__('Config value %r already present') % name)
|
||||
else:
|
||||
self.values[name] = (default, rebuild, types)
|
||||
|
||||
def filter(self, rebuild):
|
||||
# type: (Union[str, List[str]]) -> Iterator[ConfigValue]
|
||||
def filter(self, rebuild: Union[str, List[str]]) -> Iterator[ConfigValue]:
|
||||
if isinstance(rebuild, str):
|
||||
rebuild = [rebuild]
|
||||
return (value for value in self if value.rebuild in rebuild)
|
||||
|
||||
def __getstate__(self):
|
||||
# type: () -> Dict
|
||||
def __getstate__(self) -> Dict:
|
||||
"""Obtains serializable data for pickling."""
|
||||
# remove potentially pickling-problematic values from config
|
||||
__dict__ = {}
|
||||
@ -319,13 +303,11 @@ class Config:
|
||||
|
||||
return __dict__
|
||||
|
||||
def __setstate__(self, state):
|
||||
# type: (Dict) -> None
|
||||
def __setstate__(self, state: Dict) -> None:
|
||||
self.__dict__.update(state)
|
||||
|
||||
|
||||
def eval_config_file(filename, tags):
|
||||
# type: (str, Tags) -> Dict[str, Any]
|
||||
def eval_config_file(filename: str, tags: Tags) -> Dict[str, Any]:
|
||||
"""Evaluate a config file."""
|
||||
namespace = {} # type: Dict[str, Any]
|
||||
namespace['__file__'] = filename
|
||||
@ -349,8 +331,7 @@ def eval_config_file(filename, tags):
|
||||
return namespace
|
||||
|
||||
|
||||
def convert_source_suffix(app, config):
|
||||
# type: (Sphinx, Config) -> None
|
||||
def convert_source_suffix(app: "Sphinx", config: Config) -> None:
|
||||
"""This converts old styled source_suffix to new styled one.
|
||||
|
||||
* old style: str or list
|
||||
@ -375,8 +356,7 @@ def convert_source_suffix(app, config):
|
||||
"But `%r' is given." % source_suffix))
|
||||
|
||||
|
||||
def init_numfig_format(app, config):
|
||||
# type: (Sphinx, Config) -> None
|
||||
def init_numfig_format(app: "Sphinx", config: Config) -> None:
|
||||
"""Initialize :confval:`numfig_format`."""
|
||||
numfig_format = {'section': _('Section %s'),
|
||||
'figure': _('Fig. %s'),
|
||||
@ -388,8 +368,7 @@ def init_numfig_format(app, config):
|
||||
config.numfig_format = numfig_format # type: ignore
|
||||
|
||||
|
||||
def correct_copyright_year(app, config):
|
||||
# type: (Sphinx, Config) -> None
|
||||
def correct_copyright_year(app: "Sphinx", config: Config) -> None:
|
||||
"""correct values of copyright year that are not coherent with
|
||||
the SOURCE_DATE_EPOCH environment variable (if set)
|
||||
|
||||
@ -402,8 +381,7 @@ def correct_copyright_year(app, config):
|
||||
config[k] = copyright_year_re.sub(replace, config[k])
|
||||
|
||||
|
||||
def check_confval_types(app, config):
|
||||
# type: (Sphinx, Config) -> None
|
||||
def check_confval_types(app: "Sphinx", config: Config) -> None:
|
||||
"""check all values for deviation from the default value's type, since
|
||||
that can result in TypeErrors all over the place NB.
|
||||
"""
|
||||
@ -458,8 +436,7 @@ def check_confval_types(app, config):
|
||||
default=type(default)))
|
||||
|
||||
|
||||
def check_unicode(config):
|
||||
# type: (Config) -> None
|
||||
def check_unicode(config: Config) -> None:
|
||||
"""check all string values for non-ASCII characters in bytestrings,
|
||||
since that can result in UnicodeErrors all over the place
|
||||
"""
|
||||
@ -475,16 +452,15 @@ def check_unicode(config):
|
||||
'Please use Unicode strings, e.g. %r.'), name, 'Content')
|
||||
|
||||
|
||||
def check_primary_domain(app, config):
|
||||
# type: (Sphinx, Config) -> None
|
||||
def check_primary_domain(app: "Sphinx", config: Config) -> None:
|
||||
primary_domain = config.primary_domain
|
||||
if primary_domain and not app.registry.has_domain(primary_domain):
|
||||
logger.warning(__('primary_domain %r not found, ignored.'), primary_domain)
|
||||
config.primary_domain = None # type: ignore
|
||||
|
||||
|
||||
def check_master_doc(app, env, added, changed, removed):
|
||||
# type: (Sphinx, BuildEnvironment, Set[str], Set[str], Set[str]) -> Set[str]
|
||||
def check_master_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str],
|
||||
changed: Set[str], removed: Set[str]) -> Set[str]:
|
||||
"""Adjust master_doc to 'contents' to support an old project which does not have
|
||||
no master_doc setting.
|
||||
"""
|
||||
@ -498,8 +474,7 @@ def check_master_doc(app, env, added, changed, removed):
|
||||
return changed
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[str, Any]
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
app.connect('config-inited', convert_source_suffix)
|
||||
app.connect('config-inited', init_numfig_format)
|
||||
app.connect('config-inited', correct_copyright_year)
|
||||
|
@ -11,11 +11,8 @@
|
||||
import sys
|
||||
import warnings
|
||||
from importlib import import_module
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict # NOQA
|
||||
from typing import Type # for python3.5.1
|
||||
from typing import Any, Dict
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
|
||||
class RemovedInSphinx40Warning(DeprecationWarning):
|
||||
@ -29,22 +26,20 @@ class RemovedInSphinx50Warning(PendingDeprecationWarning):
|
||||
RemovedInNextVersionWarning = RemovedInSphinx40Warning
|
||||
|
||||
|
||||
def deprecated_alias(modname, objects, warning):
|
||||
# type: (str, Dict, Type[Warning]) -> None
|
||||
def deprecated_alias(modname: str, objects: Dict, warning: Type[Warning]) -> None:
|
||||
module = import_module(modname)
|
||||
sys.modules[modname] = _ModuleWrapper(module, modname, objects, warning) # type: ignore
|
||||
|
||||
|
||||
class _ModuleWrapper:
|
||||
def __init__(self, module, modname, objects, warning):
|
||||
# type: (Any, str, Dict, Type[Warning]) -> None
|
||||
def __init__(self, module: Any, modname: str, objects: Dict, warning: Type[Warning]
|
||||
) -> None:
|
||||
self._module = module
|
||||
self._modname = modname
|
||||
self._objects = objects
|
||||
self._warning = warning
|
||||
|
||||
def __getattr__(self, name):
|
||||
# type: (str) -> Any
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
if name in self._objects:
|
||||
warnings.warn("%s.%s is deprecated. Check CHANGES for Sphinx "
|
||||
"API modifications." % (self._modname, name),
|
||||
@ -57,33 +52,27 @@ class _ModuleWrapper:
|
||||
class DeprecatedDict(dict):
|
||||
"""A deprecated dict which warns on each access."""
|
||||
|
||||
def __init__(self, data, message, warning):
|
||||
# type: (Dict, str, Type[Warning]) -> None
|
||||
def __init__(self, data: Dict, message: str, warning: Type[Warning]) -> None:
|
||||
self.message = message
|
||||
self.warning = warning
|
||||
super().__init__(data)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
# type: (str, Any) -> None
|
||||
def __setitem__(self, key: str, value: Any) -> None:
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
super().__setitem__(key, value)
|
||||
|
||||
def setdefault(self, key, default=None):
|
||||
# type: (str, Any) -> None
|
||||
def setdefault(self, key: str, default: Any = None) -> Any:
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
return super().setdefault(key, default)
|
||||
|
||||
def __getitem__(self, key):
|
||||
# type: (str) -> None
|
||||
def __getitem__(self, key: str) -> None:
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
return super().__getitem__(key)
|
||||
|
||||
def get(self, key, default=None):
|
||||
# type: (str, Any) -> None
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
return super().get(key, default)
|
||||
|
||||
def update(self, other=None): # type: ignore
|
||||
# type: (Dict) -> None
|
||||
def update(self, other: Dict = None) -> None: # type: ignore
|
||||
warnings.warn(self.message, self.warning, stacklevel=2)
|
||||
super().update(other)
|
||||
|
@ -640,7 +640,7 @@ class BuildEnvironment:
|
||||
@property
|
||||
def indexentries(self) -> Dict[str, List[Tuple[str, str, str, str, str]]]:
|
||||
warnings.warn('env.indexentries() is deprecated. Please use IndexDomain instead.',
|
||||
RemovedInSphinx40Warning)
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
from sphinx.domains.index import IndexDomain
|
||||
domain = cast(IndexDomain, self.get_domain('index'))
|
||||
return domain.entries
|
||||
|
@ -12,8 +12,10 @@ import re
|
||||
import unicodedata
|
||||
from itertools import groupby
|
||||
from typing import Any, Dict, Pattern, List, Tuple
|
||||
from typing import cast
|
||||
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.domains.index import IndexDomain
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.errors import NoUri
|
||||
from sphinx.locale import _, __
|
||||
@ -53,7 +55,8 @@ class IndexEntries:
|
||||
# maintain links in sorted/deterministic order
|
||||
bisect.insort(entry[0], (main, uri))
|
||||
|
||||
for fn, entries in self.env.indexentries.items():
|
||||
domain = cast(IndexDomain, self.env.get_domain('index'))
|
||||
for fn, entries in domain.entries.items():
|
||||
# new entry types must be listed in directives/other.py!
|
||||
for type, value, tid, main, index_key in entries:
|
||||
try:
|
||||
|
@ -12,9 +12,12 @@ from typing import Dict, List, Set
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
class EnvironmentCollector:
|
||||
"""An EnvironmentCollector is a specific data collector from each document.
|
||||
@ -27,7 +30,7 @@ class EnvironmentCollector:
|
||||
|
||||
listener_ids = None # type: Dict[str, int]
|
||||
|
||||
def enable(self, app: 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),
|
||||
@ -37,38 +40,38 @@ class EnvironmentCollector:
|
||||
'env-get-outdated': app.connect('env-get-outdated', self.get_outdated_docs),
|
||||
}
|
||||
|
||||
def disable(self, app: 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: Sphinx, env: BuildEnvironment, docname: 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: Sphinx, env: BuildEnvironment,
|
||||
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: Sphinx, doctree: 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: Sphinx, env: 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: Sphinx, env: BuildEnvironment,
|
||||
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.
|
||||
|
||||
|
@ -9,9 +9,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from typing import Any
|
||||
|
||||
|
||||
class SphinxError(Exception):
|
||||
@ -51,21 +49,18 @@ class ExtensionError(SphinxError):
|
||||
"""Extension error."""
|
||||
category = 'Extension error'
|
||||
|
||||
def __init__(self, message, orig_exc=None):
|
||||
# type: (str, Exception) -> None
|
||||
def __init__(self, message: str, orig_exc: Exception = None) -> None:
|
||||
super().__init__(message)
|
||||
self.message = message
|
||||
self.orig_exc = orig_exc
|
||||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
def __repr__(self) -> str:
|
||||
if self.orig_exc:
|
||||
return '%s(%r, %r)' % (self.__class__.__name__,
|
||||
self.message, self.orig_exc)
|
||||
return '%s(%r)' % (self.__class__.__name__, self.message)
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
def __str__(self) -> str:
|
||||
parent_str = super().__str__()
|
||||
if self.orig_exc:
|
||||
return '%s (exception: %s)' % (parent_str, self.orig_exc)
|
||||
@ -102,21 +97,18 @@ class SphinxParallelError(SphinxError):
|
||||
|
||||
category = 'Sphinx parallel build error'
|
||||
|
||||
def __init__(self, message, traceback):
|
||||
# type: (str, Any) -> None
|
||||
def __init__(self, message: str, traceback: Any) -> None:
|
||||
self.message = message
|
||||
self.traceback = traceback
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
def __str__(self) -> str:
|
||||
return self.message
|
||||
|
||||
|
||||
class PycodeError(Exception):
|
||||
"""Pycode Python source code analyser error."""
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
def __str__(self) -> str:
|
||||
res = self.args[0]
|
||||
if len(self.args) > 1:
|
||||
res += ' (exception was: %r)' % self.args[1]
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
import warnings
|
||||
from collections import OrderedDict, defaultdict
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.errors import ExtensionError
|
||||
@ -20,8 +21,8 @@ from sphinx.util import logging
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Callable, Dict, List # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -50,8 +51,7 @@ core_events = {
|
||||
class EventManager:
|
||||
"""Event manager for Sphinx."""
|
||||
|
||||
def __init__(self, app=None):
|
||||
# type: (Sphinx) -> None
|
||||
def __init__(self, app: "Sphinx" = None) -> None:
|
||||
if app is None:
|
||||
warnings.warn('app argument is required for EventManager.',
|
||||
RemovedInSphinx40Warning)
|
||||
@ -60,15 +60,13 @@ class EventManager:
|
||||
self.listeners = defaultdict(OrderedDict) # type: Dict[str, Dict[int, Callable]]
|
||||
self.next_listener_id = 0
|
||||
|
||||
def add(self, name):
|
||||
# type: (str) -> None
|
||||
def add(self, name: str) -> None:
|
||||
"""Register a custom Sphinx event."""
|
||||
if name in self.events:
|
||||
raise ExtensionError(__('Event %r already present') % name)
|
||||
self.events[name] = ''
|
||||
|
||||
def connect(self, name, callback):
|
||||
# type: (str, Callable) -> int
|
||||
def connect(self, name: str, callback: Callable) -> int:
|
||||
"""Connect a handler to specific event."""
|
||||
if name not in self.events:
|
||||
raise ExtensionError(__('Unknown event name: %s') % name)
|
||||
@ -78,14 +76,12 @@ class EventManager:
|
||||
self.listeners[name][listener_id] = callback
|
||||
return listener_id
|
||||
|
||||
def disconnect(self, listener_id):
|
||||
# type: (int) -> None
|
||||
def disconnect(self, listener_id: int) -> None:
|
||||
"""Disconnect a handler."""
|
||||
for event in self.listeners.values():
|
||||
event.pop(listener_id, None)
|
||||
|
||||
def emit(self, name, *args):
|
||||
# type: (str, Any) -> List
|
||||
def emit(self, name: str, *args) -> List:
|
||||
"""Emit a Sphinx event."""
|
||||
try:
|
||||
logger.debug('[app] emitting event: %r%s', name, repr(args)[:100])
|
||||
@ -103,8 +99,7 @@ class EventManager:
|
||||
results.append(callback(self.app, *args))
|
||||
return results
|
||||
|
||||
def emit_firstresult(self, name, *args):
|
||||
# type: (str, Any) -> Any
|
||||
def emit_firstresult(self, name: str, *args) -> Any:
|
||||
"""Emit a Sphinx event and returns first result.
|
||||
|
||||
This returns the result of the first handler that doesn't return ``None``.
|
||||
|
@ -59,6 +59,11 @@ class DummyApplication:
|
||||
self.registry = SphinxComponentRegistry()
|
||||
self.messagelog = [] # type: List[str]
|
||||
self.verbosity = 0
|
||||
self._warncount = 0
|
||||
self.warningiserror = False
|
||||
|
||||
def emit_firstresult(self, *args) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def setup_documenters(app: Any) -> None:
|
||||
|
@ -8,22 +8,22 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict
|
||||
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import VersionRequirementError
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.config import Config # NOQA
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Extension:
|
||||
def __init__(self, name, module, **kwargs):
|
||||
# type: (str, Any, Any) -> None
|
||||
def __init__(self, name: str, module: Any, **kwargs) -> None:
|
||||
self.name = name
|
||||
self.module = module
|
||||
self.metadata = kwargs
|
||||
@ -40,8 +40,7 @@ class Extension:
|
||||
self.parallel_write_safe = kwargs.pop('parallel_write_safe', True)
|
||||
|
||||
|
||||
def verify_needs_extensions(app, config):
|
||||
# type: (Sphinx, Config) -> None
|
||||
def verify_needs_extensions(app: "Sphinx", config: Config) -> None:
|
||||
"""Verify the required Sphinx extensions are loaded."""
|
||||
if config.needs_extensions is None:
|
||||
return
|
||||
@ -60,8 +59,7 @@ def verify_needs_extensions(app, config):
|
||||
(extname, reqversion, extension.version))
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[str, Any]
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
app.connect('config-inited', verify_needs_extensions)
|
||||
|
||||
return {
|
||||
|
@ -10,14 +10,17 @@
|
||||
|
||||
from functools import partial
|
||||
from importlib import import_module
|
||||
from typing import Any, Dict
|
||||
|
||||
from pygments import highlight
|
||||
from pygments.filters import ErrorToken
|
||||
from pygments.formatter import Formatter
|
||||
from pygments.formatters import HtmlFormatter, LatexFormatter
|
||||
from pygments.lexer import Lexer
|
||||
from pygments.lexers import get_lexer_by_name, guess_lexer
|
||||
from pygments.lexers import PythonLexer, Python3Lexer, PythonConsoleLexer, \
|
||||
CLexer, TextLexer, RstLexer
|
||||
from pygments.style import Style
|
||||
from pygments.styles import get_style_by_name
|
||||
from pygments.util import ClassNotFound
|
||||
|
||||
@ -25,12 +28,6 @@ from sphinx.locale import __
|
||||
from sphinx.pygments_styles import SphinxStyle, NoneStyle
|
||||
from sphinx.util import logging, texescape
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict # NOQA
|
||||
from pygments.formatter import Formatter # NOQA
|
||||
from pygments.style import Style # NOQA
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -63,8 +60,8 @@ class PygmentsBridge:
|
||||
html_formatter = HtmlFormatter
|
||||
latex_formatter = LatexFormatter
|
||||
|
||||
def __init__(self, dest='html', stylename='sphinx', latex_engine=None):
|
||||
# type: (str, str, str) -> None
|
||||
def __init__(self, dest: str = 'html', stylename: str = 'sphinx',
|
||||
latex_engine: str = None) -> None:
|
||||
self.dest = dest
|
||||
self.latex_engine = latex_engine
|
||||
|
||||
@ -76,8 +73,7 @@ class PygmentsBridge:
|
||||
self.formatter = self.latex_formatter
|
||||
self.formatter_args['commandprefix'] = 'PYG'
|
||||
|
||||
def get_style(self, stylename):
|
||||
# type: (str) -> Style
|
||||
def get_style(self, stylename: str) -> Style:
|
||||
if stylename is None or stylename == 'sphinx':
|
||||
return SphinxStyle
|
||||
elif stylename == 'none':
|
||||
@ -88,13 +84,12 @@ class PygmentsBridge:
|
||||
else:
|
||||
return get_style_by_name(stylename)
|
||||
|
||||
def get_formatter(self, **kwargs):
|
||||
# type: (Any) -> Formatter
|
||||
def get_formatter(self, **kwargs) -> Formatter:
|
||||
kwargs.update(self.formatter_args)
|
||||
return self.formatter(**kwargs)
|
||||
|
||||
def get_lexer(self, source, lang, opts=None, force=False, location=None):
|
||||
# type: (str, str, Dict, bool, Any) -> Lexer
|
||||
def get_lexer(self, source: str, lang: str, opts: Dict = None,
|
||||
force: bool = False, location: Any = None) -> Lexer:
|
||||
if not opts:
|
||||
opts = {}
|
||||
|
||||
@ -137,8 +132,8 @@ class PygmentsBridge:
|
||||
|
||||
return lexer
|
||||
|
||||
def highlight_block(self, source, lang, opts=None, force=False, location=None, **kwargs):
|
||||
# type: (str, str, Dict, bool, Any, Any) -> str
|
||||
def highlight_block(self, source: str, lang: str, opts: Dict = None,
|
||||
force: bool = False, location: Any = None, **kwargs) -> str:
|
||||
if not isinstance(source, str):
|
||||
source = source.decode()
|
||||
|
||||
@ -167,8 +162,7 @@ class PygmentsBridge:
|
||||
# MEMO: this is done to escape Unicode chars with non-Unicode engines
|
||||
return texescape.hlescape(hlsource, self.latex_engine)
|
||||
|
||||
def get_stylesheet(self):
|
||||
# type: () -> str
|
||||
def get_stylesheet(self) -> str:
|
||||
formatter = self.get_formatter()
|
||||
if self.dest == 'html':
|
||||
return formatter.get_style_defs('.highlight')
|
||||
|
64
sphinx/io.py
64
sphinx/io.py
@ -9,16 +9,23 @@
|
||||
"""
|
||||
import codecs
|
||||
import warnings
|
||||
from typing import Any
|
||||
from typing import Any, List, Tuple
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.core import Publisher
|
||||
from docutils.io import FileInput, NullOutput
|
||||
from docutils.frontend import Values
|
||||
from docutils.io import FileInput, Input, NullOutput
|
||||
from docutils.parsers import Parser
|
||||
from docutils.parsers.rst import Parser as RSTParser
|
||||
from docutils.readers import standalone
|
||||
from docutils.statemachine import StringList, string2lines
|
||||
from docutils.transforms import Transform
|
||||
from docutils.transforms.references import DanglingReferences
|
||||
from docutils.writers import UnfilteredWriter
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.errors import FiletypeNotFoundError
|
||||
from sphinx.transforms import (
|
||||
AutoIndexUpgrader, DoctreeReadEvent, FigureAligner, SphinxTransformer
|
||||
@ -34,15 +41,7 @@ from sphinx.versioning import UIDTransform
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Dict, List, Tuple # NOQA
|
||||
from typing import Type # for python3.5.1
|
||||
from docutils import nodes # NOQA
|
||||
from docutils.frontend import Values # NOQA
|
||||
from docutils.io import Input # NOQA
|
||||
from docutils.parsers import Parser # NOQA
|
||||
from docutils.transforms import Transform # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -57,8 +56,7 @@ class SphinxBaseReader(standalone.Reader):
|
||||
|
||||
transforms = [] # type: List[Type[Transform]]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# type: (Any, Any) -> None
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
from sphinx.application import Sphinx
|
||||
if len(args) > 0 and isinstance(args[0], Sphinx):
|
||||
self._app = args[0]
|
||||
@ -68,26 +66,22 @@ class SphinxBaseReader(standalone.Reader):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def app(self):
|
||||
# type: () -> Sphinx
|
||||
def app(self) -> "Sphinx":
|
||||
warnings.warn('SphinxBaseReader.app is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return self._app
|
||||
|
||||
@property
|
||||
def env(self):
|
||||
# type: () -> BuildEnvironment
|
||||
def env(self) -> BuildEnvironment:
|
||||
warnings.warn('SphinxBaseReader.env is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return self._env
|
||||
|
||||
def setup(self, app):
|
||||
# type: (Sphinx) -> None
|
||||
def setup(self, app: "Sphinx") -> None:
|
||||
self._app = app # hold application object only for compatibility
|
||||
self._env = app.env
|
||||
|
||||
def get_transforms(self):
|
||||
# type: () -> List[Type[Transform]]
|
||||
def get_transforms(self) -> List[Type[Transform]]:
|
||||
transforms = super().get_transforms() + self.transforms
|
||||
|
||||
# remove transforms which is not needed for Sphinx
|
||||
@ -98,8 +92,7 @@ class SphinxBaseReader(standalone.Reader):
|
||||
|
||||
return transforms
|
||||
|
||||
def new_document(self):
|
||||
# type: () -> nodes.document
|
||||
def new_document(self) -> nodes.document:
|
||||
"""Creates a new document object which having a special reporter object good
|
||||
for logging.
|
||||
"""
|
||||
@ -121,13 +114,11 @@ class SphinxStandaloneReader(SphinxBaseReader):
|
||||
A basic document reader for Sphinx.
|
||||
"""
|
||||
|
||||
def setup(self, app):
|
||||
# type: (Sphinx) -> None
|
||||
def setup(self, app: "Sphinx") -> None:
|
||||
self.transforms = self.transforms + app.registry.get_transforms()
|
||||
super().setup(app)
|
||||
|
||||
def read(self, source, parser, settings):
|
||||
# type: (Input, Parser, Values) -> nodes.document
|
||||
def read(self, source: Input, parser: Parser, settings: Values) -> nodes.document:
|
||||
self.source = source
|
||||
if not self.parser:
|
||||
self.parser = parser
|
||||
@ -136,8 +127,7 @@ class SphinxStandaloneReader(SphinxBaseReader):
|
||||
self.parse()
|
||||
return self.document
|
||||
|
||||
def read_source(self, env):
|
||||
# type: (BuildEnvironment) -> str
|
||||
def read_source(self, env: BuildEnvironment) -> str:
|
||||
"""Read content from source and do post-process."""
|
||||
content = self.source.read()
|
||||
|
||||
@ -156,8 +146,7 @@ class SphinxI18nReader(SphinxBaseReader):
|
||||
Because the translated texts are partial and they don't have correct line numbers.
|
||||
"""
|
||||
|
||||
def setup(self, app):
|
||||
# type: (Sphinx) -> None
|
||||
def setup(self, app: "Sphinx") -> None:
|
||||
super().setup(app)
|
||||
|
||||
self.transforms = self.transforms + app.registry.get_transforms()
|
||||
@ -174,27 +163,24 @@ class SphinxDummyWriter(UnfilteredWriter):
|
||||
|
||||
supported = ('html',) # needed to keep "meta" nodes
|
||||
|
||||
def translate(self):
|
||||
# type: () -> None
|
||||
def translate(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def SphinxDummySourceClass(source, *args, **kwargs):
|
||||
# type: (Any, Any, Any) -> Any
|
||||
def SphinxDummySourceClass(source: Any, *args, **kwargs) -> Any:
|
||||
"""Bypass source object as is to cheat Publisher."""
|
||||
return source
|
||||
|
||||
|
||||
class SphinxFileInput(FileInput):
|
||||
"""A basic FileInput for Sphinx."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
# type: (Any, Any) -> None
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
kwargs['error_handler'] = 'sphinx'
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
def read_doc(app, env, filename):
|
||||
# type: (Sphinx, BuildEnvironment, str) -> nodes.document
|
||||
|
||||
def read_doc(app: "Sphinx", env: BuildEnvironment, filename: str) -> nodes.document:
|
||||
"""Parse a document and convert to doctree."""
|
||||
# set up error_handler for the target document
|
||||
error_handler = UnicodeDecodeErrorHandler(env.docname)
|
||||
|
@ -10,42 +10,37 @@
|
||||
|
||||
from os import path
|
||||
from pprint import pformat
|
||||
from typing import Any, Callable, Iterator, Tuple # NOQA
|
||||
from typing import Any, Callable, Dict, Iterator, List, Tuple, Union
|
||||
|
||||
from jinja2 import FileSystemLoader, BaseLoader, TemplateNotFound, \
|
||||
contextfunction
|
||||
from jinja2 import FileSystemLoader, BaseLoader, TemplateNotFound, contextfunction
|
||||
from jinja2.environment import Environment
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from jinja2.utils import open_if_exists
|
||||
|
||||
from sphinx.application import TemplateBridge
|
||||
from sphinx.theming import Theme
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.osutil import mtimes_of_files
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Dict, List, Union # NOQA
|
||||
from jinja2.environment import Environment # NOQA
|
||||
from sphinx.builders import Builder # NOQA
|
||||
from sphinx.theming import Theme # NOQA
|
||||
from sphinx.builders import Builder
|
||||
|
||||
|
||||
def _tobool(val):
|
||||
# type: (str) -> bool
|
||||
def _tobool(val: str) -> bool:
|
||||
if isinstance(val, str):
|
||||
return val.lower() in ('true', '1', 'yes', 'on')
|
||||
return bool(val)
|
||||
|
||||
|
||||
def _toint(val):
|
||||
# type: (str) -> int
|
||||
def _toint(val: str) -> int:
|
||||
try:
|
||||
return int(val)
|
||||
except ValueError:
|
||||
return 0
|
||||
|
||||
|
||||
def _todim(val):
|
||||
# type: (Union[int, str]) -> str
|
||||
def _todim(val: Union[int, str]) -> str:
|
||||
"""
|
||||
Make val a css dimension. In particular the following transformations
|
||||
are performed:
|
||||
@ -63,8 +58,7 @@ def _todim(val):
|
||||
return val # type: ignore
|
||||
|
||||
|
||||
def _slice_index(values, slices):
|
||||
# type: (List, int) -> Iterator[List]
|
||||
def _slice_index(values: List, slices: int) -> Iterator[List]:
|
||||
seq = list(values)
|
||||
length = 0
|
||||
for value in values:
|
||||
@ -85,8 +79,7 @@ def _slice_index(values, slices):
|
||||
yield seq[start:offset]
|
||||
|
||||
|
||||
def accesskey(context, key):
|
||||
# type: (Any, str) -> str
|
||||
def accesskey(context: Any, key: str) -> str:
|
||||
"""Helper to output each access key only once."""
|
||||
if '_accesskeys' not in context:
|
||||
context.vars['_accesskeys'] = {}
|
||||
@ -97,24 +90,20 @@ def accesskey(context, key):
|
||||
|
||||
|
||||
class idgen:
|
||||
def __init__(self):
|
||||
# type: () -> None
|
||||
def __init__(self) -> None:
|
||||
self.id = 0
|
||||
|
||||
def current(self):
|
||||
# type: () -> int
|
||||
def current(self) -> int:
|
||||
return self.id
|
||||
|
||||
def __next__(self):
|
||||
# type: () -> int
|
||||
def __next__(self) -> int:
|
||||
self.id += 1
|
||||
return self.id
|
||||
next = __next__ # Python 2/Jinja compatibility
|
||||
|
||||
|
||||
@contextfunction
|
||||
def warning(context, message, *args, **kwargs):
|
||||
# type: (Dict, str, Any, Any) -> str
|
||||
def warning(context: Dict, message: str, *args, **kwargs) -> str:
|
||||
if 'pagename' in context:
|
||||
filename = context.get('pagename') + context.get('file_suffix', '')
|
||||
message = 'in rendering %s: %s' % (filename, message)
|
||||
@ -129,8 +118,7 @@ class SphinxFileSystemLoader(FileSystemLoader):
|
||||
template names.
|
||||
"""
|
||||
|
||||
def get_source(self, environment, template):
|
||||
# type: (Environment, str) -> Tuple[str, str, Callable]
|
||||
def get_source(self, environment: Environment, template: str) -> Tuple[str, str, Callable]:
|
||||
for searchpath in self.searchpath:
|
||||
filename = path.join(searchpath, template)
|
||||
f = open_if_exists(filename)
|
||||
@ -141,8 +129,7 @@ class SphinxFileSystemLoader(FileSystemLoader):
|
||||
|
||||
mtime = path.getmtime(filename)
|
||||
|
||||
def uptodate():
|
||||
# type: () -> bool
|
||||
def uptodate() -> bool:
|
||||
try:
|
||||
return path.getmtime(filename) == mtime
|
||||
except OSError:
|
||||
@ -158,8 +145,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
||||
|
||||
# TemplateBridge interface
|
||||
|
||||
def init(self, builder, theme=None, dirs=None):
|
||||
# type: (Builder, Theme, List[str]) -> None
|
||||
def init(self, builder: "Builder", theme: Theme = None, dirs: List[str] = None) -> None:
|
||||
# create a chain of paths to search
|
||||
if theme:
|
||||
# the theme's own dir and its bases' dirs
|
||||
@ -202,22 +188,18 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
||||
if use_i18n:
|
||||
self.environment.install_gettext_translations(builder.app.translator) # type: ignore # NOQA
|
||||
|
||||
def render(self, template, context): # type: ignore
|
||||
# type: (str, Dict) -> str
|
||||
def render(self, template: str, context: Dict) -> str: # type: ignore
|
||||
return self.environment.get_template(template).render(context)
|
||||
|
||||
def render_string(self, source, context):
|
||||
# type: (str, Dict) -> str
|
||||
def render_string(self, source: str, context: Dict) -> str:
|
||||
return self.environment.from_string(source).render(context)
|
||||
|
||||
def newest_template_mtime(self):
|
||||
# type: () -> float
|
||||
def newest_template_mtime(self) -> float:
|
||||
return max(mtimes_of_files(self.pathchain, '.html'))
|
||||
|
||||
# Loader interface
|
||||
|
||||
def get_source(self, environment, template):
|
||||
# type: (Environment, str) -> Tuple[str, str, Callable]
|
||||
def get_source(self, environment: Environment, template: str) -> Tuple[str, str, Callable]:
|
||||
loaders = self.loaders
|
||||
# exclamation mark starts search from theme
|
||||
if template.startswith('!'):
|
||||
|
@ -12,10 +12,9 @@ import gettext
|
||||
import locale
|
||||
from collections import UserString, defaultdict
|
||||
from gettext import NullTranslations
|
||||
from typing import Any, Callable, Dict, Iterable, List, Tuple, Union
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Callable, Dict, Iterable, List, Tuple, Union # NOQA
|
||||
from sphinx.deprecation import RemovedInSphinx30Warning
|
||||
|
||||
|
||||
class _TranslationProxy(UserString):
|
||||
@ -32,32 +31,27 @@ class _TranslationProxy(UserString):
|
||||
"""
|
||||
__slots__ = ('_func', '_args')
|
||||
|
||||
def __new__(cls, func, *args): # type: ignore
|
||||
# type: (Callable, str) -> object
|
||||
def __new__(cls, func: Callable, *args: str) -> object: # type: ignore
|
||||
if not args:
|
||||
# not called with "function" and "arguments", but a plain string
|
||||
return str(func)
|
||||
return object.__new__(cls)
|
||||
|
||||
def __getnewargs__(self):
|
||||
# type: () -> Tuple[str]
|
||||
def __getnewargs__(self) -> Tuple[str]:
|
||||
return (self._func,) + self._args # type: ignore
|
||||
|
||||
def __init__(self, func, *args):
|
||||
# type: (Callable, str) -> None
|
||||
def __init__(self, func: Callable, *args: str) -> None:
|
||||
self._func = func
|
||||
self._args = args
|
||||
|
||||
@property
|
||||
def data(self): # type: ignore
|
||||
# type: () -> str
|
||||
def data(self) -> str: # type: ignore
|
||||
return self._func(*self._args)
|
||||
|
||||
# replace function from UserString; it instantiates a self.__class__
|
||||
# for the encoding result
|
||||
|
||||
def encode(self, encoding=None, errors=None): # type: ignore
|
||||
# type: (str, str) -> bytes
|
||||
def encode(self, encoding: str = None, errors: str = None) -> bytes: # type: ignore
|
||||
if encoding:
|
||||
if errors:
|
||||
return self.data.encode(encoding, errors)
|
||||
@ -66,58 +60,45 @@ class _TranslationProxy(UserString):
|
||||
else:
|
||||
return self.data.encode()
|
||||
|
||||
def __dir__(self):
|
||||
# type: () -> List[str]
|
||||
def __dir__(self) -> List[str]:
|
||||
return dir(str)
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
def __str__(self) -> str:
|
||||
return str(self.data)
|
||||
|
||||
def __add__(self, other): # type: ignore
|
||||
# type: (str) -> str
|
||||
def __add__(self, other: str) -> str: # type: ignore
|
||||
return self.data + other
|
||||
|
||||
def __radd__(self, other):
|
||||
# type: (str) -> str
|
||||
def __radd__(self, other: str) -> str:
|
||||
return other + self.data
|
||||
|
||||
def __mod__(self, other): # type: ignore
|
||||
# type: (str) -> str
|
||||
def __mod__(self, other: str) -> str: # type: ignore
|
||||
return self.data % other
|
||||
|
||||
def __rmod__(self, other):
|
||||
# type: (str) -> str
|
||||
def __rmod__(self, other: str) -> str:
|
||||
return other % self.data
|
||||
|
||||
def __mul__(self, other): # type: ignore
|
||||
# type: (Any) -> str
|
||||
def __mul__(self, other: Any) -> str: # type: ignore
|
||||
return self.data * other
|
||||
|
||||
def __rmul__(self, other):
|
||||
# type: (Any) -> str
|
||||
def __rmul__(self, other: Any) -> str:
|
||||
return other * self.data
|
||||
|
||||
def __getattr__(self, name):
|
||||
# type: (str) -> Any
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
if name == '__members__':
|
||||
return self.__dir__()
|
||||
return getattr(self.data, name)
|
||||
|
||||
def __getstate__(self):
|
||||
# type: () -> Tuple[Callable, Tuple[str, ...]]
|
||||
def __getstate__(self) -> Tuple[Callable, Tuple[str, ...]]:
|
||||
return self._func, self._args
|
||||
|
||||
def __setstate__(self, tup):
|
||||
# type: (Tuple[Callable, Tuple[str]]) -> None
|
||||
def __setstate__(self, tup: Tuple[Callable, Tuple[str]]) -> None:
|
||||
self._func, self._args = tup
|
||||
|
||||
def __copy__(self):
|
||||
# type: () -> _TranslationProxy
|
||||
def __copy__(self) -> "_TranslationProxy":
|
||||
return self
|
||||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
def __repr__(self) -> str:
|
||||
try:
|
||||
return 'i' + repr(str(self.data))
|
||||
except Exception:
|
||||
@ -127,8 +108,8 @@ class _TranslationProxy(UserString):
|
||||
translators = defaultdict(NullTranslations) # type: Dict[Tuple[str, str], NullTranslations]
|
||||
|
||||
|
||||
def init(locale_dirs, language, catalog='sphinx', namespace='general'):
|
||||
# type: (List[str], str, str, str) -> Tuple[NullTranslations, bool]
|
||||
def init(locale_dirs: List[str], language: str,
|
||||
catalog: str = 'sphinx', namespace: str = 'general') -> Tuple[NullTranslations, bool]:
|
||||
"""Look for message catalogs in `locale_dirs` and *ensure* that there is at
|
||||
least a NullTranslations catalog set in `translators`. If called multiple
|
||||
times or if several ``.mo`` files are found, their contents are merged
|
||||
@ -167,8 +148,7 @@ def init(locale_dirs, language, catalog='sphinx', namespace='general'):
|
||||
return translator, has_translation
|
||||
|
||||
|
||||
def setlocale(category, value=None):
|
||||
# type: (int, Union[str, Iterable[str]]) -> None
|
||||
def setlocale(category: int, value: Union[str, Iterable[str]] = None) -> None:
|
||||
"""Update locale settings.
|
||||
|
||||
This does not throw any exception even if update fails.
|
||||
@ -188,8 +168,7 @@ def setlocale(category, value=None):
|
||||
pass
|
||||
|
||||
|
||||
def init_console(locale_dir, catalog):
|
||||
# type: (str, str) -> Tuple[NullTranslations, bool]
|
||||
def init_console(locale_dir: str, catalog: str) -> Tuple[NullTranslations, bool]:
|
||||
"""Initialize locale for console.
|
||||
|
||||
.. versionadded:: 1.8
|
||||
@ -204,18 +183,15 @@ def init_console(locale_dir, catalog):
|
||||
return init([locale_dir], language, catalog, 'console')
|
||||
|
||||
|
||||
def get_translator(catalog='sphinx', namespace='general'):
|
||||
# type: (str, str) -> NullTranslations
|
||||
def get_translator(catalog: str = 'sphinx', namespace: str = 'general') -> NullTranslations:
|
||||
return translators[(namespace, catalog)]
|
||||
|
||||
|
||||
def is_translator_registered(catalog='sphinx', namespace='general'):
|
||||
# type: (str, str) -> bool
|
||||
def is_translator_registered(catalog: str = 'sphinx', namespace: str = 'general') -> bool:
|
||||
return (namespace, catalog) in translators
|
||||
|
||||
|
||||
def _lazy_translate(catalog, namespace, message):
|
||||
# type: (str, str, str) -> str
|
||||
def _lazy_translate(catalog: str, namespace: str, message: str) -> str:
|
||||
"""Used instead of _ when creating TranslationProxy, because _ is
|
||||
not bound yet at that time.
|
||||
"""
|
||||
@ -248,8 +224,7 @@ def get_translation(catalog, namespace='general'):
|
||||
|
||||
.. versionadded:: 1.8
|
||||
"""
|
||||
def gettext(message, *args):
|
||||
# type: (str, *Any) -> str
|
||||
def gettext(message: str, *args) -> str:
|
||||
if not is_translator_registered(catalog, namespace):
|
||||
# not initialized yet
|
||||
return _TranslationProxy(_lazy_translate, catalog, namespace, message) # type: ignore # NOQA
|
||||
|
@ -8,8 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Union
|
||||
|
||||
import docutils.parsers
|
||||
import docutils.parsers.rst
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import states
|
||||
from docutils.statemachine import StringList
|
||||
from docutils.transforms.universal import SmartQuotes
|
||||
@ -18,11 +21,9 @@ from sphinx.util.rst import append_epilog, prepend_prolog
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, List, Union # NOQA
|
||||
from typing import Type # for python3.5.1
|
||||
from docutils import nodes # NOQA
|
||||
from docutils.transforms import Transform # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from typing import Type # NOQA # for python3.5.1
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
class Parser(docutils.parsers.Parser):
|
||||
@ -48,8 +49,7 @@ class Parser(docutils.parsers.Parser):
|
||||
``warn()`` and ``info()`` is deprecated. Use :mod:`sphinx.util.logging` instead.
|
||||
"""
|
||||
|
||||
def set_application(self, app):
|
||||
# type: (Sphinx) -> None
|
||||
def set_application(self, app: "Sphinx") -> None:
|
||||
"""set_application will be called from Sphinx to set app and other instance variables
|
||||
|
||||
:param sphinx.application.Sphinx app: Sphinx application object
|
||||
@ -62,8 +62,7 @@ class Parser(docutils.parsers.Parser):
|
||||
class RSTParser(docutils.parsers.rst.Parser, Parser):
|
||||
"""A reST parser for Sphinx."""
|
||||
|
||||
def get_transforms(self):
|
||||
# type: () -> List[Type[Transform]]
|
||||
def get_transforms(self) -> List["Type[Transform]"]:
|
||||
"""Sphinx's reST parser replaces a transform class for smart-quotes by own's
|
||||
|
||||
refs: sphinx.io.SphinxStandaloneReader
|
||||
@ -72,8 +71,7 @@ class RSTParser(docutils.parsers.rst.Parser, Parser):
|
||||
transforms.remove(SmartQuotes)
|
||||
return transforms
|
||||
|
||||
def parse(self, inputstring, document):
|
||||
# type: (Union[str, StringList], nodes.document) -> None
|
||||
def parse(self, inputstring: Union[str, StringList], document: nodes.document) -> None:
|
||||
"""Parse text and generate a document tree."""
|
||||
self.setup_parse(inputstring, document) # type: ignore
|
||||
self.statemachine = states.RSTStateMachine(
|
||||
@ -95,15 +93,13 @@ class RSTParser(docutils.parsers.rst.Parser, Parser):
|
||||
self.statemachine.run(inputlines, document, inliner=self.inliner)
|
||||
self.finish_parse()
|
||||
|
||||
def decorate(self, content):
|
||||
# type: (StringList) -> None
|
||||
def decorate(self, content: StringList) -> None:
|
||||
"""Preprocess reST content before parsing."""
|
||||
prepend_prolog(content, self.config.rst_prolog)
|
||||
append_epilog(content, self.config.rst_epilog)
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[str, Any]
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
app.add_source_parser(RSTParser)
|
||||
|
||||
return {
|
||||
|
@ -11,36 +11,37 @@
|
||||
import traceback
|
||||
from importlib import import_module
|
||||
from types import MethodType
|
||||
from typing import Any, Callable, Dict, Iterator, List, Tuple, Union
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.io import Input
|
||||
from docutils.nodes import Element, Node, TextElement
|
||||
from docutils.parsers import Parser
|
||||
from docutils.parsers.rst import Directive
|
||||
from docutils.transforms import Transform
|
||||
from pkg_resources import iter_entry_points
|
||||
|
||||
from sphinx.domains import ObjType
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx30Warning
|
||||
from sphinx.domains import Domain, Index, ObjType
|
||||
from sphinx.domains.std import GenericObject, Target
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.errors import ExtensionError, SphinxError, VersionRequirementError
|
||||
from sphinx.extension import Extension
|
||||
from sphinx.io import SphinxFileInput
|
||||
from sphinx.locale import __
|
||||
from sphinx.parsers import Parser as SphinxParser
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.logging import prefixed_warnings
|
||||
from sphinx.util.typing import RoleFunction, TitleGetter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Callable, Dict, Iterator, List, Tuple, Union # NOQA
|
||||
from typing import Type # for python3.5.1
|
||||
from docutils import nodes # NOQA
|
||||
from docutils.io import Input # NOQA
|
||||
from docutils.parsers import Parser # NOQA
|
||||
from docutils.transforms import Transform # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.builders import Builder # NOQA
|
||||
from sphinx.config import Config # NOQA
|
||||
from sphinx.domains import Domain, Index # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
from sphinx.ext.autodoc import Documenter # NOQA
|
||||
from sphinx.io import SphinxFileInput # NOQA
|
||||
from sphinx.util.typing import RoleFunction, TitleGetter # NOQA
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.ext.autodoc import Documenter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -52,8 +53,7 @@ EXTENSION_BLACKLIST = {
|
||||
|
||||
|
||||
class SphinxComponentRegistry:
|
||||
def __init__(self):
|
||||
# type: () -> None
|
||||
def __init__(self) -> None:
|
||||
#: special attrgetter for autodoc; class object -> attrgetter
|
||||
self.autodoc_attrgettrs = {} # type: Dict[Type, Callable[[Any, str, Any], Any]]
|
||||
|
||||
@ -87,7 +87,7 @@ class SphinxComponentRegistry:
|
||||
|
||||
#: additional enumerable nodes
|
||||
#: a dict of node class -> tuple of figtype and title_getter function
|
||||
self.enumerable_nodes = {} # type: Dict[Type[nodes.Node], Tuple[str, TitleGetter]]
|
||||
self.enumerable_nodes = {} # type: Dict[Type[Node], Tuple[str, TitleGetter]]
|
||||
|
||||
#: HTML inline and block math renderers
|
||||
#: a dict of name -> tuple of visit function and depart function
|
||||
@ -122,8 +122,7 @@ class SphinxComponentRegistry:
|
||||
#: additional transforms; list of transforms
|
||||
self.transforms = [] # type: List[Type[Transform]]
|
||||
|
||||
def add_builder(self, builder, override=False):
|
||||
# type: (Type[Builder], bool) -> None
|
||||
def add_builder(self, builder: "Type[Builder]", override: bool = False) -> None:
|
||||
logger.debug('[app] adding builder: %r', builder)
|
||||
if not hasattr(builder, 'name'):
|
||||
raise ExtensionError(__('Builder class %s has no "name" attribute') % builder)
|
||||
@ -132,8 +131,7 @@ class SphinxComponentRegistry:
|
||||
(builder.name, self.builders[builder.name].__module__))
|
||||
self.builders[builder.name] = builder
|
||||
|
||||
def preload_builder(self, app, name):
|
||||
# type: (Sphinx, str) -> None
|
||||
def preload_builder(self, app: "Sphinx", name: str) -> None:
|
||||
if name is None:
|
||||
return
|
||||
|
||||
@ -147,26 +145,22 @@ class SphinxComponentRegistry:
|
||||
|
||||
self.load_extension(app, entry_point.module_name)
|
||||
|
||||
def create_builder(self, app, name):
|
||||
# type: (Sphinx, str) -> Builder
|
||||
def create_builder(self, app: "Sphinx", name: str) -> Builder:
|
||||
if name not in self.builders:
|
||||
raise SphinxError(__('Builder name %s not registered') % name)
|
||||
|
||||
return self.builders[name](app)
|
||||
|
||||
def add_domain(self, domain, override=False):
|
||||
# type: (Type[Domain], bool) -> None
|
||||
def add_domain(self, domain: "Type[Domain]", override: bool = False) -> None:
|
||||
logger.debug('[app] adding domain: %r', domain)
|
||||
if domain.name in self.domains and not override:
|
||||
raise ExtensionError(__('domain %s already registered') % domain.name)
|
||||
self.domains[domain.name] = domain
|
||||
|
||||
def has_domain(self, domain):
|
||||
# type: (str) -> bool
|
||||
def has_domain(self, domain: str) -> bool:
|
||||
return domain in self.domains
|
||||
|
||||
def create_domains(self, env):
|
||||
# type: (BuildEnvironment) -> Iterator[Domain]
|
||||
def create_domains(self, env: BuildEnvironment) -> Iterator[Domain]:
|
||||
for DomainClass in self.domains.values():
|
||||
domain = DomainClass(env)
|
||||
|
||||
@ -179,8 +173,8 @@ class SphinxComponentRegistry:
|
||||
|
||||
yield domain
|
||||
|
||||
def add_directive_to_domain(self, domain, name, cls, override=False):
|
||||
# type: (str, str, Type[Directive], bool) -> None
|
||||
def add_directive_to_domain(self, domain: str, name: str,
|
||||
cls: "Type[Directive]", override: bool = False) -> None:
|
||||
logger.debug('[app] adding directive to domain: %r', (domain, name, cls))
|
||||
if domain not in self.domains:
|
||||
raise ExtensionError(__('domain %s not yet registered') % domain)
|
||||
@ -191,8 +185,9 @@ class SphinxComponentRegistry:
|
||||
(name, domain))
|
||||
directives[name] = cls
|
||||
|
||||
def add_role_to_domain(self, domain, name, role, override=False):
|
||||
# type: (str, str, Union[RoleFunction, XRefRole], bool) -> None
|
||||
def add_role_to_domain(self, domain: str, name: str,
|
||||
role: Union[RoleFunction, XRefRole], override: bool = False
|
||||
) -> None:
|
||||
logger.debug('[app] adding role to domain: %r', (domain, name, role))
|
||||
if domain not in self.domains:
|
||||
raise ExtensionError(__('domain %s not yet registered') % domain)
|
||||
@ -202,8 +197,8 @@ class SphinxComponentRegistry:
|
||||
(name, domain))
|
||||
roles[name] = role
|
||||
|
||||
def add_index_to_domain(self, domain, index, override=False):
|
||||
# type: (str, Type[Index], bool) -> None
|
||||
def add_index_to_domain(self, domain: str, index: "Type[Index]",
|
||||
override: bool = False) -> None:
|
||||
logger.debug('[app] adding index to domain: %r', (domain, index))
|
||||
if domain not in self.domains:
|
||||
raise ExtensionError(__('domain %s not yet registered') % domain)
|
||||
@ -213,10 +208,10 @@ class SphinxComponentRegistry:
|
||||
(index.name, domain))
|
||||
indices.append(index)
|
||||
|
||||
def add_object_type(self, directivename, rolename, indextemplate='',
|
||||
parse_node=None, ref_nodeclass=None, objname='',
|
||||
doc_field_types=[], override=False):
|
||||
# type: (str, str, str, Callable, Type[nodes.TextElement], str, List, bool) -> None
|
||||
def add_object_type(self, directivename: str, rolename: str, indextemplate: str = '',
|
||||
parse_node: Callable = None, ref_nodeclass: "Type[TextElement]" = None,
|
||||
objname: str = '', doc_field_types: List = [], override: bool = False
|
||||
) -> None:
|
||||
logger.debug('[app] adding object type: %r',
|
||||
(directivename, rolename, indextemplate, parse_node,
|
||||
ref_nodeclass, objname, doc_field_types))
|
||||
@ -237,9 +232,9 @@ class SphinxComponentRegistry:
|
||||
directivename)
|
||||
object_types[directivename] = ObjType(objname or directivename, rolename)
|
||||
|
||||
def add_crossref_type(self, directivename, rolename, indextemplate='',
|
||||
ref_nodeclass=None, objname='', override=False):
|
||||
# type: (str, str, str, Type[nodes.TextElement], str, bool) -> None
|
||||
def add_crossref_type(self, directivename: str, rolename: str, indextemplate: str = '',
|
||||
ref_nodeclass: "Type[TextElement]" = None, objname: str = '',
|
||||
override: bool = False) -> None:
|
||||
logger.debug('[app] adding crossref type: %r',
|
||||
(directivename, rolename, indextemplate, ref_nodeclass, objname))
|
||||
|
||||
@ -257,17 +252,16 @@ class SphinxComponentRegistry:
|
||||
directivename)
|
||||
object_types[directivename] = ObjType(objname or directivename, rolename)
|
||||
|
||||
def add_source_suffix(self, suffix, filetype, override=False):
|
||||
# type: (str, str, bool) -> None
|
||||
def add_source_suffix(self, suffix: str, filetype: str, override: bool = False) -> None:
|
||||
logger.debug('[app] adding source_suffix: %r, %r', suffix, filetype)
|
||||
if suffix in self.source_suffix and not override:
|
||||
raise ExtensionError(__('source_suffix %r is already registered') % suffix)
|
||||
else:
|
||||
self.source_suffix[suffix] = filetype
|
||||
|
||||
def add_source_parser(self, parser, **kwargs):
|
||||
# type: (Type[Parser], bool) -> None
|
||||
def add_source_parser(self, parser: "Type[Parser]", **kwargs) -> None:
|
||||
logger.debug('[app] adding search source_parser: %r', parser)
|
||||
|
||||
# create a map from filetype to parser
|
||||
for filetype in parser.supported:
|
||||
if filetype in self.source_parsers and not kwargs.get('override'):
|
||||
@ -276,27 +270,23 @@ class SphinxComponentRegistry:
|
||||
else:
|
||||
self.source_parsers[filetype] = parser
|
||||
|
||||
def get_source_parser(self, filetype):
|
||||
# type: (str) -> Type[Parser]
|
||||
def get_source_parser(self, filetype: str) -> "Type[Parser]":
|
||||
try:
|
||||
return self.source_parsers[filetype]
|
||||
except KeyError:
|
||||
raise SphinxError(__('Source parser for %s not registered') % filetype)
|
||||
|
||||
def get_source_parsers(self):
|
||||
# type: () -> Dict[str, Type[Parser]]
|
||||
def get_source_parsers(self) -> Dict[str, "Type[Parser]"]:
|
||||
return self.source_parsers
|
||||
|
||||
def create_source_parser(self, app, filename):
|
||||
# type: (Sphinx, str) -> Parser
|
||||
def create_source_parser(self, app: "Sphinx", filename: str) -> Parser:
|
||||
parser_class = self.get_source_parser(filename)
|
||||
parser = parser_class()
|
||||
if isinstance(parser, SphinxParser):
|
||||
parser.set_application(app)
|
||||
return parser
|
||||
|
||||
def get_source_input(self, filetype):
|
||||
# type: (str) -> Type[Input]
|
||||
def get_source_input(self, filetype: str) -> "Type[Input]":
|
||||
try:
|
||||
return self.source_inputs[filetype]
|
||||
except KeyError:
|
||||
@ -306,15 +296,14 @@ class SphinxComponentRegistry:
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def add_translator(self, name, translator, override=False):
|
||||
# type: (str, Type[nodes.NodeVisitor], bool) -> None
|
||||
def add_translator(self, name: str, translator: "Type[nodes.NodeVisitor]",
|
||||
override: bool = False) -> None:
|
||||
logger.debug('[app] Change of translator for the %s builder.' % name)
|
||||
if name in self.translators and not override:
|
||||
raise ExtensionError(__('Translator for %r already exists') % name)
|
||||
self.translators[name] = translator
|
||||
|
||||
def add_translation_handlers(self, node, **kwargs):
|
||||
# type: (Type[nodes.Element], Any) -> None
|
||||
def add_translation_handlers(self, node: "Type[Element]", **kwargs) -> None:
|
||||
logger.debug('[app] adding translation_handlers: %r, %r', node, kwargs)
|
||||
for builder_name, handlers in kwargs.items():
|
||||
translation_handlers = self.translation_handlers.setdefault(builder_name, {})
|
||||
@ -325,13 +314,11 @@ class SphinxComponentRegistry:
|
||||
raise ExtensionError(__('kwargs for add_node() must be a (visit, depart) '
|
||||
'function tuple: %r=%r') % builder_name, handlers)
|
||||
|
||||
def get_translator_class(self, builder):
|
||||
# type: (Builder) -> Type[nodes.NodeVisitor]
|
||||
def get_translator_class(self, builder: Builder) -> "Type[nodes.NodeVisitor]":
|
||||
return self.translators.get(builder.name,
|
||||
builder.default_translator_class)
|
||||
|
||||
def create_translator(self, builder, *args):
|
||||
# type: (Builder, Any) -> nodes.NodeVisitor
|
||||
def create_translator(self, builder: Builder, *args) -> nodes.NodeVisitor:
|
||||
translator_class = self.get_translator_class(builder)
|
||||
assert translator_class, "translator not found for %s" % builder.name
|
||||
translator = translator_class(*args)
|
||||
@ -349,54 +336,48 @@ class SphinxComponentRegistry:
|
||||
|
||||
return translator
|
||||
|
||||
def add_transform(self, transform):
|
||||
# type: (Type[Transform]) -> None
|
||||
def add_transform(self, transform: "Type[Transform]") -> None:
|
||||
logger.debug('[app] adding transform: %r', transform)
|
||||
self.transforms.append(transform)
|
||||
|
||||
def get_transforms(self):
|
||||
# type: () -> List[Type[Transform]]
|
||||
def get_transforms(self) -> List["Type[Transform]"]:
|
||||
return self.transforms
|
||||
|
||||
def add_post_transform(self, transform):
|
||||
# type: (Type[Transform]) -> None
|
||||
def add_post_transform(self, transform: "Type[Transform]") -> None:
|
||||
logger.debug('[app] adding post transform: %r', transform)
|
||||
self.post_transforms.append(transform)
|
||||
|
||||
def get_post_transforms(self):
|
||||
# type: () -> List[Type[Transform]]
|
||||
def get_post_transforms(self) -> List["Type[Transform]"]:
|
||||
return self.post_transforms
|
||||
|
||||
def add_documenter(self, objtype, documenter):
|
||||
# type: (str, Type[Documenter]) -> None
|
||||
def add_documenter(self, objtype: str, documenter: "Type[Documenter]") -> None:
|
||||
self.documenters[objtype] = documenter
|
||||
|
||||
def add_autodoc_attrgetter(self, typ, attrgetter):
|
||||
# type: (Type, Callable[[Any, str, Any], Any]) -> None
|
||||
def add_autodoc_attrgetter(self, typ: "Type",
|
||||
attrgetter: Callable[[Any, str, Any], Any]) -> None:
|
||||
self.autodoc_attrgettrs[typ] = attrgetter
|
||||
|
||||
def add_css_files(self, filename, **attributes):
|
||||
self.css_files.append((filename, attributes))
|
||||
|
||||
def add_js_file(self, filename, **attributes):
|
||||
# type: (str, **str) -> None
|
||||
def add_js_file(self, filename: str, **attributes: str) -> None:
|
||||
logger.debug('[app] adding js_file: %r, %r', filename, attributes)
|
||||
self.js_files.append((filename, attributes))
|
||||
|
||||
def add_latex_package(self, name, options):
|
||||
# type: (str, str) -> None
|
||||
def add_latex_package(self, name: str, options: str) -> None:
|
||||
logger.debug('[app] adding latex package: %r', name)
|
||||
self.latex_packages.append((name, options))
|
||||
|
||||
def add_enumerable_node(self, node, figtype, title_getter=None, override=False):
|
||||
# type: (Type[nodes.Node], str, TitleGetter, bool) -> None
|
||||
def add_enumerable_node(self, node: "Type[Node]", figtype: str,
|
||||
title_getter: TitleGetter = None, override: bool = False) -> None:
|
||||
logger.debug('[app] adding enumerable node: (%r, %r, %r)', node, figtype, title_getter)
|
||||
if node in self.enumerable_nodes and not override:
|
||||
raise ExtensionError(__('enumerable_node %r already registered') % node)
|
||||
self.enumerable_nodes[node] = (figtype, title_getter)
|
||||
|
||||
def add_html_math_renderer(self, name, inline_renderers, block_renderers):
|
||||
# type: (str, Tuple[Callable, Callable], Tuple[Callable, Callable]) -> None
|
||||
def add_html_math_renderer(self, name: str,
|
||||
inline_renderers: Tuple[Callable, Callable],
|
||||
block_renderers: Tuple[Callable, Callable]) -> None:
|
||||
logger.debug('[app] adding html_math_renderer: %s, %r, %r',
|
||||
name, inline_renderers, block_renderers)
|
||||
if name in self.html_inline_math_renderers:
|
||||
@ -405,8 +386,7 @@ class SphinxComponentRegistry:
|
||||
self.html_inline_math_renderers[name] = inline_renderers
|
||||
self.html_block_math_renderers[name] = block_renderers
|
||||
|
||||
def load_extension(self, app, extname):
|
||||
# type: (Sphinx, str) -> None
|
||||
def load_extension(self, app: "Sphinx", extname: str) -> None:
|
||||
"""Load a Sphinx extension."""
|
||||
if extname in app.extensions: # alread loaded
|
||||
return
|
||||
@ -451,8 +431,7 @@ class SphinxComponentRegistry:
|
||||
|
||||
app.extensions[extname] = Extension(extname, mod, **metadata)
|
||||
|
||||
def get_envversion(self, app):
|
||||
# type: (Sphinx) -> Dict[str, str]
|
||||
def get_envversion(self, app: "Sphinx") -> Dict[str, str]:
|
||||
from sphinx.environment import ENV_VERSION
|
||||
envversion = {ext.name: ext.metadata['env_version'] for ext in app.extensions.values()
|
||||
if ext.metadata.get('env_version')}
|
||||
@ -460,8 +439,7 @@ class SphinxComponentRegistry:
|
||||
return envversion
|
||||
|
||||
|
||||
def merge_source_suffix(app, config):
|
||||
# type: (Sphinx, Config) -> None
|
||||
def merge_source_suffix(app: "Sphinx", config: Config) -> None:
|
||||
"""Merge source_suffix which specified by user and added by extensions."""
|
||||
for suffix, filetype in app.registry.source_suffix.items():
|
||||
if suffix not in app.config.source_suffix:
|
||||
@ -475,8 +453,7 @@ def merge_source_suffix(app, config):
|
||||
app.registry.source_suffix = app.config.source_suffix
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[str, Any]
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
app.connect('config-inited', merge_source_suffix)
|
||||
|
||||
return {
|
||||
|
117
sphinx/roles.py
117
sphinx/roles.py
@ -10,25 +10,27 @@
|
||||
|
||||
import re
|
||||
import warnings
|
||||
from typing import Any, Dict, List, Tuple
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
from docutils import nodes, utils
|
||||
from docutils.nodes import Element, Node, TextElement, system_message
|
||||
from docutils.parsers.rst.states import Inliner
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.locale import _
|
||||
from sphinx.util import ws_re
|
||||
from sphinx.util.docutils import ReferenceRole, SphinxRole
|
||||
from sphinx.util.nodes import split_explicit_title, process_index_entry, \
|
||||
set_role_source_info
|
||||
from sphinx.util.nodes import (
|
||||
split_explicit_title, process_index_entry, set_role_source_info
|
||||
)
|
||||
from sphinx.util.typing import RoleFunction
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, List, Tuple # NOQA
|
||||
from typing import Type # for python3.5.1
|
||||
from docutils.parsers.rst.states import Inliner # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
from sphinx.util.typing import RoleFunction # NOQA
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
|
||||
generic_docroles = {
|
||||
@ -71,12 +73,12 @@ class XRefRole(ReferenceRole):
|
||||
* Subclassing and overwriting `process_link()` and/or `result_nodes()`.
|
||||
"""
|
||||
|
||||
nodeclass = addnodes.pending_xref # type: Type[nodes.Element]
|
||||
innernodeclass = nodes.literal # type: Type[nodes.TextElement]
|
||||
nodeclass = addnodes.pending_xref # type: Type[Element]
|
||||
innernodeclass = nodes.literal # type: Type[TextElement]
|
||||
|
||||
def __init__(self, fix_parens=False, lowercase=False,
|
||||
nodeclass=None, innernodeclass=None, warn_dangling=False):
|
||||
# type: (bool, bool, Type[nodes.Element], Type[nodes.TextElement], bool) -> None
|
||||
def __init__(self, fix_parens: bool = False, lowercase: bool = False,
|
||||
nodeclass: Type[Element] = None, innernodeclass: Type[TextElement] = None,
|
||||
warn_dangling: bool = False) -> None:
|
||||
self.fix_parens = fix_parens
|
||||
self.lowercase = lowercase
|
||||
self.warn_dangling = warn_dangling
|
||||
@ -87,8 +89,8 @@ class XRefRole(ReferenceRole):
|
||||
|
||||
super().__init__()
|
||||
|
||||
def _fix_parens(self, env, has_explicit_title, title, target):
|
||||
# type: (BuildEnvironment, bool, str, str) -> Tuple[str, str]
|
||||
def _fix_parens(self, env: "BuildEnvironment", has_explicit_title: bool, title: str,
|
||||
target: str) -> Tuple[str, str]:
|
||||
warnings.warn('XRefRole._fix_parens() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
if not has_explicit_title:
|
||||
@ -103,8 +105,7 @@ class XRefRole(ReferenceRole):
|
||||
target = target[:-2]
|
||||
return title, target
|
||||
|
||||
def update_title_and_target(self, title, target):
|
||||
# type: (str, str) -> Tuple[str, str]
|
||||
def update_title_and_target(self, title: str, target: str) -> Tuple[str, str]:
|
||||
if not self.has_explicit_title:
|
||||
if title.endswith('()'):
|
||||
# remove parentheses
|
||||
@ -117,8 +118,7 @@ class XRefRole(ReferenceRole):
|
||||
target = target[:-2]
|
||||
return title, target
|
||||
|
||||
def run(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]]
|
||||
def run(self) -> Tuple[List[Node], List[system_message]]:
|
||||
if ':' not in self.name:
|
||||
self.refdomain, self.reftype = '', self.name
|
||||
self.classes = ['xref', self.reftype]
|
||||
@ -132,8 +132,7 @@ class XRefRole(ReferenceRole):
|
||||
else:
|
||||
return self.create_xref_node()
|
||||
|
||||
def create_non_xref_node(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]]
|
||||
def create_non_xref_node(self) -> Tuple[List[Node], List[system_message]]:
|
||||
text = utils.unescape(self.text[1:])
|
||||
if self.fix_parens:
|
||||
self.has_explicit_title = False # treat as implicit
|
||||
@ -142,8 +141,7 @@ class XRefRole(ReferenceRole):
|
||||
node = self.innernodeclass(self.rawtext, text, classes=self.classes)
|
||||
return self.result_nodes(self.inliner.document, self.env, node, is_ref=False)
|
||||
|
||||
def create_xref_node(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]]
|
||||
def create_xref_node(self) -> Tuple[List[Node], List[system_message]]:
|
||||
target = self.target
|
||||
title = self.title
|
||||
if self.lowercase:
|
||||
@ -170,8 +168,8 @@ class XRefRole(ReferenceRole):
|
||||
|
||||
# methods that can be overwritten
|
||||
|
||||
def process_link(self, env, refnode, has_explicit_title, title, target):
|
||||
# type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str]
|
||||
def process_link(self, env: "BuildEnvironment", refnode: Element, has_explicit_title: bool,
|
||||
title: str, target: str) -> Tuple[str, str]:
|
||||
"""Called after parsing title and target text, and creating the
|
||||
reference node (given in *refnode*). This method can alter the
|
||||
reference node and must return a new (or the same) ``(title, target)``
|
||||
@ -179,8 +177,8 @@ class XRefRole(ReferenceRole):
|
||||
"""
|
||||
return title, ws_re.sub(' ', target)
|
||||
|
||||
def result_nodes(self, document, env, node, is_ref):
|
||||
# type: (nodes.document, BuildEnvironment, nodes.Element, bool) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
|
||||
def result_nodes(self, document: nodes.document, env: "BuildEnvironment", node: Element,
|
||||
is_ref: bool) -> Tuple[List[Node], List[system_message]]:
|
||||
"""Called before returning the finished nodes. *node* is the reference
|
||||
node if one was created (*is_ref* is then true), else the content node.
|
||||
This method can add other nodes and must return a ``(nodes, messages)``
|
||||
@ -190,16 +188,17 @@ class XRefRole(ReferenceRole):
|
||||
|
||||
|
||||
class AnyXRefRole(XRefRole):
|
||||
def process_link(self, env, refnode, has_explicit_title, title, target):
|
||||
# type: (BuildEnvironment, nodes.Element, bool, str, str) -> Tuple[str, str]
|
||||
def process_link(self, env: "BuildEnvironment", refnode: Element, has_explicit_title: bool,
|
||||
title: str, target: str) -> Tuple[str, str]:
|
||||
result = super().process_link(env, refnode, has_explicit_title, title, target)
|
||||
# add all possible context info (i.e. std:program, py:module etc.)
|
||||
refnode.attributes.update(env.ref_context)
|
||||
return result
|
||||
|
||||
|
||||
def indexmarkup_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
# type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
|
||||
def indexmarkup_role(typ: str, rawtext: str, text: str, lineno: int, inliner: Inliner,
|
||||
options: Dict = {}, content: List[str] = []
|
||||
) -> Tuple[List[Node], List[system_message]]:
|
||||
"""Role for PEP/RFC references that generate an index entry."""
|
||||
warnings.warn('indexmarkup_role() is deprecated. Please use PEP or RFC class instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
@ -267,8 +266,7 @@ def indexmarkup_role(typ, rawtext, text, lineno, inliner, options={}, content=[]
|
||||
|
||||
|
||||
class PEP(ReferenceRole):
|
||||
def run(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]]
|
||||
def run(self) -> Tuple[List[Node], List[system_message]]:
|
||||
target_id = 'index-%s' % self.env.new_serialno('index')
|
||||
entries = [('single', _('Python Enhancement Proposals; PEP %s') % self.target,
|
||||
target_id, '', None)]
|
||||
@ -293,8 +291,7 @@ class PEP(ReferenceRole):
|
||||
|
||||
return [index, target, reference], []
|
||||
|
||||
def build_uri(self):
|
||||
# type: () -> str
|
||||
def build_uri(self) -> str:
|
||||
base_url = self.inliner.document.settings.pep_base_url
|
||||
ret = self.target.split('#', 1)
|
||||
if len(ret) == 2:
|
||||
@ -304,8 +301,7 @@ class PEP(ReferenceRole):
|
||||
|
||||
|
||||
class RFC(ReferenceRole):
|
||||
def run(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
|
||||
def run(self) -> Tuple[List[Node], List[system_message]]:
|
||||
target_id = 'index-%s' % self.env.new_serialno('index')
|
||||
entries = [('single', 'RFC; RFC %s' % self.target, target_id, '', None)]
|
||||
|
||||
@ -329,8 +325,7 @@ class RFC(ReferenceRole):
|
||||
|
||||
return [index, target, reference], []
|
||||
|
||||
def build_uri(self):
|
||||
# type: () -> str
|
||||
def build_uri(self) -> str:
|
||||
base_url = self.inliner.document.settings.rfc_base_url
|
||||
ret = self.target.split('#', 1)
|
||||
if len(ret) == 2:
|
||||
@ -342,8 +337,9 @@ class RFC(ReferenceRole):
|
||||
_amp_re = re.compile(r'(?<!&)&(?![&\s])')
|
||||
|
||||
|
||||
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
# type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
|
||||
def menusel_role(typ: str, rawtext: str, text: str, lineno: int, inliner: Inliner,
|
||||
options: Dict = {}, content: List[str] = []
|
||||
) -> Tuple[List[Node], List[system_message]]:
|
||||
warnings.warn('menusel_role() is deprecated. '
|
||||
'Please use MenuSelection or GUILabel class instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
@ -382,8 +378,7 @@ def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
class GUILabel(SphinxRole):
|
||||
amp_re = re.compile(r'(?<!&)&(?![&\s])')
|
||||
|
||||
def run(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]]
|
||||
def run(self) -> Tuple[List[Node], List[system_message]]:
|
||||
node = nodes.inline(rawtext=self.rawtext, classes=[self.name])
|
||||
spans = self.amp_re.split(self.text)
|
||||
node += nodes.Text(spans.pop(0))
|
||||
@ -399,8 +394,7 @@ class GUILabel(SphinxRole):
|
||||
|
||||
|
||||
class MenuSelection(GUILabel):
|
||||
def run(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]]
|
||||
def run(self) -> Tuple[List[Node], List[system_message]]:
|
||||
self.text = self.text.replace('-->', '\N{TRIANGULAR BULLET}')
|
||||
return super().run()
|
||||
|
||||
@ -409,9 +403,9 @@ _litvar_re = re.compile('{([^}]+)}')
|
||||
parens_re = re.compile(r'(\\*{|\\*})')
|
||||
|
||||
|
||||
def emph_literal_role(typ, rawtext, text, lineno, inliner,
|
||||
options={}, content=[]):
|
||||
# type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
|
||||
def emph_literal_role(typ: str, rawtext: str, text: str, lineno: int, inliner: Inliner,
|
||||
options: Dict = {}, content: List[str] = []
|
||||
) -> Tuple[List[Node], List[system_message]]:
|
||||
warnings.warn('emph_literal_role() is deprecated. '
|
||||
'Please use EmphasizedLiteral class instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
@ -465,17 +459,15 @@ def emph_literal_role(typ, rawtext, text, lineno, inliner,
|
||||
class EmphasizedLiteral(SphinxRole):
|
||||
parens_re = re.compile(r'(\\\\|\\{|\\}|{|})')
|
||||
|
||||
def run(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]]
|
||||
def run(self) -> Tuple[List[Node], List[system_message]]:
|
||||
children = self.parse(self.text)
|
||||
node = nodes.literal(self.rawtext, '', *children,
|
||||
role=self.name.lower(), classes=[self.name])
|
||||
|
||||
return [node], []
|
||||
|
||||
def parse(self, text):
|
||||
# type: (str) -> List[nodes.Node]
|
||||
result = [] # type: List[nodes.Node]
|
||||
def parse(self, text: str) -> List[Node]:
|
||||
result = [] # type: List[Node]
|
||||
|
||||
stack = ['']
|
||||
for part in self.parens_re.split(text):
|
||||
@ -517,8 +509,9 @@ class EmphasizedLiteral(SphinxRole):
|
||||
_abbr_re = re.compile(r'\((.*)\)$', re.S)
|
||||
|
||||
|
||||
def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
# type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
|
||||
def abbr_role(typ: str, rawtext: str, text: str, lineno: int, inliner: Inliner,
|
||||
options: Dict = {}, content: List[str] = []
|
||||
) -> Tuple[List[Node], List[system_message]]:
|
||||
warnings.warn('abbr_role() is deprecated. Please use Abbrevation class instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
text = utils.unescape(text)
|
||||
@ -535,8 +528,7 @@ def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
class Abbreviation(SphinxRole):
|
||||
abbr_re = re.compile(r'\((.*)\)$', re.S)
|
||||
|
||||
def run(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]]
|
||||
def run(self) -> Tuple[List[Node], List[system_message]]:
|
||||
matched = self.abbr_re.search(self.text)
|
||||
if matched:
|
||||
text = self.text[:matched.start()].strip()
|
||||
@ -547,8 +539,9 @@ class Abbreviation(SphinxRole):
|
||||
return [nodes.abbreviation(self.rawtext, text, **self.options)], []
|
||||
|
||||
|
||||
def index_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
# type: (str, str, str, int, Inliner, Dict, List[str]) -> Tuple[List[nodes.Node], List[nodes.system_message]] # NOQA
|
||||
def index_role(typ: str, rawtext: str, text: str, lineno: int, inliner: Inliner,
|
||||
options: Dict = {}, content: List[str] = []
|
||||
) -> Tuple[List[Node], List[system_message]]:
|
||||
warnings.warn('index_role() is deprecated. Please use Index class instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
# create new reference target
|
||||
@ -579,8 +572,7 @@ def index_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
|
||||
|
||||
class Index(ReferenceRole):
|
||||
def run(self):
|
||||
# type: () -> Tuple[List[nodes.Node], List[nodes.system_message]]
|
||||
def run(self) -> Tuple[List[Node], List[system_message]]:
|
||||
target_id = 'index-%s' % self.env.new_serialno('index')
|
||||
if self.has_explicit_title:
|
||||
# if an explicit target is given, process it as a full entry
|
||||
@ -619,8 +611,7 @@ specific_docroles = {
|
||||
} # type: Dict[str, RoleFunction]
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[str, Any]
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
from docutils.parsers.rst import roles
|
||||
|
||||
for rolename, nodeclass in generic_docroles.items():
|
||||
|
@ -13,21 +13,21 @@ import re
|
||||
import warnings
|
||||
from importlib import import_module
|
||||
from os import path
|
||||
from typing import Any, Dict, IO, Iterable, List, Tuple, Set
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx import package_dir
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.search.jssplitter import splitter_code
|
||||
from sphinx.util import jsdump, rpartition
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, IO, Iterable, List, Tuple, Set # NOQA
|
||||
from typing import Type # for python3.5.1
|
||||
from docutils import nodes # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
|
||||
|
||||
class SearchLanguage:
|
||||
@ -69,19 +69,16 @@ var Stemmer = function() {
|
||||
|
||||
_word_re = re.compile(r'(?u)\w+')
|
||||
|
||||
def __init__(self, options):
|
||||
# type: (Dict) -> None
|
||||
def __init__(self, options: Dict) -> None:
|
||||
self.options = options
|
||||
self.init(options)
|
||||
|
||||
def init(self, options):
|
||||
# type: (Dict) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
"""
|
||||
Initialize the class with the options the user has given.
|
||||
"""
|
||||
|
||||
def split(self, input):
|
||||
# type: (str) -> List[str]
|
||||
def split(self, input: str) -> List[str]:
|
||||
"""
|
||||
This method splits a sentence into words. Default splitter splits input
|
||||
at white spaces, which should be enough for most languages except CJK
|
||||
@ -89,8 +86,7 @@ var Stemmer = function() {
|
||||
"""
|
||||
return self._word_re.findall(input)
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
"""
|
||||
This method implements stemming algorithm of the Python version.
|
||||
|
||||
@ -103,8 +99,7 @@ var Stemmer = function() {
|
||||
"""
|
||||
return word
|
||||
|
||||
def word_filter(self, word):
|
||||
# type: (str) -> bool
|
||||
def word_filter(self, word: str) -> bool:
|
||||
"""
|
||||
Return true if the target word should be registered in the search index.
|
||||
This method is called after stemming.
|
||||
@ -121,8 +116,7 @@ var Stemmer = function() {
|
||||
from sphinx.search.en import SearchEnglish
|
||||
|
||||
|
||||
def parse_stop_word(source):
|
||||
# type: (str) -> Set[str]
|
||||
def parse_stop_word(source: str) -> Set[str]:
|
||||
"""
|
||||
parse snowball style word list like this:
|
||||
|
||||
@ -166,24 +160,20 @@ class _JavaScriptIndex:
|
||||
PREFIX = 'Search.setIndex('
|
||||
SUFFIX = ')'
|
||||
|
||||
def dumps(self, data):
|
||||
# type: (Any) -> str
|
||||
def dumps(self, data: Any) -> str:
|
||||
return self.PREFIX + jsdump.dumps(data) + self.SUFFIX
|
||||
|
||||
def loads(self, s):
|
||||
# type: (str) -> Any
|
||||
def loads(self, s: str) -> Any:
|
||||
data = s[len(self.PREFIX):-len(self.SUFFIX)]
|
||||
if not data or not s.startswith(self.PREFIX) or not \
|
||||
s.endswith(self.SUFFIX):
|
||||
raise ValueError('invalid data')
|
||||
return jsdump.loads(data)
|
||||
|
||||
def dump(self, data, f):
|
||||
# type: (Any, IO) -> None
|
||||
def dump(self, data: Any, f: IO) -> None:
|
||||
f.write(self.dumps(data))
|
||||
|
||||
def load(self, f):
|
||||
# type: (IO) -> Any
|
||||
def load(self, f: IO) -> Any:
|
||||
return self.loads(f.read())
|
||||
|
||||
|
||||
@ -195,15 +185,13 @@ class WordCollector(nodes.NodeVisitor):
|
||||
A special visitor that collects words for the `IndexBuilder`.
|
||||
"""
|
||||
|
||||
def __init__(self, document, lang):
|
||||
# type: (nodes.document, SearchLanguage) -> None
|
||||
def __init__(self, document: nodes.document, lang: SearchLanguage) -> None:
|
||||
super().__init__(document)
|
||||
self.found_words = [] # type: List[str]
|
||||
self.found_title_words = [] # type: List[str]
|
||||
self.lang = lang
|
||||
|
||||
def is_meta_keywords(self, node, nodetype=None):
|
||||
# type: (addnodes.meta, Any) -> bool
|
||||
def is_meta_keywords(self, node: addnodes.meta, nodetype: Any = None) -> bool:
|
||||
if nodetype is not None:
|
||||
warnings.warn('"nodetype" argument for WordCollector.is_meta_keywords() '
|
||||
'is deprecated.', RemovedInSphinx40Warning)
|
||||
@ -217,8 +205,7 @@ class WordCollector(nodes.NodeVisitor):
|
||||
|
||||
return False
|
||||
|
||||
def dispatch_visit(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
def dispatch_visit(self, node: Node) -> None:
|
||||
if isinstance(node, nodes.comment):
|
||||
raise nodes.SkipNode
|
||||
elif isinstance(node, nodes.raw):
|
||||
@ -251,8 +238,7 @@ class IndexBuilder:
|
||||
'pickle': pickle
|
||||
}
|
||||
|
||||
def __init__(self, env, lang, options, scoring):
|
||||
# type: (BuildEnvironment, str, Dict, str) -> None
|
||||
def __init__(self, env: BuildEnvironment, lang: str, options: Dict, scoring: str) -> None:
|
||||
self.env = env
|
||||
self._titles = {} # type: Dict[str, str]
|
||||
# docname -> title
|
||||
@ -292,8 +278,7 @@ class IndexBuilder:
|
||||
self.js_scorer_code = ''
|
||||
self.js_splitter_code = splitter_code
|
||||
|
||||
def load(self, stream, format):
|
||||
# type: (IO, Any) -> None
|
||||
def load(self, stream: IO, format: Any) -> None:
|
||||
"""Reconstruct from frozen data."""
|
||||
if isinstance(format, str):
|
||||
format = self.formats[format]
|
||||
@ -306,8 +291,7 @@ class IndexBuilder:
|
||||
self._filenames = dict(zip(index2fn, frozen['filenames']))
|
||||
self._titles = dict(zip(index2fn, frozen['titles']))
|
||||
|
||||
def load_terms(mapping):
|
||||
# type: (Dict[str, Any]) -> Dict[str, Set[str]]
|
||||
def load_terms(mapping: Dict[str, Any]) -> Dict[str, Set[str]]:
|
||||
rv = {}
|
||||
for k, v in mapping.items():
|
||||
if isinstance(v, int):
|
||||
@ -320,15 +304,14 @@ class IndexBuilder:
|
||||
self._title_mapping = load_terms(frozen['titleterms'])
|
||||
# no need to load keywords/objtypes
|
||||
|
||||
def dump(self, stream, format):
|
||||
# type: (IO, Any) -> None
|
||||
def dump(self, stream: IO, format: Any) -> None:
|
||||
"""Dump the frozen index to a stream."""
|
||||
if isinstance(format, str):
|
||||
format = self.formats[format]
|
||||
format.dump(self.freeze(), stream)
|
||||
|
||||
def get_objects(self, fn2index):
|
||||
# type: (Dict[str, int]) -> Dict[str, Dict[str, Tuple[int, int, int, str]]]
|
||||
def get_objects(self, fn2index: Dict[str, int]
|
||||
) -> Dict[str, Dict[str, Tuple[int, int, int, str]]]:
|
||||
rv = {} # type: Dict[str, Dict[str, Tuple[int, int, int, str]]]
|
||||
otypes = self._objtypes
|
||||
onames = self._objnames
|
||||
@ -364,8 +347,7 @@ class IndexBuilder:
|
||||
pdict[name] = (fn2index[docname], typeindex, prio, shortanchor)
|
||||
return rv
|
||||
|
||||
def get_terms(self, fn2index):
|
||||
# type: (Dict) -> Tuple[Dict[str, List[str]], Dict[str, List[str]]]
|
||||
def get_terms(self, fn2index: Dict) -> Tuple[Dict[str, List[str]], Dict[str, List[str]]]:
|
||||
rvs = {}, {} # type: Tuple[Dict[str, List[str]], Dict[str, List[str]]]
|
||||
for rv, mapping in zip(rvs, (self._mapping, self._title_mapping)):
|
||||
for k, v in mapping.items():
|
||||
@ -377,8 +359,7 @@ class IndexBuilder:
|
||||
rv[k] = sorted([fn2index[fn] for fn in v if fn in fn2index])
|
||||
return rvs
|
||||
|
||||
def freeze(self):
|
||||
# type: () -> Dict[str, Any]
|
||||
def freeze(self) -> Dict[str, Any]:
|
||||
"""Create a usable data structure for serializing."""
|
||||
docnames, titles = zip(*sorted(self._titles.items()))
|
||||
filenames = [self._filenames.get(docname) for docname in docnames]
|
||||
@ -392,12 +373,10 @@ class IndexBuilder:
|
||||
objects=objects, objtypes=objtypes, objnames=objnames,
|
||||
titleterms=title_terms, envversion=self.env.version)
|
||||
|
||||
def label(self):
|
||||
# type: () -> str
|
||||
def label(self) -> str:
|
||||
return "%s (code: %s)" % (self.lang.language_name, self.lang.lang)
|
||||
|
||||
def prune(self, docnames):
|
||||
# type: (Iterable[str]) -> None
|
||||
def prune(self, docnames: Iterable[str]) -> None:
|
||||
"""Remove data for all docnames not in the list."""
|
||||
new_titles = {}
|
||||
new_filenames = {}
|
||||
@ -412,8 +391,7 @@ class IndexBuilder:
|
||||
for wordnames in self._title_mapping.values():
|
||||
wordnames.intersection_update(docnames)
|
||||
|
||||
def feed(self, docname, filename, title, doctree):
|
||||
# type: (str, str, str, nodes.document) -> None
|
||||
def feed(self, docname: str, filename: str, title: str, doctree: nodes.document) -> None:
|
||||
"""Feed a doctree to the index."""
|
||||
self._titles[docname] = title
|
||||
self._filenames[docname] = filename
|
||||
@ -422,8 +400,7 @@ class IndexBuilder:
|
||||
doctree.walk(visitor)
|
||||
|
||||
# memoize self.lang.stem
|
||||
def stem(word):
|
||||
# type: (str) -> str
|
||||
def stem(word: str) -> str:
|
||||
try:
|
||||
return self._stem_cache[word]
|
||||
except KeyError:
|
||||
@ -447,8 +424,7 @@ class IndexBuilder:
|
||||
if _filter(stemmed_word) and not already_indexed:
|
||||
self._mapping.setdefault(stemmed_word, set()).add(docname)
|
||||
|
||||
def context_for_searchtool(self):
|
||||
# type: () -> Dict[str, Any]
|
||||
def context_for_searchtool(self) -> Dict[str, Any]:
|
||||
return {
|
||||
'search_language_stemming_code': self.lang.js_stemmer_code,
|
||||
'search_language_stop_words': jsdump.dumps(sorted(self.lang.stopwords)),
|
||||
@ -456,8 +432,7 @@ class IndexBuilder:
|
||||
'search_word_splitter_code': self.js_splitter_code,
|
||||
}
|
||||
|
||||
def get_js_stemmer_rawcode(self):
|
||||
# type: () -> str
|
||||
def get_js_stemmer_rawcode(self) -> str:
|
||||
if self.lang.js_stemmer_rawcode:
|
||||
return path.join(package_dir, 'search', 'non-minified-js',
|
||||
self.lang.js_stemmer_rawcode)
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
danish_stopwords = parse_stop_word('''
|
||||
@ -128,10 +126,8 @@ class SearchDanish(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = danish_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('danish')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
german_stopwords = parse_stop_word('''
|
||||
@ -311,10 +309,8 @@ class SearchGerman(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = german_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('german')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from typing import Dict
|
||||
|
||||
from sphinx.search import SearchLanguage
|
||||
from sphinx.util.stemmer import get_stemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Dict # NOQA
|
||||
|
||||
english_stopwords = set("""
|
||||
a and are as at
|
||||
be but by
|
||||
@ -220,10 +218,8 @@ class SearchEnglish(SearchLanguage):
|
||||
js_stemmer_code = js_porter_stemmer
|
||||
stopwords = english_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Dict) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = get_stemmer()
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stem(word.lower())
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
spanish_stopwords = parse_stop_word('''
|
||||
@ -371,10 +369,8 @@ class SearchSpanish(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = spanish_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('spanish')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
finnish_stopwords = parse_stop_word('''
|
||||
@ -121,10 +119,8 @@ class SearchFinnish(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = finnish_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('finnish')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
french_stopwords = parse_stop_word('''
|
||||
@ -207,10 +205,8 @@ class SearchFrench(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = french_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('french')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
hungarian_stopwords = parse_stop_word('''
|
||||
@ -235,10 +233,8 @@ class SearchHungarian(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = hungarian_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('hungarian')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
italian_stopwords = parse_stop_word('''
|
||||
@ -324,10 +322,8 @@ class SearchItalian(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = italian_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('italian')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -19,6 +19,7 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from typing import Any, Dict, List
|
||||
|
||||
try:
|
||||
import MeCab
|
||||
@ -36,21 +37,13 @@ from sphinx.errors import SphinxError, ExtensionError
|
||||
from sphinx.search import SearchLanguage
|
||||
from sphinx.util import import_object
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, List # NOQA
|
||||
|
||||
|
||||
class BaseSplitter:
|
||||
|
||||
def __init__(self, options):
|
||||
# type: (Dict) -> None
|
||||
def __init__(self, options: Dict) -> None:
|
||||
self.options = options
|
||||
|
||||
def split(self, input):
|
||||
# type: (str) -> List[str]
|
||||
def split(self, input: str) -> List[str]:
|
||||
"""
|
||||
|
||||
:param str input:
|
||||
:return:
|
||||
:rtype: list[str]
|
||||
@ -59,8 +52,7 @@ class BaseSplitter:
|
||||
|
||||
|
||||
class MecabSplitter(BaseSplitter):
|
||||
def __init__(self, options):
|
||||
# type: (Dict) -> None
|
||||
def __init__(self, options: Dict) -> None:
|
||||
super().__init__(options)
|
||||
self.ctypes_libmecab = None # type: Any
|
||||
self.ctypes_mecab = None # type: Any
|
||||
@ -70,8 +62,7 @@ class MecabSplitter(BaseSplitter):
|
||||
self.init_native(options)
|
||||
self.dict_encode = options.get('dic_enc', 'utf-8')
|
||||
|
||||
def split(self, input):
|
||||
# type: (str) -> List[str]
|
||||
def split(self, input: str) -> List[str]:
|
||||
if native_module:
|
||||
result = self.native.parse(input)
|
||||
else:
|
||||
@ -79,16 +70,14 @@ class MecabSplitter(BaseSplitter):
|
||||
self.ctypes_mecab, input.encode(self.dict_encode))
|
||||
return result.split(' ')
|
||||
|
||||
def init_native(self, options):
|
||||
# type: (Dict) -> None
|
||||
def init_native(self, options: Dict) -> None:
|
||||
param = '-Owakati'
|
||||
dict = options.get('dict')
|
||||
if dict:
|
||||
param += ' -d %s' % dict
|
||||
self.native = MeCab.Tagger(param)
|
||||
|
||||
def init_ctypes(self, options):
|
||||
# type: (Dict) -> None
|
||||
def init_ctypes(self, options: Dict) -> None:
|
||||
import ctypes.util
|
||||
|
||||
lib = options.get('lib')
|
||||
@ -124,8 +113,7 @@ class MecabSplitter(BaseSplitter):
|
||||
if self.ctypes_mecab is None:
|
||||
raise SphinxError('mecab initialization failed')
|
||||
|
||||
def __del__(self):
|
||||
# type: () -> None
|
||||
def __del__(self) -> None:
|
||||
if self.ctypes_libmecab:
|
||||
self.ctypes_libmecab.mecab_destroy(self.ctypes_mecab)
|
||||
|
||||
@ -133,21 +121,18 @@ MeCabBinder = MecabSplitter # keep backward compatibility until Sphinx-1.6
|
||||
|
||||
|
||||
class JanomeSplitter(BaseSplitter):
|
||||
def __init__(self, options):
|
||||
# type: (Dict) -> None
|
||||
def __init__(self, options: Dict) -> None:
|
||||
super().__init__(options)
|
||||
self.user_dict = options.get('user_dic')
|
||||
self.user_dict_enc = options.get('user_dic_enc', 'utf8')
|
||||
self.init_tokenizer()
|
||||
|
||||
def init_tokenizer(self):
|
||||
# type: () -> None
|
||||
def init_tokenizer(self) -> None:
|
||||
if not janome_module:
|
||||
raise RuntimeError('Janome is not available')
|
||||
self.tokenizer = janome.tokenizer.Tokenizer(udic=self.user_dict, udic_enc=self.user_dict_enc)
|
||||
|
||||
def split(self, input):
|
||||
# type: (str) -> List[str]
|
||||
def split(self, input: str) -> List[str]:
|
||||
result = ' '.join(token.surface for token in self.tokenizer.tokenize(input))
|
||||
return result.split(' ')
|
||||
|
||||
@ -423,23 +408,20 @@ class DefaultSplitter(BaseSplitter):
|
||||
'郎': 1082, '1': -270, 'E1': 306, 'ル': -673, 'ン': -496}
|
||||
|
||||
# ctype_
|
||||
def ctype_(self, char):
|
||||
# type: (str) -> str
|
||||
def ctype_(self, char: str) -> str:
|
||||
for pattern, value in self.patterns_.items():
|
||||
if pattern.match(char):
|
||||
return value
|
||||
return 'O'
|
||||
|
||||
# ts_
|
||||
def ts_(self, dict, key):
|
||||
# type: (Dict[str, int], str) -> int
|
||||
def ts_(self, dict: Dict[str, int], key: str) -> int:
|
||||
if key in dict:
|
||||
return dict[key]
|
||||
return 0
|
||||
|
||||
# segment
|
||||
def split(self, input):
|
||||
# type: (str) -> List[str]
|
||||
def split(self, input: str) -> List[str]:
|
||||
if not input:
|
||||
return []
|
||||
|
||||
@ -542,8 +524,7 @@ class SearchJapanese(SearchLanguage):
|
||||
lang = 'ja'
|
||||
language_name = 'Japanese'
|
||||
|
||||
def init(self, options):
|
||||
# type: (Dict) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
dotted_path = options.get('type', 'sphinx.search.ja.DefaultSplitter')
|
||||
try:
|
||||
self.splitter = import_object(dotted_path)(options)
|
||||
@ -551,14 +532,11 @@ class SearchJapanese(SearchLanguage):
|
||||
raise ExtensionError("Splitter module %r can't be imported" %
|
||||
dotted_path)
|
||||
|
||||
def split(self, input):
|
||||
# type: (str) -> List[str]
|
||||
def split(self, input: str) -> List[str]:
|
||||
return self.splitter.split(input)
|
||||
|
||||
def word_filter(self, stemmed_word):
|
||||
# type: (str) -> bool
|
||||
def word_filter(self, stemmed_word: str) -> bool:
|
||||
return len(stemmed_word) > 1
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return word
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
dutch_stopwords = parse_stop_word('''
|
||||
@ -135,10 +133,8 @@ class SearchDutch(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = dutch_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('dutch')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
norwegian_stopwords = parse_stop_word('''
|
||||
@ -210,10 +208,8 @@ class SearchNorwegian(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = norwegian_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('norwegian')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
portuguese_stopwords = parse_stop_word('''
|
||||
@ -270,10 +268,8 @@ class SearchPortuguese(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = portuguese_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('portuguese')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
File diff suppressed because one or more lines are too long
@ -8,13 +8,11 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
russian_stopwords = parse_stop_word('''
|
||||
@ -259,10 +257,8 @@ class SearchRussian(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = russian_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('russian')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -8,13 +8,12 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
from typing import Dict
|
||||
|
||||
import snowballstemmer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any
|
||||
from sphinx.search import SearchLanguage, parse_stop_word
|
||||
|
||||
|
||||
swedish_stopwords = parse_stop_word('''
|
||||
| source: http://snowball.tartarus.org/algorithms/swedish/stop.txt
|
||||
@ -147,10 +146,8 @@ class SearchSwedish(SearchLanguage):
|
||||
js_stemmer_code = js_stemmer
|
||||
stopwords = swedish_stopwords
|
||||
|
||||
def init(self, options):
|
||||
# type: (Any) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
self.stemmer = snowballstemmer.stemmer('swedish')
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
def stem(self, word: str) -> str:
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
File diff suppressed because one or more lines are too long
@ -10,6 +10,7 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
from typing import Dict, List
|
||||
|
||||
from sphinx.search import SearchLanguage
|
||||
from sphinx.util.stemmer import get_stemmer
|
||||
@ -20,10 +21,6 @@ try:
|
||||
except ImportError:
|
||||
JIEBA = False
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Dict, List # NOQA
|
||||
|
||||
english_stopwords = set("""
|
||||
a and are as at
|
||||
be but by
|
||||
@ -235,8 +232,7 @@ class SearchChinese(SearchLanguage):
|
||||
latin1_letters = re.compile(r'[a-zA-Z0-9_]+')
|
||||
latin_terms = [] # type: List[str]
|
||||
|
||||
def init(self, options):
|
||||
# type: (Dict) -> None
|
||||
def init(self, options: Dict) -> None:
|
||||
if JIEBA:
|
||||
dict_path = options.get('dict')
|
||||
if dict_path and os.path.isfile(dict_path):
|
||||
@ -244,8 +240,7 @@ class SearchChinese(SearchLanguage):
|
||||
|
||||
self.stemmer = get_stemmer()
|
||||
|
||||
def split(self, input):
|
||||
# type: (str) -> List[str]
|
||||
def split(self, input: str) -> List[str]:
|
||||
chinese = [] # type: List[str]
|
||||
if JIEBA:
|
||||
chinese = list(jieba.cut_for_search(input))
|
||||
@ -255,13 +250,10 @@ class SearchChinese(SearchLanguage):
|
||||
self.latin_terms.extend(latin1)
|
||||
return chinese + latin1
|
||||
|
||||
def word_filter(self, stemmed_word):
|
||||
# type: (str) -> bool
|
||||
def word_filter(self, stemmed_word: str) -> bool:
|
||||
return len(stemmed_word) > 1
|
||||
|
||||
def stem(self, word):
|
||||
# type: (str) -> str
|
||||
|
||||
def stem(self, word: str) -> str:
|
||||
# Don't stem Latin words that are long enough to be relevant for search
|
||||
# if not stemmed, but would be too short after being stemmed
|
||||
# avoids some issues with acronyms
|
||||
|
@ -13,6 +13,7 @@ import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from os import path
|
||||
from typing import Any, Dict, List
|
||||
from zipfile import ZipFile
|
||||
|
||||
import pkg_resources
|
||||
@ -23,19 +24,18 @@ from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.osutil import ensuredir
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, List # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
NODEFAULT = object()
|
||||
THEMECONF = 'theme.conf'
|
||||
|
||||
|
||||
def extract_zip(filename, targetdir):
|
||||
# type: (str, str) -> None
|
||||
def extract_zip(filename: str, targetdir: str) -> None:
|
||||
"""Extract zip file to target directory."""
|
||||
ensuredir(targetdir)
|
||||
|
||||
@ -54,8 +54,7 @@ class Theme:
|
||||
|
||||
This class supports both theme directory and theme archive (zipped theme)."""
|
||||
|
||||
def __init__(self, name, theme_path, factory):
|
||||
# type: (str, str, HTMLThemeFactory) -> None
|
||||
def __init__(self, name: str, theme_path: str, factory: "HTMLThemeFactory") -> None:
|
||||
self.name = name
|
||||
self.base = None
|
||||
self.rootdir = None
|
||||
@ -87,8 +86,7 @@ class Theme:
|
||||
raise ThemeError(__('no theme named %r found, inherited by %r') %
|
||||
(inherit, name))
|
||||
|
||||
def get_theme_dirs(self):
|
||||
# type: () -> List[str]
|
||||
def get_theme_dirs(self) -> List[str]:
|
||||
"""Return a list of theme directories, beginning with this theme's,
|
||||
then the base theme's, then that one's base theme's, etc.
|
||||
"""
|
||||
@ -97,8 +95,7 @@ class Theme:
|
||||
else:
|
||||
return [self.themedir] + self.base.get_theme_dirs()
|
||||
|
||||
def get_config(self, section, name, default=NODEFAULT):
|
||||
# type: (str, str, Any) -> Any
|
||||
def get_config(self, section: str, name: str, default: Any = NODEFAULT) -> Any:
|
||||
"""Return the value for a theme configuration setting, searching the
|
||||
base theme chain.
|
||||
"""
|
||||
@ -114,8 +111,7 @@ class Theme:
|
||||
else:
|
||||
return default
|
||||
|
||||
def get_options(self, overrides={}):
|
||||
# type: (Dict[str, Any]) -> Dict[str, Any]
|
||||
def get_options(self, overrides: Dict[str, Any] = {}) -> Dict[str, Any]:
|
||||
"""Return a dictionary of theme options and their values."""
|
||||
if self.base:
|
||||
options = self.base.get_options()
|
||||
@ -135,8 +131,7 @@ class Theme:
|
||||
|
||||
return options
|
||||
|
||||
def cleanup(self):
|
||||
# type: () -> None
|
||||
def cleanup(self) -> None:
|
||||
"""Remove temporary directories."""
|
||||
if self.rootdir:
|
||||
try:
|
||||
@ -147,8 +142,7 @@ class Theme:
|
||||
self.base.cleanup()
|
||||
|
||||
|
||||
def is_archived_theme(filename):
|
||||
# type: (str) -> bool
|
||||
def is_archived_theme(filename: str) -> bool:
|
||||
"""Check the specified file is an archived theme file or not."""
|
||||
try:
|
||||
with ZipFile(filename) as f:
|
||||
@ -160,23 +154,20 @@ def is_archived_theme(filename):
|
||||
class HTMLThemeFactory:
|
||||
"""A factory class for HTML Themes."""
|
||||
|
||||
def __init__(self, app):
|
||||
# type: (Sphinx) -> None
|
||||
def __init__(self, app: "Sphinx") -> None:
|
||||
self.app = app
|
||||
self.themes = app.html_themes
|
||||
self.load_builtin_themes()
|
||||
if getattr(app.config, 'html_theme_path', None):
|
||||
self.load_additional_themes(app.config.html_theme_path)
|
||||
|
||||
def load_builtin_themes(self):
|
||||
# type: () -> None
|
||||
def load_builtin_themes(self) -> None:
|
||||
"""Load built-in themes."""
|
||||
themes = self.find_themes(path.join(package_dir, 'themes'))
|
||||
for name, theme in themes.items():
|
||||
self.themes[name] = theme
|
||||
|
||||
def load_additional_themes(self, theme_paths):
|
||||
# type: (str) -> None
|
||||
def load_additional_themes(self, theme_paths: str) -> None:
|
||||
"""Load additional themes placed at specified directories."""
|
||||
for theme_path in theme_paths:
|
||||
abs_theme_path = path.abspath(path.join(self.app.confdir, theme_path))
|
||||
@ -184,8 +175,7 @@ class HTMLThemeFactory:
|
||||
for name, theme in themes.items():
|
||||
self.themes[name] = theme
|
||||
|
||||
def load_extra_theme(self, name):
|
||||
# type: (str) -> None
|
||||
def load_extra_theme(self, name: str) -> None:
|
||||
"""Try to load a theme having specifed name."""
|
||||
if name == 'alabaster':
|
||||
self.load_alabaster_theme()
|
||||
@ -194,14 +184,12 @@ class HTMLThemeFactory:
|
||||
else:
|
||||
self.load_external_theme(name)
|
||||
|
||||
def load_alabaster_theme(self):
|
||||
# type: () -> None
|
||||
def load_alabaster_theme(self) -> None:
|
||||
"""Load alabaster theme."""
|
||||
import alabaster
|
||||
self.themes['alabaster'] = path.join(alabaster.get_path(), 'alabaster')
|
||||
|
||||
def load_sphinx_rtd_theme(self):
|
||||
# type: () -> None
|
||||
def load_sphinx_rtd_theme(self) -> None:
|
||||
"""Load sphinx_rtd_theme theme (if exists)."""
|
||||
try:
|
||||
import sphinx_rtd_theme
|
||||
@ -210,8 +198,7 @@ class HTMLThemeFactory:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def load_external_theme(self, name):
|
||||
# type: (str) -> None
|
||||
def load_external_theme(self, name: str) -> None:
|
||||
"""Try to load a theme using entry_points.
|
||||
|
||||
Sphinx refers to ``sphinx_themes`` entry_points.
|
||||
@ -225,8 +212,7 @@ class HTMLThemeFactory:
|
||||
except StopIteration:
|
||||
pass
|
||||
|
||||
def find_themes(self, theme_path):
|
||||
# type: (str) -> Dict[str, str]
|
||||
def find_themes(self, theme_path: str) -> Dict[str, str]:
|
||||
"""Search themes from specified directory."""
|
||||
themes = {} # type: Dict[str, str]
|
||||
if not path.isdir(theme_path):
|
||||
@ -247,8 +233,7 @@ class HTMLThemeFactory:
|
||||
|
||||
return themes
|
||||
|
||||
def create(self, name):
|
||||
# type: (str) -> Theme
|
||||
def create(self, name: str) -> Theme:
|
||||
"""Create an instance of theme."""
|
||||
if name not in self.themes:
|
||||
self.load_extra_theme(name)
|
||||
|
@ -273,8 +273,7 @@ class DoctestTransform(SphinxTransform):
|
||||
"""Set "doctest" style to each doctest_block node"""
|
||||
default_priority = 500
|
||||
|
||||
def apply(self, **kwargs):
|
||||
# type: (Any) -> None
|
||||
def apply(self, **kwargs) -> None:
|
||||
for node in self.document.traverse(nodes.doctest_block):
|
||||
node['classes'].append('doctest')
|
||||
|
||||
|
@ -119,8 +119,7 @@ def get_matching_docs(dirname: str, suffixes: List[str],
|
||||
break
|
||||
|
||||
|
||||
def get_filetype(source_suffix, filename):
|
||||
# type: (Dict[str, str], str) -> str
|
||||
def get_filetype(source_suffix: Dict[str, str], filename: str) -> str:
|
||||
for suffix, filetype in source_suffix.items():
|
||||
if filename.endswith(suffix):
|
||||
# If default filetype (None), considered as restructuredtext.
|
||||
|
@ -12,15 +12,17 @@ import pickle
|
||||
from itertools import product, zip_longest
|
||||
from operator import itemgetter
|
||||
from os import path
|
||||
from typing import Any, Dict, Iterator
|
||||
from uuid import uuid4
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
|
||||
from sphinx.transforms import SphinxTransform
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, Iterator # NOQA
|
||||
from docutils import nodes # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
try:
|
||||
import Levenshtein
|
||||
@ -32,8 +34,7 @@ except ImportError:
|
||||
VERSIONING_RATIO = 65
|
||||
|
||||
|
||||
def add_uids(doctree, condition):
|
||||
# type: (nodes.Node, Any) -> Iterator[nodes.Node]
|
||||
def add_uids(doctree: Node, condition: Any) -> Iterator[Node]:
|
||||
"""Add a unique id to every node in the `doctree` which matches the
|
||||
condition and yield the nodes.
|
||||
|
||||
@ -48,8 +49,7 @@ def add_uids(doctree, condition):
|
||||
yield node
|
||||
|
||||
|
||||
def merge_doctrees(old, new, condition):
|
||||
# type: (nodes.Node, nodes.Node, Any) -> Iterator[nodes.Node]
|
||||
def merge_doctrees(old: Node, new: Node, condition: Any) -> Iterator[Node]:
|
||||
"""Merge the `old` doctree with the `new` one while looking at nodes
|
||||
matching the `condition`.
|
||||
|
||||
@ -116,8 +116,7 @@ def merge_doctrees(old, new, condition):
|
||||
yield new_node
|
||||
|
||||
|
||||
def get_ratio(old, new):
|
||||
# type: (str, str) -> float
|
||||
def get_ratio(old: str, new: str) -> float:
|
||||
"""Return a "similiarity ratio" (in percent) representing the similarity
|
||||
between the two strings where 0 is equal and anything above less than equal.
|
||||
"""
|
||||
@ -130,8 +129,7 @@ def get_ratio(old, new):
|
||||
return levenshtein_distance(old, new) / (len(old) / 100.0)
|
||||
|
||||
|
||||
def levenshtein_distance(a, b):
|
||||
# type: (str, str) -> int
|
||||
def levenshtein_distance(a: str, b: str) -> int:
|
||||
"""Return the Levenshtein edit distance between two strings *a* and *b*."""
|
||||
if a == b:
|
||||
return 0
|
||||
@ -155,8 +153,7 @@ class UIDTransform(SphinxTransform):
|
||||
"""Add UIDs to doctree for versioning."""
|
||||
default_priority = 880
|
||||
|
||||
def apply(self, **kwargs):
|
||||
# type: (Any) -> None
|
||||
def apply(self, **kwargs) -> None:
|
||||
env = self.env
|
||||
old_doctree = None
|
||||
if not env.versioning_condition:
|
||||
@ -178,8 +175,7 @@ class UIDTransform(SphinxTransform):
|
||||
list(merge_doctrees(old_doctree, self.document, env.versioning_condition))
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[str, Any]
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
app.add_transform(UIDTransform)
|
||||
|
||||
return {
|
||||
|
Loading…
Reference in New Issue
Block a user