Merge branch '2.0' into 6574_annotation_for_varidic_params

This commit is contained in:
Takeshi KOMIYA 2019-08-02 01:29:39 +09:00 committed by GitHub
commit b3eb853680
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 650 additions and 2176 deletions

View File

@ -32,6 +32,8 @@ Features added
* #6514: html: Add a label to search input for accessability purposes
* #5602: apidoc: Add ``--templatedir`` option
* #6475: Add ``override`` argument to ``app.add_autodocumenter()``
* #6310: imgmath: let :confval:`imgmath_use_preview` work also with the SVG
format for images rendering inline math
* #6533: LaTeX: refactor visit_enumerated_list() to use ``\sphinxsetlistlabels``
Bugs fixed
@ -44,6 +46,10 @@ Bugs fixed
* #5502: linkcheck: Consider HTTP 503 response as not an error
* #6439: Make generated download links reproducible
* #6486: UnboundLocalError is raised if broken extension installed
* #6567: autodoc: :confval:`autodoc_inherit_docstrings` does not effect to
``__init__()`` and ``__new__()``
* #6574: autodoc: :confval:`autodoc_member_order` does not refer order of
imports when ``'bysource'`` order
* #6574: autodoc: missing type annotation for variadic and keyword parameters
* #6498: autosummary: crashed with wrong autosummary_generate setting
* #6507: autosummary: crashes without no autosummary_generate setting
@ -56,6 +62,9 @@ Bugs fixed
each comma separated option
* #6549: sphinx-build: Escaped characters in error messages
* #6545: doctest comments not getting trimmed since Sphinx 1.8.0
* #6561: glossary: Wrong hyperlinks are generated for non alphanumeric terms
* #6620: i18n: classifiers of definition list are not translated with
docutils-0.15
Testing
--------

View File

@ -30,13 +30,39 @@ This extension renders math via LaTeX and dvipng_ or dvisvgm_ into PNG or SVG
images. This of course means that the computer where the docs are built must
have both programs available.
There are various config values you can set to influence how the images are
built:
There are various configuration values you can set to influence how the images
are built:
.. confval:: imgmath_image_format
The output image format. The default is ``'png'``. It should be either
``'png'`` or ``'svg'``.
The output image format. The default is ``'png'``. It should be either
``'png'`` or ``'svg'``. The image is produced by first executing ``latex``
on the TeX mathematical mark-up then (depending on the requested format)
either `dvipng`_ or `dvisvgm`_.
.. confval:: imgmath_use_preview
``dvipng`` and ``dvisvgm`` both have the ability to collect from LaTeX the
"depth" of the rendered math: an inline image should use this "depth" in a
``vertical-align`` style to get correctly aligned with surrounding text.
This mechanism requires the `LaTeX preview package`_ (available as
``preview-latex-style`` on Ubuntu xenial). Therefore, the default for this
option is ``False`` but it is strongly recommended to set it to ``True``.
.. versionchanged:: 2.2
This option can be used with the ``'svg'`` :confval:`imgmath_image_format`.
.. confval:: imgmath_add_tooltips
Default: ``True``. If false, do not add the LaTeX code as an "alt" attribute
for math images.
.. confval:: imgmath_font_size
The font size (in ``pt``) of the displayed math. The default value is
``12``. It must be a positive integer.
.. confval:: imgmath_latex
@ -54,20 +80,6 @@ built:
This value should only contain the path to the latex executable, not further
arguments; use :confval:`imgmath_latex_args` for that purpose.
.. confval:: imgmath_dvipng
The command name with which to invoke ``dvipng``. The default is
``'dvipng'``; you may need to set this to a full path if ``dvipng`` is not in
the executable search path. This option is only used when
``imgmath_image_format`` is set to ``'png'``.
.. confval:: imgmath_dvisvgm
The command name with which to invoke ``dvisvgm``. The default is
``'dvisvgm'``; you may need to set this to a full path if ``dvisvgm`` is not
in the executable search path. This option is only used when
``imgmath_image_format`` is ``'svg'``.
.. confval:: imgmath_latex_args
Additional arguments to give to latex, as a list. The default is an empty
@ -75,49 +87,43 @@ built:
.. confval:: imgmath_latex_preamble
Additional LaTeX code to put into the preamble of the short LaTeX files that
are used to translate the math snippets. This is empty by default. Use it
e.g. to add more packages whose commands you want to use in the math.
Additional LaTeX code to put into the preamble of the LaTeX files used to
translate the math snippets. This is left empty by default. Use it
e.g. to add packages which modify the fonts used for math, such as
``'\\usepackage{newtxsf}'`` for sans-serif fonts, or
``'\\usepackage{fouriernc}'`` for serif fonts. Indeed, the default LaTeX
math fonts have rather thin glyphs which (in HTML output) often do not
match well with the font for text.
.. confval:: imgmath_dvipng
The command name to invoke ``dvipng``. The default is
``'dvipng'``; you may need to set this to a full path if ``dvipng`` is not in
the executable search path. This option is only used when
``imgmath_image_format`` is set to ``'png'``.
.. confval:: imgmath_dvipng_args
Additional arguments to give to dvipng, as a list. The default value is
``['-gamma', '1.5', '-D', '110', '-bg', 'Transparent']`` which makes the
image a bit darker and larger then it is by default, and produces PNGs with a
image a bit darker and larger then it is by default (this compensates
somewhat for the thinness of default LaTeX math fonts), and produces PNGs with a
transparent background. This option is used only when
``imgmath_image_format`` is ``'png'``.
.. confval:: imgmath_dvisvgm
The command name to invoke ``dvisvgm``. The default is
``'dvisvgm'``; you may need to set this to a full path if ``dvisvgm`` is not
in the executable search path. This option is only used when
``imgmath_image_format`` is ``'svg'``.
.. confval:: imgmath_dvisvgm_args
Additional arguments to give to dvisvgm, as a list. The default value is
``['--no-fonts']``. This option is used only when ``imgmath_image_format``
is ``'svg'``.
.. confval:: imgmath_use_preview
``dvipng`` has the ability to determine the "depth" of the rendered text: for
example, when typesetting a fraction inline, the baseline of surrounding text
should not be flush with the bottom of the image, rather the image should
extend a bit below the baseline. This is what TeX calls "depth". When this
is enabled, the images put into the HTML document will get a
``vertical-align`` style that correctly aligns the baselines.
Unfortunately, this only works when the `preview-latex package`_ is
installed (on Ubuntu xenial, it is available as `preview-latex-style`_).
Therefore, the default for this option is ``False``.
Currently this option is only used when ``imgmath_image_format`` is
``'png'``.
.. confval:: imgmath_add_tooltips
Default: ``True``. If false, do not add the LaTeX code as an "alt" attribute
for math images.
.. confval:: imgmath_font_size
The font size (in ``pt``) of the displayed math. The default value is
``12``. It must be a positive integer.
Additional arguments to give to dvisvgm, as a list. The default value is
``['--no-fonts']``, which means that ``dvisvgm`` will render glyphs as path
elements (cf the `dvisvgm FAQ`_). This option is used only when
``imgmath_image_format`` is ``'svg'``.
:mod:`sphinx.ext.mathjax` -- Render math via JavaScript
@ -219,7 +225,7 @@ package jsMath_. It provides this config value:
.. _dvipng: https://savannah.nongnu.org/projects/dvipng/
.. _dvisvgm: https://dvisvgm.de/
.. _dvisvgm FAQ: https://dvisvgm.de/FAQ
.. _MathJax: https://www.mathjax.org/
.. _jsMath: http://www.math.union.edu/~dpvc/jsmath/
.. _preview-latex package: https://www.gnu.org/software/auctex/preview-latex.html
.. _preview-latex-style: https://packages.ubuntu.com/xenial/preview-latex-style
.. _LaTeX preview package: https://www.gnu.org/software/auctex/preview-latex.html

