summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2016-11-08 14:05:58 +0900
committerTakeshi KOMIYA <i.tkomiya@gmail.com>2016-11-16 12:06:22 +0900
commitceec82451bfbefc0fd720bbf48e4b9a029cacd99 (patch)
tree1d76b5d59db131fb574cd649e0c283534fd6710f
parent3407ef0ca8a8ce41e67092d2605f8fc77bebb982 (diff)
downloadsphinx-git-ceec82451bfbefc0fd720bbf48e4b9a029cacd99.tar.gz
Add type-check annotations to sphinx.*
-rw-r--r--sphinx/__init__.py2
-rw-r--r--sphinx/apidoc.py24
-rw-r--r--sphinx/cmdline.py25
-rw-r--r--sphinx/config.py44
-rw-r--r--sphinx/directives/__init__.py26
-rw-r--r--sphinx/directives/code.py22
-rw-r--r--sphinx/directives/other.py38
-rw-r--r--sphinx/highlighting.py3
-rw-r--r--sphinx/io.py30
-rw-r--r--sphinx/jinja2glue.py23
-rw-r--r--sphinx/locale/__init__.py21
-rw-r--r--sphinx/make_mode.py36
-rw-r--r--sphinx/pycode/__init__.py38
-rw-r--r--sphinx/pycode/nodes.py6
-rw-r--r--sphinx/pycode/pgen2/grammar.py18
-rw-r--r--sphinx/pycode/pgen2/parse.py15
-rw-r--r--sphinx/pycode/pgen2/pgen.py27
-rw-r--r--sphinx/pycode/pgen2/tokenize.py16
-rw-r--r--sphinx/quickstart.py5
-rw-r--r--sphinx/roles.py4
-rw-r--r--sphinx/search/__init__.py95
-rw-r--r--sphinx/search/en.py5
-rw-r--r--sphinx/search/ja.py21
-rw-r--r--sphinx/search/ro.py4
-rw-r--r--sphinx/search/tr.py4
-rw-r--r--sphinx/search/zh.py11
-rw-r--r--sphinx/setup_command.py35
-rw-r--r--sphinx/theming.py26
-rw-r--r--sphinx/transforms/__init__.py13
-rw-r--r--sphinx/transforms/compact_bullet_list.py6
-rw-r--r--sphinx/transforms/i18n.py19
-rw-r--r--sphinx/versioning.py13
-rw-r--r--sphinx/websupport/__init__.py6
-rw-r--r--sphinx/websupport/storage/sqlalchemy_db.py10
-rw-r--r--sphinx/websupport/storage/sqlalchemystorage.py4
35 files changed, 510 insertions, 185 deletions
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 368f9d8fe..2f126b6f6 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -39,7 +39,7 @@ if __version__.endswith('+'):
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if out:
- __display_version__ += '/' + out.decode().strip()
+ __display_version__ += '/' + out.decode().strip() # type: ignore
except Exception:
pass
diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py
index d4793ff4d..e48a527a5 100644
--- a/sphinx/apidoc.py
+++ b/sphinx/apidoc.py
@@ -26,6 +26,10 @@ from fnmatch import fnmatch
from sphinx.util.osutil import FileAvoidWrite, walk
from sphinx import __display_version__
+if False:
+ # For type annotation
+ from typing import Any, Tuple # NOQA
+
# automodule options
if 'SPHINX_APIDOC_OPTIONS' in os.environ:
OPTIONS = os.environ['SPHINX_APIDOC_OPTIONS'].split(',')
@@ -42,6 +46,7 @@ PY_SUFFIXES = set(['.py', '.pyx'])
def makename(package, module):
+ # type: (unicode, unicode) -> unicode
"""Join package and module with a dot."""
# Both package and module can be None/empty.
if package:
@@ -54,6 +59,7 @@ def makename(package, module):
def write_file(name, text, opts):
+ # type: (unicode, unicode, Any) -> None
"""Write the output file for module/package <name>."""
fname = path.join(opts.destdir, '%s.%s' % (name, opts.suffix))
if opts.dryrun:
@@ -68,12 +74,14 @@ def write_file(name, text, opts):
def format_heading(level, text):
+ # type: (int, unicode) -> unicode
"""Create a heading of <level> [1, 2 or 3 supported]."""
underlining = ['=', '-', '~', ][level - 1] * len(text)
return '%s\n%s\n\n' % (text, underlining)
def format_directive(module, package=None):
+ # type: (unicode, unicode) -> unicode
"""Create the automodule directive and add the options."""
directive = '.. automodule:: %s\n' % makename(package, module)
for option in OPTIONS:
@@ -82,6 +90,7 @@ def format_directive(module, package=None):
def create_module_file(package, module, opts):
+ # type: (unicode, unicode, Any) -> None
"""Build the text of the file and write the file."""
if not opts.noheadings:
text = format_heading(1, '%s module' % module)
@@ -93,6 +102,7 @@ def create_module_file(package, module, opts):
def create_package_file(root, master_package, subroot, py_files, opts, subs, is_namespace):
+ # type: (unicode, unicode, unicode, List[unicode], Any, List[unicode], bool) -> None
"""Build the text of the file and write the file."""
text = format_heading(1, ('%s package' if not is_namespace else "%s namespace")
% makename(master_package, subroot))
@@ -148,13 +158,14 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs, is_
def create_modules_toc_file(modules, opts, name='modules'):
+ # type: (List[unicode], Any, unicode) -> None
"""Create the module's index."""
text = format_heading(1, '%s' % opts.header)
text += '.. toctree::\n'
text += ' :maxdepth: %s\n\n' % opts.maxdepth
modules.sort()
- prev_module = ''
+ prev_module = '' # type: unicode
for module in modules:
# look if the module is a subpackage and, if yes, ignore it
if module.startswith(prev_module + '.'):
@@ -166,6 +177,7 @@ def create_modules_toc_file(modules, opts, name='modules'):
def shall_skip(module, opts):
+ # type: (unicode, Any) -> bool
"""Check if we want to skip this module."""
# skip if the file doesn't exist and not using implicit namespaces
if not opts.implicit_namespaces and not path.exists(module):
@@ -184,6 +196,7 @@ def shall_skip(module, opts):
def recurse_tree(rootpath, excludes, opts):
+ # type: (unicode, List[unicode], Any) -> List[unicode]
"""
Look for every file in the directory tree and create the corresponding
ReST files.
@@ -217,7 +230,7 @@ def recurse_tree(rootpath, excludes, opts):
# remove hidden ('.') and private ('_') directories, as well as
# excluded dirs
if includeprivate:
- exclude_prefixes = ('.',)
+ exclude_prefixes = ('.',) # type: Tuple[unicode, ...]
else:
exclude_prefixes = ('.', '_')
subs[:] = sorted(sub for sub in subs if not sub.startswith(exclude_prefixes) and
@@ -247,23 +260,26 @@ def recurse_tree(rootpath, excludes, opts):
def normalize_excludes(rootpath, excludes):
+ # type: (unicode, List[unicode]) -> List[unicode]
"""Normalize the excluded directory list."""
return [path.abspath(exclude) for exclude in excludes]
def is_excluded(root, excludes):
+ # type: (unicode, List[unicode]) -> bool
"""Check if the directory is in the exclude list.
Note: by having trailing slashes, we avoid common prefix issues, like
e.g. an exlude "foo" also accidentally excluding "foobar".
"""
for exclude in excludes:
- if fnmatch(root, exclude):
+ if fnmatch(root, exclude): # type: ignore
return True
return False
def main(argv=sys.argv):
+ # type: (List[str]) -> int
"""Parse and check the command line arguments."""
parser = optparse.OptionParser(
usage="""\
@@ -359,7 +375,7 @@ Note: By default this script will not overwrite already created files.""")
if opts.full:
from sphinx import quickstart as qs
modules.sort()
- prev_module = ''
+ prev_module = '' # type: unicode
text = ''
for module in modules:
if module.startswith(prev_module + '.'):
diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py
index 0d85767e4..7a97e10e2 100644
--- a/sphinx/cmdline.py
+++ b/sphinx/cmdline.py
@@ -16,17 +16,22 @@ import traceback
from os import path
from six import text_type, binary_type
+
from docutils.utils import SystemMessage
from sphinx import __display_version__
from sphinx.errors import SphinxError
from sphinx.application import Sphinx
from sphinx.util import Tee, format_exception_cut_frames, save_traceback
-from sphinx.util.console import red, nocolor, color_terminal
+from sphinx.util.console import red, nocolor, color_terminal # type: ignore
from sphinx.util.docutils import docutils_namespace
from sphinx.util.osutil import abspath, fs_encoding
from sphinx.util.pycompat import terminal_safe
+if False:
+ # For type annotation
+ from typing import Any, IO, Union # NOQA
+
USAGE = """\
Sphinx v%s
@@ -45,18 +50,21 @@ For more information, visit <http://sphinx-doc.org/>.
class MyFormatter(optparse.IndentedHelpFormatter):
def format_usage(self, usage):
+ # type: (Any) -> Any
return usage
def format_help(self, formatter):
- result = []
- if self.description:
+ # type: (Any) -> unicode
+ result = [] # type: List[unicode]
+ if self.description: # type: ignore
result.append(self.format_description(formatter))
- if self.option_list:
- result.append(self.format_option_help(formatter))
+ if self.option_list: # type: ignore
+ result.append(self.format_option_help(formatter)) # type: ignore
return "\n".join(result)
def handle_exception(app, opts, exception, stderr=sys.stderr):
+ # type: (Sphinx, Any, Union[Exception, KeyboardInterrupt], IO) -> None
if opts.pdb:
import pdb
print(red('Exception occurred while building, starting debugger:'),
@@ -107,6 +115,7 @@ def handle_exception(app, opts, exception, stderr=sys.stderr):
def main(argv):
+ # type: (List[unicode]) -> int
if not color_terminal():
nocolor()
@@ -210,11 +219,11 @@ def main(argv):
# handle remaining filename arguments
filenames = args[2:]
- err = 0
+ err = 0 # type: ignore
for filename in filenames:
if not path.isfile(filename):
print('Error: Cannot find file %r.' % filename, file=sys.stderr)
- err = 1
+ err = 1 # type: ignore
if err:
return 1
@@ -249,7 +258,7 @@ def main(argv):
print('Error: Cannot open warning file %r: %s' %
(opts.warnfile, exc), file=sys.stderr)
sys.exit(1)
- warning = Tee(warning, warnfp)
+ warning = Tee(warning, warnfp) # type: ignore
error = warning
confoverrides = {}
diff --git a/sphinx/config.py b/sphinx/config.py
index 5741d66bf..9bfdd2976 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -16,9 +16,14 @@ from six import PY2, PY3, iteritems, string_types, binary_type, text_type, integ
from sphinx.errors import ConfigError
from sphinx.locale import l_
+from sphinx.util.i18n import format_date
from sphinx.util.osutil import cd
from sphinx.util.pycompat import execfile_, NoneType
-from sphinx.util.i18n import format_date
+
+if False:
+ # For type annotation
+ from typing import Any, Callable, Tuple # NOQA
+ from sphinx.util.tags import Tags # NOQA
nonascii_re = re.compile(br'[\x80-\xff]')
copyright_year_re = re.compile(r'^((\d{4}-)?)(\d{4})(?=[ ,])')
@@ -43,13 +48,15 @@ class ENUM(object):
app.add_config_value('latex_show_urls', 'no', ENUM('no', 'footnote', 'inline'))
"""
def __init__(self, *candidates):
+ # type: (unicode) -> None
self.candidates = candidates
def match(self, value):
+ # type: (unicode) -> bool
return value in self.candidates
-string_classes = [text_type]
+string_classes = [text_type] # type: List
if PY2:
string_classes.append(binary_type) # => [str, unicode]
@@ -114,12 +121,13 @@ class Config(object):
# pre-initialized confval for HTML builder
html_translator_class = (None, 'html', string_classes),
- )
+ ) # type: Dict[unicode, Tuple]
def __init__(self, dirname, filename, overrides, tags):
+ # type: (unicode, unicode, Dict, Tags) -> None
self.overrides = overrides
self.values = Config.config_values.copy()
- config = {}
+ config = {} # type: Dict[unicode, Any]
if dirname is not None:
config_file = path.join(dirname, filename)
config['__file__'] = config_file
@@ -137,14 +145,14 @@ class Config(object):
self._raw_config = config
# these two must be preinitialized because extensions can add their
# own config values
- self.setup = config.get('setup', None)
+ self.setup = config.get('setup', None) # type: Callable
if 'extensions' in overrides:
if isinstance(overrides['extensions'], string_types):
config['extensions'] = overrides.pop('extensions').split(',')
else:
config['extensions'] = overrides.pop('extensions')
- self.extensions = config.get('extensions', [])
+ self.extensions = config.get('extensions', []) # type: List[unicode]
# correct values of copyright year that are not coherent with
# the SOURCE_DATE_EPOCH environment variable (if set)
@@ -152,10 +160,11 @@ class Config(object):
if getenv('SOURCE_DATE_EPOCH') is not None:
for k in ('copyright', 'epub_copyright'):
if k in config:
- config[k] = copyright_year_re.sub('\g<1>%s' % format_date('%Y'),
+ config[k] = copyright_year_re.sub('\g<1>%s' % format_date('%Y'), # type: ignore # NOQA
config[k])
def check_types(self, warn):
+ # type: (Callable) -> None
# check all values for deviation from the default value's type, since
# that can result in TypeErrors all over the place
# NB. since config values might use l_() we have to wait with calling
@@ -197,15 +206,17 @@ class Config(object):
name=name, current=type(current), default=type(default)))
def check_unicode(self, warn):
+ # type: (Callable) -> None
# check all string values for non-ASCII characters in bytestrings,
# since that can result in UnicodeErrors all over the place
for name, value in iteritems(self._raw_config):
- if isinstance(value, binary_type) and nonascii_re.search(value):
+ if isinstance(value, binary_type) and nonascii_re.search(value): # type: ignore
warn('the config value %r is set to a string with non-ASCII '
'characters; this can lead to Unicode errors occurring. '
'Please use Unicode strings, e.g. %r.' % (name, u'Content'))
def convert_overrides(self, name, value):
+ # type: (unicode, Any) -> Any
if not isinstance(value, string_types):
return value
else:
@@ -215,10 +226,10 @@ class Config(object):
'ignoring (use %r to set individual elements)' %
(name, name + '.key=value'))
elif isinstance(defvalue, list):
- return value.split(',')
+ return value.split(',') # type: ignore
elif isinstance(defvalue, integer_types):
try:
- return int(value)
+ return int(value) # type: ignore
except ValueError:
raise ValueError('invalid number %r for config value %r, ignoring' %
(value, name))
@@ -231,6 +242,7 @@ class Config(object):
return value
def pre_init_values(self, warn):
+ # type: (Callable) -> None
"""Initialize some limited config variables before loading extensions"""
variables = ['needs_sphinx', 'suppress_warnings', 'html_translator_class']
for name in variables:
@@ -243,12 +255,13 @@ class Config(object):
warn(exc)
def init_values(self, warn):
+ # type: (Callable) -> None
config = self._raw_config
for valname, value in iteritems(self.overrides):
try:
if '.' in valname:
realvalname, key = valname.split('.', 1)
- config.setdefault(realvalname, {})[key] = value
+ config.setdefault(realvalname, {})[key] = value # type: ignore
continue
elif valname not in self.values:
warn('unknown config value %r in override, ignoring' % valname)
@@ -262,10 +275,11 @@ class Config(object):
for name in config:
if name in self.values:
self.__dict__[name] = config[name]
- if isinstance(self.source_suffix, string_types):
- self.source_suffix = [self.source_suffix]
+ if isinstance(self.source_suffix, string_types): # type: ignore
+ self.source_suffix = [self.source_suffix] # type: ignore
def __getattr__(self, name):
+ # type: (unicode) -> Any
if name.startswith('_'):
raise AttributeError(name)
if name not in self.values:
@@ -276,13 +290,17 @@ class Config(object):
return default
def __getitem__(self, name):
+ # type: (unicode) -> unicode
return getattr(self, name)
def __setitem__(self, name, value):
+ # type: (unicode, Any) -> None
setattr(self, name, value)
def __delitem__(self, name):
+ # type: (unicode) -> None
delattr(self, name)
def __contains__(self, name):
+ # type: (unicode) -> bool
return name in self.values
diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py
index 76b54f9d6..ea09daff5 100644
--- a/sphinx/directives/__init__.py
+++ b/sphinx/directives/__init__.py
@@ -29,6 +29,12 @@ from sphinx.directives.patches import ( # noqa
Figure, Meta
)
+if False:
+ # For type annotation
+ from typing import Any # NOQA
+ from sphinx.application import Sphinx # NOQA
+ from sphinx.environment import BuildEnvironment # NOQA
+
# RE to strip backslash escapes
nl_escape_re = re.compile(r'\\\n')
@@ -51,9 +57,13 @@ class ObjectDescription(Directive):
}
# types of doc fields that this directive handles, see sphinx.util.docfields
- doc_field_types = []
+ doc_field_types = [] # type: List[Any]
+ domain = None # type: unicode
+ objtype = None # type: unicode
+ indexnode = None # type: addnodes.index
def get_signatures(self):
+ # type: () -> List[unicode]
"""
Retrieve the signatures to document from the directive arguments. By
default, signatures are given as arguments, one per line.
@@ -65,6 +75,7 @@ class ObjectDescription(Directive):
return [strip_backslash_re.sub(r'\1', line.strip()) for line in lines]
def handle_signature(self, sig, signode):
+ # type: (unicode, addnodes.desc_signature) -> Any
"""
Parse the signature *sig* into individual nodes and append them to
*signode*. If ValueError is raised, parsing is aborted and the whole
@@ -77,6 +88,7 @@ class ObjectDescription(Directive):
raise ValueError
def add_target_and_index(self, name, sig, signode):
+ # type: (Any, unicode, addnodes.desc_signature) -> None
"""
Add cross-reference IDs and entries to self.indexnode, if applicable.
@@ -85,6 +97,7 @@ class ObjectDescription(Directive):
return # do nothing by default
def before_content(self):
+ # type: () -> None
"""
Called before parsing content. Used to set information about the current
directive context on the build environment.
@@ -92,6 +105,7 @@ class ObjectDescription(Directive):
pass
def after_content(self):
+ # type: () -> None
"""
Called after parsing content. Used to reset information about the
current directive context on the build environment.
@@ -99,6 +113,7 @@ class ObjectDescription(Directive):
pass
def run(self):
+ # type: () -> List[nodes.Node]
"""
Main directive entry function, called by docutils upon encountering the
directive.
@@ -120,7 +135,7 @@ class ObjectDescription(Directive):
self.domain, self.objtype = self.name.split(':', 1)
else:
self.domain, self.objtype = '', self.name
- self.env = self.state.document.settings.env
+ self.env = self.state.document.settings.env # type: BuildEnvironment
self.indexnode = addnodes.index(entries=[])
node = addnodes.desc()
@@ -130,7 +145,7 @@ class ObjectDescription(Directive):
node['objtype'] = node['desctype'] = self.objtype
node['noindex'] = noindex = ('noindex' in self.options)
- self.names = []
+ self.names = [] # type: List[unicode]
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
# add a signature node for each signature in the current unit
@@ -181,6 +196,7 @@ class DefaultRole(Directive):
final_argument_whitespace = False
def run(self):
+ # type: () -> List[nodes.Node]
if not self.arguments:
if '' in roles._roles:
# restore the "default" default role
@@ -209,9 +225,10 @@ class DefaultDomain(Directive):
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = False
- option_spec = {}
+ option_spec = {} # type: Dict
def run(self):
+ # type: () -> List[nodes.Node]
env = self.state.document.settings.env
domain_name = self.arguments[0].lower()
# if domain_name not in env.domains:
@@ -225,6 +242,7 @@ class DefaultDomain(Directive):
def setup(app):
+ # type: (Sphinx) -> None
directives.register_directive('default-role', DefaultRole)
directives.register_directive('default-domain', DefaultDomain)
directives.register_directive('describe', ObjectDescription)
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index 5bef8c386..e401a50de 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -11,17 +11,22 @@ import sys
import codecs
from difflib import unified_diff
+from six import string_types
+
from docutils import nodes
from docutils.parsers.rst import Directive, directives
from docutils.statemachine import ViewList
-from six import string_types
-
from sphinx import addnodes
from sphinx.locale import _
from sphinx.util import parselinenos
from sphinx.util.nodes import set_source_info
+if False:
+ # For type annotation
+ from typing import Any # NOQA
+ from sphinx.application import Sphinx # NOQA
+
class Highlight(Directive):
"""
@@ -38,6 +43,7 @@ class Highlight(Directive):
}
def run(self):
+ # type: () -> List[nodes.Node]
if 'linenothreshold' in self.options:
try:
linenothreshold = int(self.options['linenothreshold'])
@@ -50,6 +56,7 @@ class Highlight(Directive):
def dedent_lines(lines, dedent):
+ # type: (List[unicode], int) -> List[unicode]
if not dedent:
return lines
@@ -64,6 +71,7 @@ def dedent_lines(lines, dedent):
def container_wrapper(directive, literal_node, caption):
+ # type: (Directive, nodes.Node, unicode) -> nodes.container
container_node = nodes.container('', literal_block=True,
classes=['literal-block-wrapper'])
parsed = nodes.Element()
@@ -101,6 +109,7 @@ class CodeBlock(Directive):
}
def run(self):
+ # type: () -> List[nodes.Node]
code = u'\n'.join(self.content)
linespec = self.options.get('emphasize-lines')
@@ -137,7 +146,7 @@ class CodeBlock(Directive):
literal = container_wrapper(self, literal, caption)
except ValueError as exc:
document = self.state.document
- errmsg = _('Invalid caption: %s' % exc[0][0].astext())
+ errmsg = _('Invalid caption: %s' % exc[0][0].astext()) # type: ignore
return [document.reporter.warning(errmsg, line=self.lineno)]
# literal will be note_implicit_target that is linked from caption and numref.
@@ -182,11 +191,12 @@ class LiteralInclude(Directive):
}
def read_with_encoding(self, filename, document, codec_info, encoding):
+ # type: (unicode, nodes.Node, Any, unicode) -> List
try:
with codecs.StreamReaderWriter(open(filename, 'rb'), codec_info[2],
codec_info[3], 'strict') as f:
lines = f.readlines()
- lines = dedent_lines(lines, self.options.get('dedent'))
+ lines = dedent_lines(lines, self.options.get('dedent')) # type: ignore
return lines
except (IOError, OSError):
return [document.reporter.warning(
@@ -199,6 +209,7 @@ class LiteralInclude(Directive):
(encoding, filename))]
def run(self):
+ # type: () -> List[nodes.Node]
document = self.state.document
if not document.settings.file_insertion_enabled:
return [document.reporter.warning('File insertion disabled',
@@ -367,7 +378,7 @@ class LiteralInclude(Directive):
retnode = container_wrapper(self, retnode, caption)
except ValueError as exc:
document = self.state.document
- errmsg = _('Invalid caption: %s' % exc[0][0].astext())
+ errmsg = _('Invalid caption: %s' % exc[0][0].astext()) # type: ignore
return [document.reporter.warning(errmsg, line=self.lineno)]
# retnode will be note_implicit_target that is linked from caption and numref.
@@ -378,6 +389,7 @@ class LiteralInclude(Directive):
def setup(app):
+ # type: (Sphinx) -> None
directives.register_directive('highlight', Highlight)
directives.register_directive('highlightlang', Highlight) # old
directives.register_directive('code-block', CodeBlock)
diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py
index e071b327e..15944668e 100644
--- a/sphinx/directives/other.py
+++ b/sphinx/directives/other.py
@@ -8,6 +8,7 @@
"""
from six.moves import range
+
from docutils import nodes
from docutils.parsers.rst import Directive, directives
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
@@ -21,8 +22,14 @@ from sphinx.util.nodes import explicit_title_re, set_source_info, \
process_index_entry
from sphinx.util.matching import patfilter
+if False:
+ # For type annotation
+ from typing import Tuple # NOQA
+ from sphinx.application import Sphinx # NOQA
+
def int_or_nothing(argument):
+ # type: (unicode) -> int
if not argument:
return 999
return int(argument)
@@ -50,6 +57,7 @@ class TocTree(Directive):
}
def run(self):
+ # type: () -> List[nodes.Node]
env = self.state.document.settings.env
suffixes = env.config.source_suffix
glob = 'glob' in self.options
@@ -57,7 +65,7 @@ class TocTree(Directive):
ret = []
# (title, ref) pairs, where ref may be a document, or an external link,
# and title may be None if the document's title is to be used
- entries = []
+ entries = [] # type: List[Tuple[unicode, unicode]]
includefiles = []
all_docnames = env.found_docs.copy()
# don't add the currently visited file in catch-all patterns
@@ -136,9 +144,10 @@ class Author(Directive):
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
- option_spec = {}
+ option_spec = {} # type: Dict
def run(self):
+ # type: () -> List[nodes.Node]
env = self.state.document.settings.env
if not env.config.show_authors:
return []
@@ -168,20 +177,21 @@ class Index(Directive):
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
- option_spec = {}
+ option_spec = {} # type: Dict
def run(self):
+ # type: () -> List[nodes.Node]
arguments = self.arguments[0].split('\n')
env = self.state.document.settings.env
targetid = 'index-%s' % env.new_serialno('index')
targetnode = nodes.target('', '', ids=[targetid])
self.state.document.note_explicit_target(targetnode)
indexnode = addnodes.index()
- indexnode['entries'] = ne = []
+ indexnode['entries'] = []
indexnode['inline'] = False
set_source_info(self, indexnode)
for entry in arguments:
- ne.extend(process_index_entry(entry, targetid))
+ indexnode['entries'].extend(process_index_entry(entry, targetid))
return [indexnode, targetnode]
@@ -193,9 +203,10 @@ class VersionChange(Directive):
required_arguments = 1
optional_arguments = 1
final_argument_whitespace = True
- option_spec = {}
+ option_spec = {} # type: Dict
def run(self):
+ # type: () -> List[nodes.Node]
node = addnodes.versionmodified()
node.document = self.state.document
set_source_info(self, node)
@@ -248,9 +259,10 @@ class TabularColumns(Directive):
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
- option_spec = {}
+ option_spec = {} # type: Dict
def run(self):
+ # type: () -> List[nodes.Node]
node = addnodes.tabular_col_spec()
node['spec'] = self.arguments[0]
set_source_info(self, node)
@@ -265,9 +277,10 @@ class Centered(Directive):
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
- option_spec = {}
+ option_spec = {} # type: Dict
def run(self):
+ # type: () -> List[nodes.Node]
if not self.arguments:
return []
subnode = addnodes.centered()
@@ -285,9 +298,10 @@ class Acks(Directive):
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = False
- option_spec = {}
+ option_spec = {} # type: Dict
def run(self):
+ # type: () -> List[nodes.Node]
node = addnodes.acks()
node.document = self.state.document
self.state.nested_parse(self.content, self.content_offset, node)
@@ -311,6 +325,7 @@ class HList(Directive):
}
def run(self):
+ # type: () -> List[nodes.Node]
ncolumns = self.options.get('columns', 2)
node = nodes.paragraph()
node.document = self.state.document
@@ -342,9 +357,10 @@ class Only(Directive):
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
- option_spec = {}
+ option_spec = {} # type: Dict
def run(self):
+ # type: () -> List[nodes.Node]
node = addnodes.only()
node.document = self.state.document
set_source_info(self, node)
@@ -398,6 +414,7 @@ class Include(BaseInclude):
"""
def run(self):
+ # type: () -> List[nodes.Node]
env = self.state.document.settings.env
if self.arguments[0].startswith('<') and \
self.arguments[0].endswith('>'):
@@ -410,6 +427,7 @@ class Include(BaseInclude):
def setup(app):
+ # type: (Sphinx) -> None
directives.register_directive('toctree', TocTree)
directives.register_directive('sectionauthor', Author)
directives.register_directive('moduleauthor', Author)
diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py
index 9594b5336..543e1485a 100644
--- a/sphinx/highlighting.py
+++ b/sphinx/highlighting.py
@@ -16,6 +16,7 @@ from sphinx.util.texescape import tex_hl_escape_map_new
from sphinx.ext import doctest
from pygments import highlight
+from pygments.lexer import Lexer # NOQA
from pygments.lexers import PythonLexer, Python3Lexer, PythonConsoleLexer, \
CLexer, TextLexer, RstLexer
from pygments.lexers import get_lexer_by_name, guess_lexer
@@ -33,7 +34,7 @@ lexers = dict(
pycon3 = PythonConsoleLexer(python3=True, stripnl=False),
rest = RstLexer(stripnl=False),
c = CLexer(stripnl=False),
-)
+) # type: Dict[unicode, Lexer]
for _lexer in lexers.values():
_lexer.add_filter('raiseonerror')
diff --git a/sphinx/io.py b/sphinx/io.py
index f1386c9a8..c6fea570e 100644
--- a/sphinx/io.py
+++ b/sphinx/io.py
@@ -12,6 +12,7 @@ from docutils.io import FileInput
from docutils.readers import standalone
from docutils.writers import UnfilteredWriter
from six import string_types, text_type
+from typing import Any, Union # NOQA
from sphinx.transforms import (
ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
@@ -24,23 +25,36 @@ from sphinx.transforms.i18n import (
)
from sphinx.util import import_object, split_docinfo
+if False:
+ # For type annotation
+ from typing import Any, Union # NOQA
+ 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.environment import BuildEnvironment # NOQA
+
class SphinxBaseReader(standalone.Reader):
"""
Add our source parsers
"""
def __init__(self, app, parsers={}, *args, **kwargs):
+ # type: (Sphinx, Dict[unicode, Parser], Any, Any) -> None
standalone.Reader.__init__(self, *args, **kwargs)
- self.parser_map = {}
+ self.parser_map = {} # type: Dict[unicode, Parser]
for suffix, parser_class in parsers.items():
if isinstance(parser_class, string_types):
- parser_class = import_object(parser_class, 'source parser')
+ parser_class = import_object(parser_class, 'source parser') # type: ignore
parser = parser_class()
if hasattr(parser, 'set_application'):
parser.set_application(app)
self.parser_map[suffix] = parser
def read(self, source, parser, settings):
+ # type: (Input, Parser, Dict) -> nodes.document
self.source = source
for suffix in self.parser_map:
@@ -56,6 +70,7 @@ class SphinxBaseReader(standalone.Reader):
return self.document
def get_transforms(self):
+ # type: () -> List[Transform]
return standalone.Reader.get_transforms(self) + self.transforms
@@ -84,13 +99,16 @@ class SphinxI18nReader(SphinxBaseReader):
FilterSystemMessages, RefOnlyBulletListTransform]
def __init__(self, *args, **kwargs):
+ # type: (Any, Any) -> None
SphinxBaseReader.__init__(self, *args, **kwargs)
- self.lineno = None
+ self.lineno = None # type: int
def set_lineno_for_reporter(self, lineno):
+ # type: (int) -> None
self.lineno = lineno
def new_document(self):
+ # type: () -> nodes.document
document = SphinxBaseReader.new_document(self)
reporter = document.reporter
@@ -105,28 +123,32 @@ class SphinxDummyWriter(UnfilteredWriter):
supported = ('html',) # needed to keep "meta" nodes
def translate(self):
+ # type: () -> None
pass
class SphinxFileInput(FileInput):
def __init__(self, app, env, *args, **kwds):
+ # type: (Sphinx, BuildEnvironment, Any, Any) -> None
self.app = app
self.env = env
kwds['error_handler'] = 'sphinx' # py3: handle error on open.
FileInput.__init__(self, *args, **kwds)
def decode(self, data):
+ # type: (Union[unicode, bytes]) -> unicode
if isinstance(data, text_type): # py3: `data` already decoded.
return data
return data.decode(self.encoding, 'sphinx') # py2: decoding
def read(self):
+ # type: () -> unicode
def get_parser_type(source_path):
for suffix in self.env.config.source_parsers:
if source_path.endswith(suffix):
parser_class = self.env.config.source_parsers[suffix]
if isinstance(parser_class, string_types):
- parser_class = import_object(parser_class, 'source parser')
+ parser_class = import_object(parser_class, 'source parser') # type: ignore # NOQA
return parser_class.supported
else:
return ('restructuredtext',)
diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py
index 6e2ef7186..c1bd04765 100644
--- a/sphinx/jinja2glue.py
+++ b/sphinx/jinja2glue.py
@@ -17,18 +17,28 @@ from jinja2 import FileSystemLoader, BaseLoader, TemplateNotFound, \
contextfunction
from jinja2.utils import open_if_exists
from jinja2.sandbox import SandboxedEnvironment
+from typing import Any, Callable, Iterator, Tuple # NOQA
from sphinx.application import TemplateBridge
from sphinx.util.osutil import mtimes_of_files
+if False:
+ # For type annotation
+ from typing import Any, Callable, Iterator, Tuple # NOQA
+ from sphinx.builders import Builder # NOQA
+ from sphinx.environment import BuildEnvironment # NOQA
+ from sphinx.themes import Theme # NOQA
+
def _tobool(val):
+ # type: (unicode) -> bool
if isinstance(val, string_types):
- return val.lower() in ('true', '1', 'yes', 'on')
+ return val.lower() in ('true', '1', 'yes', 'on') # type: ignore
return bool(val)
def _toint(val):
+ # type: (unicode) -> int
try:
return int(val)
except ValueError:
@@ -36,6 +46,7 @@ def _toint(val):
def _slice_index(values, slices):
+ # type: (List, int) -> Iterator[List]
seq = list(values)
length = 0
for value in values:
@@ -57,6 +68,7 @@ def _slice_index(values, slices):
def accesskey(context, key):
+ # type: (Any, unicode) -> unicode
"""Helper to output each access key only once."""
if '_accesskeys' not in context:
context.vars['_accesskeys'] = {}
@@ -68,12 +80,15 @@ def accesskey(context, key):
class idgen(object):
def __init__(self):
+ # type: () -> None
self.id = 0
def current(self):
+ # type: () -> int
return self.id
def __next__(self):
+ # type: () -> int
self.id += 1
return self.id
next = __next__ # Python 2/Jinja compatibility
@@ -86,6 +101,7 @@ class SphinxFileSystemLoader(FileSystemLoader):
"""
def get_source(self, environment, template):
+ # type: (BuildEnvironment, unicode) -> Tuple[unicode, unicode, Callable]
for searchpath in self.searchpath:
filename = path.join(searchpath, template)
f = open_if_exists(filename)
@@ -113,6 +129,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
# TemplateBridge interface
def init(self, builder, theme=None, dirs=None):
+ # type: (Builder, Theme, List[unicode]) -> None
# create a chain of paths to search
if theme:
# the theme's own dir and its bases' dirs
@@ -155,17 +172,21 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
builder.app.translator)
def render(self, template, context):
+ # type: (unicode, Dict) -> None
return self.environment.get_template(template).render(context)
def render_string(self, source, context):
+ # type: (unicode, Dict) -> unicode
return self.environment.from_string(source).render(context)
def newest_template_mtime(self):
+ # type: () -> float
return max(mtimes_of_files(self.pathchain, '.html'))
# Loader interface
def get_source(self, environment, template):
+ # type: (BuildEnvironment, unicode) -> Tuple[unicode, unicode, Callable]
loaders = self.loaders
# exclamation mark starts search from theme
if template.startswith('!'):
diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py
index d6ce7329b..44ad64304 100644
--- a/sphinx/locale/__init__.py
+++ b/sphinx/locale/__init__.py
@@ -14,6 +14,10 @@ import gettext
from six import PY3, text_type
from six.moves import UserString
+if False:
+ # For type annotation
+ from typing import Any, Tuple # NOQA
+
class _TranslationProxy(UserString, object):
"""
@@ -140,6 +144,7 @@ class _TranslationProxy(UserString, object):
def mygettext(string):
+ # type: (unicode) -> unicode
"""Used instead of _ when creating TranslationProxies, because _ is
not bound yet at that time.
"""
@@ -147,10 +152,11 @@ def mygettext(string):
def lazy_gettext(string):
+ # type: (unicode) -> unicode
"""A lazy version of `gettext`."""
# if isinstance(string, _TranslationProxy):
# return string
- return _TranslationProxy(mygettext, string)
+ return _TranslationProxy(mygettext, string) # type: ignore
l_ = lazy_gettext
@@ -184,19 +190,22 @@ pairindextypes = {
'exception': l_('exception'),
'statement': l_('statement'),
'builtin': l_('built-in function'),
-}
+} # Dict[unicode, _TranslationProxy]
-translators = {}
+translators = {} # type: Dict[unicode, Any]
if PY3:
def _(message):
+ # type: (unicode) -> unicode
return translators['sphinx'].gettext(message)
else:
def _(message):
+ # type: (unicode) -> unicode
return translators['sphinx'].ugettext(message)
def init(locale_dirs, language, catalog='sphinx'):
+ # type: (List, unicode, unicode) -> Tuple[Any, 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
@@ -213,12 +222,12 @@ def init(locale_dirs, language, catalog='sphinx'):
# loading
for dir_ in locale_dirs:
try:
- trans = gettext.translation(catalog, localedir=dir_,
- languages=[language])
+ trans = gettext.translation(catalog, localedir=dir_, # type: ignore
+ languages=[language]) # type: ignore
if translator is None:
translator = trans
else:
- translator._catalog.update(trans._catalog)
+ translator._catalog.update(trans._catalog) # type: ignore
except Exception:
# Language couldn't be found in the specified path
pass
diff --git a/sphinx/make_mode.py b/sphinx/make_mode.py
index 28316458e..87333301c 100644
--- a/sphinx/make_mode.py
+++ b/sphinx/make_mode.py
@@ -22,7 +22,7 @@ from os import path
from subprocess import call
import sphinx
-from sphinx.util.console import bold, blue
+from sphinx.util.console import bold, blue # type: ignore
from sphinx.util.osutil import cd, rmtree
proj_name = os.getenv('SPHINXPROJ', '<project>')
@@ -59,14 +59,17 @@ BUILDERS = [
class Make(object):
def __init__(self, srcdir, builddir, opts):
+ # type: (unicode, unicode, List[unicode]) -> None
self.srcdir = srcdir
self.builddir = builddir
self.opts = opts
def builddir_join(self, *comps):
+ # type: (unicode) -> unicode
return path.join(self.builddir, *comps)
def build_clean(self):
+ # type: () -> int
if not path.exists(self.builddir):
return
elif not path.isdir(self.builddir):
@@ -77,19 +80,22 @@ class Make(object):
rmtree(self.builddir_join(item))
def build_help(self):
+ # type: () -> None
print(bold("Sphinx v%s" % sphinx.__display_version__))
- print("Please use `make %s' where %s is one of" % ((blue('target'),)*2))
+ print("Please use `make %s' where %s is one of" % ((blue('target'),)*2)) # type: ignore # NOQA
for osname, bname, description in BUILDERS:
if not osname or os.name == osname:
print(' %s %s' % (blue(bname.ljust(10)), description))
def build_html(self):
+ # type: () -> int
if self.run_generic_build('html') > 0:
return 1
print()
print('Build finished. The HTML pages are in %s.' % self.builddir_join('html'))
def build_dirhtml(self):
+ # type: () -> int
if self.run_generic_build('dirhtml') > 0:
return 1
print()
@@ -97,6 +103,7 @@ class Make(object):
self.builddir_join('dirhtml'))
def build_singlehtml(self):
+ # type: () -> int
if self.run_generic_build('singlehtml') > 0:
return 1
print()
@@ -104,18 +111,21 @@ class Make(object):
self.builddir_join('singlehtml'))
def build_pickle(self):
+ # type: () -> int
if self.run_generic_build('pickle') > 0:
return 1
print()
print('Build finished; now you can process the pickle files.')
def build_json(self):
+ # type: () -> int
if self.run_generic_build('json') > 0:
return 1
print()
print('Build finished; now you can process the JSON files.')
def build_htmlhelp(self):
+ # type: () -> int
if self.run_generic_build('htmlhelp') > 0:
return 1
print()
@@ -123,6 +133,7 @@ class Make(object):
'.hhp project file in %s.' % self.builddir_join('htmlhelp'))
def build_qthelp(self):
+ # type: () -> int
if self.run_generic_build('qthelp') > 0:
return 1
print()
@@ -134,6 +145,7 @@ class Make(object):
self.builddir_join('qthelp', proj_name))
def build_devhelp(self):
+ # type: () -> int
if self.run_generic_build('devhelp') > 0:
return 1
print()
@@ -145,12 +157,14 @@ class Make(object):
print("$ devhelp")
def build_epub(self):
+ # type: () -> int
if self.run_generic_build('epub') > 0:
return 1
print()
print('Build finished. The ePub file is in %s.' % self.builddir_join('epub'))
def build_latex(self):
+ # type: () -> int
if self.run_generic_build('latex') > 0:
return 1
print("Build finished; the LaTeX files are in %s." % self.builddir_join('latex'))
@@ -159,24 +173,28 @@ class Make(object):
print("(use `make latexpdf' here to do that automatically).")
def build_latexpdf(self):
+ # type: () -> int
if self.run_generic_build('latex') > 0:
return 1
with cd(self.builddir_join('latex')):
os.system('make all-pdf')
def build_latexpdfja(self):
+ # type: () -> int
if self.run_generic_build('latex') > 0:
return 1
with cd(self.builddir_join('latex')):
os.system('make all-pdf-ja')
def build_text(self):
+ # type: () -> int
if self.run_generic_build('text') > 0:
return 1
print()
print('Build finished. The text files are in %s.' % self.builddir_join('text'))
def build_texinfo(self):
+ # type: () -> int
if self.run_generic_build('texinfo') > 0:
return 1
print("Build finished; the Texinfo files are in %s." %
@@ -186,12 +204,14 @@ class Make(object):
print("(use `make info' here to do that automatically).")
def build_info(self):
+ # type: () -> int
if self.run_generic_build('texinfo') > 0:
return 1
with cd(self.builddir_join('texinfo')):
os.system('make info')
def build_gettext(self):
+ # type: () -> int
dtdir = self.builddir_join('gettext', '.doctrees')
if self.run_generic_build('gettext', doctreedir=dtdir) > 0:
return 1
@@ -200,6 +220,7 @@ class Make(object):
self.builddir_join('gettext'))
def build_changes(self):
+ # type: () -> int
if self.run_generic_build('changes') > 0:
return 1
print()
@@ -207,6 +228,7 @@ class Make(object):
self.builddir_join('changes'))
def build_linkcheck(self):
+ # type: () -> int
res = self.run_generic_build('linkcheck')
print()
print('Link check complete; look for any errors in the above output '
@@ -214,12 +236,14 @@ class Make(object):
return res
def build_doctest(self):
+ # type: () -> int
res = self.run_generic_build('doctest')
print("Testing of doctests in the sources finished, look at the "
"results in %s." % self.builddir_join('doctest', 'output.txt'))
return res
def build_coverage(self):
+ # type: () -> int
if self.run_generic_build('coverage') > 0:
print("Has the coverage extension been enabled?")
return 1
@@ -228,12 +252,14 @@ class Make(object):
"results in %s." % self.builddir_join('coverage'))
def build_xml(self):
+ # type: () -> int
if self.run_generic_build('xml') > 0:
return 1
print()
print('Build finished. The XML files are in %s.' % self.builddir_join('xml'))
def build_pseudoxml(self):
+ # type: () -> int
if self.run_generic_build('pseudoxml') > 0:
return 1
print()
@@ -241,6 +267,7 @@ class Make(object):
self.builddir_join('pseudoxml'))
def run_generic_build(self, builder, doctreedir=None):
+ # type: (unicode, unicode) -> int
# compatibility with old Makefile
papersize = os.getenv('PAPER', '')
opts = self.opts
@@ -261,11 +288,12 @@ class Make(object):
# linux, mac: 'sphinx-build' or 'sphinx-build.py'
cmd = [sys.executable, orig_cmd]
- return call(cmd + ['-b', builder] + opts +
- ['-d', doctreedir, self.srcdir, self.builddir_join(builder)])
+ return call(cmd + ['-b', builder] + opts + # type: ignore
+ ['-d', doctreedir, self.srcdir, self.builddir_join(builder)]) # type: ignore # NOQA
def run_make_mode(args):
+ # type: (List[unicode]) -> int
if len(args) < 3:
print('Error: at least 3 arguments (builder, source '
'dir, build dir) are required.', file=sys.stderr)
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index baf5c0068..2c898560b 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -24,6 +24,10 @@ from sphinx.util import get_module_source, detect_encoding
from sphinx.util.pycompat import TextIOWrapper
from sphinx.util.docstrings import prepare_docstring, prepare_commentdoc
+if False:
+ # For type annotation
+ from typing import Any, Tuple # NOQA
+
# load the Python grammar
_grammarfile = path.join(package_dir, 'pycode',
@@ -63,10 +67,10 @@ class AttrDocVisitor(nodes.NodeVisitor):
self.scope = scope
self.in_init = 0
self.encoding = encoding
- self.namespace = []
- self.collected = {}
+ self.namespace = [] # type: List[unicode]
+ self.collected = {} # type: Dict[Tuple[unicode, unicode], unicode]
self.tagnumber = 0
- self.tagorder = {}
+ self.tagorder = {} # type: Dict[unicode, int]
def add_tag(self, name):
name = '.'.join(self.namespace + [name])
@@ -102,10 +106,10 @@ class AttrDocVisitor(nodes.NodeVisitor):
parent = node.parent
idx = parent.children.index(node) + 1
while idx < len(parent):
- if parent[idx].type == sym.SEMI:
+ if parent[idx].type == sym.SEMI: # type: ignore
idx += 1
continue # skip over semicolon
- if parent[idx].type == sym.NEWLINE:
+ if parent[idx].type == sym.NEWLINE: # type: ignore
prefix = parent[idx].get_prefix()
if not isinstance(prefix, text_type):
prefix = prefix.decode(self.encoding)
@@ -138,8 +142,8 @@ class AttrDocVisitor(nodes.NodeVisitor):
prev = node.get_prev_sibling()
if not prev:
return
- if prev.type == sym.simple_stmt and \
- prev[0].type == sym.expr_stmt and _eq in prev[0].children:
+ if (prev.type == sym.simple_stmt and # type: ignore
+ prev[0].type == sym.expr_stmt and _eq in prev[0].children): # type: ignore
# need to "eval" the string because it's returned in its
# original form
docstring = literals.evalString(node[0].value, self.encoding)
@@ -178,7 +182,7 @@ class AttrDocVisitor(nodes.NodeVisitor):
class ModuleAnalyzer(object):
# cache for analyzer objects -- caches both by module and file name
- cache = {}
+ cache = {} # type: Dict[Tuple[unicode, unicode], Any]
@classmethod
def for_string(cls, string, modname, srcname='<string>'):
@@ -240,14 +244,14 @@ class ModuleAnalyzer(object):
self.source.seek(pos)
# will be filled by tokenize()
- self.tokens = None
+ self.tokens = None # type: List[unicode]
# will be filled by parse()
- self.parsetree = None
+ self.parsetree = None # type: Any
# will be filled by find_attr_docs()
- self.attr_docs = None
- self.tagorder = None
+ self.attr_docs = None # type: List[unicode]
+ self.tagorder = None # type: Dict[unicode, int]
# will be filled by find_tags()
- self.tags = None
+ self.tags = None # type: List[unicode]
def tokenize(self):
"""Generate tokens from the source."""
@@ -289,8 +293,8 @@ class ModuleAnalyzer(object):
return self.tags
self.tokenize()
result = {}
- namespace = []
- stack = []
+ namespace = [] # type: List[unicode]
+ stack = [] # type: List[Tuple[unicode, unicode, unicode, int]]
indent = 0
defline = False
expect_indent = False
@@ -301,7 +305,7 @@ class ModuleAnalyzer(object):
if tokentup[0] not in ignore:
yield tokentup
tokeniter = tokeniter()
- for type, tok, spos, epos, line in tokeniter:
+ for type, tok, spos, epos, line in tokeniter: # type: ignore
if expect_indent and type != token.NL:
if type != token.INDENT:
# no suite -- one-line definition
@@ -312,7 +316,7 @@ class ModuleAnalyzer(object):
result[fullname] = (dtype, startline, endline - emptylines)
expect_indent = False
if tok in ('def', 'class'):
- name = next(tokeniter)[1]
+ name = next(tokeniter)[1] # type: ignore
namespace.append(name)
fullname = '.'.join(namespace)
stack.append((tok, fullname, spos[0], indent))
diff --git a/sphinx/pycode/nodes.py b/sphinx/pycode/nodes.py
index ee40f3c0d..b6b3355c0 100644
--- a/sphinx/pycode/nodes.py
+++ b/sphinx/pycode/nodes.py
@@ -14,7 +14,7 @@ class BaseNode(object):
"""
Node superclass for both terminal and nonterminal nodes.
"""
- parent = None
+ parent = None # type: BaseNode
def _eq(self, other):
raise NotImplementedError
@@ -29,7 +29,7 @@ class BaseNode(object):
return NotImplemented
return not self._eq(other)
- __hash__ = None
+ __hash__ = None # type: str
def get_prev_sibling(self):
"""Return previous child in parent's children, or None."""
@@ -204,5 +204,5 @@ class NodeVisitor(object):
def generic_visit(self, node):
"""Called if no explicit visitor function exists for a node."""
if isinstance(node, Node):
- for child in node:
+ for child in node: # type: ignore
self.visit(child)
diff --git a/sphinx/pycode/pgen2/grammar.py b/sphinx/pycode/pgen2/grammar.py
index 42e6d72ee..cd6a435d5 100644
--- a/sphinx/pycode/pgen2/grammar.py
+++ b/sphinx/pycode/pgen2/grammar.py
@@ -19,6 +19,10 @@ import pickle
# Local imports
from sphinx.pycode.pgen2 import token
+if False:
+ # For type annotation
+ from typing import Tuple # NOQA
+
class Grammar(object):
"""Pgen parsing tables tables conversion class.
@@ -75,14 +79,14 @@ class Grammar(object):
"""
def __init__(self):
- self.symbol2number = {}
- self.number2symbol = {}
- self.states = []
- self.dfas = {}
+ self.symbol2number = {} # type: Dict[unicode, int]
+ self.number2symbol = {} # type: Dict[int, unicode]
+ self.states = [] # type: List[List[List[Tuple[int, int]]]]
+ self.dfas = {} # type: Dict[int, Tuple[List[List[Tuple[int, int]]], unicode]]
self.labels = [(0, "EMPTY")]
- self.keywords = {}
- self.tokens = {}
- self.symbol2label = {}
+ self.keywords = {} # type: Dict[unicode, unicode]
+ self.tokens = {} # type: Dict[unicode, unicode]
+ self.symbol2label = {} # type: Dict[unicode, unicode]
self.start = 256
def dump(self, filename):
diff --git a/sphinx/pycode/pgen2/parse.py b/sphinx/pycode/pgen2/parse.py
index 60eec05ea..43b88b519 100644
--- a/sphinx/pycode/pgen2/parse.py
+++ b/sphinx/pycode/pgen2/parse.py
@@ -13,6 +13,10 @@ how this parsing engine works.
# Local imports
from sphinx.pycode.pgen2 import token
+if False:
+ # For type annotation
+ from typing import Any, Tuple # NOQA
+
class ParseError(Exception):
"""Exception to signal the parser is stuck."""
@@ -104,11 +108,12 @@ class Parser(object):
# Each stack entry is a tuple: (dfa, state, node).
# A node is a tuple: (type, value, context, children),
# where children is a list of nodes or None, and context may be None.
- newnode = (start, None, None, [])
+ newnode = (start, None, None, []) # type: Tuple[unicode, unicode, unicode, List]
stackentry = (self.grammar.dfas[start], 0, newnode)
self.stack = [stackentry]
- self.rootnode = None
- self.used_names = set() # Aliased to self.rootnode.used_names in pop()
+ self.rootnode = None # type: Any
+ self.used_names = set() # type: Set[unicode]
+ # Aliased to self.rootnode.used_names in pop()
def addtoken(self, type, value, context):
"""Add a token; return True iff this is the end of the program."""
@@ -175,7 +180,7 @@ class Parser(object):
def shift(self, type, value, newstate, context):
"""Shift a token. (Internal)"""
dfa, state, node = self.stack[-1]
- newnode = (type, value, context, None)
+ newnode = (type, value, context, None) # type: Tuple[unicode, unicode, unicode, List]
newnode = self.convert(self.grammar, newnode)
if newnode is not None:
node[-1].append(newnode)
@@ -184,7 +189,7 @@ class Parser(object):
def push(self, type, newdfa, newstate, context):
"""Push a nonterminal. (Internal)"""
dfa, state, node = self.stack[-1]
- newnode = (type, None, context, [])
+ newnode = (type, None, context, []) # type: Tuple[unicode, unicode, unicode, List]
self.stack[-1] = (dfa, newstate, node)
self.stack.append((newdfa, 0, newnode))
diff --git a/sphinx/pycode/pgen2/pgen.py b/sphinx/pycode/pgen2/pgen.py
index 7598e6abc..3fe91e57e 100644
--- a/sphinx/pycode/pgen2/pgen.py
+++ b/sphinx/pycode/pgen2/pgen.py
@@ -7,9 +7,13 @@ from six import iteritems
from collections import OrderedDict
# Pgen imports
-
from sphinx.pycode.pgen2 import grammar, token, tokenize
+if False:
+ # For type annotation
+ from typing import Any, Tuple # NOQA
+
+
class PgenGrammar(grammar.Grammar):
pass
@@ -27,7 +31,8 @@ class ParserGenerator(object):
self.dfas, self.startsymbol = self.parse()
if close_stream is not None:
close_stream()
- self.first = {} # map from symbol name to set of tokens
+ self.first = {} # type: Dict[unicode, List[unicode]]
+ # map from symbol name to set of tokens
self.addfirstsets()
def make_grammar(self):
@@ -42,7 +47,7 @@ class ParserGenerator(object):
c.number2symbol[i] = name
for name in names:
dfa = self.dfas[name]
- states = []
+ states = [] # type: List[List[Tuple[int, int]]]
for state in dfa:
arcs = []
for label, next in iteritems(state.arcs):
@@ -122,7 +127,7 @@ class ParserGenerator(object):
dfa = self.dfas[name]
self.first[name] = None # dummy to detect left recursion
state = dfa[0]
- totalset = {}
+ totalset = {} # type: Dict[unicode, int]
overlapcheck = {}
for label, next in iteritems(state.arcs):
if label in self.dfas:
@@ -138,7 +143,7 @@ class ParserGenerator(object):
else:
totalset[label] = 1
overlapcheck[label] = {label: 1}
- inverse = {}
+ inverse = {} # type: Dict[unicode, unicode]
for label, itsfirst in sorted(overlapcheck.items()):
for symbol in sorted(itsfirst):
if symbol in inverse:
@@ -180,7 +185,7 @@ class ParserGenerator(object):
assert isinstance(start, NFAState)
assert isinstance(finish, NFAState)
def closure(state):
- base = {}
+ base = {} # type: Dict
addclosure(state, base)
return base
def addclosure(state, base):
@@ -188,12 +193,12 @@ class ParserGenerator(object):
if state in base:
return
base[state] = 1
- for label, next in state.arcs:
+ for label, next in state.arcs: # type: ignore
if label is None:
addclosure(next, base)
states = [DFAState(closure(start), finish)]
for state in states: # NB states grows while we're iterating
- arcs = {}
+ arcs = {} # type: Dict[unicode, Dict]
for nfastate in state.nfaset:
for label, next in nfastate.arcs:
if label is not None:
@@ -343,7 +348,8 @@ class ParserGenerator(object):
class NFAState(object):
def __init__(self):
- self.arcs = [] # list of (label, NFAState) pairs
+ self.arcs = [] # type: List[Tuple[unicode, Any]]
+ # list of (label, NFAState) pairs
def addarc(self, next, label=None):
assert label is None or isinstance(label, str)
@@ -361,7 +367,8 @@ class DFAState(object):
assert isinstance(final, NFAState)
self.nfaset = nfaset
self.isfinal = final in nfaset
- self.arcs = OrderedDict() # map from label to DFAState
+ self.arcs = OrderedDict() # type: OrderedDict
+ # map from label to DFAState
def __hash__(self):
return hash(tuple(self.arcs))
diff --git a/sphinx/pycode/pgen2/tokenize.py b/sphinx/pycode/pgen2/tokenize.py
index c7013bf91..a096795f8 100644
--- a/sphinx/pycode/pgen2/tokenize.py
+++ b/sphinx/pycode/pgen2/tokenize.py
@@ -183,7 +183,7 @@ def tokenize_loop(readline, tokeneater):
class Untokenizer:
def __init__(self):
- self.tokens = []
+ self.tokens = [] # type: List[unicode]
self.prev_row = 1
self.prev_col = 0
@@ -294,17 +294,17 @@ def generate_tokens(readline):
if contstr: # continued string
if not line:
- raise TokenError("EOF in multi-line string", strstart)
- endmatch = endprog.match(line)
+ raise TokenError("EOF in multi-line string", strstart) # type: ignore
+ endmatch = endprog.match(line) # type: ignore
if endmatch:
pos = end = endmatch.end(0)
- yield (STRING, contstr + line[:end],
- strstart, (lnum, end), contline + line)
+ yield (STRING, contstr + line[:end], # type: ignore
+ strstart, (lnum, end), contline + line) # type: ignore
contstr, needcont = '', 0
contline = None
elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n':
- yield (ERRORTOKEN, contstr + line,
- strstart, (lnum, len(line)), contline)
+ yield (ERRORTOKEN, contstr + line, # type: ignore
+ strstart, (lnum, len(line)), contline) # type: ignore
contstr = ''
contline = None
continue
@@ -333,7 +333,7 @@ def generate_tokens(readline):
yield (NL, line[nl_pos:],
(lnum, nl_pos), (lnum, len(line)), line)
else:
- yield ((NL, COMMENT)[line[pos] == '#'], line[pos:],
+ yield ((NL, COMMENT)[line[pos] == '#'], line[pos:], # type: ignore
(lnum, pos), (lnum, len(line)), line)
continue
diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py
index 3c7ab3d97..eb5349ede 100644
--- a/sphinx/quickstart.py
+++ b/sphinx/quickstart.py
@@ -36,8 +36,9 @@ from docutils.utils import column_width
from sphinx import __display_version__, package_dir
from sphinx.util.osutil import make_filename
-from sphinx.util.console import purple, bold, red, turquoise, \
- nocolor, color_terminal
+from sphinx.util.console import ( # type: ignore
+ purple, bold, red, turquoise, nocolor, color_terminal
+)
from sphinx.util.template import SphinxRenderer
from sphinx.util import texescape
diff --git a/sphinx/roles.py b/sphinx/roles.py
index 6e8de3b4a..01e34fa71 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -175,7 +175,7 @@ def indexmarkup_role(typ, rawtext, text, lineno, inliner,
typ = env.config.default_role
else:
typ = typ.lower()
- has_explicit_title, title, target = split_explicit_title(text)
+ has_explicit_title, title, target = split_explicit_title(text) # type: bool, unicode, unicode # NOQA
title = utils.unescape(title)
target = utils.unescape(target)
targetid = 'index-%s' % env.new_serialno('index')
@@ -186,7 +186,7 @@ def indexmarkup_role(typ, rawtext, text, lineno, inliner,
indexnode['entries'] = [
('single', _('Python Enhancement Proposals; PEP %s') % target,
targetid, '', None)]
- anchor = ''
+ anchor = '' # type: unicode
anchorindex = target.find('#')
if anchorindex > 0:
target, anchor = target[:anchorindex], target[anchorindex:]
diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py
index d3c6c0eba..959e335c3 100644
--- a/sphinx/search/__init__.py
+++ b/sphinx/search/__init__.py
@@ -9,16 +9,23 @@
:license: BSD, see LICENSE for details.
"""
import re
+from os import path
from six import iteritems, itervalues, text_type, string_types
from six.moves import cPickle as pickle
+
from docutils.nodes import raw, comment, title, Text, NodeVisitor, SkipNode
-from os import path
import sphinx
from sphinx.util import jsdump, rpartition
from sphinx.util.pycompat import htmlescape
+if False:
+ # For type annotation
+ from typing import Any, IO, Iterable, Tuple, Type # NOQA
+ from docutils import nodes # NOQA
+ from sphinx.environment import BuildEnvironment # NOQA
+
class SearchLanguage(object):
"""
@@ -42,10 +49,10 @@ class SearchLanguage(object):
This class is used to preprocess search word which Sphinx HTML readers
type, before searching index. Default implementation does nothing.
"""
- lang = None
- language_name = None
- stopwords = set()
- js_stemmer_rawcode = None
+ lang = None # type: unicode
+ language_name = None # type: unicode
+ stopwords = set() # type: Set[unicode]
+ js_stemmer_rawcode = None # type: unicode
js_stemmer_code = """
/**
* Dummy stemmer for languages without stemming rules.
@@ -60,23 +67,27 @@ var Stemmer = function() {
_word_re = re.compile(r'\w+(?u)')
def __init__(self, options):
+ # type: (Dict) -> None
self.options = options
self.init(options)
def init(self, options):
+ # type: (Dict) -> None
"""
Initialize the class with the options the user has given.
"""
def split(self, input):
+ # type: (unicode) -> List[unicode]
"""
This method splits a sentence into words. Default splitter splits input
at white spaces, which should be enough for most languages except CJK
languages.
"""
- return self._word_re.findall(input)
+ return self._word_re.findall(input) # type: ignore
def stem(self, word):
+ # type: (unicode) -> unicode
"""
This method implements stemming algorithm of the Python version.
@@ -90,6 +101,7 @@ var Stemmer = function() {
return word
def word_filter(self, word):
+ # type: (unicode) -> bool
"""
Return true if the target word should be registered in the search index.
This method is called after stemming.
@@ -107,6 +119,7 @@ from sphinx.search.en import SearchEnglish
def parse_stop_word(source):
+ # type: (unicode) -> Set[unicode]
"""
parse snowball style word list like this:
@@ -138,7 +151,7 @@ languages = {
'sv': 'sphinx.search.sv.SearchSwedish',
'tr': 'sphinx.search.tr.SearchTurkish',
'zh': 'sphinx.search.zh.SearchChinese',
-}
+} # type: Dict[unicode, Any]
class _JavaScriptIndex(object):
@@ -151,9 +164,11 @@ class _JavaScriptIndex(object):
SUFFIX = ')'
def dumps(self, data):
+ # type: (Any) -> unicode
return self.PREFIX + jsdump.dumps(data) + self.SUFFIX
def loads(self, s):
+ # type: (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):
@@ -161,9 +176,11 @@ class _JavaScriptIndex(object):
return jsdump.loads(data)
def dump(self, data, f):
+ # type: (Any, IO) -> None
f.write(self.dumps(data))
def load(self, f):
+ # type: (IO) -> Any
return self.loads(f.read())
@@ -176,12 +193,14 @@ class WordCollector(NodeVisitor):
"""
def __init__(self, document, lang):
+ # type: (nodes.Node, SearchLanguage) -> None
NodeVisitor.__init__(self, document)
- self.found_words = []
- self.found_title_words = []
+ self.found_words = [] # type: List[unicode]
+ self.found_title_words = [] # type: List[unicode]
self.lang = lang
def is_meta_keywords(self, node, nodetype):
+ # type: (nodes.Node, Type) -> bool
if isinstance(node, sphinx.addnodes.meta) and node.get('name') == 'keywords':
meta_lang = node.get('lang')
if meta_lang is None: # lang not specified
@@ -192,6 +211,7 @@ class WordCollector(NodeVisitor):
return False
def dispatch_visit(self, node):
+ # type: (nodes.Node) -> None
nodetype = type(node)
if issubclass(nodetype, comment):
raise SkipNode
@@ -223,28 +243,29 @@ class IndexBuilder(object):
formats = {
'jsdump': jsdump,
'pickle': pickle
- }
+ } # type: Dict[unicode, Any]
def __init__(self, env, lang, options, scoring):
+ # type: (BuildEnvironment, unicode, Dict, unicode) -> None
self.env = env
- # docname -> title
- self._titles = {}
- # docname -> filename
- self._filenames = {}
- # stemmed word -> set(docname)
- self._mapping = {}
- # stemmed words in titles -> set(docname)
- self._title_mapping = {}
- # word -> stemmed word
- self._stem_cache = {}
- # objtype -> index
- self._objtypes = {}
- # objtype index -> (domain, type, objname (localized))
- self._objnames = {}
- # add language-specific SearchLanguage instance
- lang_class = languages.get(lang)
+ self._titles = {} # type: Dict[unicode, unicode]
+ # docname -> title
+ self._filenames = {} # type: Dict[unicode, unicode]
+ # docname -> filename
+ self._mapping = {} # type: Dict[unicode, Set[unicode]]
+ # stemmed word -> set(docname)
+ self._title_mapping = {} # type: Dict[unicode, Set[unicode]]
+ # stemmed words in titles -> set(docname)
+ self._stem_cache = {} # type: Dict[unicode, unicode]
+ # word -> stemmed word
+ self._objtypes = {} # type: Dict[Tuple[unicode, unicode], int]
+ # objtype -> index
+ self._objnames = {} # type: Dict[int, Tuple[unicode, unicode, unicode]]
+ # objtype index -> (domain, type, objname (localized))
+ lang_class = languages.get(lang) # type: Type[SearchLanguage]
+ # add language-specific SearchLanguage instance
if lang_class is None:
- self.lang = SearchEnglish(options)
+ self.lang = SearchEnglish(options) # type: SearchLanguage
elif isinstance(lang_class, str):
module, classname = lang_class.rsplit('.', 1)
lang_class = getattr(__import__(module, None, None, [classname]),
@@ -261,6 +282,7 @@ class IndexBuilder(object):
self.js_scorer_code = u''
def load(self, stream, format):
+ # type: (IO, Any) -> None
"""Reconstruct from frozen data."""
if isinstance(format, string_types):
format = self.formats[format]
@@ -273,6 +295,7 @@ class IndexBuilder(object):
self._titles = dict(zip(index2fn, frozen['titles']))
def load_terms(mapping):
+ # type: (Dict[unicode, Any]) -> Dict[unicode, Set[unicode]]
rv = {}
for k, v in iteritems(mapping):
if isinstance(v, int):
@@ -286,13 +309,15 @@ class IndexBuilder(object):
# no need to load keywords/objtypes
def dump(self, stream, format):
+ # type: (IO, Any) -> None
"""Dump the frozen index to a stream."""
if isinstance(format, string_types):
format = self.formats[format]
- format.dump(self.freeze(), stream)
+ format.dump(self.freeze(), stream) # type: ignore
def get_objects(self, fn2index):
- rv = {}
+ # type: (Dict[unicode, int]) -> Dict[unicode, Dict[unicode, Tuple[int, int, int, unicode]]] # NOQA
+ rv = {} # type: Dict[unicode, Dict[unicode, Tuple[int, int, int, unicode]]]
otypes = self._objtypes
onames = self._objnames
for domainname, domain in sorted(iteritems(self.env.domains)):
@@ -319,7 +344,7 @@ class IndexBuilder(object):
else:
onames[typeindex] = (domainname, type, type)
if anchor == fullname:
- shortanchor = ''
+ shortanchor = '' # type: unicode
elif anchor == type + '-' + fullname:
shortanchor = '-'
else:
@@ -328,7 +353,8 @@ class IndexBuilder(object):
return rv
def get_terms(self, fn2index):
- rvs = {}, {}
+ # type: (Dict) -> Tuple[Dict[unicode, List[unicode]], Dict[unicode, List[unicode]]]
+ rvs = {}, {} # type: Tuple[Dict[unicode, List[unicode]], Dict[unicode, List[unicode]]]
for rv, mapping in zip(rvs, (self._mapping, self._title_mapping)):
for k, v in iteritems(mapping):
if len(v) == 1:
@@ -340,6 +366,7 @@ class IndexBuilder(object):
return rvs
def freeze(self):
+ # type: () -> Dict[unicode, Any]
"""Create a usable data structure for serializing."""
docnames, titles = zip(*sorted(self._titles.items()))
filenames = [self._filenames.get(docname) for docname in docnames]
@@ -355,9 +382,11 @@ class IndexBuilder(object):
titleterms=title_terms, envversion=self.env.version)
def label(self):
+ # type: () -> unicode
return "%s (code: %s)" % (self.lang.language_name, self.lang.lang)
def prune(self, filenames):
+ # type: (Iterable[unicode]) -> None
"""Remove data for all filenames not in the list."""
new_titles = {}
for filename in filenames:
@@ -370,6 +399,7 @@ class IndexBuilder(object):
wordnames.intersection_update(filenames)
def feed(self, docname, filename, title, doctree):
+ # type: (unicode, unicode, unicode, nodes.Node) -> None
"""Feed a doctree to the index."""
self._titles[docname] = title
self._filenames[docname] = filename
@@ -379,6 +409,7 @@ class IndexBuilder(object):
# memoize self.lang.stem
def stem(word):
+ # type: (unicode) -> unicode
try:
return self._stem_cache[word]
except KeyError:
@@ -403,6 +434,7 @@ class IndexBuilder(object):
self._mapping.setdefault(stemmed_word, set()).add(docname)
def context_for_searchtool(self):
+ # type: () -> Dict[unicode, Any]
return dict(
search_language_stemming_code = self.lang.js_stemmer_code,
search_language_stop_words = jsdump.dumps(sorted(self.lang.stopwords)),
@@ -410,6 +442,7 @@ class IndexBuilder(object):
)
def get_js_stemmer_rawcode(self):
+ # type: () -> unicode
if self.lang.js_stemmer_rawcode:
return path.join(
path.dirname(path.abspath(__file__)),
diff --git a/sphinx/search/en.py b/sphinx/search/en.py
index d5259bed7..22d4e5acb 100644
--- a/sphinx/search/en.py
+++ b/sphinx/search/en.py
@@ -224,12 +224,15 @@ class SearchEnglish(SearchLanguage):
stopwords = english_stopwords
def init(self, options):
+ # type: (Dict) -> None
if PYSTEMMER:
class Stemmer(object):
def __init__(self):
+ # type: () -> None
self.stemmer = PyStemmer('porter')
def stem(self, word):
+ # type: (unicode) -> unicode
return self.stemmer.stemWord(word)
else:
class Stemmer(PorterStemmer):
@@ -237,9 +240,11 @@ class SearchEnglish(SearchLanguage):
make at least the stem method nicer.
"""
def stem(self, word):
+ # type: (unicode) -> unicode
return PorterStemmer.stem(self, word, 0, len(word) - 1)
self.stemmer = Stemmer()
def stem(self, word):
+ # type: (unicode) -> unicode
return self.stemmer.stem(word.lower())
diff --git a/sphinx/search/ja.py b/sphinx/search/ja.py
index 0d4d01b9c..cf3b67c00 100644
--- a/sphinx/search/ja.py
+++ b/sphinx/search/ja.py
@@ -43,9 +43,11 @@ from sphinx.util import import_object
class BaseSplitter(object):
def __init__(self, options):
+ # type: (Dict) -> None
self.options = options
def split(self, input):
+ # type: (unicode) -> List[unicode]
"""
:param str input:
@@ -57,9 +59,10 @@ class BaseSplitter(object):
class MecabSplitter(BaseSplitter):
def __init__(self, options):
+ # type: (Dict) -> None
super(MecabSplitter, self).__init__(options)
- self.ctypes_libmecab = None
- self.ctypes_mecab = None
+ self.ctypes_libmecab = None # type: ignore
+ self.ctypes_mecab = None # type: ignore
if not native_module:
self.init_ctypes(options)
else:
@@ -67,6 +70,7 @@ class MecabSplitter(BaseSplitter):
self.dict_encode = options.get('dic_enc', 'utf-8')
def split(self, input):
+ # type: (unicode) -> List[unicode]
input2 = input if PY3 else input.encode(self.dict_encode)
if native_module:
result = self.native.parse(input2)
@@ -79,6 +83,7 @@ class MecabSplitter(BaseSplitter):
return result.decode(self.dict_encode).split(' ')
def init_native(self, options):
+ # type: (Dict) -> None
param = '-Owakati'
dict = options.get('dict')
if dict:
@@ -86,6 +91,7 @@ class MecabSplitter(BaseSplitter):
self.native = MeCab.Tagger(param)
def init_ctypes(self, options):
+ # type: (Dict) -> None
import ctypes.util
lib = options.get('lib')
@@ -122,6 +128,7 @@ class MecabSplitter(BaseSplitter):
raise SphinxError('mecab initialization failed')
def __del__(self):
+ # type: () -> None
if self.ctypes_libmecab:
self.ctypes_libmecab.mecab_destroy(self.ctypes_mecab)
@@ -130,17 +137,20 @@ MeCabBinder = MecabSplitter # keep backward compatibility until Sphinx-1.6
class JanomeSplitter(BaseSplitter):
def __init__(self, options):
+ # type: (Dict) -> None
super(JanomeSplitter, self).__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
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: (unicode) -> List[unicode]
result = u' '.join(token.surface for token in self.tokenizer.tokenize(input))
return result.split(u' ')
@@ -417,6 +427,7 @@ class DefaultSplitter(BaseSplitter):
# ctype_
def ctype_(self, char):
+ # type: (unicode) -> unicode
for pattern, value in iteritems(self.patterns_):
if pattern.match(char):
return value
@@ -424,12 +435,14 @@ class DefaultSplitter(BaseSplitter):
# ts_
def ts_(self, dict, key):
+ # type: (Dict[unicode, int], unicode) -> int
if key in dict:
return dict[key]
return 0
# segment
def split(self, input):
+ # type: (unicode) -> List[unicode]
if not input:
return []
@@ -538,6 +551,7 @@ class SearchJapanese(SearchLanguage):
}
def init(self, options):
+ # type: (Dict) -> None
type = options.get('type', 'default')
if type in self.splitters:
dotted_path = self.splitters[type]
@@ -550,10 +564,13 @@ class SearchJapanese(SearchLanguage):
dotted_path)
def split(self, input):
+ # type: (unicode) -> List[unicode]
return self.splitter.split(input)
def word_filter(self, stemmed_word):
+ # type: (unicode) -> bool
return len(stemmed_word) > 1
def stem(self, word):
+ # type: (unicode) -> unicode
return word
diff --git a/sphinx/search/ro.py b/sphinx/search/ro.py
index 78ae01851..f44f38e34 100644
--- a/sphinx/search/ro.py
+++ b/sphinx/search/ro.py
@@ -24,10 +24,12 @@ class SearchRomanian(SearchLanguage):
language_name = 'Romanian'
js_stemmer_rawcode = 'romanian-stemmer.js'
js_stemmer_code = js_stemmer
- stopwords = []
+ stopwords = [] # type: List[unicode]
def init(self, options):
+ # type: (Dict) -> None
self.stemmer = snowballstemmer.stemmer('romanian')
def stem(self, word):
+ # type: (unicode) -> unicode
return self.stemmer.stemWord(word)
diff --git a/sphinx/search/tr.py b/sphinx/search/tr.py
index 33c5c5192..14cc710f8 100644
--- a/sphinx/search/tr.py
+++ b/sphinx/search/tr.py
@@ -24,10 +24,12 @@ class SearchTurkish(SearchLanguage):
language_name = 'Turkish'
js_stemmer_rawcode = 'turkish-stemmer.js'
js_stemmer_code = js_stemmer
- stopwords = []
+ stopwords = [] # type: List[unicode]
def init(self, options):
+ # type: (Dict) -> None
self.stemmer = snowballstemmer.stemmer('turkish')
def stem(self, word):
+ # type: (unicode) -> unicode
return self.stemmer.stemWord(word)
diff --git a/sphinx/search/zh.py b/sphinx/search/zh.py
index c1fecefc6..bd4787506 100644
--- a/sphinx/search/zh.py
+++ b/sphinx/search/zh.py
@@ -238,6 +238,7 @@ class SearchChinese(SearchLanguage):
latin1_letters = re.compile(r'\w+(?u)[\u0000-\u00ff]')
def init(self, options):
+ # type: (Dict) -> None
if JIEBA:
dict_path = options.get('dict')
if dict_path and os.path.isfile(dict_path):
@@ -246,9 +247,11 @@ class SearchChinese(SearchLanguage):
if PYSTEMMER:
class Stemmer(object):
def __init__(self):
+ # type: () -> None
self.stemmer = PyStemmer('porter')
def stem(self, word):
+ # type: (unicode) -> unicode
return self.stemmer.stemWord(word)
else:
class Stemmer(PorterStemmer):
@@ -256,20 +259,24 @@ class SearchChinese(SearchLanguage):
make at least the stem method nicer.
"""
def stem(self, word):
+ # type: (unicode) -> unicode
return PorterStemmer.stem(self, word, 0, len(word) - 1)
self.stemmer = Stemmer()
def split(self, input):
- chinese = []
+ # type: (unicode) -> List[unicode]
+ chinese = [] # type: List[unicode]
if JIEBA:
chinese = list(jieba.cut_for_search(input))
- latin1 = self.latin1_letters.findall(input)
+ latin1 = self.latin1_letters.findall(input) # type: ignore
return chinese + latin1
def word_filter(self, stemmed_word):
+ # type: (unicode) -> bool
return len(stemmed_word) > 1
def stem(self, word):
+ # type: (unicode) -> unicode
return self.stemmer.stem(word)
diff --git a/sphinx/setup_command.py b/sphinx/setup_command.py
index c23f22228..f263f8df1 100644
--- a/sphinx/setup_command.py
+++ b/sphinx/setup_command.py
@@ -18,7 +18,7 @@ import os
from six import StringIO, string_types
from distutils.cmd import Command
-from distutils.errors import DistutilsOptionError, DistutilsExecError
+from distutils.errors import DistutilsOptionError, DistutilsExecError # type: ignore
from sphinx.application import Sphinx
from sphinx.cmdline import handle_exception
@@ -26,6 +26,10 @@ from sphinx.util.console import nocolor, color_terminal
from sphinx.util.docutils import docutils_namespace
from sphinx.util.osutil import abspath
+if False:
+ # For type annotation
+ from typing import Any # NOQA
+
class BuildDoc(Command):
"""
@@ -87,22 +91,24 @@ class BuildDoc(Command):
'link-index']
def initialize_options(self):
+ # type: () -> None
self.fresh_env = self.all_files = False
self.pdb = False
- self.source_dir = self.build_dir = None
+ self.source_dir = self.build_dir = None # type: unicode
self.builder = 'html'
self.warning_is_error = False
self.project = ''
self.version = ''
self.release = ''
self.today = ''
- self.config_dir = None
+ self.config_dir = None # type: unicode
self.link_index = False
self.copyright = ''
self.verbosity = 0
self.traceback = False
def _guess_source_dir(self):
+ # type: () -> unicode
for guess in ('doc', 'docs'):
if not os.path.isdir(guess):
continue
@@ -115,6 +121,7 @@ class BuildDoc(Command):
# unicode, causing finalize_options to fail if invoked again. Workaround
# for http://bugs.python.org/issue19570
def _ensure_stringlike(self, option, what, default=None):
+ # type: (unicode, unicode, Any) -> Any
val = getattr(self, option)
if val is None:
setattr(self, option, default)
@@ -125,10 +132,11 @@ class BuildDoc(Command):
return val
def finalize_options(self):
+ # type: () -> None
if self.source_dir is None:
self.source_dir = self._guess_source_dir()
- self.announce('Using source directory %s' % self.source_dir)
- self.ensure_dirname('source_dir')
+ self.announce('Using source directory %s' % self.source_dir) # type: ignore
+ self.ensure_dirname('source_dir') # type: ignore
if self.source_dir is None:
self.source_dir = os.curdir
self.source_dir = abspath(self.source_dir)
@@ -137,22 +145,23 @@ class BuildDoc(Command):
self.config_dir = abspath(self.config_dir)
if self.build_dir is None:
- build = self.get_finalized_command('build')
+ build = self.get_finalized_command('build') # type: ignore
self.build_dir = os.path.join(abspath(build.build_base), 'sphinx')
- self.mkpath(self.build_dir)
+ self.mkpath(self.build_dir) # type: ignore
self.build_dir = abspath(self.build_dir)
self.doctree_dir = os.path.join(self.build_dir, 'doctrees')
- self.mkpath(self.doctree_dir)
+ self.mkpath(self.doctree_dir) # type: ignore
self.builder_target_dir = os.path.join(self.build_dir, self.builder)
- self.mkpath(self.builder_target_dir)
+ self.mkpath(self.builder_target_dir) # type: ignore
def run(self):
+ # type: () -> None
if not color_terminal():
nocolor()
- if not self.verbose:
+ if not self.verbose: # type: ignore
status_stream = StringIO()
else:
- status_stream = sys.stdout
+ status_stream = sys.stdout # type: ignore
confoverrides = {}
if self.project:
confoverrides['project'] = self.project
@@ -182,6 +191,6 @@ class BuildDoc(Command):
raise SystemExit(1)
if self.link_index:
- src = app.config.master_doc + app.builder.out_suffix
- dst = app.builder.get_outfilename('index')
+ src = app.config.master_doc + app.builder.out_suffix # type: ignore
+ dst = app.builder.get_outfilename('index') # type: ignore
os.symlink(src, dst)
diff --git a/sphinx/theming.py b/sphinx/theming.py
index 42e4448db..4e05652cd 100644
--- a/sphinx/theming.py
+++ b/sphinx/theming.py
@@ -16,7 +16,8 @@ import tempfile
from os import path
from six import string_types, iteritems
-from six.moves import configparser
+from six.moves import configparser # type: ignore
+from typing import Any, Callable, Tuple # NOQA
try:
import pkg_resources
@@ -26,6 +27,10 @@ except ImportError:
from sphinx import package_dir
from sphinx.errors import ThemeError
+if False:
+ # For type annotation
+ from typing import Any, Callable, Tuple # NOQA
+
NODEFAULT = object()
THEMECONF = 'theme.conf'
@@ -34,10 +39,12 @@ class Theme(object):
"""
Represents the theme chosen in the configuration.
"""
- themes = {}
+ themes = {} # type: Dict[unicode, Tuple[unicode, zipfile.ZipFile]]
+ themepath = [] # type: List[unicode]
@classmethod
def init_themes(cls, confdir, theme_path, warn=None):
+ # type: (unicode, unicode, Callable) -> None
"""Search all theme paths for available themes."""
cls.themepath = list(theme_path)
cls.themepath.append(path.join(package_dir, 'themes'))
@@ -49,7 +56,7 @@ class Theme(object):
for theme in os.listdir(themedir):
if theme.lower().endswith('.zip'):
try:
- zfile = zipfile.ZipFile(path.join(themedir, theme))
+ zfile = zipfile.ZipFile(path.join(themedir, theme)) # type: ignore
if THEMECONF not in zfile.namelist():
continue
tname = theme[:-4]
@@ -68,6 +75,7 @@ class Theme(object):
@classmethod
def load_extra_theme(cls, name):
+ # type: (unicode) -> None
themes = ['alabaster']
try:
import sphinx_rtd_theme
@@ -98,6 +106,7 @@ class Theme(object):
return
def __init__(self, name, warn=None):
+ # type: (unicode, Callable) -> None
if name not in self.themes:
self.load_extra_theme(name)
if name not in self.themes:
@@ -156,6 +165,7 @@ class Theme(object):
self.base = Theme(inherit, warn=warn)
def get_confstr(self, section, name, default=NODEFAULT):
+ # type: (unicode, unicode, Any) -> Any
"""Return the value for a theme configuration setting, searching the
base theme chain.
"""
@@ -171,13 +181,14 @@ class Theme(object):
return default
def get_options(self, overrides):
+ # type: (Dict) -> Any
"""Return a dictionary of theme options and their values."""
chain = [self.themeconf]
base = self.base
while base is not None:
chain.append(base.themeconf)
base = base.base
- options = {}
+ options = {} # type: Dict[unicode, Any]
for conf in reversed(chain):
try:
options.update(conf.items('options'))
@@ -190,6 +201,7 @@ class Theme(object):
return options
def get_dirchain(self):
+ # type: () -> List[unicode]
"""Return a list of theme directories, beginning with this theme's,
then the base theme's, then that one's base theme's, etc.
"""
@@ -201,6 +213,7 @@ class Theme(object):
return chain
def cleanup(self):
+ # type: () -> None
"""Remove temporary directories."""
if self.themedir_created:
try:
@@ -212,6 +225,7 @@ class Theme(object):
def load_theme_plugins():
+ # type: () -> List[unicode]
"""load plugins by using``sphinx_themes`` section in setuptools entry_points.
This API will return list of directory that contain some theme directory.
"""
@@ -219,7 +233,7 @@ def load_theme_plugins():
if not pkg_resources:
return []
- theme_paths = []
+ theme_paths = [] # type: List[unicode]
for plugin in pkg_resources.iter_entry_points('sphinx_themes'):
func_or_path = plugin.load()
@@ -229,7 +243,7 @@ def load_theme_plugins():
path = func_or_path
if isinstance(path, string_types):
- theme_paths.append(path)
+ theme_paths.append(path) # type: ignore
else:
raise ThemeError('Plugin %r does not response correctly.' %
plugin.module_name)
diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py
index 79ac99c9f..68e45d62d 100644
--- a/sphinx/transforms/__init__.py
+++ b/sphinx/transforms/__init__.py
@@ -33,6 +33,7 @@ class DefaultSubstitutions(Transform):
default_priority = 210
def apply(self):
+ # type: () -> None
env = self.document.settings.env
config = self.document.settings.env.config
# only handle those not otherwise defined in the document
@@ -58,6 +59,7 @@ class MoveModuleTargets(Transform):
default_priority = 210
def apply(self):
+ # type: () -> None
for node in self.document.traverse(nodes.target):
if not node['ids']:
continue
@@ -76,6 +78,7 @@ class HandleCodeBlocks(Transform):
default_priority = 210
def apply(self):
+ # type: () -> None
# move doctest blocks out of blockquotes
for node in self.document.traverse(nodes.block_quote):
if all(isinstance(child, nodes.doctest_block) for child
@@ -100,6 +103,7 @@ class AutoNumbering(Transform):
default_priority = 210
def apply(self):
+ # type: () -> None
domain = self.document.settings.env.domains['std']
for node in self.document.traverse(nodes.Element):
@@ -114,6 +118,7 @@ class SortIds(Transform):
default_priority = 261
def apply(self):
+ # type: () -> None
for node in self.document.traverse(nodes.section):
if len(node['ids']) > 1 and node['ids'][0].startswith('id'):
node['ids'] = node['ids'][1:] + [node['ids'][0]]
@@ -127,6 +132,7 @@ class CitationReferences(Transform):
default_priority = 619
def apply(self):
+ # type: () -> None
for citnode in self.document.traverse(nodes.citation_reference):
cittext = citnode.astext()
refnode = addnodes.pending_xref(cittext, refdomain='std', reftype='citation',
@@ -154,6 +160,7 @@ class ApplySourceWorkaround(Transform):
default_priority = 10
def apply(self):
+ # type: () -> None
for n in self.document.traverse():
if isinstance(n, nodes.TextElement):
apply_source_workaround(n)
@@ -166,6 +173,7 @@ class AutoIndexUpgrader(Transform):
default_priority = 210
def apply(self):
+ # type: () -> None
env = self.document.settings.env
for node in self.document.traverse(addnodes.index):
if 'entries' in node and any(len(entry) == 4 for entry in node['entries']):
@@ -184,12 +192,14 @@ class ExtraTranslatableNodes(Transform):
default_priority = 10
def apply(self):
+ # type: () -> None
targets = self.document.settings.env.config.gettext_additional_targets
target_nodes = [v for k, v in TRANSLATABLE_NODES.items() if k in targets]
if not target_nodes:
return
def is_translatable_node(node):
+ # type: (nodes.Node) -> bool
return isinstance(node, tuple(target_nodes))
for node in self.document.traverse(is_translatable_node):
@@ -201,6 +211,7 @@ class FilterSystemMessages(Transform):
default_priority = 999
def apply(self):
+ # type: () -> None
env = self.document.settings.env
filterlevel = env.config.keep_warnings and 2 or 5
for node in self.document.traverse(nodes.system_message):
@@ -215,9 +226,11 @@ class SphinxContentsFilter(ContentsFilter):
within table-of-contents link nodes.
"""
def visit_pending_xref(self, node):
+ # type: (nodes.Node) -> None
text = node.astext()
self.parent.append(nodes.literal(text, text))
raise nodes.SkipNode
def visit_image(self, node):
+ # type: (nodes.Node) -> None
raise nodes.SkipNode
diff --git a/sphinx/transforms/compact_bullet_list.py b/sphinx/transforms/compact_bullet_list.py
index 61b23f382..0fe2e8b83 100644
--- a/sphinx/transforms/compact_bullet_list.py
+++ b/sphinx/transforms/compact_bullet_list.py
@@ -23,12 +23,15 @@ class RefOnlyListChecker(nodes.GenericNodeVisitor):
"""
def default_visit(self, node):
+ # type: (nodes.Node) -> None
raise nodes.NodeFound
def visit_bullet_list(self, node):
+ # type: (nodes.Node) -> None
pass
def visit_list_item(self, node):
+ # type: (nodes.Node) -> None
children = []
for child in node.children:
if not isinstance(child, nodes.Invisible):
@@ -45,6 +48,7 @@ class RefOnlyListChecker(nodes.GenericNodeVisitor):
raise nodes.SkipChildren
def invisible_visit(self, node):
+ # type: (nodes.Node) -> None
"""Invisible nodes should be ignored."""
pass
@@ -58,11 +62,13 @@ class RefOnlyBulletListTransform(Transform):
default_priority = 100
def apply(self):
+ # type: () -> None
env = self.document.settings.env
if env.config.html_compact_lists:
return
def check_refonly_list(node):
+ # type: (nodes.Node) -> bool
"""Check for list with only references in it."""
visitor = RefOnlyListChecker(self.document)
try:
diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py
index 38c5aef25..693ae663e 100644
--- a/sphinx/transforms/i18n.py
+++ b/sphinx/transforms/i18n.py
@@ -27,8 +27,15 @@ from sphinx.util.pycompat import indent
from sphinx.locale import init as init_locale
from sphinx.domains.std import make_glossary_term, split_term_classifiers
+if False:
+ # For type annotation
+ from typing import Any, Tuple # NOQA
+ from sphinx.application import Sphinx # NOQA
+ from sphinx.config import Config # NOQA
+
def publish_msgstr(app, source, source_path, source_line, config, settings):
+ # type: (Sphinx, unicode, unicode, int, Config, Dict) -> nodes.document
"""Publish msgstr (single line) into docutils document
:param sphinx.application.Sphinx app: sphinx application
@@ -66,6 +73,7 @@ class PreserveTranslatableMessages(Transform):
default_priority = 10 # this MUST be invoked before Locale transform
def apply(self):
+ # type: () -> None
for node in self.document.traverse(addnodes.translatable):
node.preserve_original_messages()
@@ -77,6 +85,7 @@ class Locale(Transform):
default_priority = 20
def apply(self):
+ # type: () -> None
env = self.document.settings.env
settings, source = self.document.settings, self.document['source']
# XXX check if this is reliable
@@ -176,6 +185,7 @@ class Locale(Transform):
# replace target's refname to new target name
def is_named_target(node):
+ # type: (nodes.Node) -> bool
return isinstance(node, nodes.target) and \
node.get('refname') == old_name
for old_target in self.document.traverse(is_named_target):
@@ -249,10 +259,12 @@ class Locale(Transform):
# auto-numbered foot note reference should use original 'ids'.
def is_autonumber_footnote_ref(node):
+ # type: (nodes.Node) -> bool
return isinstance(node, nodes.footnote_reference) and \
node.get('auto') == 1
def list_replace_or_append(lst, old, new):
+ # type: (List, Any, Any) -> None
if old in lst:
lst[lst.index(old)] = new
else:
@@ -262,7 +274,7 @@ class Locale(Transform):
if len(old_foot_refs) != len(new_foot_refs):
env.warn_node('inconsistent footnote references in '
'translated message', node)
- old_foot_namerefs = {}
+ old_foot_namerefs = {} # type: Dict[unicode, List[nodes.footnote_reference]]
for r in old_foot_refs:
old_foot_namerefs.setdefault(r.get('refname'), []).append(r)
for new in new_foot_refs:
@@ -315,6 +327,7 @@ class Locale(Transform):
# refnamed footnote and citation should use original 'ids'.
def is_refnamed_footnote_ref(node):
+ # type: (nodes.Node) -> bool
footnote_ref_classes = (nodes.footnote_reference,
nodes.citation_reference)
return isinstance(node, footnote_ref_classes) and \
@@ -343,6 +356,7 @@ class Locale(Transform):
'translated message', node)
def get_ref_key(node):
+ # type: (nodes.Node) -> Tuple[unicode, unicode, unicode]
case = node["refdomain"], node["reftype"]
if case == ('std', 'term'):
return None
@@ -384,7 +398,7 @@ class Locale(Transform):
if 'index' in env.config.gettext_additional_targets:
# Extract and translate messages for index entries.
for node, entries in traverse_translatable_index(self.document):
- new_entries = []
+ new_entries = [] # type: List[Tuple[unicode, unicode, unicode, unicode, unicode]] # NOQA
for type, msg, tid, main, key_ in entries:
msg_parts = split_index_msg(type, msg)
msgstr_parts = []
@@ -407,6 +421,7 @@ class RemoveTranslatableInline(Transform):
default_priority = 999
def apply(self):
+ # type: () -> None
from sphinx.builders.gettext import MessageCatalogBuilder
env = self.document.settings.env
builder = env.app.builder
diff --git a/sphinx/versioning.py b/sphinx/versioning.py
index f6c446b4f..0f862ac67 100644
--- a/sphinx/versioning.py
+++ b/sphinx/versioning.py
@@ -16,6 +16,11 @@ from itertools import product
from six import iteritems
from six.moves import range, zip_longest
+if False:
+ # For type annotation
+ from typing import Any, Iterator # NOQA
+ from docutils import nodes # NOQA
+
try:
import Levenshtein
IS_SPEEDUP = True
@@ -27,6 +32,7 @@ VERSIONING_RATIO = 65
def add_uids(doctree, condition):
+ # type: (nodes.Node, Any) -> Iterator[nodes.Node]
"""Add a unique id to every node in the `doctree` which matches the
condition and yield the nodes.
@@ -42,6 +48,7 @@ def add_uids(doctree, condition):
def merge_doctrees(old, new, condition):
+ # type: (nodes.Node, nodes.Node, Any) -> Iterator[nodes.Node]
"""Merge the `old` doctree with the `new` one while looking at nodes
matching the `condition`.
@@ -90,7 +97,7 @@ def merge_doctrees(old, new, condition):
# choose the old node with the best ratio for each new node and set the uid
# as long as the ratio is under a certain value, in which case we consider
# them not changed but different
- ratios = sorted(iteritems(ratios), key=itemgetter(1))
+ ratios = sorted(iteritems(ratios), key=itemgetter(1)) # type: ignore
for (old_node, new_node), ratio in ratios:
if new_node in seen:
continue
@@ -109,6 +116,7 @@ def merge_doctrees(old, new, condition):
def get_ratio(old, new):
+ # type: (unicode, unicode) -> float
"""Return a "similiarity ratio" (in percent) representing the similarity
between the two strings where 0 is equal and anything above less than equal.
"""
@@ -122,6 +130,7 @@ def get_ratio(old, new):
def levenshtein_distance(a, b):
+ # type: (unicode, unicode) -> int
"""Return the Levenshtein edit distance between two strings *a* and *b*."""
if a == b:
return 0
@@ -137,5 +146,5 @@ def levenshtein_distance(a, b):
deletions = current_row[j] + 1
substitutions = previous_row[j] + (column1 != column2)
current_row.append(min(insertions, deletions, substitutions))
- previous_row = current_row
+ previous_row = current_row # type: ignore
return previous_row[-1]
diff --git a/sphinx/websupport/__init__.py b/sphinx/websupport/__init__.py
index 69914da95..f7b215f83 100644
--- a/sphinx/websupport/__init__.py
+++ b/sphinx/websupport/__init__.py
@@ -66,7 +66,7 @@ class WebSupport(object):
self._init_search(search)
self._init_storage(storage)
- self._globalcontext = None
+ self._globalcontext = None # type: ignore
self._make_base_comment_options()
@@ -119,7 +119,7 @@ class WebSupport(object):
raise RuntimeError('No srcdir associated with WebSupport object')
app = Sphinx(self.srcdir, self.srcdir, self.outdir, self.doctreedir,
'websupport', status=self.status, warning=self.warning)
- app.builder.set_webinfo(self.staticdir, self.staticroot,
+ app.builder.set_webinfo(self.staticdir, self.staticroot, # type: ignore
self.search, self.storage)
self.storage.pre_build()
@@ -384,7 +384,7 @@ class WebSupport(object):
that remains the same throughout the lifetime of the
:class:`~sphinx.websupport.WebSupport` object.
"""
- self.base_comment_opts = {}
+ self.base_comment_opts = {} # type: Dict[unicode, unicode]
if self.docroot != '':
comment_urls = [
diff --git a/sphinx/websupport/storage/sqlalchemy_db.py b/sphinx/websupport/storage/sqlalchemy_db.py
index b412ad488..16418ec8f 100644
--- a/sphinx/websupport/storage/sqlalchemy_db.py
+++ b/sphinx/websupport/storage/sqlalchemy_db.py
@@ -14,7 +14,7 @@ from datetime import datetime
from sqlalchemy import Column, Integer, Text, String, Boolean, \
ForeignKey, DateTime
-from sqlalchemy.orm import relation, sessionmaker, aliased
+from sqlalchemy.orm import relation, sessionmaker, aliased # type: ignore
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
@@ -23,7 +23,7 @@ Session = sessionmaker()
db_prefix = 'sphinx_'
-class Node(Base):
+class Node(Base): # type: ignore
"""Data about a Node in a doctree."""
__tablename__ = db_prefix + 'nodes'
@@ -74,7 +74,7 @@ class Node(Base):
:param results: the flat list of comments
:param username: the name of the user requesting the comments.
"""
- comments = []
+ comments = [] # type: List
list_stack = [comments]
for r in results:
if username:
@@ -101,7 +101,7 @@ class Node(Base):
self.source = source
-class CommentVote(Base):
+class CommentVote(Base): # type: ignore
"""A vote a user has made on a Comment."""
__tablename__ = db_prefix + 'commentvote'
@@ -117,7 +117,7 @@ class CommentVote(Base):
self.value = value
-class Comment(Base):
+class Comment(Base): # type: ignore
"""An individual Comment being stored."""
__tablename__ = db_prefix + 'comments'
diff --git a/sphinx/websupport/storage/sqlalchemystorage.py b/sphinx/websupport/storage/sqlalchemystorage.py
index c8794f75c..8b7d76714 100644
--- a/sphinx/websupport/storage/sqlalchemystorage.py
+++ b/sphinx/websupport/storage/sqlalchemystorage.py
@@ -12,7 +12,7 @@
from datetime import datetime
import sqlalchemy
-from sqlalchemy.orm import aliased
+from sqlalchemy.orm import aliased # type: ignore
from sqlalchemy.sql import func
from sphinx.websupport.errors import CommentNotAllowedError, \
@@ -22,7 +22,7 @@ from sphinx.websupport.storage.sqlalchemy_db import Base, Node, \
Comment, CommentVote, Session
from sphinx.websupport.storage.differ import CombinedHtmlDiff
-if sqlalchemy.__version__[:3] < '0.5':
+if sqlalchemy.__version__[:3] < '0.5': # type: ignore
raise ImportError('SQLAlchemy version 0.5 or greater is required for this '
'storage backend; you have version %s' % sqlalchemy.__version__)