Add mypy annotations

This commit is contained in:
Takeshi KOMIYA 2017-02-10 15:53:42 +09:00
parent 82e011cae6
commit da6f4c0019
22 changed files with 368 additions and 36 deletions

View File

@ -60,6 +60,7 @@ if __version__.endswith('+'):
def main(argv=sys.argv):
# type: (List[str]) -> None
if sys.argv[1:2] == ['-M']:
sys.exit(make_main(argv))
else:
@ -67,6 +68,7 @@ def main(argv=sys.argv):
def build_main(argv=sys.argv):
# type: (List[str]) -> int
"""Sphinx build "main" command-line entry."""
if (sys.version_info[:3] < (2, 7, 0) or
(3, 0, 0) <= sys.version_info[:3] < (3, 4, 0)):
@ -104,14 +106,15 @@ def build_main(argv=sys.argv):
sys.stderr.write('Error: Sphinx requires at least Docutils 0.10 to '
'run.\n')
return 1
return cmdline.main(argv)
return cmdline.main(argv) # type: ignore
def make_main(argv=sys.argv):
# type: (List[str]) -> int
"""Sphinx build "make mode" entry."""
from sphinx import make_mode
return make_mode.run_make_mode(argv[2:])
return make_mode.run_make_mode(argv[2:]) # type: ignore
if __name__ == '__main__':
sys.exit(main(sys.argv))
sys.exit(main(sys.argv)) # type: ignore

View File

@ -621,7 +621,7 @@ class StandaloneHTMLBuilder(Builder):
ensuredir(path.join(self.outdir, '_static'))
# first, create pygments style file
with open(path.join(self.outdir, '_static', 'pygments.css'), 'w') as f:
f.write(self.highlighter.get_stylesheet())
f.write(self.highlighter.get_stylesheet()) # type: ignore
# then, copy translations JavaScript file
if self.config.language is not None:
jsfile = self._get_translations_js()

View File

@ -104,7 +104,7 @@ class LaTeXBuilder(Builder):
f.write('\\NeedsTeXFormat{LaTeX2e}[1995/12/01]\n')
f.write('\\ProvidesPackage{sphinxhighlight}'
'[2016/05/29 stylesheet for highlighting with pygments]\n\n')
f.write(highlighter.get_stylesheet())
f.write(highlighter.get_stylesheet()) # type: ignore
def write(self, *ignored):
# type: (Any) -> None

View File

@ -21,6 +21,7 @@ if False:
# For type annotation
from typing import Any, Callable, Iterable, Tuple, Type, Union # NOQA
from docutils import nodes # NOQA
from docutils.parsers.rst.states import Inliner # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
@ -189,8 +190,8 @@ class Domain(object):
return None
fullname = '%s:%s' % (self.name, name)
def role_adapter(typ, rawtext, text, lineno, inliner,
options={}, content=[]):
def role_adapter(typ, rawtext, text, lineno, inliner, options={}, content=[]):
# type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> nodes.Node # NOQA
return self.roles[name](fullname, rawtext, text, lineno,
inliner, options, content)
self._role_cache[name] = role_adapter
@ -210,6 +211,7 @@ class Domain(object):
class DirectiveAdapter(BaseDirective): # type: ignore
def run(self):
# type: () -> List[nodes.Node]
self.name = fullname
return BaseDirective.run(self)
self._directive_cache[name] = DirectiveAdapter

View File

@ -895,6 +895,7 @@ class StandardDomain(Domain):
# type: (nodes.Node) -> unicode
"""Get figure type of nodes."""
def has_child(node, cls):
# type: (nodes.Node, Type) -> bool
return any(isinstance(child, cls) for child in node)
if isinstance(node, nodes.section):

View File