2323
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,10 +11,10 @@
"url": "https://github.com/sphinx-doc/sphinx/issues"
},
"devDependencies": {
"jasmine-core": "^3.1.0",
"karma": "^3.0.0",
"karma-chrome-launcher": "^2.2.0",
"jasmine-core": "^3.4.0",
"karma": "^4.0.0",
"karma-chrome-launcher": "^3.0.0",
"karma-firefox-launcher": "^1.1.0",
"karma-jasmine": "^1.1.2"
"karma-jasmine": "^2.0.0"
}
}

View File

@ -48,7 +48,8 @@ from sphinx.util.tags import Tags
if False:
# For type annotation
from typing import Any, Callable, Dict, IO, Iterable, Iterator, List, Tuple, Type, Union # NOQA
from typing import Any, Callable, Dict, IO, Iterable, Iterator, List, Tuple, Union # NOQA
from typing import Type # for python3.5.1
from docutils import nodes # NOQA
from docutils.parsers import Parser # NOQA
from docutils.transforms import Transform # NOQA

View File

@ -11,7 +11,7 @@
import pickle
import time
from os import path
from typing import Any, Dict, Iterable, List, Sequence, Set, Tuple, Type, Union
from typing import Any, Dict, Iterable, List, Sequence, Set, Tuple, Union
from docutils import nodes
from docutils.nodes import Node
@ -44,6 +44,7 @@ except ImportError:
if False:
# For type annotation
from typing import Type # for python3.5.1
from sphinx.application import Sphinx
@ -117,7 +118,7 @@ class Builder:
self.env.set_versioning_method(self.versioning_method,
self.versioning_compare)
def get_translator_class(self, *args) -> Type[nodes.NodeVisitor]:
def get_translator_class(self, *args) -> "Type[nodes.NodeVisitor]":
"""Return a class of translator."""
return self.app.registry.get_translator_class(self)

View File

@ -14,7 +14,7 @@ from datetime import datetime, tzinfo, timedelta
from io import StringIO
from os import path, walk, getenv
from time import time
from typing import Any, DefaultDict, Dict, Iterable, List, Set, Tuple, Union
from typing import Any, Dict, Iterable, List, Set, Tuple, Union
from uuid import uuid4
from docutils import nodes
@ -33,6 +33,9 @@ from sphinx.util.nodes import extract_messages, traverse_translatable_index
from sphinx.util.osutil import relpath, ensuredir, canon_path
from sphinx.util.tags import Tags
if False:
# For type annotation
from typing import DefaultDict # for python3.5.1
logger = logging.getLogger(__name__)

View File

@ -15,7 +15,7 @@ import sys
import warnings
from hashlib import md5
from os import path
from typing import Any, Dict, IO, Iterable, Iterator, List, Set, Type, Tuple
from typing import Any, Dict, IO, Iterable, Iterator, List, Set, Tuple
from docutils import nodes
from docutils.core import publish_parts
@ -48,6 +48,11 @@ from sphinx.util.osutil import os_path, relative_uri, ensuredir, movefile, copyf
from sphinx.util.tags import Tags
from sphinx.writers.html import HTMLWriter, HTMLTranslator
if False:
# For type annotation
from typing import Type # for python3.5.1
# HTML5 Writer is avialable or not
if is_html5_writer_available():
from sphinx.writers.html5 import HTML5Translator
@ -331,7 +336,7 @@ class StandaloneHTMLBuilder(Builder):
self.script_files.append(JavaScript(filename, **kwargs))
@property
def default_translator_class(self) -> Type[nodes.NodeVisitor]: # type: ignore
def default_translator_class(self) -> "Type[nodes.NodeVisitor]": # type: ignore
if not html5_ready or self.config.html4_writer:
return HTMLTranslator
else:

