diff options
author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2017-02-08 14:31:59 +0900 |
---|---|---|
committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2017-02-08 18:38:42 +0900 |
commit | 6fa0262802a09050e09445c9fd630c69b5ad1204 (patch) | |
tree | a2ad8f7849540d1b027e0b99d9913394b23c58d8 | |
parent | 81eb101e9f8fcee1c439ee0dd501d135eced01c6 (diff) | |
download | sphinx-git-6fa0262802a09050e09445c9fd630c69b5ad1204.tar.gz |
Fix mypy violations
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('"', '"') t = educate_dashes_oldschool(t) - t = educate_quotes(t) + t = educate_quotes(t) # type: ignore t = t.replace('"', '"') 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): |