@ -746,7 +746,7 @@ class BuildEnvironment(object):
@property
def currmodule(self):
# type () -> None
# type: () -> None
"""Backwards compatible alias. Will be removed."""
logger.warning('env.currmodule is being referenced by an '
'extension; this API will be removed in the future',
@ -1024,6 +1024,7 @@ class BuildEnvironment(object):
traversed = set()
def traverse_toctree(parent, docname):
# type: (unicode, unicode) -> Iterator[Tuple[unicode, unicode]]
if parent == docname:
logger.warning('self referenced toctree found. Ignored.', location=docname)
return

View File

@ -42,6 +42,7 @@ class IndexEntries(object):
new = {} # type: Dict[unicode, List]
def add_entry(word, subword, main, link=True, dic=new, key=None):
# type: (unicode, unicode, unicode, bool, Dict, unicode) -> None
# Force the word to be unicode if it's a ASCII bytestring.
# This will solve problems with unicode normalization later.
# For instance the RFC role will add bytestrings at the moment
@ -96,6 +97,7 @@ class IndexEntries(object):
# sort the index entries; put all symbols at the front, even those
# following the letters in ASCII, this is where the chr(127) comes from
def keyfunc(entry, lcletters=string.ascii_lowercase + '_'):
# type: (Tuple[unicode, List], unicode) -> Tuple[unicode, unicode]
key, (void, void, category_key) = entry
if category_key:
# using specified category key to sort
@ -140,6 +142,7 @@ class IndexEntries(object):
# group the entries by letter
def keyfunc2(item, letters=string.ascii_uppercase + '_'):
# type: (Tuple[unicode, List], unicode) -> unicode
# hack: mutating the subitems dicts to a list in the keyfunc
k, v = item
v[1] = sorted((si, se) for (si, (se, void, void)) in iteritems(v[1]))

View File

@ -85,6 +85,7 @@ class TocTree(object):
toctree_ancestors = self.get_toctree_ancestors(docname)
def _toctree_add_classes(node, depth):
# type: (nodes.Node, int) -> None
"""Add 'toctree-l%d' and 'current' classes to the toctree."""
for subnode in node.children:
if isinstance(subnode, (addnodes.compact_paragraph,
@ -114,8 +115,8 @@ class TocTree(object):
subnode['iscurrent'] = True
subnode = subnode.parent
def _entries_from_toctree(toctreenode, parents,
separate=False, subtree=False):
def _entries_from_toctree(toctreenode, parents, separate=False, subtree=False):
# type: (addnodes.toctree, List[nodes.Node], bool, bool) -> List[nodes.Node]
"""Return TOC entries for a toctree node."""
refs = [(e[0], e[1]) for e in toctreenode['entries']]
entries = []

View File

@ -975,6 +975,7 @@ class Documenter(object):
tagorder = self.analyzer.tagorder
def keyfunc(entry):
# type: (Tuple[Documenter, bool]) -> int
fullname = entry[0].name.split('::')[1]
return tagorder.get(fullname, len(tagorder))
memberdocumenters.sort(key=keyfunc)
@ -1828,7 +1829,9 @@ class testcls:
"""test doc string"""
def __getattr__(self, x):
# type: (Any) -> Any
return x
def __setattr__(self, x, y):
# type: (Any, Any) -> None
"""Attr setter."""

View File

@ -58,6 +58,7 @@ else:
def compare_version(ver1, ver2, operand):
# type: (unicode, unicode, unicode) -> bool
"""Compare `ver1` to `ver2`, relying on `operand`.
Some examples:

View File

@ -27,6 +27,12 @@ from pygments.styles import get_style_by_name
from pygments.util import ClassNotFound
from sphinx.pygments_styles import SphinxStyle, NoneStyle
if False:
# For type annotation
from typing import Any # NOQA
from pygments.formatter import Formatter # NOQA
logger = logging.getLogger(__name__)
lexers = dict(
@ -59,8 +65,8 @@ class PygmentsBridge(object):
html_formatter = HtmlFormatter
latex_formatter = LatexFormatter
def __init__(self, dest='html', stylename='sphinx',
trim_doctest_flags=False):
def __init__(self, dest='html', stylename='sphinx', trim_doctest_flags=False):
# type: (unicode, unicode, bool) -> None
self.dest = dest
if stylename is None or stylename == 'sphinx':
style = SphinxStyle
@ -73,7 +79,7 @@ class PygmentsBridge(object):
else:
style = get_style_by_name(stylename)
self.trim_doctest_flags = trim_doctest_flags
self.formatter_args = {'style': style}
self.formatter_args = {'style': style} # type: Dict[unicode, Any]
if dest == 'html':
self.formatter = self.html_formatter
else:
@ -81,10 +87,12 @@ class PygmentsBridge(object):
self.formatter_args['commandprefix'] = 'PYG'
def get_formatter(self, **kwargs):
kwargs.update(self.formatter_args)
# type: (Any) -> Formatter
kwargs.update(self.formatter_args) # type: ignore
return self.formatter(**kwargs)
def unhighlighted(self, source):
# type: (unicode) -> unicode
if self.dest == 'html':
return '<pre>' + htmlescape(source) + '</pre>\n'
else:
@ -96,6 +104,7 @@ class PygmentsBridge(object):
source + '\\end{Verbatim}\n'
def highlight_block(self, source, lang, opts=None, location=None, force=False, **kwargs):
# type: (unicode, unicode, Any, Any, bool, Any) -> unicode
if not isinstance(source, text_type):
source = source.decode()
@ -131,8 +140,8 @@ class PygmentsBridge(object):
# trim doctest options if wanted
if isinstance(lexer, PythonConsoleLexer) and self.trim_doctest_flags:
source = doctest.blankline_re.sub('', source)
source = doctest.doctestopt_re.sub('', source)
source = doctest.blankline_re.sub('', source) # type: ignore
source = doctest.doctestopt_re.sub('', source) # type: ignore
# highlight via Pygments
formatter = self.get_formatter(**kwargs)
@ -157,6 +166,7 @@ class PygmentsBridge(object):
return hlsource.translate(tex_hl_escape_map_new)
def get_stylesheet(self):
# type: () -> unicode
formatter = self.get_formatter()
if self.dest == 'html':
return formatter.get_style_defs('.highlight')

View File

@ -113,6 +113,7 @@ class SphinxFileSystemLoader(FileSystemLoader):
mtime = path.getmtime(filename)
def uptodate():
# type: () -> bool
try:
return path.getmtime(filename) == mtime
except OSError:

View File

@ -16,7 +16,7 @@ from six.moves import UserString
if False:
# For type annotation
from typing import Any, Tuple # NOQA
from typing import Any, Callable, Iterator, Tuple # NOQA
class _TranslationProxy(UserString, object):
@ -35,24 +35,31 @@ class _TranslationProxy(UserString, object):
__slots__ = ('_func', '_args')
def __new__(cls, func, *args):
# type: (Callable, unicode) -> object
if not args:
# not called with "function" and "arguments", but a plain string
return text_type(func)
return object.__new__(cls)
return object.__new__(cls) # type: ignore
def __getnewargs__(self):
return (self._func,) + self._args
# type: () -> Tuple
return (self._func,) + self._args # type: ignore
def __init__(self, func, *args):
# type: (Callable, unicode) -> None
self._func = func
self._args = args
data = property(lambda x: x._func(*x._args))
@property
def data(self):
# type: () -> unicode
return self._func(*self._args)
# replace function from UserString; it instantiates a self.__class__
# for the encoding result
def encode(self, encoding=None, errors=None):
# type: (unicode, unicode) -> str
if encoding:
if errors:
return self.data.encode(encoding, errors)
@ -62,81 +69,106 @@ class _TranslationProxy(UserString, object):
return self.data.encode()
def __contains__(self, key):
# type: (Any) -> bool
return key in self.data
def __bool__(self):
# type: () -> bool
return bool(self.data)
__nonzero__ = __bool__ # for python2 compatibility
def __dir__(self):
# type: () -> List[str]
return dir(text_type)
def __iter__(self):
# type: () -> Iterator[unicode]
return iter(self.data)
def __len__(self):
# type: () -> int
return len(self.data)
def __str__(self):
# type: () -> str
return str(self.data)
def __unicode__(self):
# type: () -> unicode
return text_type(self.data)
def __add__(self, other):
# type: (unicode) -> unicode
return self.data + other
def __radd__(self, other):
# type: (unicode) -> unicode
return other + self.data
def __mod__(self, other):
# type: (unicode) -> unicode
return self.data % other
def __rmod__(self, other):
# type: (unicode) -> unicode
return other % self.data
def __mul__(self, other):
# type: (Any) -> unicode
return self.data * other
def __rmul__(self, other):
# type: (Any) -> unicode
return other * self.data
def __lt__(self, other):
# type: (unicode) -> bool
return self.data < other
def __le__(self, other):
# type: (unicode) -> bool
return self.data <= other
def __eq__(self, other):
# type: (Any) -> bool
return self.data == other
def __ne__(self, other):
# type: (Any) -> bool
return self.data != other
def __gt__(self, other):
# type: (unicode) -> bool
return self.data > other
def __ge__(self, other):
# type: (unicode) -> bool
return self.data >= other
def __getattr__(self, name):
# type: (unicode) -> Any
if name == '__members__':
return self.__dir__()
return getattr(self.data, name)
def __getstate__(self):
# type: () -> Tuple[Callable, Tuple[unicode, ...]]
return self._func, self._args
def __setstate__(self, tup):
# type: (Tuple[Callable, Tuple[unicode]]) -> None
self._func, self._args = tup
def __getitem__(self, key):
# type: (Any) -> unicode
return self.data[key]
def __copy__(self):
# type: () -> _TranslationProxy
return self
def __repr__(self):
# type: () -> str
try:
return 'i' + repr(text_type(self.data))
except:
@ -173,13 +205,13 @@ admonitionlabels = {
'seealso': l_('See also'),
'tip': l_('Tip'),
'warning': l_('Warning'),
}
} # type: Dict[unicode, unicode]
versionlabels = {
'versionadded': l_('New in version %s'),
'versionchanged': l_('Changed in version %s'),
'deprecated': l_('Deprecated since version %s'),
}
} # type: Dict[unicode, unicode]
# XXX Python specific
pairindextypes = {
@ -242,6 +274,7 @@ def init(locale_dirs, language, catalog='sphinx'):
def get_translator(catalog='sphinx'):
# type: (unicode) -> gettext.NullTranslations
global translators
translator = translators.get(catalog)
if translator is None:

View File

@ -42,6 +42,10 @@ from sphinx.util.console import ( # type: ignore
from sphinx.util.template import SphinxRenderer
from sphinx.util import texescape
if False:
# For type annotation
from typing import Any, Callable, Pattern # NOQA
TERM_ENCODING = getattr(sys.stdin, 'encoding', None)
DEFAULT_VALUE = {
@ -66,6 +70,7 @@ PROMPT_PREFIX = '> '
def mkdir_p(dir):
# type: (unicode) -> None
if path.isdir(dir):
return
os.makedirs(dir)
@ -73,6 +78,7 @@ def mkdir_p(dir):
# function to get input from terminal -- overridden by the test suite
def term_input(prompt):
# type: (unicode) -> unicode
print(prompt, end='')
return input('')
@ -82,6 +88,7 @@ class ValidationError(Exception):
def is_path(x):
# type: (unicode) -> unicode
x = path.expanduser(x)
if path.exists(x) and not path.isdir(x):
raise ValidationError("Please enter a valid path name.")
@ -89,30 +96,36 @@ def is_path(x):
def allow_empty(x):
# type: (unicode) -> unicode
return x
def nonempty(x):
# type: (unicode) -> unicode
if not x:
raise ValidationError("Please enter some text.")
return x
def choice(*l):
# type: (List[unicode]) -> Callable[[unicode], unicode]
def val(x):
# type: (unicode) -> unicode
if x not in l:
raise ValidationError('Please enter one of %s.' % ', '.join(l))
raise ValidationError('Please enter one of %s.' % ', '.join(l)) # type: ignore
return x
return val
def boolean(x):
# type: (unicode) -> bool
if x.upper() not in ('Y', 'YES', 'N', 'NO'):
raise ValidationError("Please enter either 'y' or 'n'.")
return x.upper() in ('Y', 'YES')
def suffix(x):
# type: (unicode) -> unicode
if not (x[0:1] == '.' and len(x) > 1):
raise ValidationError("Please enter a file suffix, "
"e.g. '.rst' or '.txt'.")
@ -120,10 +133,12 @@ def suffix(x):
def ok(x):
# type: (unicode) -> unicode
return x
def term_decode(text):
# type: (unicode) -> unicode
if isinstance(text, text_type):
return text
@ -145,9 +160,10 @@ def term_decode(text):
def do_prompt(d, key, text, default=None, validator=nonempty):
# type: (Dict, unicode, unicode, unicode, Callable[[unicode], Any]) -> None
while True:
if default is not None:
prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default)
prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) # type: unicode
else:
prompt = PROMPT_PREFIX + text + ': '
if PY2:
@ -179,6 +195,7 @@ def do_prompt(d, key, text, default=None, validator=nonempty):
def convert_python_source(source, rex=re.compile(r"[uU]('.*?')")):
# type: (unicode, Pattern) -> unicode
# remove Unicode literal prefixes
if PY3:
return rex.sub('\\1', source)
@ -188,10 +205,12 @@ def convert_python_source(source, rex=re.compile(r"[uU]('.*?')")):
class QuickstartRenderer(SphinxRenderer):
def __init__(self, templatedir):
# type: (unicode) -> None
self.templatedir = templatedir or ''
super(QuickstartRenderer, self).__init__()
def render(self, template_name, context):
# type: (unicode, Dict) -> unicode
user_template = path.join(self.templatedir, path.basename(template_name))
if self.templatedir and path.exists(user_template):
return self.render_from_file(user_template, context)
@ -200,6 +219,7 @@ class QuickstartRenderer(SphinxRenderer):
def ask_user(d):
# type: (Dict) -> None
"""Ask the user for quickstart values missing from *d*.
Values are:
@ -375,6 +395,7 @@ directly.''')
def generate(d, overwrite=True, silent=False, templatedir=None):
# type: (Dict, bool, bool, unicode) -> None
"""Generate project based on values in *d*."""
template = QuickstartRenderer(templatedir=templatedir)
@ -432,6 +453,7 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
mkdir_p(path.join(srcdir, d['dot'] + 'static'))
def write_file(fpath, content, newline=None):
# type: (unicode, unicode, unicode) -> None
if overwrite or not path.isfile(fpath):
print('Creating file %s.' % fpath)
with open(fpath, 'wt', encoding='utf-8', newline=newline) as f:
@ -488,6 +510,7 @@ where "builder" is one of the supported builders, e.g. html, latex or linkcheck.
def usage(argv, msg=None):
# type: (List[unicode], unicode) -> None
if msg:
print(msg, file=sys.stderr)
print(file=sys.stderr)
@ -504,6 +527,7 @@ For more information, visit <http://sphinx-doc.org/>.
def valid_dir(d):
# type: (Dict) -> bool
dir = d['path']
if not path.exists(dir):
return True
@ -534,6 +558,7 @@ def valid_dir(d):
class MyFormatter(optparse.IndentedHelpFormatter):
def format_usage(self, usage):
# type: (str) -> str
return usage
def format_help(self, formatter):
@ -546,6 +571,7 @@ class MyFormatter(optparse.IndentedHelpFormatter):
def main(argv=sys.argv):
# type: (List[str]) -> int
if not color_terminal():
nocolor()

View File

@ -21,6 +21,13 @@ from sphinx.util import ws_re
from sphinx.util.nodes import split_explicit_title, process_index_entry, \
set_role_source_info
if False:
# For type annotation
from typing import Any, Tuple, Type # NOQA
from docutils.parsers.rst.states import Inliner # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.environment import BuildEnvironment # NOQA
generic_docroles = {
'command': addnodes.literal_strong,
@ -67,6 +74,7 @@ class XRefRole(object):
def __init__(self, fix_parens=False, lowercase=False,
nodeclass=None, innernodeclass=None, warn_dangling=False):
# type: (bool, bool, Type[nodes.Node], Type[nodes.Node], bool) -> None
self.fix_parens = fix_parens
self.lowercase = lowercase
self.warn_dangling = warn_dangling
@ -76,6 +84,7 @@ class XRefRole(object):
self.innernodeclass = innernodeclass
def _fix_parens(self, env, has_explicit_title, title, target):
# type: (BuildEnvironment, bool, unicode, unicode) -> Tuple[unicode, unicode]
if not has_explicit_title:
if title.endswith('()'):
# remove parentheses
@ -90,6 +99,7 @@ class XRefRole(object):
def __call__(self, typ, rawtext, text, lineno, inliner,
options={}, content=[]):
# type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA
env = inliner.document.settings.env
if not typ:
typ = env.temp_data.get('default_role')
@ -100,7 +110,7 @@ class XRefRole(object):
else:
typ = typ.lower()
if ':' not in typ:
domain, role = '', typ
domain, role = '', typ # type: unicode, unicode
classes = ['xref', role]
else:
domain, role = typ.split(':', 1)
@ -127,7 +137,7 @@ class XRefRole(object):
refnode = self.nodeclass(rawtext, reftype=role, refdomain=domain,
refexplicit=has_explicit_title)
# we may need the line number for warnings
set_role_source_info(inliner, lineno, refnode)
set_role_source_info(inliner, lineno, refnode) # type: ignore
title, target = self.process_link(
env, refnode, has_explicit_title, title, target)
# now that the target and title are finally determined, set them
@ -142,6 +152,7 @@ class XRefRole(object):
# methods that can be overwritten
def process_link(self, env, refnode, has_explicit_title, title, target):
# type: (BuildEnvironment, nodes.reference, bool, unicode, unicode) -> Tuple[unicode, unicode] # NOQA
"""Called after parsing title and target text, and creating the
reference node (given in *refnode*). This method can alter the
reference node and must return a new (or the same) ``(title, target)``
@ -150,6 +161,7 @@ class XRefRole(object):
return title, ws_re.sub(' ', target)
def result_nodes(self, document, env, node, is_ref):
# type: (nodes.document, BuildEnvironment, nodes.Node, bool) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA
"""Called before returning the finished nodes. *node* is the reference
node if one was created (*is_ref* is then true), else the content node.
This method can add other nodes and must return a ``(nodes, messages)``
@ -160,6 +172,7 @@ class XRefRole(object):
class AnyXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target):
# type: (BuildEnvironment, nodes.reference, bool, unicode, unicode) -> Tuple[unicode, unicode] # NOQA
result = XRefRole.process_link(self, env, refnode, has_explicit_title,
title, target)
# add all possible context info (i.e. std:program, py:module etc.)
@ -169,13 +182,14 @@ class AnyXRefRole(XRefRole):
def indexmarkup_role(typ, rawtext, text, lineno, inliner,
options={}, content=[]):
# type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA
"""Role for PEP/RFC references that generate an index entry."""
env = inliner.document.settings.env
if not typ:
typ = env.config.default_role
else:
typ = typ.lower()
has_explicit_title, title, target = split_explicit_title(text) # type: bool, unicode, unicode # NOQA
has_explicit_title, title, target = split_explicit_title(text)
title = utils.unescape(title)
target = utils.unescape(target)
targetid = 'index-%s' % env.new_serialno('index')
@ -233,10 +247,11 @@ _amp_re = re.compile(r'(?<!&)&(?![&\s])')
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
# type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA
text = utils.unescape(text)
if typ == 'menuselection':
text = text.replace('-->', u'\N{TRIANGULAR BULLET}')
spans = _amp_re.split(text)
spans = _amp_re.split(text) # type: ignore
node = nodes.inline(rawtext=rawtext)
for i, span in enumerate(spans):
@ -263,10 +278,11 @@ _litvar_re = re.compile('{([^}]+)}')
def emph_literal_role(typ, rawtext, text, lineno, inliner,
options={}, content=[]):
# type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA
text = utils.unescape(text)
pos = 0
retnode = nodes.literal(role=typ.lower(), classes=[typ])
for m in _litvar_re.finditer(text):
for m in _litvar_re.finditer(text): # type: ignore
if m.start() > pos:
txt = text[pos:m.start()]
retnode += nodes.Text(txt, txt)
@ -281,8 +297,9 @@ _abbr_re = re.compile('\((.*)\)$', re.S)
def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
# type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA
text = utils.unescape(text)
m = _abbr_re.search(text)
m = _abbr_re.search(text) # type: ignore
if m is None:
return [addnodes.abbreviation(text, text, **options)], []
abbr = text[:m.start()].strip()
@ -293,6 +310,7 @@ def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
def index_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
# type: (unicode, unicode, unicode, int, Inliner, Dict, List[unicode]) -> Tuple[List[nodes.Node], List[nodes.Node]] # NOQA
# create new reference target
env = inliner.document.settings.env
targetid = 'index-%s' % env.new_serialno('index')
@ -315,7 +333,7 @@ def index_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
entries = [('single', target, targetid, main, None)]
indexnode = addnodes.index()
indexnode['entries'] = entries
set_role_source_info(inliner, lineno, indexnode)
set_role_source_info(inliner, lineno, indexnode) # type: ignore
textnode = nodes.Text(title, title)
return [indexnode, targetnode, textnode], []
@ -338,6 +356,7 @@ specific_docroles = {
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
from docutils.parsers.rst import roles
for rolename, nodeclass in iteritems(generic_docroles):

View File

@ -304,6 +304,7 @@ class Locale(Transform):
# * use translated refname for section refname.
# * inline reference "`Python <...>`_" has no 'refname'.
def is_refnamed_ref(node):
# type: (nodes.Node) -> bool
return isinstance(node, nodes.reference) and \
'refname' in node
old_refs = node.traverse(is_refnamed_ref)

View File

@ -239,9 +239,9 @@ def clean_astext(node):
def split_explicit_title(text):
# type: (str) -> Tuple[bool, unicode, unicode]
# type: (unicode) -> Tuple[bool, unicode, unicode]
"""Split role content into title and target, if given."""
match = explicit_title_re.match(text)
match = explicit_title_re.match(text) # type: ignore
if match:
return True, match.group(1), match.group(2)
return False, text, text

View File

@ -24,6 +24,12 @@ from sphinx.util import logging
from sphinx.util.images import get_image_size
from sphinx.util.smartypants import sphinx_smarty_pants
if False:
# For type annotation
from typing import Any # NOQA
from sphinx.builders.html import StandaloneHTMLBuilder # NOQA
logger = logging.getLogger(__name__)
# A good overview of the purpose behind these classes can be found here:
@ -39,10 +45,12 @@ class HTMLWriter(Writer):
_setting[2]['default'] = 0
def __init__(self, builder):
# type: (StandaloneHTMLBuilder) -> None
Writer.__init__(self)
self.builder = builder
def translate(self):
# type: () -> None
# sadly, this is mostly copied from parent class
self.visitor = visitor = self.builder.translator_class(self.builder,
self.document)
@ -63,6 +71,7 @@ class HTMLTranslator(BaseTranslator):
"""
def __init__(self, builder, *args, **kwds):
# type: (StandaloneHTMLBuilder, Any, Any) -> None
BaseTranslator.__init__(self, *args, **kwds)
self.highlighter = builder.highlighter
self.no_smarty = 0
@ -82,22 +91,28 @@ class HTMLTranslator(BaseTranslator):
self.param_separator = ''
self.optional_param_level = 0
self._table_row_index = 0
self.required_params_left = 0
def visit_start_of_file(self, node):
# type: (nodes.Node) -> None
# only occurs in the single-file builder
self.docnames.append(node['docname'])
self.body.append('<span id="document-%s"></span>' % node['docname'])
def depart_start_of_file(self, node):
# type: (nodes.Node) -> None
self.docnames.pop()
def visit_desc(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'dl', CLASS=node['objtype']))
def depart_desc(self, node):
# type: (nodes.Node) -> None
self.body.append('</dl>\n\n')
def visit_desc_signature(self, node):
# type: (nodes.Node) -> None
# the id is set automatically
self.body.append(self.starttag(node, 'dt'))
# anchor for per-desc interactive data
@ -106,44 +121,56 @@ class HTMLTranslator(BaseTranslator):
self.body.append('<!--[%s]-->' % node['ids'][0])
def depart_desc_signature(self, node):
# type: (nodes.Node) -> None
if not node.get('is_multiline'):
self.add_permalink_ref(node, _('Permalink to this definition'))
self.body.append('</dt>\n')
def visit_desc_signature_line(self, node):
# type: (nodes.Node) -> None
pass
def depart_desc_signature_line(self, node):
# type: (nodes.Node) -> None
if node.get('add_permalink'):
# the permalink info is on the parent desc_signature node
self.add_permalink_ref(node.parent, _('Permalink to this definition'))
self.body.append('<br />')
def visit_desc_addname(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'code', '', CLASS='descclassname'))
def depart_desc_addname(self, node):
# type: (nodes.Node) -> None
self.body.append('</code>')
def visit_desc_type(self, node):
# type: (nodes.Node) -> None
pass
def depart_desc_type(self, node):
# type: (nodes.Node) -> None
pass
def visit_desc_returns(self, node):
# type: (nodes.Node) -> None
self.body.append(' &rarr; ')
def depart_desc_returns(self, node):
# type: (nodes.Node) -> None
pass
def visit_desc_name(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'code', '', CLASS='descname'))
def depart_desc_name(self, node):
# type: (nodes.Node) -> None
self.body.append('</code>')
def visit_desc_parameterlist(self, node):
# type: (nodes.Node) -> None
self.body.append('<span class="sig-paren">(</span>')
self.first_param = 1
self.optional_param_level = 0
@ -153,6 +180,7 @@ class HTMLTranslator(BaseTranslator):
self.param_separator = node.child_text_separator
def depart_desc_parameterlist(self, node):
# type: (nodes.Node) -> None
self.body.append('<span class="sig-paren">)</span>')
# If required parameters are still to come, then put the comma after
@ -162,6 +190,7 @@ class HTMLTranslator(BaseTranslator):
# foo([a, ]b, c[, d])
#
def visit_desc_parameter(self, node):
# type: (nodes.Node) -> None
if self.first_param:
self.first_param = 0
elif not self.required_params_left:
@ -172,39 +201,49 @@ class HTMLTranslator(BaseTranslator):
self.body.append('<em>')
def depart_desc_parameter(self, node):
# type: (nodes.Node) -> None
if not node.hasattr('noemph'):
self.body.append('</em>')
if self.required_params_left:
self.body.append(self.param_separator)
def visit_desc_optional(self, node):
# type: (nodes.Node) -> None
self.optional_param_level += 1
self.body.append('<span class="optional">[</span>')
def depart_desc_optional(self, node):
# type: (nodes.Node) -> None
self.optional_param_level -= 1
self.body.append('<span class="optional">]</span>')
def visit_desc_annotation(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'em', '', CLASS='property'))
def depart_desc_annotation(self, node):
# type: (nodes.Node) -> None
self.body.append('</em>')
def visit_desc_content(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'dd', ''))
def depart_desc_content(self, node):
# type: (nodes.Node) -> None
self.body.append('</dd>')
def visit_versionmodified(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'div', CLASS=node['type']))
def depart_versionmodified(self, node):
# type: (nodes.Node) -> None
self.body.append('</div>\n')
# overwritten
def visit_reference(self, node):
# type: (nodes.Node) -> None
atts = {'class': 'reference'}
if node.get('internal') or 'refuri' not in node:
atts['class'] += ' internal'
@ -234,17 +273,21 @@ class HTMLTranslator(BaseTranslator):
'.'.join(map(str, node['secnumber'])))
def visit_number_reference(self, node):
# type: (nodes.Node) -> None
self.visit_reference(node)
def depart_number_reference(self, node):
# type: (nodes.Node) -> None
self.depart_reference(node)
# overwritten -- we don't want source comments to show up in the HTML
def visit_comment(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
# overwritten
def visit_admonition(self, node, name=''):
# type: (nodes.Node, unicode) -> None
self.body.append(self.starttag(
node, 'div', CLASS=('admonition ' + name)))
if name:
@ -252,12 +295,15 @@ class HTMLTranslator(BaseTranslator):
self.set_first_last(node)
def visit_seealso(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'seealso')
def depart_seealso(self, node):
# type: (nodes.Node) -> None
self.depart_admonition(node)
def add_secnumber(self, node):
# type: (nodes.Node) -> None
if node.get('secnumber'):
self.body.append('.'.join(map(str, node['secnumber'])) +
self.secnumber_suffix)
@ -279,7 +325,9 @@ class HTMLTranslator(BaseTranslator):
self.secnumber_suffix)
def add_fignumber(self, node):
# type: (nodes.Node) -> None
def append_fignumber(figtype, figure_id):
# type: (unicode, unicode) -> None
if self.builder.name == 'singlehtml':
key = (self.docnames[-1], figtype)
else:
@ -296,7 +344,7 @@ class HTMLTranslator(BaseTranslator):
self.body.append(prefix % '.'.join(map(str, numbers)) + ' ')
self.body.append('</span>')
figtype = self.builder.env.domains['std'].get_figtype(node)
figtype = self.builder.env.domains['std'].get_figtype(node) # type: ignore
if figtype:
if len(node['ids']) == 0:
msg = 'Any IDs not assigned for %s node' % node.tagname
@ -305,11 +353,13 @@ class HTMLTranslator(BaseTranslator):
append_fignumber(figtype, node['ids'][0])
def add_permalink_ref(self, node, title):
# type: (nodes.Node, unicode) -> None
if node['ids'] and self.permalink_text and self.builder.add_permalinks:
format = u'<a class="headerlink" href="#%s" title="%s">%s</a>'
self.body.append(format % (node['ids'][0], title, self.permalink_text))
def generate_targets_for_listing(self, node):
# type: (nodes.Node) -> None
"""Generate hyperlink targets for listings.
Original visit_bullet_list(), visit_definition_list() and visit_enumerated_list()
@ -325,6 +375,7 @@ class HTMLTranslator(BaseTranslator):
# overwritten
def visit_bullet_list(self, node):
# type: (nodes.Node) -> None
if len(node) == 1 and node[0].tagname == 'toctree':
# avoid emitting empty <ul></ul>
raise nodes.SkipNode
@ -333,11 +384,13 @@ class HTMLTranslator(BaseTranslator):
# overwritten
def visit_enumerated_list(self, node):
# type: (nodes.Node) -> None
self.generate_targets_for_listing(node)
BaseTranslator.visit_enumerated_list(self, node)
# overwritten
def visit_title(self, node):
# type: (nodes.Node) -> None
BaseTranslator.visit_title(self, node)
self.add_secnumber(node)
self.add_fignumber(node.parent)
@ -345,6 +398,7 @@ class HTMLTranslator(BaseTranslator):
self.body.append('<span class="caption-text">')
def depart_title(self, node):
# type: (nodes.Node) -> None
close_tag = self.context[-1]
if (self.permalink_text and self.builder.add_permalinks and
node.parent.hasattr('ids') and node.parent['ids']):
@ -367,6 +421,7 @@ class HTMLTranslator(BaseTranslator):
# overwritten
def visit_literal_block(self, node):
# type: (nodes.Node) -> None
if node.rawsource != node.astext():
# most probably a parsed-literal block -- don't highlight
return BaseTranslator.visit_literal_block(self, node)
@ -396,6 +451,7 @@ class HTMLTranslator(BaseTranslator):
raise nodes.SkipNode
def visit_caption(self, node):
# type: (nodes.Node) -> None
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
self.body.append('<div class="code-block-caption">')
else:
@ -404,6 +460,7 @@ class HTMLTranslator(BaseTranslator):
self.body.append(self.starttag(node, 'span', '', CLASS='caption-text'))
def depart_caption(self, node):
# type: (nodes.Node) -> None
self.body.append('</span>')
# append permalink if available
@ -422,26 +479,32 @@ class HTMLTranslator(BaseTranslator):
BaseTranslator.depart_caption(self, node)
def visit_doctest_block(self, node):
# type: (nodes.Node) -> None
self.visit_literal_block(node)
# overwritten to add the <div> (for XHTML compliance)
def visit_block_quote(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'blockquote') + '<div>')
def depart_block_quote(self, node):
# type: (nodes.Node) -> None
self.body.append('</div></blockquote>\n')
# overwritten
def visit_literal(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'code', '',
CLASS='docutils literal'))
self.protect_literal_text += 1
def depart_literal(self, node):
# type: (nodes.Node) -> None
self.protect_literal_text -= 1
self.body.append('</code>')
def visit_productionlist(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'pre'))
names = []
for production in node:
@ -461,23 +524,29 @@ class HTMLTranslator(BaseTranslator):
raise nodes.SkipNode
def depart_productionlist(self, node):
# type: (nodes.Node) -> None
pass
def visit_production(self, node):
# type: (nodes.Node) -> None
pass
def depart_production(self, node):
# type: (nodes.Node) -> None
pass
def visit_centered(self, node):
# type: (nodes.Node) -> None
self.body.append(self.starttag(node, 'p', CLASS="centered") +
'<strong>')
def depart_centered(self, node):
# type: (nodes.Node) -> None
self.body.append('</strong></p>')
# overwritten
def should_be_compact_paragraph(self, node):
# type: (nodes.Node) -> bool
"""Determine if the <p> tags around paragraph can be omitted."""
if isinstance(node.parent, addnodes.desc_content):
# Never compact desc_content items.
@ -488,19 +557,24 @@ class HTMLTranslator(BaseTranslator):
return BaseTranslator.should_be_compact_paragraph(self, node)
def visit_compact_paragraph(self, node):
# type: (nodes.Node) -> None
pass
def depart_compact_paragraph(self, node):
# type: (nodes.Node) -> None
pass
def visit_highlightlang(self, node):
# type: (nodes.Node) -> None
self.highlightlang = node['lang']
self.highlightlinenothreshold = node['linenothreshold']
def depart_highlightlang(self, node):
# type: (nodes.Node) -> None
pass
def visit_download_reference(self, node):
# type: (nodes.Node) -> None
if self.builder.download_support and node.hasattr('filename'):
self.body.append(
'<a class="reference download internal" href="%s" download="">' %
@ -510,10 +584,12 @@ class HTMLTranslator(BaseTranslator):
self.context.append('')
def depart_download_reference(self, node):
# type: (nodes.Node) -> None
self.body.append(self.context.pop())
# overwritten
def visit_image(self, node):
# type: (nodes.Node) -> None
olduri = node['uri']
# rewrite the URI if the environment knows about it
if olduri in self.builder.images:
@ -555,51 +631,65 @@ class HTMLTranslator(BaseTranslator):
# overwritten
def depart_image(self, node):
# type: (nodes.Node) -> None
if node['uri'].lower().endswith(('svg', 'svgz')):
self.body.append(self.context.pop())
else:
BaseTranslator.depart_image(self, node)
def visit_toctree(self, node):
# type: (nodes.Node) -> None
# this only happens when formatting a toc from env.tocs -- in this
# case we don't want to include the subtree
raise nodes.SkipNode
def visit_index(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_tabular_col_spec(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_glossary(self, node):
# type: (nodes.Node) -> None
pass
def depart_glossary(self, node):
# type: (nodes.Node) -> None
pass
def visit_acks(self, node):
# type: (nodes.Node) -> None
pass
def depart_acks(self, node):
# type: (nodes.Node) -> None
pass
def visit_hlist(self, node):
# type: (nodes.Node) -> None
self.body.append('<table class="hlist"><tr>')
def depart_hlist(self, node):
# type: (nodes.Node) -> None
self.body.append('</tr></table>\n')
def visit_hlistcol(self, node):
# type: (nodes.Node) -> None
self.body.append('<td>')
def depart_hlistcol(self, node):
# type: (nodes.Node) -> None
self.body.append('</td>')
def bulk_text_processor(self, text):
# type: (unicode) -> unicode
return text
# overwritten
def visit_Text(self, node):
# type: (nodes.Node) -> None
text = node.astext()
encoded = self.encode(text)
if self.protect_literal_text:
@ -623,94 +713,122 @@ class HTMLTranslator(BaseTranslator):
self.body.append(encoded)
def visit_note(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'note')
def depart_note(self, node):
# type: (nodes.Node) -> None
self.depart_admonition(node)
def visit_warning(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'warning')
def depart_warning(self, node):
# type: (nodes.Node) -> None
self.depart_admonition(node)
def visit_attention(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'attention')
def depart_attention(self, node):
# type: (nodes.Node) -> None
self.depart_admonition()
def visit_caution(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'caution')
def depart_caution(self, node):
# type: (nodes.Node) -> None
self.depart_admonition()
def visit_danger(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'danger')
def depart_danger(self, node):
# type: (nodes.Node) -> None
self.depart_admonition()
def visit_error(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'error')
def depart_error(self, node):
# type: (nodes.Node) -> None
self.depart_admonition()
def visit_hint(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'hint')
def depart_hint(self, node):
# type: (nodes.Node) -> None
self.depart_admonition()
def visit_important(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'important')
def depart_important(self, node):
# type: (nodes.Node) -> None
self.depart_admonition()
def visit_tip(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'tip')
def depart_tip(self, node):
# type: (nodes.Node) -> None
self.depart_admonition()
# these are only handled specially in the SmartyPantsHTMLTranslator
def visit_literal_emphasis(self, node):
# type: (nodes.Node) -> None
return self.visit_emphasis(node)
def depart_literal_emphasis(self, node):
# type: (nodes.Node) -> None
return self.depart_emphasis(node)
def visit_literal_strong(self, node):
# type: (nodes.Node) -> None
return self.visit_strong(node)
def depart_literal_strong(self, node):
# type: (nodes.Node) -> None
return self.depart_strong(node)
def visit_abbreviation(self, node):
# type: (nodes.Node) -> None
attrs = {}
if node.hasattr('explanation'):
attrs['title'] = node['explanation']
self.body.append(self.starttag(node, 'abbr', '', **attrs))
def depart_abbreviation(self, node):
# type: (nodes.Node) -> None
self.body.append('</abbr>')
def visit_manpage(self, node):
return self.visit_literal_emphasis(node)
# type: (nodes.Node) -> None
self.visit_literal_emphasis(node)
def depart_manpage(self, node):
return self.depart_literal_emphasis(node)
# type: (nodes.Node) -> None
self.depart_literal_emphasis(node)
# overwritten to add even/odd classes
def visit_table(self, node):
# type: (nodes.Node) -> None
self._table_row_index = 0
return BaseTranslator.visit_table(self, node)
def visit_row(self, node):
# type: (nodes.Node) -> None
self._table_row_index += 1
if self._table_row_index % 2 == 0:
node['classes'].append('row-even')
@ -720,10 +838,12 @@ class HTMLTranslator(BaseTranslator):
node.column = 0
def visit_field_list(self, node):
# type: (nodes.Node) -> None
self._fieldlist_row_index = 0
return BaseTranslator.visit_field_list(self, node)
def visit_field(self, node):
# type: (nodes.Node) -> None
self._fieldlist_row_index += 1
if self._fieldlist_row_index % 2 == 0:
node['classes'].append('field-even')
@ -732,6 +852,7 @@ class HTMLTranslator(BaseTranslator):
self.body.append(self.starttag(node, 'tr', '', CLASS='field'))
def visit_math(self, node, math_env=''):
# type: (nodes.Node, unicode) -> None
logger.warning('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html',
@ -739,6 +860,7 @@ class HTMLTranslator(BaseTranslator):
raise nodes.SkipNode
def unknown_visit(self, node):
# type: (nodes.Node) -> None
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)
@ -749,10 +871,12 @@ class SmartyPantsHTMLTranslator(HTMLTranslator):
"""
def __init__(self, *args, **kwds):
# type: (Any, Any) -> None
self.no_smarty = 0
HTMLTranslator.__init__(self, *args, **kwds)
def visit_literal(self, node):
# type: (nodes.Node) -> None
self.no_smarty += 1
try:
# this raises SkipNode
@ -761,6 +885,7 @@ class SmartyPantsHTMLTranslator(HTMLTranslator):
self.no_smarty -= 1
def visit_literal_block(self, node):
# type: (nodes.Node) -> None
self.no_smarty += 1
try:
HTMLTranslator.visit_literal_block(self, node)
@ -771,34 +896,42 @@ class SmartyPantsHTMLTranslator(HTMLTranslator):
raise
def depart_literal_block(self, node):
# type: (nodes.Node) -> None
HTMLTranslator.depart_literal_block(self, node)
self.no_smarty -= 1
def visit_literal_emphasis(self, node):
# type: (nodes.Node) -> None
self.no_smarty += 1
self.visit_emphasis(node)
def depart_literal_emphasis(self, node):
# type: (nodes.Node) -> None
self.depart_emphasis(node)
self.no_smarty -= 1
def visit_literal_strong(self, node):
# type: (nodes.Node) -> None
self.no_smarty += 1
self.visit_strong(node)
def depart_literal_strong(self, node):
# type: (nodes.Node) -> None
self.depart_strong(node)
self.no_smarty -= 1
def visit_desc_signature(self, node):
# type: (nodes.Node) -> None
self.no_smarty += 1
HTMLTranslator.visit_desc_signature(self, node)
def depart_desc_signature(self, node):
# type: (nodes.Node) -> None
self.no_smarty -= 1
HTMLTranslator.depart_desc_signature(self, node)
def visit_productionlist(self, node):
# type: (nodes.Node) -> None
self.no_smarty += 1
try:
HTMLTranslator.visit_productionlist(self, node)
@ -806,14 +939,17 @@ class SmartyPantsHTMLTranslator(HTMLTranslator):
self.no_smarty -= 1
def visit_option(self, node):
# type: (nodes.Node) -> None
self.no_smarty += 1
HTMLTranslator.visit_option(self, node)
def depart_option(self, node):
# type: (nodes.Node) -> None
self.no_smarty -= 1
HTMLTranslator.depart_option(self, node)
def bulk_text_processor(self, text):
# type: (unicode) -> unicode
if self.no_smarty <= 0:
return sphinx_smarty_pants(text)
return text

View File

@ -1794,6 +1794,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\\end{sphinxadmonition}\n')
def _make_visit_admonition(name):
# type: (unicode) -> Callable[[LaTeXTranslator, nodes.Node], None]
def visit_admonition(self, node):
# type: (nodes.Node) -> None
self.body.append(u'\n\\begin{sphinxadmonition}{%s}{%s:}' %

View File

@ -22,17 +22,24 @@ from sphinx.util import logging
import sphinx.util.docutils
from sphinx.util.i18n import format_date
if False:
# For type annotation
from typing import Any # NOQA
from sphinx.builders import Builder # NOQA
logger = logging.getLogger(__name__)
class ManualPageWriter(Writer):
def __init__(self, builder):
# type: (Builder) -> None
Writer.__init__(self)
self.builder = builder
self.translator_class = (
self.builder.translator_class or ManualPageTranslator)
def translate(self):
# type: () -> None
transform = NestedInlineTransform(self.document)
transform.apply()
visitor = self.translator_class(self.builder, self.document)
@ -53,10 +60,13 @@ class NestedInlineTransform(object):
<strong>&bar=</strong><emphasis>2</emphasis>
"""
def __init__(self, document):
# type: (nodes.document) -> None
self.document = document
def apply(self):
# type: () -> None
def is_inline(node):
# type: (nodes.Node) -> bool
return isinstance(node, (nodes.literal, nodes.emphasis, nodes.strong))
for node in self.document.traverse(is_inline):
@ -77,6 +87,7 @@ class ManualPageTranslator(BaseTranslator):
"""
def __init__(self, builder, *args, **kwds):
# type: (Builder, Any, Any) -> None
BaseTranslator.__init__(self, *args, **kwds)
self.builder = builder
@ -114,6 +125,7 @@ class ManualPageTranslator(BaseTranslator):
# overwritten -- added quotes around all .TH arguments
def header(self):
# type: () -> unicode
tmpl = (".TH \"%(title_upper)s\" \"%(manual_section)s\""
" \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n"
".SH NAME\n"
@ -121,96 +133,125 @@ class ManualPageTranslator(BaseTranslator):
return tmpl % self._docinfo
def visit_start_of_file(self, node):
# type: (nodes.Node) -> None
pass
def depart_start_of_file(self, node):
# type: (nodes.Node) -> None
pass
def visit_desc(self, node):
# type: (nodes.Node) -> None
self.visit_definition_list(node)
def depart_desc(self, node):
# type: (nodes.Node) -> None
self.depart_definition_list(node)
def visit_desc_signature(self, node):
# type: (nodes.Node) -> None
self.visit_definition_list_item(node)
self.visit_term(node)
def depart_desc_signature(self, node):
# type: (nodes.Node) -> None
self.depart_term(node)
def visit_desc_signature_line(self, node):
# type: (nodes.Node) -> None
pass
def depart_desc_signature_line(self, node):
# type: (nodes.Node) -> None
self.body.append(' ')
def visit_desc_addname(self, node):
# type: (nodes.Node) -> None
pass
def depart_desc_addname(self, node):
# type: (nodes.Node) -> None
pass
def visit_desc_type(self, node):
# type: (nodes.Node) -> None
pass
def depart_desc_type(self, node):
# type: (nodes.Node) -> None
pass
def visit_desc_returns(self, node):
# type: (nodes.Node) -> None
self.body.append(' -> ')
def depart_desc_returns(self, node):
# type: (nodes.Node) -> None
pass
def visit_desc_name(self, node):
# type: (nodes.Node) -> None
pass
def depart_desc_name(self, node):
# type: (nodes.Node) -> None
pass
def visit_desc_parameterlist(self, node):
# type: (nodes.Node) -> None
self.body.append('(')
self.first_param = 1
def depart_desc_parameterlist(self, node):
# type: (nodes.Node) -> None
self.body.append(')')
def visit_desc_parameter(self, node):
# type: (nodes.Node) -> None
if not self.first_param:
self.body.append(', ')
else:
self.first_param = 0
def depart_desc_parameter(self, node):
# type: (nodes.Node) -> None
pass
def visit_desc_optional(self, node):
# type: (nodes.Node) -> None
self.body.append('[')
def depart_desc_optional(self, node):
# type: (nodes.Node) -> None
self.body.append(']')
def visit_desc_annotation(self, node):
# type: (nodes.Node) -> None
pass
def depart_desc_annotation(self, node):
# type: (nodes.Node) -> None
pass
def visit_desc_content(self, node):
# type: (nodes.Node) -> None
self.visit_definition(node)
def depart_desc_content(self, node):
# type: (nodes.Node) -> None
self.depart_definition(node)
def visit_versionmodified(self, node):
# type: (nodes.Node) -> None
self.visit_paragraph(node)
def depart_versionmodified(self, node):
# type: (nodes.Node) -> None
self.depart_paragraph(node)
# overwritten -- don't make whole of term bold if it includes strong node
def visit_term(self, node):
# type: (nodes.Node) -> None
if node.traverse(nodes.strong):
self.body.append('\n')
else:
@ -218,15 +259,18 @@ class ManualPageTranslator(BaseTranslator):
# overwritten -- we don't want source comments to show up
def visit_comment(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
# overwritten -- added ensure_eol()
def visit_footnote(self, node):
# type: (nodes.Node) -> None
self.ensure_eol()
BaseTranslator.visit_footnote(self, node)
# overwritten -- handle footnotes rubric
def visit_rubric(self, node):
# type: (nodes.Node) -> None
self.ensure_eol()
if len(node.children) == 1:
rubtitle = node.children[0].astext()
@ -238,15 +282,19 @@ class ManualPageTranslator(BaseTranslator):
self.body.append('.sp\n')
def depart_rubric(self, node):
# type: (nodes.Node) -> None
pass
def visit_seealso(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, 'seealso')
def depart_seealso(self, node):
# type: (nodes.Node) -> None
self.depart_admonition(node)
def visit_productionlist(self, node):
# type: (nodes.Node) -> None
self.ensure_eol()
names = []
self.in_productionlist += 1
@ -271,13 +319,16 @@ class ManualPageTranslator(BaseTranslator):
raise nodes.SkipNode
def visit_production(self, node):
# type: (nodes.Node) -> None
pass
def depart_production(self, node):
# type: (nodes.Node) -> None
pass
# overwritten -- don't emit a warning for images
def visit_image(self, node):
# type: (nodes.Node) -> None
if 'alt' in node.attributes:
self.body.append(_('[image: %s]') % node['alt'] + '\n')
self.body.append(_('[image]') + '\n')
@ -285,6 +336,7 @@ class ManualPageTranslator(BaseTranslator):
# overwritten -- don't visit inner marked up nodes
def visit_reference(self, node):
# type: (nodes.Node) -> None
self.body.append(self.defs['reference'][0])
# avoid repeating escaping code... fine since
# visit_Text calls astext() and only works on that afterwards
@ -306,51 +358,66 @@ class ManualPageTranslator(BaseTranslator):
raise nodes.SkipNode
def visit_number_reference(self, node):
# type: (nodes.Node) -> None
text = nodes.Text(node.get('title', '#'))
self.visit_Text(text)
raise nodes.SkipNode
def visit_centered(self, node):
# type: (nodes.Node) -> None
self.ensure_eol()
self.body.append('.sp\n.ce\n')
def depart_centered(self, node):
# type: (nodes.Node) -> None
self.body.append('\n.ce 0\n')
def visit_compact_paragraph(self, node):
# type: (nodes.Node) -> None
pass
def depart_compact_paragraph(self, node):
# type: (nodes.Node) -> None
pass
def visit_highlightlang(self, node):
# type: (nodes.Node) -> None
pass
def depart_highlightlang(self, node):
# type: (nodes.Node) -> None
pass
def visit_download_reference(self, node):
# type: (nodes.Node) -> None
pass
def depart_download_reference(self, node):
# type: (nodes.Node) -> None
pass
def visit_toctree(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_index(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_tabular_col_spec(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_glossary(self, node):
# type: (nodes.Node) -> None
pass
def depart_glossary(self, node):
# type: (nodes.Node) -> None
pass
def visit_acks(self, node):
# type: (nodes.Node) -> None
self.ensure_eol()
self.body.append(', '.join(n.astext()
for n in node.children[0].children) + '.')
@ -358,43 +425,56 @@ class ManualPageTranslator(BaseTranslator):
raise nodes.SkipNode
def visit_hlist(self, node):
# type: (nodes.Node) -> None
self.visit_bullet_list(node)
def depart_hlist(self, node):
# type: (nodes.Node) -> None
self.depart_bullet_list(node)
def visit_hlistcol(self, node):
# type: (nodes.Node) -> None
pass
def depart_hlistcol(self, node):
# type: (nodes.Node) -> None
pass
def visit_literal_emphasis(self, node):
# type: (nodes.Node) -> None
return self.visit_emphasis(node)
def depart_literal_emphasis(self, node):
# type: (nodes.Node) -> None
return self.depart_emphasis(node)
def visit_literal_strong(self, node):
# type: (nodes.Node) -> None
return self.visit_strong(node)
def depart_literal_strong(self, node):
# type: (nodes.Node) -> None
return self.depart_strong(node)
def visit_abbreviation(self, node):
# type: (nodes.Node) -> None
pass
def depart_abbreviation(self, node):
# type: (nodes.Node) -> None
pass
def visit_manpage(self, node):
# type: (nodes.Node) -> None
return self.visit_strong(node)
def depart_manpage(self, node):
# type: (nodes.Node) -> None
return self.depart_strong(node)
# overwritten: handle section titles better than in 0.6 release
def visit_title(self, node):
# type: (nodes.Node) -> None
if isinstance(node.parent, addnodes.seealso):
self.body.append('.IP "')
return
@ -409,26 +489,32 @@ class ManualPageTranslator(BaseTranslator):
return BaseTranslator.visit_title(self, node)
def depart_title(self, node):
# type: (nodes.Node) -> None
if isinstance(node.parent, addnodes.seealso):
self.body.append('"\n')
return
return BaseTranslator.depart_title(self, node)
def visit_raw(self, node):
# type: (nodes.Node) -> None
if 'manpage' in node.get('format', '').split():
self.body.append(node.astext())
raise nodes.SkipNode
def visit_meta(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_inline(self, node):
# type: (nodes.Node) -> None
pass
def depart_inline(self, node):
# type: (nodes.Node) -> None
pass
def visit_math(self, node):
# type: (nodes.Node) -> None
logger.warning('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html')
@ -437,4 +523,5 @@ class ManualPageTranslator(BaseTranslator):
visit_math_block = visit_math
def unknown_visit(self, node):
# type: (nodes.Node) -> None
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)

View File

@ -1055,6 +1055,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
pass
def visit_term(self, node):
# type: (nodes.Node) -> None
for id in node.get('ids'):
self.add_anchor(id, node)
# anchors and indexes need to go in front
@ -1209,6 +1210,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
'@end cartouche\n')
def _make_visit_admonition(name):
# type: (unicode) -> Callable[[TexinfoTranslator, nodes.Node], None]
def visit(self, node):
# type: (nodes.Node) -> None
self.visit_admonition(node, admonitionlabels[name])

View File

@ -863,6 +863,7 @@ class TextTranslator(nodes.NodeVisitor):
self.add_text(self.nl)
def _make_depart_admonition(name):
# type: (unicode) -> Callable[[TextTranslator, nodes.Node], None]
def depart_admonition(self, node):
# type: (nodes.NodeVisitor, nodes.Node) -> None
self.end_state(first=admonitionlabels[name] + ': ')