summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sphinx/addnodes.py12
-rw-r--r--sphinx/application.py2
-rw-r--r--sphinx/builders/__init__.py2
-rw-r--r--sphinx/builders/changes.py1
-rw-r--r--sphinx/builders/dummy.py13
-rw-r--r--sphinx/builders/epub3.py26
-rw-r--r--sphinx/builders/html.py5
-rw-r--r--sphinx/builders/htmlhelp.py18
-rw-r--r--sphinx/builders/latex.py3
-rw-r--r--sphinx/builders/qthelp.py1
-rw-r--r--sphinx/builders/text.py15
-rw-r--r--sphinx/builders/websupport.py25
-rw-r--r--sphinx/builders/xml.py14
-rw-r--r--sphinx/directives/patches.py7
-rw-r--r--sphinx/errors.py10
-rw-r--r--sphinx/ext/autodoc.py2
-rw-r--r--sphinx/io.py5
-rw-r--r--sphinx/parsers.py5
-rw-r--r--sphinx/pycode/pgen2/pgen.py2
-rw-r--r--sphinx/pycode/pgen2/tokenize.py4
-rw-r--r--sphinx/util/__init__.py30
-rw-r--r--sphinx/util/compat.py6
-rw-r--r--sphinx/util/console.py1
-rw-r--r--sphinx/util/docfields.py7
-rw-r--r--sphinx/util/docstrings.py2
-rw-r--r--sphinx/util/docutils.py9
-rw-r--r--sphinx/util/fileutil.py14
-rw-r--r--sphinx/util/images.py8
-rw-r--r--sphinx/util/inspect.py6
-rw-r--r--sphinx/util/jsdump.py5
-rw-r--r--sphinx/util/jsonimpl.py11
-rw-r--r--sphinx/util/logging.py12
-rw-r--r--sphinx/util/nodes.py1
-rw-r--r--sphinx/util/osutil.py12
-rw-r--r--sphinx/util/png.py2
-rw-r--r--sphinx/util/pycompat.py7
-rw-r--r--sphinx/util/requests.py12
-rw-r--r--sphinx/util/rst.py3
-rw-r--r--sphinx/util/smartypants.py14
-rw-r--r--sphinx/util/stemmer/porter.py21
-rw-r--r--sphinx/util/tags.py12
-rw-r--r--sphinx/util/template.py12
-rw-r--r--sphinx/util/texescape.py1
-rw-r--r--sphinx/util/websupport.py5
-rw-r--r--sphinx/writers/latex.py2
45 files changed, 341 insertions, 46 deletions
diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py
index c410cb9b7..1cadb27e5 100644
--- a/sphinx/addnodes.py
+++ b/sphinx/addnodes.py
@@ -11,6 +11,10 @@
from docutils import nodes
+if False:
+ # For type annotation
+ from typing import Sequence # NOQA
+
class translatable(object):
"""Node which supports translation.
@@ -27,14 +31,17 @@ class translatable(object):
"""
def preserve_original_messages(self):
+ # type: () -> None
"""Preserve original translatable messages."""
raise NotImplementedError
def apply_translated_message(self, original_message, translated_message):
+ # type: (unicode, unicode) -> None
"""Apply translated message."""
raise NotImplementedError
def extract_original_messages(self):
+ # type: () -> Sequence[unicode]
"""Extract translation messages.
:returns: list of extracted messages or messages generator
@@ -46,14 +53,17 @@ class toctree(nodes.General, nodes.Element, translatable):
"""Node for inserting a "TOC tree"."""
def preserve_original_messages(self):
+ # type: () -> None
if self.get('caption'):
self['rawcaption'] = self['caption']
def apply_translated_message(self, original_message, translated_message):
+ # type: (unicode, unicode) -> None
if self.get('rawcaption') == original_message:
self['caption'] = translated_message
def extract_original_messages(self):
+ # type: () -> List[unicode]
if 'rawcaption' in self:
return [self['rawcaption']]
else:
@@ -106,6 +116,7 @@ class desc_type(nodes.Part, nodes.Inline, nodes.TextElement):
class desc_returns(desc_type):
"""Node for a "returns" annotation (a la -> in Python)."""
def astext(self):
+ # type: () -> unicode
return ' -> ' + nodes.TextElement.astext(self)
@@ -127,6 +138,7 @@ class desc_optional(nodes.Part, nodes.Inline, nodes.TextElement):
child_text_separator = ', '
def astext(self):
+ # type: () -> unicode
return '[' + nodes.TextElement.astext(self) + ']'
diff --git a/sphinx/application.py b/sphinx/application.py
index d10b89b99..782dccb9a 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -128,7 +128,7 @@ class Sphinx(object):
confoverrides=None, status=sys.stdout, warning=sys.stderr,
freshenv=False, warningiserror=False, tags=None, verbosity=0,
parallel=0):
- # type: (unicode, unicode, unicode, unicode, unicode, Dict, IO, IO, bool, bool, unicode, int, int) -> None # NOQA
+ # type: (unicode, unicode, unicode, unicode, unicode, Dict, IO, IO, bool, bool, List[unicode], int, int) -> None # NOQA
self.verbosity = verbosity
self.next_listener_id = 0
self._extensions = {} # type: Dict[unicode, Any]
diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py
index be86b7cb1..35280f45f 100644
--- a/sphinx/builders/__init__.py
+++ b/sphinx/builders/__init__.py
@@ -180,6 +180,7 @@ class Builder(object):
return
def cat2relpath(cat):
+ # type: (CatalogInfo) -> unicode
return path.relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP)
logger.info(bold('building [mo]: ') + message)
@@ -202,6 +203,7 @@ class Builder(object):
def compile_specific_catalogs(self, specified_files):
# type: (List[unicode]) -> None
def to_domain(fpath):
+ # type: (unicode) -> unicode
docname, _ = path.splitext(path_stabilize(fpath))
dom = find_catalog(docname, self.config.gettext_compact)
return dom
diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py
index fc8532794..1dc22f4ae 100644
--- a/sphinx/builders/changes.py
+++ b/sphinx/builders/changes.py
@@ -122,6 +122,7 @@ class ChangesBuilder(Builder):
'.. deprecated:: %s' % version]
def hl(no, line):
+ # type: (int, unicode) -> unicode
line = '<a name="L%s"> </a>' % no + htmlescape(line)
for x in hltext:
if x in line:
diff --git a/sphinx/builders/dummy.py b/sphinx/builders/dummy.py
index 2fb146ecf..2ba6337a6 100644
--- a/sphinx/builders/dummy.py
+++ b/sphinx/builders/dummy.py
@@ -12,31 +12,44 @@
from sphinx.builders import Builder
+if False:
+ # For type annotation
+ from typing import Any # NOQA
+ from docutils import nodes # NOQA
+ from sphinx.application import Sphinx # NOQA
+
class DummyBuilder(Builder):
name = 'dummy'
allow_parallel = True
def init(self):
+ # type: () -> None
pass
def get_outdated_docs(self):
+ # type: () -> Set[unicode]
return self.env.found_docs
def get_target_uri(self, docname, typ=None):
+ # type: (unicode, unicode) -> unicode
return ''
def prepare_writing(self, docnames):
+ # type: (Set[unicode]) -> None
pass
def write_doc(self, docname, doctree):
+ # type: (unicode, nodes.Node) -> None
pass
def finish(self):
+ # type: () -> None
pass
def setup(app):
+ # type: (Sphinx) -> Dict[unicode, Any]
app.add_builder(DummyBuilder)
return {
diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py
index c2022e622..2723bff9c 100644
--- a/sphinx/builders/epub3.py
+++ b/sphinx/builders/epub3.py
@@ -18,6 +18,11 @@ from sphinx.config import string_classes
from sphinx.builders.epub import EpubBuilder
from sphinx.util import logging
+if False:
+ # For type annotation
+ from typing import Any, Iterable # NOQA
+ from docutils import nodes # NOQA
+ from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
@@ -117,6 +122,7 @@ class Epub3Builder(EpubBuilder):
# Finish by building the epub file
def handle_finish(self):
+ # type: () -> None
"""Create the metainfo files and finally the epub."""
self.get_toc()
self.build_mimetype(self.outdir, 'mimetype')
@@ -127,6 +133,7 @@ class Epub3Builder(EpubBuilder):
self.build_epub(self.outdir, self.config.epub_basename + '.epub')
def content_metadata(self, files, spine, guide):
+ # type: (List[unicode], List[unicode], List[unicode]) -> Dict
"""Create a dictionary with all metadata for the content.opf
file properly escaped.
"""
@@ -141,6 +148,7 @@ class Epub3Builder(EpubBuilder):
return metadata
def _page_progression_direction(self):
+ # type: () -> unicode
if self.config.epub_writing_mode == 'horizontal':
page_progression_direction = 'ltr'
elif self.config.epub_writing_mode == 'vertical':
@@ -150,6 +158,7 @@ class Epub3Builder(EpubBuilder):
return page_progression_direction
def _ibook_scroll_axis(self):
+ # type: () -> unicode
if self.config.epub_writing_mode == 'horizontal':
scroll_axis = 'vertical'
elif self.config.epub_writing_mode == 'vertical':
@@ -159,6 +168,7 @@ class Epub3Builder(EpubBuilder):
return scroll_axis
def _css_writing_mode(self):
+ # type: () -> unicode
if self.config.epub_writing_mode == 'vertical':
editing_mode = 'vertical-rl'
else:
@@ -166,10 +176,12 @@ class Epub3Builder(EpubBuilder):
return editing_mode
def prepare_writing(self, docnames):
+ # type: (Iterable[unicode]) -> None
super(Epub3Builder, self).prepare_writing(docnames)
self.globalcontext['theme_writing_mode'] = self._css_writing_mode()
def new_navlist(self, node, level, has_child):
+ # type: (nodes.Node, int, bool) -> unicode
"""Create a new entry in the toc from the node at given level."""
# XXX Modifies the node
self.tocid += 1
@@ -180,14 +192,17 @@ class Epub3Builder(EpubBuilder):
return self.navlist_template % node
def begin_navlist_block(self, level):
+ # type: (int) -> unicode
return self.navlist_template_begin_block % {
"indent": self.navlist_indent * level
}
def end_navlist_block(self, level):
+ # type: (int) -> unicode
return self.navlist_template_end_block % {"indent": self.navlist_indent * level}
- def build_navlist(self, nodes):
+ def build_navlist(self, navnodes):
+ # type: (List[nodes.Node]) -> unicode
"""Create the toc navigation structure.
This method is almost same as build_navpoints method in epub.py.
@@ -200,7 +215,7 @@ class Epub3Builder(EpubBuilder):
navlist = []
level = 1
usenodes = []
- for node in nodes:
+ for node in navnodes:
if not node['text']:
continue
file = node['refuri'].split('#')[0]
@@ -228,6 +243,7 @@ class Epub3Builder(EpubBuilder):
return '\n'.join(navlist)
def navigation_doc_metadata(self, navlist):
+ # type: (unicode) -> Dict
"""Create a dictionary with all metadata for the nav.xhtml file
properly escaped.
"""
@@ -238,6 +254,7 @@ class Epub3Builder(EpubBuilder):
return metadata
def build_navigation_doc(self, outdir, outname):
+ # type: (unicode, unicode) -> None
"""Write the metainfo file nav.xhtml."""
logger.info('writing %s file...', outname)
@@ -251,8 +268,8 @@ class Epub3Builder(EpubBuilder):
# 'includehidden'
refnodes = self.refnodes
navlist = self.build_navlist(refnodes)
- with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f:
- f.write(self.navigation_doc_template %
+ with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f: # type: ignore
+ f.write(self.navigation_doc_template % # type: ignore
self.navigation_doc_metadata(navlist))
# Add nav.xhtml to epub file
@@ -261,6 +278,7 @@ class Epub3Builder(EpubBuilder):
def setup(app):
+ # type: (Sphinx) -> Dict[unicode, Any]
app.setup_extension('sphinx.builders.epub')
app.add_builder(Epub3Builder)
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index 46daef97c..027c06205 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -598,6 +598,7 @@ class StandaloneHTMLBuilder(Builder):
def copy_download_files(self):
# type: () -> None
def to_relpath(f):
+ # type: (unicode) -> unicode
return relative_path(self.srcdir, f)
# copy downloadable files
if self.env.dlfiles:
@@ -775,6 +776,7 @@ class StandaloneHTMLBuilder(Builder):
def add_sidebars(self, pagename, ctx):
# type: (unicode, Dict) -> None
def has_wildcard(pattern):
+ # type: (unicode) -> bool
return any(char in pattern for char in '*?[')
sidebars = None
matched = None
@@ -823,6 +825,7 @@ class StandaloneHTMLBuilder(Builder):
default_baseuri = default_baseuri.rsplit('#', 1)[0]
def pathto(otheruri, resource=False, baseuri=default_baseuri):
+ # type: (unicode, bool, unicode) -> unicode
if resource and '://' in otheruri:
# allow non-local resources given by scheme
return otheruri
@@ -835,6 +838,7 @@ class StandaloneHTMLBuilder(Builder):
ctx['pathto'] = pathto
def hasdoc(name):
+ # type: (unicode) -> bool
if name in self.env.all_docs:
return True
elif name == 'search' and self.search:
@@ -879,6 +883,7 @@ class StandaloneHTMLBuilder(Builder):
copyfile(self.env.doc2path(pagename), source_name)
def update_page_context(self, pagename, templatename, ctx, event_arg):
+ # type: (unicode, unicode, Dict, Any) -> None
pass
def handle_finish(self):
diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py
index 68fd3b1db..338015aca 100644
--- a/sphinx/builders/htmlhelp.py
+++ b/sphinx/builders/htmlhelp.py
@@ -24,6 +24,11 @@ from sphinx.util import logging
from sphinx.util.osutil import make_filename
from sphinx.util.pycompat import htmlescape
+if False:
+ # For type annotation
+ from typing import Any, IO, Tuple # NOQA
+ from sphinx.application import Sphinx # NOQA
+
logger = logging.getLogger(__name__)
@@ -186,6 +191,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
encoding = 'cp1252'
def init(self):
+ # type: () -> None
StandaloneHTMLBuilder.init(self)
# the output files for HTML help must be .html only
self.out_suffix = '.html'
@@ -196,17 +202,21 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
self.lcid, self.encoding = locale
def open_file(self, outdir, basename, mode='w'):
+ # type: (unicode, unicode, unicode) -> IO
# open a file with the correct encoding for the selected language
- return codecs.open(path.join(outdir, basename), mode,
+ return codecs.open(path.join(outdir, basename), mode, # type: ignore
self.encoding, 'xmlcharrefreplace')
def update_page_context(self, pagename, templatename, ctx, event_arg):
+ # type: (unicode, unicode, Dict, unicode) -> None
ctx['encoding'] = self.encoding
def handle_finish(self):
+ # type: () -> None
self.build_hhx(self.outdir, self.config.htmlhelp_basename)
def write_doc(self, docname, doctree):
+ # type: (unicode, nodes.Node) -> None
for node in doctree.traverse(nodes.reference):
# add ``target=_blank`` attributes to external links
if node.get('internal') is None and 'refuri' in node:
@@ -215,6 +225,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
StandaloneHTMLBuilder.write_doc(self, docname, doctree)
def build_hhx(self, outdir, outname):
+ # type: (unicode, unicode) -> None
logger.info('dumping stopword list...')
with self.open_file(outdir, outname + '.stp') as f:
for word in sorted(stopwords):
@@ -255,6 +266,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
self.config.master_doc, self, prune_toctrees=False)
def write_toc(node, ullevel=0):
+ # type: (nodes.Node, int) -> None
if isinstance(node, nodes.list_item):
f.write('<LI> ')
for subnode in node:
@@ -275,6 +287,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
write_toc(subnode, ullevel)
def istoctree(node):
+ # type: (nodes.Node) -> bool
return isinstance(node, addnodes.compact_paragraph) and \
'toctree' in node
for node in tocdoc.traverse(istoctree):
@@ -287,7 +300,9 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
f.write('<UL>\n')
def write_index(title, refs, subitems):
+ # type: (unicode, List[Tuple[unicode, unicode]], List[Tuple[unicode, List[Tuple[unicode, unicode]]]]) -> None # NOQA
def write_param(name, value):
+ # type: (unicode, unicode) -> None
item = ' <param name="%s" value="%s">\n' % \
(name, value)
f.write(item)
@@ -316,6 +331,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
def setup(app):
+ # type: (Sphinx) -> Dict[unicode, Any]
app.setup_extension('sphinx.builders.html')
app.add_builder(HTMLHelpBuilder)
diff --git a/sphinx/builders/latex.py b/sphinx/builders/latex.py
index 22d2717d4..d3bc50322 100644
--- a/sphinx/builders/latex.py
+++ b/sphinx/builders/latex.py
@@ -38,6 +38,7 @@ if False:
# For type annotation
from typing import Any, Iterable, Tuple, Union # NOQA
from sphinx.application import Sphinx # NOQA
+ from sphinx.config import Config # NOQA
logger = logging.getLogger(__name__)
@@ -259,6 +260,7 @@ def validate_config_values(app):
def default_latex_engine(config):
+ # type: (Config) -> unicode
""" Better default latex_engine settings for specific languages. """
if config.language == 'ja':
return 'platex'
@@ -267,6 +269,7 @@ def default_latex_engine(config):
def default_latex_docclass(config):
+ # type: (Config) -> Dict[unicode, unicode]
""" Better default latex_docclass settings for specific languages. """
if config.language == 'ja':
return {'manual': 'jsbook',
diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py
index 25dec7586..eeb3fdb73 100644
--- a/sphinx/builders/qthelp.py
+++ b/sphinx/builders/qthelp.py
@@ -149,6 +149,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
prune_toctrees=False)
def istoctree(node):
+ # type: (nodes.Node) -> bool
return isinstance(node, addnodes.compact_paragraph) and \
'toctree' in node
sections = []
diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py
index 7147baa5c..bf70f6fdb 100644
--- a/sphinx/builders/text.py
+++ b/sphinx/builders/text.py
@@ -19,6 +19,12 @@ from sphinx.util import logging
from sphinx.util.osutil import ensuredir, os_path
from sphinx.writers.text import TextWriter
+if False:
+ # For type annotation
+ from typing import Any, Iterator # NOQA
+ from docutils import nodes # NOQA
+ from sphinx.application import Sphinx # NOQA
+
logger = logging.getLogger(__name__)
@@ -31,9 +37,11 @@ class TextBuilder(Builder):
current_docname = None # type: unicode
def init(self):
+ # type: () -> None
pass
def get_outdated_docs(self):
+ # type: () -> Iterator[unicode]
for docname in self.env.found_docs:
if docname not in self.env.all_docs:
yield docname
@@ -53,28 +61,33 @@ class TextBuilder(Builder):
pass
def get_target_uri(self, docname, typ=None):
+ # type: (unicode, unicode) -> unicode
return ''
def prepare_writing(self, docnames):
+ # type: (Set[unicode]) -> None
self.writer = TextWriter(self)
def write_doc(self, docname, doctree):
+ # type: (unicode, nodes.Node) -> None
self.current_docname = docname
destination = StringOutput(encoding='utf-8')
self.writer.write(doctree, destination)
outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix)
ensuredir(path.dirname(outfilename))
try:
- with codecs.open(outfilename, 'w', 'utf-8') as f:
+ with codecs.open(outfilename, 'w', 'utf-8') as f: # type: ignore
f.write(self.writer.output)
except (IOError, OSError) as err:
logger.warning("error writing file %s: %s", outfilename, err)
def finish(self):
+ # type: () -> None
pass
def setup(app):
+ # type: (Sphinx) -> Dict[unicode, Any]
app.add_builder(TextBuilder)
app.add_config_value('text_sectionchars', '*=-~"+`', 'env')
diff --git a/sphinx/builders/websupport.py b/sphinx/builders/websupport.py
index 2ed37a697..1982b92cd 100644
--- a/sphinx/builders/websupport.py
+++ b/sphinx/builders/websupport.py
@@ -20,6 +20,12 @@ from sphinx.util.osutil import os_path, relative_uri, ensuredir, copyfile
from sphinx.builders.html import PickleHTMLBuilder
from sphinx.writers.websupport import WebSupportTranslator
+if False:
+ # For type annotation
+ from typing import Any, Iterable, Tuple # NOQA
+ from docutils import nodes # NOQA
+ from sphinx.application import Sphinx # NOQA
+
class WebSupportBuilder(PickleHTMLBuilder):
"""
@@ -30,6 +36,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
versioning_compare = True # for commentable node's uuid stability.
def init(self):
+ # type: () -> None
PickleHTMLBuilder.init(self)
# templates are needed for this builder, but the serializing
# builder does not initialize them
@@ -41,20 +48,24 @@ class WebSupportBuilder(PickleHTMLBuilder):
self.script_files.append('_static/websupport.js')
def set_webinfo(self, staticdir, virtual_staticdir, search, storage):
+ # type: (unicode, unicode, Any, unicode) -> None
self.staticdir = staticdir
self.virtual_staticdir = virtual_staticdir
self.search = search
self.storage = storage
def init_translator_class(self):
+ # type: () -> None
if self.translator_class is None:
self.translator_class = WebSupportTranslator
def prepare_writing(self, docnames):
+ # type: (Iterable[unicode]) -> None
PickleHTMLBuilder.prepare_writing(self, docnames)
self.globalcontext['no_search_suffix'] = True
def write_doc(self, docname, doctree):
+ # type: (unicode, nodes.Node) -> None
destination = StringOutput(encoding='utf-8')
doctree.settings = self.docsettings
@@ -72,6 +83,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
self.handle_page(docname, ctx, event_arg=doctree)
def write_doc_serialized(self, docname, doctree):
+ # type: (unicode, nodes.Node) -> None
self.imgpath = '/' + posixpath.join(self.virtual_staticdir, self.imagedir)
self.post_process_images(doctree)
title = self.env.longtitles.get(docname)
@@ -79,10 +91,12 @@ class WebSupportBuilder(PickleHTMLBuilder):
self.index_page(docname, doctree, title)
def load_indexer(self, docnames):
- self.indexer = self.search
- self.indexer.init_indexing(changed=docnames)
+ # type: (Iterable[unicode]) -> None
+ self.indexer = self.search # type: ignore
+ self.indexer.init_indexing(changed=docnames) # type: ignore
def _render_page(self, pagename, addctx, templatename, event_arg=None):
+ # type: (unicode, Dict, unicode, unicode) -> Tuple[Dict, Dict]
# This is mostly copied from StandaloneHTMLBuilder. However, instead
# of rendering the template and saving the html, create a context
# dict and pickle it.
@@ -91,6 +105,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
def pathto(otheruri, resource=False,
baseuri=self.get_target_uri(pagename)):
+ # type: (unicode, bool, unicode) -> unicode
if resource and '://' in otheruri:
return otheruri
elif not resource:
@@ -128,6 +143,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
def handle_page(self, pagename, addctx, templatename='page.html',
outfilename=None, event_arg=None):
+ # type: (unicode, Dict, unicode, unicode, unicode) -> None
ctx, doc_ctx = self._render_page(pagename, addctx,
templatename, event_arg)
@@ -146,6 +162,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
copyfile(self.env.doc2path(pagename), source_name)
def handle_finish(self):
+ # type: () -> None
# get global values for css and script files
_, doc_ctx = self._render_page('tmp', {}, 'page.html')
self.globalcontext['css'] = doc_ctx['css']
@@ -164,10 +181,12 @@ class WebSupportBuilder(PickleHTMLBuilder):
shutil.move(src, dst)
def dump_search_index(self):
- self.indexer.finish_indexing()
+ # type: () -> None
+ self.indexer.finish_indexing() # type: ignore
def setup(app):
+ # type: (Sphinx) -> Dict[unicode, Any]
app.add_builder(WebSupportBuilder)
return {
diff --git a/sphinx/builders/xml.py b/sphinx/builders/xml.py
index fc43b4c12..c149df83c 100644
--- a/sphinx/builders/xml.py
+++ b/sphinx/builders/xml.py
@@ -20,6 +20,11 @@ from sphinx.util import logging
from sphinx.util.osutil import ensuredir, os_path
from sphinx.writers.xml import XMLWriter, PseudoXMLWriter
+if False:
+ # For type annotation
+ from typing import Any, Iterator # NOQA
+ from sphinx.application import Sphinx # NOQA
+
logger = logging.getLogger(__name__)
@@ -35,9 +40,11 @@ class XMLBuilder(Builder):
_writer_class = XMLWriter
def init(self):
+ # type: () -> None
pass
def get_outdated_docs(self):
+ # type: () -> Iterator[unicode]
for docname in self.env.found_docs:
if docname not in self.env.all_docs:
yield docname
@@ -57,12 +64,15 @@ class XMLBuilder(Builder):
pass
def get_target_uri(self, docname, typ=None):
+ # type: (unicode, unicode) -> unicode
return docname
def prepare_writing(self, docnames):
+ # type: (Set[unicode]) -> None
self.writer = self._writer_class(self)
def write_doc(self, docname, doctree):
+ # type: (unicode, nodes.Node) -> None
# work around multiple string % tuple issues in docutils;
# replace tuples in attribute values with lists
doctree = doctree.deepcopy()
@@ -80,12 +90,13 @@ class XMLBuilder(Builder):
outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix)
ensuredir(path.dirname(outfilename))
try:
- with codecs.open(outfilename, 'w', 'utf-8') as f:
+ with codecs.open(outfilename, 'w', 'utf-8') as f: # type: ignore
f.write(self.writer.output)
except (IOError, OSError) as err:
logger.warning("error writing file %s: %s", outfilename, err)
def finish(self):
+ # type: () -> None
pass
@@ -101,6 +112,7 @@ class PseudoXMLBuilder(XMLBuilder):
def setup(app):
+ # type: (Sphinx) -> Dict[unicode, Any]
app.add_builder(XMLBuilder)
app.add_builder(PseudoXMLBuilder)
diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py
index 8b14ba2b0..2501df417 100644
--- a/sphinx/directives/patches.py
+++ b/sphinx/directives/patches.py
@@ -13,6 +13,10 @@ from docutils.parsers.rst.directives import images, html
from sphinx import addnodes
+if False:
+ # For type annotation
+ from sphinx.application import Sphinx # NOQA
+
class Figure(images.Figure):
"""The figure directive which applies `:name:` option to the figure node
@@ -20,6 +24,7 @@ class Figure(images.Figure):
"""
def run(self):
+ # type: () -> List[nodes.Node]
name = self.options.pop('name', None)
result = images.Figure.run(self)
if len(result) == 2 or isinstance(result[0], nodes.system_message):
@@ -39,6 +44,7 @@ class Figure(images.Figure):
class Meta(html.Meta):
def run(self):
+ # type: () -> List[nodes.Node]
env = self.state.document.settings.env
result = html.Meta.run(self)
for node in result:
@@ -56,6 +62,7 @@ class Meta(html.Meta):
def setup(app):
+ # type: (Sphinx) -> Dict
directives.register_directive('figure', Figure)
directives.register_directive('meta', Meta)
diff --git a/sphinx/errors.py b/sphinx/errors.py
index 01f29d7aa..837bd5cff 100644
--- a/sphinx/errors.py
+++ b/sphinx/errors.py
@@ -10,6 +10,10 @@
:license: BSD, see LICENSE for details.
"""
+if False:
+ # For type annotation
+ from typing import Any # NOQA
+
class SphinxError(Exception):
"""
@@ -29,16 +33,19 @@ class ExtensionError(SphinxError):
category = 'Extension error'
def __init__(self, message, orig_exc=None):
+ # type: (unicode, Exception) -> None
SphinxError.__init__(self, message)
self.orig_exc = orig_exc
def __repr__(self):
+ # type: () -> str
if self.orig_exc:
return '%s(%r, %r)' % (self.__class__.__name__,
self.message, self.orig_exc)
return '%s(%r)' % (self.__class__.__name__, self.message)
def __str__(self):
+ # type: () -> str
parent_str = SphinxError.__str__(self)
if self.orig_exc:
return '%s (exception: %s)' % (parent_str, self.orig_exc)
@@ -59,6 +66,7 @@ class VersionRequirementError(SphinxError):
class PycodeError(Exception):
def __str__(self):
+ # type: () -> str
res = self.args[0]
if len(self.args) > 1:
res += ' (exception was: %r)' % self.args[1]
@@ -70,8 +78,10 @@ class SphinxParallelError(SphinxError):
category = 'Sphinx parallel build error'
def __init__(self, message, traceback):
+ # type: (str, Any) -> None
self.message = message
self.traceback = traceback
def __str__(self):
+ # type: () -> str
return self.message
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index cab900421..7f77d3a3f 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -1193,7 +1193,7 @@ class ClassLevelDocumenter(Documenter):
# ... if still None, there's no way to know
if mod_cls is None:
return None, []
- modname, cls = rpartition(mod_cls, '.')
+ modname, cls = rpartition(mod_cls, '.') # type: ignore
parents = [cls]
# if the module name is still missing, get it like above
if not modname:
diff --git a/sphinx/io.py b/sphinx/io.py
index e29420d97..52b5b1729 100644
--- a/sphinx/io.py
+++ b/sphinx/io.py
@@ -28,7 +28,7 @@ from sphinx.util.docutils import LoggingReporter
if False:
# For type annotation
- from typing import Any, Union # NOQA
+ from typing import Any, Tuple, Union # NOQA
from docutils import nodes # NOQA
from docutils.io import Input # NOQA
from docutils.parsers import Parser # NOQA
@@ -75,6 +75,7 @@ class SphinxBaseReader(standalone.Reader):
return standalone.Reader.get_transforms(self) + self.transforms
def new_document(self):
+ # type: () -> nodes.document
document = standalone.Reader.new_document(self)
reporter = document.reporter
document.reporter = LoggingReporter(reporter.source, reporter.report_level,
@@ -122,6 +123,7 @@ class SphinxI18nReader(SphinxBaseReader):
reporter = document.reporter
def get_source_and_line(lineno=None):
+ # type: (int) -> Tuple[unicode, int]
return reporter.source, self.lineno
reporter.get_source_and_line = get_source_and_line
@@ -153,6 +155,7 @@ class SphinxFileInput(FileInput):
def read(self):
# type: () -> unicode
def get_parser_type(source_path):
+ # type: (unicode) -> Tuple[unicode]
for suffix in self.env.config.source_parsers:
if source_path.endswith(suffix):
parser_class = self.env.config.source_parsers[suffix]
diff --git a/sphinx/parsers.py b/sphinx/parsers.py
index 926de9f1c..1c0a75b06 100644
--- a/sphinx/parsers.py
+++ b/sphinx/parsers.py
@@ -11,6 +11,10 @@
import docutils.parsers
+if False:
+ # For type annotation
+ from sphinx.application import Sphinx # NOQA
+
class Parser(docutils.parsers.Parser):
"""
@@ -33,6 +37,7 @@ class Parser(docutils.parsers.Parser):
"""
def set_application(self, app):
+ # type: (Sphinx) -> None
"""set_application will be called from Sphinx to set app and other instance variables
:param sphinx.application.Sphinx app: Sphinx application object
diff --git a/sphinx/pycode/pgen2/pgen.py b/sphinx/pycode/pgen2/pgen.py
index 3fe91e57e..0106763d0 100644
--- a/sphinx/pycode/pgen2/pgen.py
+++ b/sphinx/pycode/pgen2/pgen.py
@@ -193,7 +193,7 @@ class ParserGenerator(object):
if state in base:
return
base[state] = 1
- for label, next in state.arcs: # type: ignore
+ for label, next in state.arcs:
if label is None:
addclosure(next, base)
states = [DFAState(closure(start), finish)]
diff --git a/sphinx/pycode/pgen2/tokenize.py b/sphinx/pycode/pgen2/tokenize.py
index a096795f8..cbe64a581 100644
--- a/sphinx/pycode/pgen2/tokenize.py
+++ b/sphinx/pycode/pgen2/tokenize.py
@@ -298,12 +298,12 @@ def generate_tokens(readline):
endmatch = endprog.match(line) # type: ignore
if endmatch:
pos = end = endmatch.end(0)
- yield (STRING, contstr + line[:end], # type: ignore
+ yield (STRING, contstr + line[:end],
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, # type: ignore
+ yield (ERRORTOKEN, contstr + line,
strstart, (lnum, len(line)), contline) # type: ignore
contstr = ''
contline = None
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index 3b1f076a9..8206c911d 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -45,7 +45,7 @@ from sphinx.util.matching import patfilter # noqa
if False:
# For type annotation
- from typing import Any, Callable, Iterable, Iterator, Pattern, Sequence, Tuple, Union # NOQA
+ from typing import Any, Callable, IO, Iterable, Iterator, Pattern, Sequence, Tuple, Union # NOQA
logger = logging.getLogger(__name__)
@@ -121,6 +121,7 @@ class FilenameUniqDict(dict):
appear in. Used for images and downloadable files in the environment.
"""
def __init__(self):
+ # type: () -> None
self._existing = set() # type: Set[unicode]
def add_file(self, docname, newfile):
@@ -153,9 +154,11 @@ class FilenameUniqDict(dict):
self.add_file(doc, filename)
def __getstate__(self):
+ # type: () -> Set[unicode]
return self._existing
def __setstate__(self, state):
+ # type: (Set[unicode]) -> None
self._existing = state
@@ -214,7 +217,7 @@ def save_traceback(app):
last_msgs = ''
if app is not None:
last_msgs = '\n'.join(
- '# %s' % strip_colors(force_decode(s, 'utf-8')).strip()
+ '# %s' % strip_colors(force_decode(s, 'utf-8')).strip() # type: ignore
for s in app.messagelog)
os.write(fd, (_DEBUG_HEADER %
(sphinx.__display_version__,
@@ -301,12 +304,14 @@ def detect_encoding(readline):
"""Like tokenize.detect_encoding() from Py3k, but a bit simplified."""
def read_or_stop():
+ # type: () -> unicode
try:
return readline()
except StopIteration:
return None
def get_normal_name(orig_enc):
+ # type: (str) -> str
"""Imitates get_normal_name in tokenizer.c."""
# Only care about the first 12 characters.
enc = orig_enc[:12].lower().replace('_', '-')
@@ -318,12 +323,13 @@ def detect_encoding(readline):
return orig_enc
def find_cookie(line):
+ # type: (unicode) -> unicode
try:
line_string = line.decode('ascii')
except UnicodeDecodeError:
return None
- matches = _coding_re.findall(line_string)
+ matches = _coding_re.findall(line_string) # type: ignore
if not matches:
return None
return get_normal_name(matches[0])
@@ -354,14 +360,17 @@ class Tee(object):
File-like object writing to two streams.
"""
def __init__(self, stream1, stream2):
+ # type: (IO, IO) -> None
self.stream1 = stream1
self.stream2 = stream2
def write(self, text):
+ # type: (unicode) -> None
self.stream1.write(text)
self.stream2.write(text)
def flush(self):
+ # type: () -> None
if hasattr(self.stream1, 'flush'):
self.stream1.flush()
if hasattr(self.stream2, 'flush'):
@@ -369,6 +378,7 @@ class Tee(object):
def parselinenos(spec, total):
+ # type: (unicode, int) -> List[int]
"""Parse a line number spec (such as "1,2,4-6") and return a list of
wanted line numbers.
"""
@@ -391,6 +401,7 @@ def parselinenos(spec, total):
def force_decode(string, encoding):
+ # type: (unicode, unicode) -> unicode
"""Forcibly get a unicode string out of a bytestring."""
if isinstance(string, binary_type):
try:
@@ -407,16 +418,20 @@ def force_decode(string, encoding):
class attrdict(dict):
def __getattr__(self, key):
+ # type: (unicode) -> unicode
return self[key]
def __setattr__(self, key, val):
+ # type: (unicode, unicode) -> None
self[key] = val
def __delattr__(self, key):
+ # type: (unicode) -> None
del self[key]
def rpartition(s, t):
+ # type: (unicode, unicode) -> Tuple[unicode, unicode]
"""Similar to str.rpartition from 2.5, but doesn't return the separator."""
i = s.rfind(t)
if i != -1:
@@ -425,6 +440,7 @@ def rpartition(s, t):
def split_into(n, type, value):
+ # type: (int, unicode, unicode) -> List[unicode]
"""Split an index entry into a given number of parts at semicolons."""
parts = [x.strip() for x in value.split(';', n - 1)]
if sum(1 for part in parts if part) < n:
@@ -433,6 +449,7 @@ def split_into(n, type, value):
def split_index_msg(type, value):
+ # type: (unicode, unicode) -> List[unicode]
# new entry types must be listed in directives/other.py!
if type == 'single':
try:
@@ -471,13 +488,16 @@ class PeekableIterator(object):
what's the next item.
"""
def __init__(self, iterable):
+ # type: (Iterable) -> None
self.remaining = deque() # type: deque
self._iterator = iter(iterable)
def __iter__(self):
+ # type: () -> PeekableIterator
return self
def __next__(self):
+ # type: () -> Any
"""Return the next item from the iterator."""
if self.remaining:
return self.remaining.popleft()
@@ -486,14 +506,16 @@ class PeekableIterator(object):
next = __next__ # Python 2 compatibility
def push(self, item):
+ # type: (Any) -> None
"""Push the `item` on the internal stack, it will be returned on the
next :meth:`next` call.
"""
self.remaining.append(item)
def peek(self):
+ # type: () -> Any
"""Return the next item without changing the state of the iterator."""
- item = next(self)
+ item = next(self) # type: ignore
self.push(item)
return item
diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py
index f47237d11..42406afe7 100644
--- a/sphinx/util/compat.py
+++ b/sphinx/util/compat.py
@@ -20,13 +20,19 @@ from sphinx.deprecation import RemovedInSphinx17Warning
docutils_version = tuple(int(x) for x in _du_version.split('.')[:2])
+if False:
+ # For type annotation
+ from typing import Any # NOQA
+
class _DeprecationWrapper(object):
def __init__(self, mod, deprecated):
+ # type: (Any, Dict) -> None
self._mod = mod
self._deprecated = deprecated
def __getattr__(self, attr):
+ # type: (str) -> Any
if attr in self._deprecated:
warnings.warn("sphinx.util.compat.%s is deprecated and will be "
"removed in Sphinx 1.7, please use the standard "
diff --git a/sphinx/util/console.py b/sphinx/util/console.py
index b418edfb8..ac3d2282f 100644
--- a/sphinx/util/console.py
+++ b/sphinx/util/console.py
@@ -95,6 +95,7 @@ def strip_colors(s):
def create_color_func(name):
# type: (str) -> None
def inner(text):
+ # type: (unicode) -> unicode
return colorize(name, text)
globals()[name] = inner
diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py
index 81b8347c6..f0af0c59d 100644
--- a/sphinx/util/docfields.py
+++ b/sphinx/util/docfields.py
@@ -81,7 +81,7 @@ class Field(object):
return (fieldarg, content)
def make_field(self, types, domain, item):
- # type: (List, unicode, Tuple) -> nodes.field
+ # type: (Dict[unicode, List[nodes.Node]], unicode, Tuple) -> nodes.field
fieldarg, content = item
fieldname = nodes.field_name('', self.label)
if fieldarg:
@@ -122,7 +122,7 @@ class GroupedField(Field):
self.can_collapse = can_collapse
def make_field(self, types, domain, items):
- # type: (List, unicode, Tuple) -> nodes.field
+ # type: (Dict[unicode, List[nodes.Node]], unicode, Tuple) -> nodes.field
fieldname = nodes.field_name('', self.label)
listnode = self.list_type()
for fieldarg, content in items:
@@ -170,8 +170,9 @@ class TypedField(GroupedField):
self.typerolename = typerolename
def make_field(self, types, domain, items):
- # type: (List, unicode, Tuple) -> nodes.field
+ # type: (Dict[unicode, List[nodes.Node]], unicode, Tuple) -> nodes.field
def handle_item(fieldarg, content):
+ # type: (unicode, unicode) -> nodes.paragraph
par = nodes.paragraph()
par.extend(self.make_xrefs(self.rolename, domain, fieldarg,
addnodes.literal_strong))
diff --git a/sphinx/util/docstrings.py b/sphinx/util/docstrings.py
index fba9bf490..e79408da2 100644
--- a/sphinx/util/docstrings.py
+++ b/sphinx/util/docstrings.py
@@ -13,6 +13,7 @@ import sys
def prepare_docstring(s, ignore=1):
+ # type: (unicode, int) -> List[unicode]
"""Convert a docstring into lines of parseable reST. Remove common leading
indentation, where the indentation of a given number of lines (usually just
one) is ignored.
@@ -46,6 +47,7 @@ def prepare_docstring(s, ignore=1):
def prepare_commentdoc(s):
+ # type: (unicode) -> List[unicode]
"""Extract documentation comment lines (starting with #:) and return them
as a list of lines. Returns an empty list if there is no documentation.
"""
diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py
index ae106c190..38fdcde28 100644
--- a/sphinx/util/docutils.py
+++ b/sphinx/util/docutils.py
@@ -63,12 +63,15 @@ class sphinx_domains(object):
self.roles_func = None # type: Callable
def __enter__(self):
+ # type: () -> None
self.enable()
def __exit__(self, type, value, traceback):
+ # type: (unicode, unicode, unicode) -> None
self.disable()
def enable(self):
+ # type: () -> None
self.directive_func = directives.directive
self.role_func = roles.role
@@ -76,6 +79,7 @@ class sphinx_domains(object):
roles.role = self.lookup_role
def disable(self):
+ # type: () -> None
directives.directive = self.directive_func
roles.role = self.role_func
@@ -125,7 +129,8 @@ class sphinx_domains(object):
class WarningStream(object):
def write(self, text):
- matched = report_re.search(text)
+ # type: (unicode) -> None
+ matched = report_re.search(text) # type: ignore
if not matched:
logger.warning(text.rstrip("\r\n"))
else:
@@ -136,9 +141,11 @@ class WarningStream(object):
class LoggingReporter(Reporter):
def __init__(self, source, report_level, halt_level,
debug=False, error_handler='backslashreplace'):
+ # type: (unicode, int, int, bool, unicode) -> None
stream = WarningStream()
Reporter.__init__(self, source, report_level, halt_level,
stream, debug, error_handler=error_handler)
def set_conditions(self, category, report_level, halt_level, debug=False):
+ # type: (unicode, int, int, bool) -> None
Reporter.set_conditions(self, category, report_level, halt_level, debug=debug)
diff --git a/sphinx/util/fileutil.py b/sphinx/util/fileutil.py
index b258c2039..ddfb61e6b 100644
--- a/sphinx/util/fileutil.py
+++ b/sphinx/util/fileutil.py
@@ -16,8 +16,15 @@ import posixpath
from docutils.utils import relative_path
from sphinx.util.osutil import copyfile, ensuredir, walk
+if False:
+ # For type annotation
+ from typing import Callable, Union # NOQA
+ from sphinx.util.matching import Matcher # NOQA
+ from sphinx.util.template import BaseRenderer # NOQA
+
def copy_asset_file(source, destination, context=None, renderer=None):
+ # type: (unicode, unicode, Dict, BaseRenderer) -> None
"""Copy an asset file to destination.
On copying, it expands the template variables if context argument is given and
@@ -40,16 +47,17 @@ def copy_asset_file(source, destination, context=None, renderer=None):
from sphinx.util.template import SphinxRenderer
renderer = SphinxRenderer()
- with codecs.open(source, 'r', encoding='utf-8') as fsrc:
+ with codecs.open(source, 'r', encoding='utf-8') as fsrc: # type: ignore
if destination.lower().endswith('_t'):
destination = destination[:-2]
- with codecs.open(destination, 'w', encoding='utf-8') as fdst:
- fdst.write(renderer.render_string(fsrc.read(), context))
+ with codecs.open(destination, 'w', encoding='utf-8') as fdst: # type: ignore
+ fdst.write(renderer.render_string(fsrc.read(), context)) # type: ignore
else:
copyfile(source, destination)
def copy_asset(source, destination, excluded=lambda path: False, context=None, renderer=None):
+ # type: (unicode, unicode, Union[Callable[[unicode], bool], Matcher], Dict, BaseRenderer) -> None # NOQA
"""Copy asset files to destination recursively.
On copying, it expands the template variables if context argument is given and
diff --git a/sphinx/util/images.py b/sphinx/util/images.py
index 698a030ad..81dfaf681 100644
--- a/sphinx/util/images.py
+++ b/sphinx/util/images.py
@@ -21,14 +21,19 @@ except ImportError:
except ImportError:
Image = None
+if False:
+ # For type annotation
+ from typing import Tuple # NOQA
+
mime_suffixes = {
'.pdf': 'application/pdf',
'.svg': 'image/svg+xml',
'.svgz': 'image/svg+xml',
-}
+} # type: Dict[unicode, unicode]
def get_image_size(filename):
+ # type: (unicode) -> Tuple[int, int]
try:
size = imagesize.get(filename)
if size[0] == -1:
@@ -48,6 +53,7 @@ def get_image_size(filename):
def guess_mimetype(filename):
+ # type: (unicode) -> unicode
_, ext = path.splitext(filename)
if ext in mime_suffixes:
return mime_suffixes[ext]
diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py
index 28bc877b3..3cb795339 100644
--- a/sphinx/util/inspect.py
+++ b/sphinx/util/inspect.py
@@ -18,7 +18,7 @@ from sphinx.util import force_decode
if False:
# For type annotation
- from typing import Any, Callable, Tuple # NOQA
+ from typing import Any, Callable, Tuple, Type # NOQA
# this imports the standard library inspect module without resorting to
# relatively import this module
@@ -68,6 +68,7 @@ else: # 2.7
from functools import partial
def getargspec(func):
+ # type: (Any) -> Any
"""Like inspect.getargspec but supports functools.partial as well."""
if inspect.ismethod(func):
func = func.__func__
@@ -105,6 +106,7 @@ except ImportError:
def isenumclass(x):
+ # type: (Type) -> bool
"""Check if the object is subclass of enum."""
if enum is None:
return False
@@ -174,7 +176,7 @@ def object_description(object):
except Exception:
raise ValueError
if isinstance(s, binary_type):
- s = force_decode(s, None)
+ s = force_decode(s, None) # type: ignore
# Strip non-deterministic memory addresses such as
# ``<__main__.A at 0x7f68cb685710>``
s = memory_address_re.sub('', s)
diff --git a/sphinx/util/jsdump.py b/sphinx/util/jsdump.py
index 7c60a1b70..592a4565f 100644
--- a/sphinx/util/jsdump.py
+++ b/sphinx/util/jsdump.py
@@ -18,7 +18,7 @@ from sphinx.util.pycompat import u
if False:
# For type annotation
- from typing import Any, IO, Union # NOQA
+ from typing import Any, IO, Match, Union # NOQA
_str_re = re.compile(r'"(\\\\|\\"|[^"])*"')
_int_re = re.compile(r'\d+')
@@ -43,6 +43,7 @@ ESCAPED = re.compile(r'\\u.{4}|\\.')
def encode_string(s):
# type: (str) -> str
def replace(match):
+ # type: (Match) -> unicode
s = match.group(0)
try:
return ESCAPE_DICT[s]
@@ -56,7 +57,7 @@ def encode_string(s):
s1 = 0xd800 | ((n >> 10) & 0x3ff)
s2 = 0xdc00 | (n & 0x3ff)
return '\\u%04x\\u%04x' % (s1, s2)
- return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
+ return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' # type: ignore
def decode_string(s):
diff --git a/sphinx/util/jsonimpl.py b/sphinx/util/jsonimpl.py
index 215dfe44d..e5f6a0e72 100644
--- a/sphinx/util/jsonimpl.py
+++ b/sphinx/util/jsonimpl.py
@@ -14,28 +14,37 @@ import json
from six import text_type
from six.moves import UserString
+if False:
+ # For type annotation
+ from typing import Any, IO # NOQA
+
class SphinxJSONEncoder(json.JSONEncoder):
"""JSONEncoder subclass that forces translation proxies."""
def default(self, obj):
+ # type: (Any) -> unicode
if isinstance(obj, UserString):
return text_type(obj)
return json.JSONEncoder.default(self, obj)
def dump(obj, fp, *args, **kwds):
+ # type: (Any, IO, Any, Any) -> unicode
kwds['cls'] = SphinxJSONEncoder
- return json.dump(obj, fp, *args, **kwds)
+ json.dump(obj, fp, *args, **kwds)
def dumps(obj, *args, **kwds):
+ # type: (Any, Any, Any) -> unicode
kwds['cls'] = SphinxJSONEncoder
return json.dumps(obj, *args, **kwds)
def load(*args, **kwds):
+ # type: (Any, Any) -> Any
return json.load(*args, **kwds)
def loads(*args, **kwds):
+ # type: (Any, Any) -> Any
return json.loads(*args, **kwds)
diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py
index b4f8f5796..bc85df6b5 100644
--- a/sphinx/util/logging.py
+++ b/sphinx/util/logging.py
@@ -63,6 +63,7 @@ def getLogger(name):
def convert_serializable(records):
+ # type: (List[logging.LogRecord]) -> None
"""Convert LogRecord serializable."""
for r in records:
# extract arguments to a message and clear them
@@ -174,6 +175,7 @@ class MemoryHandler(logging.handlers.BufferingHandler):
"""Handler buffering all logs."""
def __init__(self):
+ # type: () -> None
super(MemoryHandler, self).__init__(-1)
def shouldFlush(self, record):
@@ -248,10 +250,12 @@ def pending_logging():
class LogCollector(object):
def __init__(self):
- self.logs = [] # type: logging.LogRecord
+ # type: () -> None
+ self.logs = [] # type: List[logging.LogRecord]
@contextmanager
def collect(self):
+ # type: () -> Generator
with pending_logging() as memhandler:
yield
@@ -368,13 +372,14 @@ class WarningLogRecordTranslator(logging.Filter):
class ColorizeFormatter(logging.Formatter):
def format(self, record):
+ # type: (logging.LogRecord) -> str
message = super(ColorizeFormatter, self).format(record)
color = getattr(record, 'color', None)
if color is None:
color = COLOR_MAP.get(record.levelno)
if color:
- return colorize(color, message)
+ return colorize(color, message) # type: ignore
else:
return message
@@ -382,10 +387,12 @@ class ColorizeFormatter(logging.Formatter):
class SafeEncodingWriter(object):
"""Stream writer which ignores UnicodeEncodeError silently"""
def __init__(self, stream):
+ # type: (IO) -> None
self.stream = stream
self.encoding = getattr(stream, 'encoding', 'ascii') or 'ascii'
def write(self, data):
+ # type: (unicode) -> None
try:
self.stream.write(data)
except UnicodeEncodeError:
@@ -394,6 +401,7 @@ class SafeEncodingWriter(object):
self.stream.write(data.encode(self.encoding, 'replace').decode(self.encoding))
def flush(self):
+ # type: () -> None
if hasattr(self.stream, 'flush'):
self.stream.flush()
diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py
index 17584e7c9..44c28f6b2 100644
--- a/sphinx/util/nodes.py
+++ b/sphinx/util/nodes.py
@@ -196,6 +196,7 @@ def traverse_translatable_index(doctree):
# type: (nodes.Node) -> Iterable[Tuple[nodes.Node, List[unicode]]]
"""Traverse translatable index node from a document tree."""
def is_block_index(node):
+ # type: (nodes.Node) -> bool
return isinstance(node, addnodes.index) and \
node.get('inline') is False
for node in doctree.traverse(is_block_index):
diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py
index ba2e1abf4..acf236027 100644
--- a/sphinx/util/osutil.py
+++ b/sphinx/util/osutil.py
@@ -21,7 +21,7 @@ import filecmp
from os import path
import contextlib
from io import BytesIO, StringIO
-from six import PY2, text_type
+from six import PY2, PY3, text_type
if False:
# For type annotation
@@ -33,6 +33,9 @@ ENOENT = getattr(errno, 'ENOENT', 0)
EPIPE = getattr(errno, 'EPIPE', 0)
EINVAL = getattr(errno, 'EINVAL', 0)
+if PY3:
+ unicode = str # special alias for static typing...
+
# SEP separates path elements in the canonical file names
#
# Define SEP as a manifest constant, not so much because we expect it to change
@@ -256,14 +259,14 @@ class FileAvoidWrite(object):
self._io = None # type: Union[StringIO, BytesIO]
def write(self, data):
- # type: (Union[str, bytes]) -> None
+ # type: (Union[str, unicode]) -> None
if not self._io:
if isinstance(data, text_type):
self._io = StringIO()
else:
self._io = BytesIO()
- self._io.write(data)
+ self._io.write(data) # type: ignore
def close(self):
# type: () -> None
@@ -294,12 +297,15 @@ class FileAvoidWrite(object):
f.write(buf)
def __enter__(self):
+ # type: () -> FileAvoidWrite
return self
def __exit__(self, type, value, traceback):
+ # type: (unicode, unicode, unicode) -> None
self.close()
def __getattr__(self, name):
+ # type: (str) -> Any
# Proxy to _io instance.
if not self._io:
raise Exception('Must write to FileAvoidWrite before other '
diff --git a/sphinx/util/png.py b/sphinx/util/png.py
index 476d45ccd..1543e4a5b 100644
--- a/sphinx/util/png.py
+++ b/sphinx/util/png.py
@@ -22,6 +22,7 @@ IEND_CHUNK = b'\x00\x00\x00\x00IEND\xAE\x42\x60\x82'
def read_png_depth(filename):
+ # type: (unicode) -> int
"""Read the special tEXt chunk indicating the depth from a PNG file."""
with open(filename, 'rb') as f:
f.seek(- (LEN_IEND + LEN_DEPTH), 2)
@@ -34,6 +35,7 @@ def read_png_depth(filename):
def write_png_depth(filename, depth):
+ # type: (unicode, int) -> None
"""Write the special tEXt chunk indicating the depth to a PNG file.
The chunk is placed immediately before the special IEND chunk.
diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py
index d4be08267..69a4351bf 100644
--- a/sphinx/util/pycompat.py
+++ b/sphinx/util/pycompat.py
@@ -16,7 +16,7 @@ from six import PY3, text_type, exec_
if False:
# For type annotation
- from typing import Any, Callable # NOQA
+ from typing import Any, Callable, Generator # NOQA
NoneType = type(None)
@@ -103,7 +103,8 @@ else:
methods in Python 2 or 3."""
def __str__(self):
- return self.__unicode__().encode('utf8')
+ # type: () -> str
+ return self.__unicode__().encode('utf8') # type: ignore
# indent()
@@ -115,9 +116,11 @@ else:
# type: (unicode, unicode, Callable) -> unicode
if predicate is None:
def predicate(line):
+ # type: (unicode) -> unicode
return line.strip()
def prefixed_lines():
+ # type: () -> Generator
for line in text.splitlines(True):
yield (prefix + line if predicate(line) else line)
return ''.join(prefixed_lines())
diff --git a/sphinx/util/requests.py b/sphinx/util/requests.py
index 14264e318..ec5aa232e 100644
--- a/sphinx/util/requests.py
+++ b/sphinx/util/requests.py
@@ -61,11 +61,17 @@ except pkg_resources.UnknownExtra:
'install requests-2.4.1+.'
)
+if False:
+ # For type annotation
+ from typing import Any, Generator, Union # NOQA
+ from sphinx.config import Config # NOQA
+
useragent_header = [('User-Agent',
'Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0')]
def is_ssl_error(exc):
+ # type: (Exception) -> bool
"""Check an exception is SSLError."""
if isinstance(exc, SSLError):
return True
@@ -79,6 +85,7 @@ def is_ssl_error(exc):
@contextmanager
def ignore_insecure_warning(**kwargs):
+ # type: (Any) -> Generator
with warnings.catch_warnings():
if not kwargs.get('verify') and InsecureRequestWarning:
# ignore InsecureRequestWarning if verify=False
@@ -87,6 +94,7 @@ def ignore_insecure_warning(**kwargs):
def _get_tls_cacert(url, config):
+ # type: (unicode, Config) -> Union[str, bool]
"""Get addiotinal CA cert for a specific URL.
This also returns ``False`` if verification is disabled.
@@ -99,7 +107,7 @@ def _get_tls_cacert(url, config):
if not certs:
return True
elif isinstance(certs, (string_types, tuple)): # type: ignore
- return certs
+ return certs # type: ignore
else:
hostname = urlsplit(url)[1]
if '@' in hostname:
@@ -109,6 +117,7 @@ def _get_tls_cacert(url, config):
def get(url, **kwargs):
+ # type: (unicode, Any) -> requests.Response
"""Sends a GET request like requests.get().
This sets up User-Agent header and TLS verification automatically."""
@@ -122,6 +131,7 @@ def get(url, **kwargs):
def head(url, **kwargs):
+ # type: (unicode, Any) -> requests.Response
"""Sends a HEAD request like requests.head().
This sets up User-Agent header and TLS verification automatically."""
diff --git a/sphinx/util/rst.py b/sphinx/util/rst.py
index 437ba516b..afb452f45 100644
--- a/sphinx/util/rst.py
+++ b/sphinx/util/rst.py
@@ -15,4 +15,5 @@ symbols_re = re.compile('([!-/:-@\[-`{-~])')
def escape(text):
- return symbols_re.sub(r'\\\1', text)
+ # type: (unicode) -> unicode
+ return symbols_re.sub(r'\\\1', text) # type: ignore
diff --git a/sphinx/util/smartypants.py b/sphinx/util/smartypants.py
index dee2f50ba..0146ba6e9 100644
--- a/sphinx/util/smartypants.py
+++ b/sphinx/util/smartypants.py
@@ -73,11 +73,16 @@ smartypants.py license::
import re
+if False:
+ # For type annotation
+ from typing import Tuple # NOQA
+
def sphinx_smarty_pants(t):
+ # type: (unicode) -> unicode
t = t.replace('&quot;', '"')
t = educate_dashes_oldschool(t)
- t = educate_quotes(t)
+ t = educate_quotes(t) # type: ignore
t = t.replace('"', '&quot;')
return t
@@ -155,6 +160,7 @@ closing_single_quotes_regex_2 = re.compile(r"""
def educate_quotes(s):
+ # type: (str) -> str
"""
Parameter: String.
@@ -194,6 +200,7 @@ def educate_quotes(s):
def educate_quotes_latex(s, dquotes=("``", "''")):
+ # type: (str, Tuple[str, str]) -> unicode
"""
Parameter: String.
@@ -237,6 +244,7 @@ def educate_quotes_latex(s, dquotes=("``", "''")):
def educate_backticks(s):
+ # type: (unicode) -> unicode
"""
Parameter: String.
Returns: The string, with ``backticks'' -style double quotes
@@ -248,6 +256,7 @@ def educate_backticks(s):
def educate_single_backticks(s):
+ # type: (unicode) -> unicode
"""
Parameter: String.
Returns: The string, with `backticks' -style single quotes
@@ -260,6 +269,7 @@ def educate_single_backticks(s):
def educate_dashes_oldschool(s):
+ # type: (unicode) -> unicode
"""
Parameter: String.
@@ -271,6 +281,7 @@ def educate_dashes_oldschool(s):
def educate_dashes_oldschool_inverted(s):
+ # type: (unicode) -> unicode
"""
Parameter: String.
@@ -289,6 +300,7 @@ def educate_dashes_oldschool_inverted(s):
def educate_ellipses(s):
+ # type: (unicode) -> unicode
"""
Parameter: String.
Returns: The string, with each instance of "..." translated to
diff --git a/sphinx/util/stemmer/porter.py b/sphinx/util/stemmer/porter.py
index 5f8d14ed6..beb860c9e 100644
--- a/sphinx/util/stemmer/porter.py
+++ b/sphinx/util/stemmer/porter.py
@@ -32,6 +32,7 @@
class PorterStemmer(object):
def __init__(self):
+ # type: () -> None
"""The main part of the stemming algorithm starts here.
b is a buffer holding a word to be stemmed. The letters are in b[k0],
b[k0+1] ... ending at b[k]. In fact k0 = 0 in this demo program. k is
@@ -42,12 +43,14 @@ class PorterStemmer(object):
should be done before stem(...) is called.
"""
- self.b = "" # buffer for word to be stemmed
+ self.b = "" # type: unicode
+ # buffer for word to be stemmed
self.k = 0
self.k0 = 0
- self.j = 0 # j is a general offset into the string
+ self.j = 0 # j is a general offset into the string
def cons(self, i):
+ # type: (int) -> int
"""cons(i) is TRUE <=> b[i] is a consonant."""
if self.b[i] == 'a' or self.b[i] == 'e' or self.b[i] == 'i' \
or self.b[i] == 'o' or self.b[i] == 'u':
@@ -60,6 +63,7 @@ class PorterStemmer(object):
return 1
def m(self):
+ # type: () -> int
"""m() measures the number of consonant sequences between k0 and j.
if c is a consonant sequence and v a vowel sequence, and <..>
indicates arbitrary presence,
@@ -97,6 +101,7 @@ class PorterStemmer(object):
i = i + 1
def vowelinstem(self):
+ # type: () -> int
"""vowelinstem() is TRUE <=> k0,...j contains a vowel"""
for i in range(self.k0, self.j + 1):
if not self.cons(i):
@@ -104,6 +109,7 @@ class PorterStemmer(object):
return 0
def doublec(self, j):
+ # type: (int) -> int
"""doublec(j) is TRUE <=> j,(j-1) contain a double consonant."""
if j < (self.k0 + 1):
return 0
@@ -112,6 +118,7 @@ class PorterStemmer(object):
return self.cons(j)
def cvc(self, i):
+ # type: (int) -> int
"""cvc(i) is TRUE <=> i-2,i-1,i has the form
consonant - vowel - consonant
and also if the second c is not w,x or y. this is used when trying to
@@ -129,6 +136,7 @@ class PorterStemmer(object):
return 1
def ends(self, s):
+ # type: (unicode) -> int
"""ends(s) is TRUE <=> k0,...k ends with the string s."""
length = len(s)
if s[length - 1] != self.b[self.k]: # tiny speed-up
@@ -141,6 +149,7 @@ class PorterStemmer(object):
return 1
def setto(self, s):
+ # type: (unicode) -> None
"""setto(s) sets (j+1),...k to the characters in the string s,
readjusting k."""
length = len(s)
@@ -148,11 +157,13 @@ class PorterStemmer(object):
self.k = self.j + length
def r(self, s):
+ # type: (unicode) -> None
"""r(s) is used further down."""
if self.m() > 0:
self.setto(s)
def step1ab(self):
+ # type: () -> None
"""step1ab() gets rid of plurals and -ed or -ing. e.g.
caresses -> caress
@@ -200,12 +211,14 @@ class PorterStemmer(object):
self.setto("e")
def step1c(self):
+ # type: () -> None
"""step1c() turns terminal y to i when there is another vowel in
the stem."""
if (self.ends("y") and self.vowelinstem()):
self.b = self.b[:self.k] + 'i' + self.b[self.k + 1:]
def step2(self):
+ # type: () -> None
"""step2() maps double suffices to single ones.
so -ization ( = -ize plus -ation) maps to -ize etc. note that the
string before the suffix must give m() > 0.
@@ -265,6 +278,7 @@ class PorterStemmer(object):
# To match the published algorithm, delete this phrase
def step3(self):
+ # type: () -> None
"""step3() dels with -ic-, -full, -ness etc. similar strategy
to step2."""
if self.b[self.k] == 'e':
@@ -287,6 +301,7 @@ class PorterStemmer(object):
self.r("")
def step4(self):
+ # type: () -> None
"""step4() takes off -ant, -ence etc., in context <c>vcvc<v>."""
if self.b[self.k - 1] == 'a':
if self.ends("al"):
@@ -370,6 +385,7 @@ class PorterStemmer(object):
self.k = self.j
def step5(self):
+ # type: () -> None
"""step5() removes a final -e if m() > 1, and changes -ll to -l if
m() > 1.
"""
@@ -382,6 +398,7 @@ class PorterStemmer(object):
self.k = self.k - 1
def stem(self, p, i, j):
+ # type: (unicode, int, int) -> unicode
"""In stem(p,i,j), p is a char pointer, and the string to be stemmed
is from p[i] to p[j] inclusive. Typically i is zero and j is the
offset to the last character of a string, (p[j+1] == '\0'). The
diff --git a/sphinx/util/tags.py b/sphinx/util/tags.py
index 180cb49ec..78ef7a22f 100644
--- a/sphinx/util/tags.py
+++ b/sphinx/util/tags.py
@@ -14,6 +14,10 @@ from jinja2.environment import Environment
env = Environment()
+if False:
+ # For type annotation
+ from typing import Iterator # NOQA
+
class BooleanParser(Parser):
"""
@@ -21,6 +25,7 @@ class BooleanParser(Parser):
"""
def parse_compare(self):
+ # type: () -> None
token = self.stream.current
if token.type == 'name':
if token.value in ('true', 'false', 'True', 'False'):
@@ -42,23 +47,29 @@ class BooleanParser(Parser):
class Tags(object):
def __init__(self, tags=None):
+ # type: (List[unicode]) -> None
self.tags = dict.fromkeys(tags or [], True)
def has(self, tag):
+ # type: (unicode) -> bool
return tag in self.tags
__contains__ = has
def __iter__(self):
+ # type: () -> Iterator[unicode]
return iter(self.tags)
def add(self, tag):
+ # type: (unicode) -> None
self.tags[tag] = True
def remove(self, tag):
+ # type: (unicode) -> None
self.tags.pop(tag, None)
def eval_condition(self, condition):
+ # type: (unicode) -> bool
# exceptions are handled by the caller
parser = BooleanParser(env, condition, state='variable')
expr = parser.parse_expression()
@@ -66,6 +77,7 @@ class Tags(object):
raise ValueError('chunk after expression')
def eval_node(node):
+ # type: (nodes.Node) -> bool
if isinstance(node, nodes.CondExpr):
if eval_node(node.test):
return eval_node(node.expr1)
diff --git a/sphinx/util/template.py b/sphinx/util/template.py
index f6db8034b..c742bbd17 100644
--- a/sphinx/util/template.py
+++ b/sphinx/util/template.py
@@ -16,27 +16,36 @@ from sphinx import package_dir
from sphinx.jinja2glue import SphinxFileSystemLoader
from sphinx.locale import get_translator
+if False:
+ # For type annotation
+ from jinja2.loaders import BaseLoader # NOQA
+
class BaseRenderer(object):
def __init__(self, loader=None):
+ # type: (BaseLoader) -> None
self.env = SandboxedEnvironment(loader=loader, extensions=['jinja2.ext.i18n'])
self.env.filters['repr'] = repr
self.env.install_gettext_translations(get_translator())
def render(self, template_name, context):
+ # type: (unicode, Dict) -> unicode
return self.env.get_template(template_name).render(context)
def render_string(self, source, context):
+ # type: (unicode, Dict) -> unicode
return self.env.from_string(source).render(context)
class FileRenderer(BaseRenderer):
def __init__(self, search_path):
+ # type: (unicode) -> None
loader = SphinxFileSystemLoader(search_path)
super(FileRenderer, self).__init__(loader)
@classmethod
def render_from_file(cls, filename, context):
+ # type: (unicode, Dict) -> unicode
dirname = os.path.dirname(filename)
basename = os.path.basename(filename)
return cls(dirname).render(basename, context)
@@ -44,17 +53,20 @@ class FileRenderer(BaseRenderer):
class SphinxRenderer(FileRenderer):
def __init__(self, template_path=None):
+ # type: (unicode) -> None
if template_path is None:
template_path = os.path.join(package_dir, 'templates')
super(SphinxRenderer, self).__init__(template_path)
@classmethod
def render_from_file(cls, filename, context):
+ # type: (unicode, Dict) -> unicode
return FileRenderer.render_from_file(filename, context)
class LaTeXRenderer(SphinxRenderer):
def __init__(self):
+ # type: () -> None
template_path = os.path.join(package_dir, 'templates', 'latex')
super(LaTeXRenderer, self).__init__(template_path)
diff --git a/sphinx/util/texescape.py b/sphinx/util/texescape.py
index 60f3d8322..2a6d7233d 100644
--- a/sphinx/util/texescape.py
+++ b/sphinx/util/texescape.py
@@ -126,6 +126,7 @@ tex_hl_escape_map_new = {}
def init():
+ # type: () -> None
for a, b in tex_replacements:
tex_escape_map[ord(a)] = b
tex_replace_map[ord(a)] = '_'
diff --git a/sphinx/util/websupport.py b/sphinx/util/websupport.py
index f91cca97a..a416fa48c 100644
--- a/sphinx/util/websupport.py
+++ b/sphinx/util/websupport.py
@@ -7,7 +7,12 @@
:license: BSD, see LICENSE for details.
"""
+if False:
+ # For type annotation
+ from docutils import nodes # NOQA
+
def is_commentable(node):
+ # type: (nodes.Node) -> bool
# return node.__class__.__name__ in ('paragraph', 'literal_block')
return node.__class__.__name__ == 'paragraph'
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 7b27eb3ab..8292367d8 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -2472,7 +2472,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
# type: (nodes.Node) -> None
text = self.encode(node.astext())
if not self.no_contractions and not self.in_parsed_literal:
- text = educate_quotes_latex(text)
+ text = educate_quotes_latex(text) # type: ignore
self.body.append(text)
def depart_Text(self, node):