View File

@ -9,7 +9,7 @@
"""
from os import path
from typing import Any, Dict, Iterator, Set, Type, Union
from typing import Any, Dict, Iterator, Set, Union
from docutils import nodes
from docutils.io import StringOutput
@ -23,6 +23,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 Type # for python3.5.1
logger = logging.getLogger(__name__)

View File

@ -14,7 +14,8 @@ from importlib import import_module
if False:
# For type annotation
from typing import Any, Dict, Type # NOQA
from typing import Any, Dict # NOQA
from typing import Type # for python3.5.1
class RemovedInSphinx30Warning(DeprecationWarning):

View File

@ -10,7 +10,7 @@
"""
import copy
from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, Type, Union
from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, Union
from docutils import nodes
from docutils.nodes import Element, Node, system_message
@ -24,6 +24,7 @@ from sphinx.util.typing import RoleFunction
if False:
# For type annotation
from typing import Type # for python3.5.1
from sphinx.builders import Builder
from sphinx.environment import BuildEnvironment

View File

@ -10,7 +10,7 @@
import re
import warnings
from typing import Any, Dict, Iterable, Iterator, List, Tuple, Type
from typing import Any, Dict, Iterable, Iterator, List, Tuple
from typing import cast
from docutils import nodes
@ -35,6 +35,10 @@ from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import make_refnode
from sphinx.util.typing import TextlikeNode
if False:
# For type annotation
from typing import Type # for python3.5.1
logger = logging.getLogger(__name__)
@ -119,7 +123,7 @@ def _pseudo_parse_arglist(signode: desc_signature, arglist: str) -> None:
# when it comes to handling "." and "~" prefixes.
class PyXrefMixin:
def make_xref(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = nodes.emphasis,
innernode: "Type[TextlikeNode]" = nodes.emphasis,
contnode: Node = None, env: BuildEnvironment = None) -> Node:
result = super().make_xref(rolename, domain, target, # type: ignore
innernode, contnode, env)
@ -136,7 +140,7 @@ class PyXrefMixin:
return result
def make_xrefs(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = nodes.emphasis,
innernode: "Type[TextlikeNode]" = nodes.emphasis,
contnode: Node = None, env: BuildEnvironment = None) -> List[Node]:
delims = r'(\s*[\[\]\(\),](?:\s*or\s)?\s*|\s+or\s+)'
delims_re = re.compile(delims)
@ -160,7 +164,7 @@ class PyXrefMixin:
class PyField(PyXrefMixin, Field):
def make_xref(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = nodes.emphasis,
innernode: "Type[TextlikeNode]" = nodes.emphasis,
contnode: Node = None, env: BuildEnvironment = None) -> Node:
if rolename == 'class' and target == 'None':
# None is not a type, so use obj role instead.
@ -175,7 +179,7 @@ class PyGroupedField(PyXrefMixin, GroupedField):
class PyTypedField(PyXrefMixin, TypedField):
def make_xref(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = nodes.emphasis,
innernode: "Type[TextlikeNode]" = nodes.emphasis,
contnode: Node = None, env: BuildEnvironment = None) -> Node:
if rolename == 'class' and target == 'None':
# None is not a type, so use obj role instead.

View File

@ -12,7 +12,7 @@ import re
import unicodedata
import warnings
from copy import copy
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Type, Union
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union
from typing import cast
from docutils import nodes
@ -35,6 +35,7 @@ from sphinx.util.typing import RoleFunction
if False:
# For type annotation
from typing import Type # for python3.5.1
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.environment import BuildEnvironment
@ -255,9 +256,9 @@ def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index
new_id = nodes.make_id('term-' + termtext)
if new_id == 'term':
# the term is not good for node_id. Generate it by sequence number instead.
new_id = 'term-' + str(len(gloss_entries))
if new_id in gloss_entries:
new_id = 'term-' + str(len(gloss_entries))
new_id = 'term-%d' % env.new_serialno('glossary')
while new_id in gloss_entries:
new_id = 'term-%d' % env.new_serialno('glossary')
gloss_entries.add(new_id)
std = cast(StandardDomain, env.get_domain('std'))
@ -910,7 +911,7 @@ class StandardDomain(Domain):
def get_enumerable_node_type(self, node: Node) -> str:
"""Get type of enumerable nodes."""
def has_child(node: Element, cls: Type) -> bool:
def has_child(node: Element, cls: "Type") -> bool:
return any(isinstance(child, cls) for child in node)
if isinstance(node, nodes.section):

View File

@ -8,7 +8,7 @@
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict, List, Set, Tuple, Type, TypeVar
from typing import Any, Dict, List, Set, Tuple, TypeVar
from typing import cast
from docutils import nodes
@ -23,6 +23,10 @@ from sphinx.locale import __
from sphinx.transforms import SphinxContentsFilter
from sphinx.util import url_re, logging
if False:
# For type annotation
from typing import Type # for python3.5.1
N = TypeVar('N')
@ -64,7 +68,7 @@ class TocTreeCollector(EnvironmentCollector):
docname = app.env.docname
numentries = [0] # nonlocal again...
def traverse_in_section(node: Element, cls: Type[N]) -> List[N]:
def traverse_in_section(node: Element, cls: "Type[N]") -> List[N]:
"""Like traverse(), but stay within the same section."""
result = [] # type: List[N]
if isinstance(node, cls):

View File

@ -13,7 +13,7 @@
import re
import warnings
from types import ModuleType
from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union
from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Union
from docutils.statemachine import StringList
@ -38,6 +38,7 @@ from sphinx.util.inspect import (
if False:
# For type annotation
from typing import Type # NOQA # for python3.5.1
from sphinx.ext.autodoc.directive import DocumenterBridge
@ -255,7 +256,7 @@ class Documenter:
self.analyzer = None # type: ModuleAnalyzer
@property
def documenters(self) -> Dict[str, Type["Documenter"]]:
def documenters(self) -> Dict[str, "Type[Documenter]"]:
"""Returns registered Documenter classes"""
return get_documenters(self.env.app)
@ -1128,8 +1129,9 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
# for classes, what the "docstring" is can be controlled via a
# config value; the default is only the class docstring
if content in ('both', 'init'):
initdocstring = self.get_attr(
self.get_attr(self.object, '__init__', None), '__doc__')
__init__ = self.get_attr(self.object, '__init__', None)
initdocstring = getdoc(__init__, self.get_attr,
self.env.config.autodoc_inherit_docstrings)
# for new-style classes, no __init__ means default __init__
if (initdocstring is not None and
(initdocstring == object.__init__.__doc__ or # for pypy
@ -1137,8 +1139,9 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
initdocstring = None
if not initdocstring:
# try __new__
initdocstring = self.get_attr(
self.get_attr(self.object, '__new__', None), '__doc__')
__new__ = self.get_attr(self.object, '__new__', None)
initdocstring = getdoc(__new__, self.get_attr,
self.env.config.autodoc_inherit_docstrings)
# for new-style classes, no __new__ means default __new__
if (initdocstring is not None and
(initdocstring == object.__new__.__doc__ or # for pypy
@ -1484,7 +1487,7 @@ class SlotsAttributeDocumenter(AttributeDocumenter):
return []
def get_documenters(app: Sphinx) -> Dict[str, Type[Documenter]]:
def get_documenters(app: Sphinx) -> Dict[str, "Type[Documenter]"]:
"""Returns registered Documenter classes"""
return app.registry.documenters

View File

@ -7,7 +7,7 @@
"""
import warnings
from typing import Any, Callable, Dict, List, Set, Type
from typing import Any, Callable, Dict, List, Set
from docutils import nodes
from docutils.nodes import Element, Node
@ -23,6 +23,11 @@ from sphinx.util import logging
from sphinx.util.docutils import SphinxDirective, switch_source_input
from sphinx.util.nodes import nested_parse_with_titles
if False:
# For type annotation
from typing import Type # for python3.5.1
logger = logging.getLogger(__name__)
@ -70,7 +75,7 @@ class DocumenterBridge:
logger.warning(msg, location=(self.env.docname, self.lineno))
def process_documenter_options(documenter: Type[Documenter], config: Config, options: Dict
def process_documenter_options(documenter: "Type[Documenter]", config: Config, options: Dict
) -> Options:
"""Recognize options of Documenter from user input."""
for name in AUTODOC_DEFAULT_OPTIONS:

View File

@ -60,7 +60,7 @@ import sys
import warnings
from os import path
from types import ModuleType
from typing import Any, Dict, List, Tuple, Type
from typing import Any, Dict, List, Tuple
from typing import cast
from docutils import nodes
@ -88,6 +88,10 @@ from sphinx.util.docutils import (
from sphinx.util.matching import Matcher
from sphinx.writers.html import HTMLTranslator
if False:
# For type annotation
from typing import Type # for python3.5.1
logger = logging.getLogger(__name__)
@ -173,7 +177,7 @@ class FakeDirective(DocumenterBridge):
super().__init__({}, None, Options(), 0, state) # type: ignore
def get_documenter(app: Sphinx, obj: Any, parent: Any) -> Type[Documenter]:
def get_documenter(app: Sphinx, obj: Any, parent: Any) -> "Type[Documenter]":
"""Get an autodoc.Documenter class suitable for documenting the given
object.

View File

@ -24,7 +24,7 @@ import pydoc
import re
import sys
import warnings
from typing import Any, Callable, Dict, List, Set, Tuple, Type
from typing import Any, Callable, Dict, List, Set, Tuple
from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound
from jinja2.sandbox import SandboxedEnvironment
@ -44,6 +44,10 @@ from sphinx.util import rst
from sphinx.util.inspect import safe_getattr
from sphinx.util.osutil import ensuredir
if False:
# For type annotation
from typing import Type # for python3.5.1
logger = logging.getLogger(__name__)

View File

@ -16,7 +16,7 @@ import time
import warnings
from io import StringIO
from os import path
from typing import Any, Callable, Dict, Iterable, List, Sequence, Set, Tuple, Type
from typing import Any, Callable, Dict, Iterable, List, Sequence, Set, Tuple
from docutils import nodes
from docutils.nodes import Element, Node, TextElement
@ -35,6 +35,7 @@ from sphinx.util.osutil import relpath
if False:
# For type annotation
from typing import Type # for python3.5.1
from sphinx.application import Sphinx

View File

@ -87,14 +87,38 @@ DOC_BODY_PREVIEW = r'''
'''
depth_re = re.compile(br'\[\d+ depth=(-?\d+)\]')
depthsvg_re = re.compile(br'.*, depth=(.*)pt')
depthsvgcomment_re = re.compile(r'<!-- DEPTH=(-?\d+) -->')
def generate_latex_macro(math: str, config: Config, confdir: str = '') -> str:
def read_svg_depth(filename: str) -> int:
"""Read the depth from comment at last line of SVG file
"""
with open(filename, 'r') as f:
for line in f:
pass
# Only last line is checked
matched = depthsvgcomment_re.match(line)
if matched:
return int(matched.group(1))
return None
def write_svg_depth(filename: str, depth:int) -> None:
"""Write the depth to SVG file as a comment at end of file
"""
with open(filename, 'a') as f:
f.write('\n<!-- DEPTH=%s -->' % depth)
def generate_latex_macro(image_format: str,
math: str, config: Config, confdir: str = '') -> str:
"""Generate LaTeX macro."""
variables = {
'fontsize': config.imgmath_font_size,
'baselineskip': int(round(config.imgmath_font_size * 1.2)),
'preamble': config.imgmath_latex_preamble,
'tightpage': '' if image_format == 'png' else ',tightpage',
'math': math
}
@ -201,8 +225,18 @@ def convert_dvi_to_svg(dvipath: str, builder: Builder) -> Tuple[str, int]:
command.extend(builder.config.imgmath_dvisvgm_args)
command.append(dvipath)
convert_dvi_to_image(command, name)
return filename, None
stdout, stderr = convert_dvi_to_image(command, name)
depth = None
if builder.config.imgmath_use_preview:
for line in stderr.splitlines(): # not stdout !
matched = depthsvg_re.match(line)
if matched:
depth = round(float(matched.group(1)) * 100 / 72.27) # assume 100ppi
write_svg_depth(filename, depth)
break
return filename, depth
def render_math(self: HTMLTranslator, math: str) -> Tuple[str, int]:
@ -223,13 +257,19 @@ def render_math(self: HTMLTranslator, math: str) -> Tuple[str, int]:
if image_format not in SUPPORT_FORMAT:
raise MathExtError('imgmath_image_format must be either "png" or "svg"')
latex = generate_latex_macro(math, self.builder.config, self.builder.confdir)
latex = generate_latex_macro(image_format,
math,
self.builder.config,
self.builder.confdir)
filename = "%s.%s" % (sha1(latex.encode()).hexdigest(), image_format)
relfn = posixpath.join(self.builder.imgpath, 'math', filename)
outfn = path.join(self.builder.outdir, self.builder.imagedir, 'math', filename)
if path.isfile(outfn):
depth = read_png_depth(outfn)
if image_format == 'png':
depth = read_png_depth(outfn)
elif image_format == 'svg':
depth = read_svg_depth(outfn)
return relfn, depth
# if latex or dvipng (dvisvgm) has failed once, don't bother to try again

View File

@ -13,13 +13,17 @@
import inspect
import re
from functools import partial
from typing import Any, Callable, Dict, List, Tuple, Type, Union
from typing import Any, Callable, Dict, List, Tuple, Union
from sphinx.application import Sphinx
from sphinx.config import Config as SphinxConfig
from sphinx.ext.napoleon.iterators import modify_iter
from sphinx.locale import _
if False:
# For type annotation
from typing import Type # for python3.5.1
_directive_regex = re.compile(r'\.\. \S+::')
_google_section_regex = re.compile(r'^(\s|\w)+:\s*$')
@ -735,7 +739,7 @@ class GoogleDocstring:
colon,
"".join(after_colon).strip())
def _qualify_name(self, attr_name: str, klass: Type) -> str:
def _qualify_name(self, attr_name: str, klass: "Type") -> str:
if klass and '.' not in attr_name:
if attr_name.startswith('~'):
attr_name = attr_name[1:]

View File

@ -35,7 +35,8 @@ from sphinx.versioning import UIDTransform
if False:
# For type annotation
from typing import Dict, List, Tuple, Type # NOQA
from typing import Dict, List, Tuple # NOQA
from typing import Type # for python3.5.1
from docutils import nodes # NOQA
from docutils.frontend import Values # NOQA
from docutils.io import Input # NOQA

View File

@ -18,7 +18,8 @@ from sphinx.util.rst import append_epilog, prepend_prolog
if False:
# For type annotation
from typing import Any, Dict, List, Type, Union # NOQA
from typing import Any, Dict, List, Union # NOQA
from typing import Type # for python3.5.1
from docutils import nodes # NOQA
from docutils.transforms import Transform # NOQA
from sphinx.application import Sphinx # NOQA

View File

@ -9,7 +9,6 @@
"""
import os
from typing import TYPE_CHECKING
from sphinx.locale import __
from sphinx.util import get_matching_files
@ -17,9 +16,11 @@ from sphinx.util import logging
from sphinx.util.matching import compile_matchers
from sphinx.util.osutil import SEP, relpath
if TYPE_CHECKING:
if False:
# For type annotation
from typing import Dict, List, Set # NOQA
logger = logging.getLogger(__name__)
EXCLUDE_PATHS = ['**/_sources', '.#*', '**/.#*', '*.lproj/**']

View File

@ -270,6 +270,22 @@ class VariableCommentPicker(ast.NodeVisitor):
super().visit(node)
self.previous = node
def visit_Import(self, node: ast.Import) -> None:
"""Handles Import node and record it to definition orders."""
for name in node.names:
if name.asname:
self.add_entry(name.asname)
else:
self.add_entry(name.name)
def visit_ImportFrom(self, node: ast.Import) -> None:
"""Handles Import node and record it to definition orders."""
for name in node.names:
if name.asname:
self.add_entry(name.asname)
else:
self.add_entry(name.name)
def visit_Assign(self, node: ast.Assign) -> None:
"""Handles Assign node and pick up a variable comment."""
try:

View File

@ -30,7 +30,8 @@ from sphinx.util.logging import prefixed_warnings
if False:
# For type annotation
from typing import Any, Callable, Dict, Iterator, List, Tuple, Type, Union # NOQA
from typing import Any, Callable, Dict, Iterator, List, Tuple, Union # NOQA
from typing import Type # for python3.5.1
from docutils import nodes # NOQA
from docutils.io import Input # NOQA
from docutils.parsers import Parser # NOQA

View File

@ -23,7 +23,8 @@ from sphinx.util.nodes import split_explicit_title, process_index_entry, \
if False:
# For type annotation
from typing import Any, Dict, List, Tuple, Type # NOQA
from typing import Any, Dict, List, Tuple # NOQA
from typing import Type # for python3.5.1
from docutils.parsers.rst.states import Inliner # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.environment import BuildEnvironment # NOQA

View File

@ -23,7 +23,8 @@ from sphinx.util import jsdump, rpartition
if False:
# For type annotation
from typing import Any, Dict, IO, Iterable, List, Tuple, Type, Set # NOQA
from typing import Any, Dict, IO, Iterable, List, Tuple, Set # NOQA
from typing import Type # for python3.5.1
from docutils import nodes # NOQA
from sphinx.environment import BuildEnvironment # NOQA

View File

@ -9,7 +9,7 @@
\pagestyle{empty}
<%= preamble %>
\usepackage[active]{preview}
\usepackage[active<%= tightpage %>]{preview}
\begin{document}
\begin{preview}

View File

@ -29,7 +29,8 @@ from sphinx.util.nodes import (
if False:
# For type annotation
from typing import Dict, List, Tuple, Type # NOQA
from typing import Dict, List, Tuple # NOQA
from typing import Type # for python3.5.1
from sphinx.application import Sphinx # NOQA
from sphinx.config import Config # NOQA

View File

@ -24,9 +24,7 @@ from datetime import datetime
from hashlib import md5
from os import path
from time import mktime, strptime
from typing import (
Any, Callable, Dict, IO, Iterable, Iterator, List, Pattern, Set, Tuple, Type
)
from typing import Any, Callable, Dict, IO, Iterable, Iterator, List, Pattern, Set, Tuple
from urllib.parse import urlsplit, urlunsplit, quote_plus, parse_qsl, urlencode
from docutils.utils import relative_path
@ -53,6 +51,7 @@ from sphinx.util.matching import patfilter # noqa
if False:
# For type annotation
from typing import Type # for python3.5.1
from sphinx.application import Sphinx
from sphinx.builders import Builder
@ -655,7 +654,7 @@ class progress_message:
def __enter__(self) -> None:
logger.info(bold(self.message + '... '), nonl=True)
def __exit__(self, exc_type: Type[Exception], exc_value: Exception, traceback: Any) -> bool: # NOQA
def __exit__(self, exc_type: "Type[Exception]", exc_value: Exception, traceback: Any) -> bool: # NOQA
if isinstance(exc_value, SkipProgressMessage):
logger.info(__('skipped'))
if exc_value.args:

View File

@ -10,7 +10,7 @@
"""
import warnings
from typing import Any, Dict, List, Tuple, Type, Union
from typing import Any, Dict, List, Tuple, Union
from typing import cast
from docutils import nodes
@ -22,6 +22,7 @@ from sphinx.util.typing import TextlikeNode
if False:
# For type annotation
from typing import Type # for python3.5.1
from sphinx.environment import BuildEnvironment
from sphinx.directive import ObjectDescription
@ -65,7 +66,7 @@ class Field:
self.bodyrolename = bodyrolename
def make_xref(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = addnodes.literal_emphasis,
innernode: "Type[TextlikeNode]" = addnodes.literal_emphasis,
contnode: Node = None, env: "BuildEnvironment" = None) -> Node:
if not rolename:
return contnode or innernode(target, target)
@ -77,7 +78,7 @@ class Field:
return refnode
def make_xrefs(self, rolename: str, domain: str, target: str,
innernode: Type[TextlikeNode] = addnodes.literal_emphasis,
innernode: "Type[TextlikeNode]" = addnodes.literal_emphasis,
contnode: Node = None, env: "BuildEnvironment" = None) -> List[Node]:
return [self.make_xref(rolename, domain, target, innernode, contnode, env)]

View File

@ -17,7 +17,7 @@ from copy import copy
from distutils.version import LooseVersion
from os import path
from types import ModuleType
from typing import Any, Callable, Dict, Generator, IO, List, Optional, Set, Tuple, Type
from typing import Any, Callable, Dict, Generator, IO, List, Optional, Set, Tuple
from typing import cast
import docutils
@ -40,6 +40,7 @@ report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(
if False:
# For type annotation
from typing import Type # for python3.5.1
from sphinx.builders import Builder
from sphinx.config import Config
from sphinx.environment import BuildEnvironment
@ -71,7 +72,7 @@ def is_directive_registered(name: str) -> bool:
return name in directives._directives
def register_directive(name: str, directive: Type[Directive]) -> None:
def register_directive(name: str, directive: "Type[Directive]") -> None:
"""Register a directive to docutils.
This modifies global state of docutils. So it is better to use this
@ -99,12 +100,12 @@ def unregister_role(name: str) -> None:
roles._roles.pop(name, None)
def is_node_registered(node: Type[Element]) -> bool:
def is_node_registered(node: "Type[Element]") -> bool:
"""Check the *node* is already registered."""
return hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__)
def register_node(node: Type[Element]) -> None:
def register_node(node: "Type[Element]") -> None:
"""Register a node to docutils.
This modifies global state of some visitors. So it is better to use this
@ -115,7 +116,7 @@ def register_node(node: Type[Element]) -> None:
additional_nodes.add(node)
def unregister_node(node: Type[Element]) -> None:
def unregister_node(node: "Type[Element]") -> None:
"""Unregister a node from docutils.
This is inverse of ``nodes._add_nodes_class_names()``.
@ -186,7 +187,7 @@ class sphinx_domains:
def __enter__(self) -> None:
self.enable()
def __exit__(self, exc_type: Type[Exception], exc_value: Exception, traceback: Any) -> bool: # NOQA
def __exit__(self, exc_type: "Type[Exception]", exc_value: Exception, traceback: Any) -> bool: # NOQA
self.disable()
return False
@ -229,7 +230,7 @@ class sphinx_domains:
raise ElementLookupError
def lookup_directive(self, directive_name: str, language_module: ModuleType, document: nodes.document) -> Tuple[Optional[Type[Directive]], List[system_message]]: # NOQA
def lookup_directive(self, directive_name: str, language_module: ModuleType, document: nodes.document) -> Tuple[Optional["Type[Directive]"], List[system_message]]: # NOQA
try:
return self.lookup_domain_element('directive', directive_name)
except ElementLookupError:

View File

@ -543,25 +543,18 @@ class Signature:
else:
qualname = repr(annotation)
if (hasattr(typing, 'TupleMeta') and
isinstance(annotation, typing.TupleMeta) and
not hasattr(annotation, '__tuple_params__')):
# This is for Python 3.6+, 3.5 case is handled below
if (isinstance(annotation, typing.TupleMeta) and
not hasattr(annotation, '__tuple_params__')): # for Python 3.6
params = annotation.__args__
if params:
param_str = ', '.join(self.format_annotation(p) for p in params)
return '%s[%s]' % (qualname, param_str)
else:
return qualname
elif (hasattr(typing, 'GenericMeta') and # for py36 or below
isinstance(annotation, typing.GenericMeta)):
# In Python 3.5.2+, all arguments are stored in __args__,
# whereas __parameters__ only contains generic parameters.
#
# Prior to Python 3.5.2, __args__ is not available, and all
# arguments are in __parameters__.
elif isinstance(annotation, typing.GenericMeta):
params = None
if hasattr(annotation, '__args__'):
# for Python 3.5.2+
if annotation.__args__ is None or len(annotation.__args__) <= 2: # type: ignore # NOQA
params = annotation.__args__ # type: ignore
else: # typing.Callable
@ -570,13 +563,14 @@ class Signature:
result = self.format_annotation(annotation.__args__[-1]) # type: ignore
return '%s[[%s], %s]' % (qualname, args, result)
elif hasattr(annotation, '__parameters__'):
# for Python 3.5.0 and 3.5.1
params = annotation.__parameters__ # type: ignore
if params is not None:
param_str = ', '.join(self.format_annotation(p) for p in params)
return '%s[%s]' % (qualname, param_str)
elif (hasattr(typing, 'UnionMeta') and # for py35 or below
elif (hasattr(typing, 'UnionMeta') and
isinstance(annotation, typing.UnionMeta) and
hasattr(annotation, '__union_params__')):
hasattr(annotation, '__union_params__')): # for Python 3.5
params = annotation.__union_params__
if params is not None:
if len(params) == 2 and params[1] is NoneType: # type: ignore
@ -584,9 +578,8 @@ class Signature:
else:
param_str = ', '.join(self.format_annotation(p) for p in params)
return '%s[%s]' % (qualname, param_str)
elif (hasattr(typing, 'Union') and # for py36
hasattr(annotation, '__origin__') and
annotation.__origin__ is typing.Union):
elif (hasattr(annotation, '__origin__') and
annotation.__origin__ is typing.Union): # for Python 3.5.2+
params = annotation.__args__
if params is not None:
if len(params) == 2 and params[1] is NoneType: # type: ignore
@ -594,10 +587,9 @@ class Signature:
else:
param_str = ', '.join(self.format_annotation(p) for p in params)
return 'Union[%s]' % param_str
elif (hasattr(typing, 'CallableMeta') and # for py36 or below
isinstance(annotation, typing.CallableMeta) and
elif (isinstance(annotation, typing.CallableMeta) and
getattr(annotation, '__args__', None) is not None and
hasattr(annotation, '__result__')):
hasattr(annotation, '__result__')): # for Python 3.5
# Skipped in the case of plain typing.Callable
args = annotation.__args__
if args is None:
@ -610,10 +602,9 @@ class Signature:
return '%s[%s, %s]' % (qualname,
args_str,
self.format_annotation(annotation.__result__))
elif (hasattr(typing, 'TupleMeta') and # for py36 or below
isinstance(annotation, typing.TupleMeta) and
elif (isinstance(annotation, typing.TupleMeta) and
hasattr(annotation, '__tuple_params__') and
hasattr(annotation, '__tuple_use_ellipsis__')):
hasattr(annotation, '__tuple_use_ellipsis__')): # for Python 3.5
params = annotation.__tuple_params__
if params is not None:
param_strings = [self.format_annotation(p) for p in params]

View File

@ -12,7 +12,7 @@ import logging
import logging.handlers
from collections import defaultdict
from contextlib import contextmanager
from typing import Any, Dict, Generator, IO, List, Tuple, Type, Union
from typing import Any, Dict, Generator, IO, List, Tuple, Union
from docutils import nodes
from docutils.nodes import Node
@ -23,6 +23,7 @@ from sphinx.util.console import colorize
if False:
# For type annotation
from typing import Type # for python3.5.1
from sphinx.application import Sphinx

View File

@ -10,7 +10,7 @@
import re
import warnings
from typing import Any, Callable, Iterable, List, Set, Tuple, Type
from typing import Any, Callable, Iterable, List, Set, Tuple
from typing import cast
from docutils import nodes
@ -26,6 +26,7 @@ from sphinx.util import logging
if False:
# For type annotation
from typing import Type # for python3.5.1
from sphinx.builders import Builder
from sphinx.utils.tags import Tags
@ -59,7 +60,7 @@ class NodeMatcher:
# => [<reference ...>, <reference ...>, ...]
"""
def __init__(self, *classes: Type[Node], **attrs) -> None:
def __init__(self, *classes: "Type[Node]", **attrs) -> None:
self.classes = classes
self.attrs = attrs
@ -132,6 +133,9 @@ def apply_source_workaround(node: Element) -> None:
node.source = definition_list_item.source
node.line = definition_list_item.line - 1
node.rawsource = node.astext() # set 'classifier1' (or 'classifier2')
elif isinstance(node, nodes.classifier) and not node.source:
# docutils-0.15 fills in rawsource attribute, but not in source.
node.source = node.parent.source
if isinstance(node, nodes.image) and node.source is None:
logger.debug('[i18n] PATCH: %r to have source, line: %s',
get_full_module_name(node), repr_domxml(node))

View File

@ -19,11 +19,15 @@ import time
import warnings
from io import StringIO
from os import path
from typing import Any, Generator, Iterator, List, Tuple, Type
from typing import Any, Generator, Iterator, List, Tuple
from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning
from sphinx.testing.path import path as Path
if False:
# For type annotation
from typing import Type # for python3.5.1
# Errnos that we need.
EEXIST = getattr(errno, 'EEXIST', 0) # RemovedInSphinx40Warning
ENOENT = getattr(errno, 'ENOENT', 0) # RemovedInSphinx40Warning
@ -248,7 +252,7 @@ class FileAvoidWrite:
def __enter__(self) -> "FileAvoidWrite":
return self
def __exit__(self, exc_type: Type[Exception], exc_value: Exception, traceback: Any) -> bool: # NOQA
def __exit__(self, exc_type: "Type[Exception]", exc_value: Exception, traceback: Any) -> bool: # NOQA
self.close()
return True

View File

@ -33,3 +33,15 @@ class F:
def __new__(cls):
"""__new__ docstring"""
class G(C):
"""A class inherits __init__ without docstring."""
def __init__(self):
pass
class H(E):
"""A class inherits __new__ without docstring."""
def __init__(self):
pass

View File

@ -244,6 +244,17 @@ def test_glossary_sorted(app):
[nodes.definition, nodes.paragraph, "description"])
def test_glossary_alphanumeric(app):
text = (".. glossary::\n"
"\n"
" 1\n"
" /\n")
restructuredtext.parse(app, text)
objects = list(app.env.get_domain("std").get_objects())
assert ("1", "1", "term", "index", "term-1", -1) in objects
assert ("/", "/", "term", "index", "term-0", -1) in objects
def test_cmdoption(app):
text = (".. program:: ls\n"
"\n"

View File

@ -131,4 +131,4 @@ def test_create_index_by_key(app):
assert len(index) == 3
assert index[0] == ('D', [('docutils', [[('main', '#term-docutils')], [], None])])
assert index[1] == ('P', [('Python', [[('main', '#term-python')], [], None])])
assert index[2] == ('', [('スフィンクス', [[('main', '#term-2')], [], ''])])
assert index[2] == ('', [('スフィンクス', [[('main', '#term-0')], [], ''])])

View File

@ -62,6 +62,18 @@ def test_autoclass_content_class(app):
' :module: target.autoclass_content',
'',
' A class having both __init__ and __new__',
' ',
'',
'.. py:class:: G()',
' :module: target.autoclass_content',
'',
' A class inherits __init__ without docstring.',
' ',
'',
'.. py:class:: H()',
' :module: target.autoclass_content',
'',
' A class inherits __new__ without docstring.',
' '
]
@ -110,6 +122,18 @@ def test_autoclass_content_init(app):
' :module: target.autoclass_content',
'',
' __init__ docstring',
' ',
'',
'.. py:class:: G()',
' :module: target.autoclass_content',
'',
' __init__ docstring',
' ',
'',
'.. py:class:: H()',
' :module: target.autoclass_content',
'',
' __new__ docstring',
' '
]
@ -164,6 +188,22 @@ def test_autoclass_content_both(app):
' A class having both __init__ and __new__',
' ',
' __init__ docstring',
' ',
'',
'.. py:class:: G()',
' :module: target.autoclass_content',
'',
' A class inherits __init__ without docstring.',
' ',
' __init__ docstring',
' ',
'',
'.. py:class:: H()',
' :module: target.autoclass_content',
'',
' A class inherits __new__ without docstring.',
' ',
' __new__ docstring',
' '
]

View File

@ -344,6 +344,22 @@ def test_async_function_and_method():
'Foo.method': ('def', 6, 7)}
def test_imports():
source = ('import sys\n'
'from os import environment, path\n'
'\n'
'import sphinx as Sphinx\n'
'from sphinx.application import Sphinx as App\n')
parser = Parser(source)
parser.parse()
assert parser.definitions == {}
assert parser.deforders == {'sys': 0,
'environment': 1,
'path': 2,
'Sphinx': 3,
'App': 4}
def test_formfeed_char():
source = ('class Foo:\n'
'\f\n'