Merge branch '2.0'

This commit is contained in:
Takeshi KOMIYA 2019-10-06 18:41:32 +09:00
commit e8925e78ca
18 changed files with 125 additions and 51 deletions

32
CHANGES
View File

@ -42,12 +42,44 @@ Incompatible changes
Deprecated Deprecated
---------- ----------
* ``sphinx.io.SphinxStandaloneReader.app``
* ``sphinx.io.SphinxStandaloneReader.env``
Features added Features added
-------------- --------------
Bugs fixed Bugs fixed
---------- ----------
* #6668: LaTeX: Longtable before header has incorrect distance
(refs: `latex3/latex2e#173`_)
.. _latex3/latex2e#173: https://github.com/latex3/latex2e/issues/173
* #6618: LaTeX: Avoid section names at the end of a page
Testing
--------
Release 2.2.1 (in development)
==============================
Dependencies
------------
Incompatible changes
--------------------
Deprecated
----------
Features added
--------------
Bugs fixed
----------
* #6641: LaTeX: Undefined control sequence ``\sphinxmaketitle``
Testing Testing
-------- --------

View File

@ -26,6 +26,16 @@ The following is a list of deprecated interfaces.
- (will be) Removed - (will be) Removed
- Alternatives - Alternatives
* - ``sphinx.io.SphinxStandaloneReader.app``
- 2.3
- 4.0
- ``sphinx.io.SphinxStandaloneReader.setup()``
* - ``sphinx.io.SphinxStandaloneReader.env``
- 2.3
- 4.0
- ``sphinx.io.SphinxStandaloneReader.setup()``
* - ``sphinx.domains.math.MathDomain.add_equation()`` * - ``sphinx.domains.math.MathDomain.add_equation()``
- 2.2 - 2.2
- 4.0 - 4.0

View File

@ -47,7 +47,7 @@ extras_require = {
'html5lib', 'html5lib',
'flake8>=3.5.0', 'flake8>=3.5.0',
'flake8-import-order', 'flake8-import-order',
'mypy>=0.720', 'mypy>=0.730',
'docutils-stubs', 'docutils-stubs',
], ],
} }

View File

@ -90,7 +90,7 @@ class Stylesheet(str):
attributes = None # type: Dict[str, str] attributes = None # type: Dict[str, str]
filename = None # type: str filename = None # type: str
def __new__(cls, filename: str, *args: str, **attributes: str) -> None: def __new__(cls, filename: str, *args: str, **attributes: str) -> "Stylesheet":
self = str.__new__(cls, filename) # type: ignore self = str.__new__(cls, filename) # type: ignore
self.filename = filename self.filename = filename
self.attributes = attributes self.attributes = attributes
@ -113,7 +113,7 @@ class JavaScript(str):
attributes = None # type: Dict[str, str] attributes = None # type: Dict[str, str]
filename = None # type: str filename = None # type: str
def __new__(cls, filename: str, **attributes: str) -> None: def __new__(cls, filename: str, **attributes: str) -> "JavaScript":
self = str.__new__(cls, filename) # type: ignore self = str.__new__(cls, filename) # type: ignore
self.filename = filename self.filename = filename
self.attributes = attributes self.attributes = attributes

View File

@ -88,7 +88,7 @@ class Make:
nocolor() nocolor()
print(bold("Sphinx v%s" % sphinx.__display_version__)) print(bold("Sphinx v%s" % sphinx.__display_version__))
print("Please use `make %s' where %s is one of" % ((blue('target'),) * 2)) # type: ignore # NOQA print("Please use `make %s' where %s is one of" % ((blue('target'),) * 2))
for osname, bname, description in BUILDERS: for osname, bname, description in BUILDERS:
if not osname or os.name == osname: if not osname or os.name == osname:
print(' %s %s' % (blue(bname.ljust(10)), description)) print(' %s %s' % (blue(bname.ljust(10)), description))

View File

@ -286,7 +286,7 @@ class DocTestBuilder(Builder):
# for doctest examples but unusable for multi-statement code such # for doctest examples but unusable for multi-statement code such
# as setup code -- to be able to use doctest error reporting with # as setup code -- to be able to use doctest error reporting with
# that code nevertheless, we monkey-patch the "compile" it uses. # that code nevertheless, we monkey-patch the "compile" it uses.
doctest.compile = self.compile doctest.compile = self.compile # type: ignore
sys.path[0:0] = self.config.doctest_path sys.path[0:0] = self.config.doctest_path
@ -507,7 +507,7 @@ Doctest summary
if len(code) == 1: if len(code) == 1:
# ordinary doctests (code/output interleaved) # ordinary doctests (code/output interleaved)
try: try:
test = parser.get_doctest(code[0].code, {}, group.name, # type: ignore test = parser.get_doctest(code[0].code, {}, group.name,
code[0].filename, code[0].lineno) code[0].filename, code[0].lineno)
except Exception: except Exception:
logger.warning(__('ignoring invalid doctest code: %r'), code[0].code, logger.warning(__('ignoring invalid doctest code: %r'), code[0].code,

View File

@ -368,7 +368,7 @@ class InheritanceDiagram(SphinxDirective):
# removed from the doctree after we're done with them. # removed from the doctree after we're done with them.
for name in graph.get_all_class_names(): for name in graph.get_all_class_names():
refnodes, x = class_role( # type: ignore refnodes, x = class_role( # type: ignore
'class', ':class:`%s`' % name, name, 0, self.state) 'class', ':class:`%s`' % name, name, 0, self.state) # type: ignore
node.extend(refnodes) node.extend(refnodes)
# Store the graph object so we can use it to generate the # Store the graph object so we can use it to generate the
# dot file later # dot file later

View File

@ -398,7 +398,7 @@ def inspect_main(argv: List[str]) -> None:
if __name__ == '__main__': if __name__ == '__main__':
import logging # type: ignore import logging as _logging
logging.basicConfig() _logging.basicConfig()
inspect_main(argv=sys.argv[1:]) inspect_main(argv=sys.argv[1:])

View File

@ -17,6 +17,7 @@ from docutils.readers import standalone
from docutils.transforms.references import DanglingReferences from docutils.transforms.references import DanglingReferences
from docutils.writers import UnfilteredWriter from docutils.writers import UnfilteredWriter
from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.transforms import ( from sphinx.transforms import (
AutoIndexUpgrader, DoctreeReadEvent, FigureAligner, SphinxTransformer AutoIndexUpgrader, DoctreeReadEvent, FigureAligner, SphinxTransformer
) )
@ -54,12 +55,35 @@ class SphinxBaseReader(standalone.Reader):
transforms = [] # type: List[Type[Transform]] transforms = [] # type: List[Type[Transform]]
def __init__(self, app, *args, **kwargs): def __init__(self, *args, **kwargs):
# type: (Sphinx, Any, Any) -> None # type: (Any, Any) -> None
self.app = app from sphinx.application import Sphinx
self.env = app.env if len(args) > 0 and isinstance(args[0], Sphinx):
self._app = args[0]
self._env = self._app.env
args = args[1:]
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@property
def app(self):
# type: () -> Sphinx
warnings.warn('SphinxBaseReader.app is deprecated.',
RemovedInSphinx40Warning, stacklevel=2)
return self._app
@property
def env(self):
# type: () -> BuildEnvironment
warnings.warn('SphinxBaseReader.env is deprecated.',
RemovedInSphinx40Warning, stacklevel=2)
return self._env
def setup(self, app):
# type: (Sphinx) -> None
self._app = app # hold application object only for compatibility
self._env = app.env
def get_transforms(self): def get_transforms(self):
# type: () -> List[Type[Transform]] # type: () -> List[Type[Transform]]
transforms = super().get_transforms() + self.transforms transforms = super().get_transforms() + self.transforms
@ -81,7 +105,7 @@ class SphinxBaseReader(standalone.Reader):
# substitute transformer # substitute transformer
document.transformer = SphinxTransformer(document) document.transformer = SphinxTransformer(document)
document.transformer.set_environment(self.env) document.transformer.set_environment(self.settings.env)
# substitute reporter # substitute reporter
reporter = document.reporter reporter = document.reporter
@ -95,10 +119,10 @@ class SphinxStandaloneReader(SphinxBaseReader):
A basic document reader for Sphinx. A basic document reader for Sphinx.
""" """
def __init__(self, app, *args, **kwargs): def setup(self, app):
# type: (Sphinx, Any, Any) -> None # type: (Sphinx) -> None
self.transforms = self.transforms + app.registry.get_transforms() self.transforms = self.transforms + app.registry.get_transforms()
super().__init__(app, *args, **kwargs) super().setup(app)
def read(self, source, parser, settings): def read(self, source, parser, settings):
# type: (Input, Parser, Values) -> nodes.document # type: (Input, Parser, Values) -> nodes.document
@ -106,18 +130,18 @@ class SphinxStandaloneReader(SphinxBaseReader):
if not self.parser: if not self.parser:
self.parser = parser self.parser = parser
self.settings = settings self.settings = settings
self.input = self.read_source() self.input = self.read_source(settings.env)
self.parse() self.parse()
return self.document return self.document
def read_source(self): def read_source(self, env):
# type: () -> str # type: (BuildEnvironment) -> str
"""Read content from source and do post-process.""" """Read content from source and do post-process."""
content = self.source.read() content = self.source.read()
# emit "source-read" event # emit "source-read" event
arg = [content] arg = [content]
self.app.emit('source-read', self.env.docname, arg) env.events.emit('source-read', env.docname, arg)
return arg[0] return arg[0]
@ -130,8 +154,10 @@ class SphinxI18nReader(SphinxBaseReader):
Because the translated texts are partial and they don't have correct line numbers. Because the translated texts are partial and they don't have correct line numbers.
""" """
def __init__(self, app, *args, **kwargs): def setup(self, app):
# type: (Sphinx, Any, Any) -> None # type: (Sphinx) -> None
super().setup(app)
self.transforms = self.transforms + app.registry.get_transforms() self.transforms = self.transforms + app.registry.get_transforms()
unused = [PreserveTranslatableMessages, Locale, RemoveTranslatableInline, unused = [PreserveTranslatableMessages, Locale, RemoveTranslatableInline,
AutoIndexUpgrader, FigureAligner, SphinxDomains, DoctreeReadEvent, AutoIndexUpgrader, FigureAligner, SphinxDomains, DoctreeReadEvent,
@ -188,7 +214,8 @@ def read_doc(app, env, filename):
error_handler = UnicodeDecodeErrorHandler(env.docname) error_handler = UnicodeDecodeErrorHandler(env.docname)
codecs.register_error('sphinx', error_handler) # type: ignore codecs.register_error('sphinx', error_handler) # type: ignore
reader = SphinxStandaloneReader(app) reader = SphinxStandaloneReader()
reader.setup(app)
filetype = get_filetype(app.config.source_suffix, filename) filetype = get_filetype(app.config.source_suffix, filename)
parser = app.registry.create_source_parser(app, filetype) parser = app.registry.create_source_parser(app, filetype)
if parser.__class__.__name__ == 'CommonMarkParser' and parser.settings_spec == (): if parser.__class__.__name__ == 'CommonMarkParser' and parser.settings_spec == ():
@ -204,10 +231,10 @@ def read_doc(app, env, filename):
# Sphinx-1.8 style # Sphinx-1.8 style
source = input_class(app, env, source=None, source_path=filename, # type: ignore source = input_class(app, env, source=None, source_path=filename, # type: ignore
encoding=env.config.source_encoding) encoding=env.config.source_encoding)
pub = Publisher(reader=reader, # type: ignore pub = Publisher(reader=reader,
parser=parser, parser=parser,
writer=SphinxDummyWriter(), writer=SphinxDummyWriter(),
source_class=SphinxDummySourceClass, source_class=SphinxDummySourceClass, # type: ignore
destination=NullOutput()) destination=NullOutput())
pub.process_programmatic_settings(None, env.settings, None) pub.process_programmatic_settings(None, env.settings, None)
pub.set_source(source, filename) pub.set_source(source, filename)

View File

@ -32,7 +32,7 @@ class _TranslationProxy(UserString):
""" """
__slots__ = ('_func', '_args') __slots__ = ('_func', '_args')
def __new__(cls, func, *args): def __new__(cls, func, *args): # type: ignore
# type: (Callable, str) -> object # type: (Callable, str) -> object
if not args: if not args:
# not called with "function" and "arguments", but a plain string # not called with "function" and "arguments", but a plain string

View File

@ -21,11 +21,13 @@ def parse(app: Sphinx, text: str, docname: str = 'index') -> nodes.document:
"""Parse a string as reStructuredText with Sphinx application.""" """Parse a string as reStructuredText with Sphinx application."""
try: try:
app.env.temp_data['docname'] = docname app.env.temp_data['docname'] = docname
reader = SphinxStandaloneReader()
reader.setup(app)
parser = RSTParser() parser = RSTParser()
parser.set_application(app) parser.set_application(app)
with sphinx_domains(app.env): with sphinx_domains(app.env):
return publish_doctree(text, path.join(app.srcdir, docname + '.rst'), return publish_doctree(text, path.join(app.srcdir, docname + '.rst'),
reader=SphinxStandaloneReader(app), reader=reader,
parser=parser, parser=parser,
settings_overrides={'env': app.env, settings_overrides={'env': app.env,
'gettext_compact': True}) 'gettext_compact': True})

View File

@ -120,8 +120,8 @@ class SphinxTestApp(application.Sphinx):
warningiserror = False warningiserror = False
self._saved_path = sys.path[:] self._saved_path = sys.path[:]
self._saved_directives = directives._directives.copy() self._saved_directives = directives._directives.copy() # type: ignore
self._saved_roles = roles._roles.copy() self._saved_roles = roles._roles.copy() # type: ignore
self._saved_nodeclasses = {v for v in dir(nodes.GenericNodeVisitor) self._saved_nodeclasses = {v for v in dir(nodes.GenericNodeVisitor)
if v.startswith('visit_')} if v.startswith('visit_')}
@ -140,8 +140,8 @@ class SphinxTestApp(application.Sphinx):
locale.translators.clear() locale.translators.clear()
sys.path[:] = self._saved_path sys.path[:] = self._saved_path
sys.modules.pop('autodoc_fodder', None) sys.modules.pop('autodoc_fodder', None)
directives._directives = self._saved_directives directives._directives = self._saved_directives # type: ignore
roles._roles = self._saved_roles roles._roles = self._saved_roles # type: ignore
for method in dir(nodes.GenericNodeVisitor): for method in dir(nodes.GenericNodeVisitor):
if method.startswith('visit_') and \ if method.startswith('visit_') and \
method not in self._saved_nodeclasses: method not in self._saved_nodeclasses:

View File

@ -6,7 +6,7 @@
% %
\NeedsTeXFormat{LaTeX2e}[1995/12/01] \NeedsTeXFormat{LaTeX2e}[1995/12/01]
\ProvidesPackage{sphinx}[2019/06/04 v2.1.1 LaTeX package (Sphinx markup)] \ProvidesPackage{sphinx}[2019/09/02 v2.3.0 LaTeX package (Sphinx markup)]
% provides \ltx@ifundefined % provides \ltx@ifundefined
% (many packages load ltxcmds: graphicx does for pdftex and lualatex but % (many packages load ltxcmds: graphicx does for pdftex and lualatex but
@ -40,7 +40,7 @@
% for \text macro and \iffirstchoice@ conditional even if amsmath not loaded % for \text macro and \iffirstchoice@ conditional even if amsmath not loaded
\RequirePackage{amstext} \RequirePackage{amstext}
\RequirePackage{textcomp}% "warn" option issued from template \RequirePackage{textcomp}% "warn" option issued from template
\RequirePackage{titlesec} \RequirePackage[nobottomtitles*]{titlesec}
\@ifpackagelater{titlesec}{2016/03/15}% \@ifpackagelater{titlesec}{2016/03/15}%
{\@ifpackagelater{titlesec}{2016/03/21}% {\@ifpackagelater{titlesec}{2016/03/21}%
{}% {}%
@ -119,7 +119,8 @@
{\dimexpr-\dp\strutbox {\dimexpr-\dp\strutbox
-\spx@ifcaptionpackage{\abovecaptionskip}{\sphinxbaselineskip}% -\spx@ifcaptionpackage{\abovecaptionskip}{\sphinxbaselineskip}%
+\sphinxbelowcaptionspace\relax}% +\sphinxbelowcaptionspace\relax}%
\def\sphinxatlongtableend{\prevdepth\z@\vskip\sphinxtablepost\relax}% \def\sphinxatlongtableend{\@nobreakfalse % latex3/latex2e#173
\prevdepth\z@\vskip\sphinxtablepost\relax}%
% B. Table with tabular or tabulary % B. Table with tabular or tabulary
\def\sphinxattablestart{\par\vskip\dimexpr\sphinxtablepre\relax}% \def\sphinxattablestart{\par\vskip\dimexpr\sphinxtablepre\relax}%
\let\sphinxattableend\sphinxatlongtableend \let\sphinxattableend\sphinxatlongtableend
@ -527,6 +528,7 @@
\fi \fi
% make commands known to non-Sphinx document classes % make commands known to non-Sphinx document classes
\providecommand*{\sphinxmaketitle}{\maketitle}
\providecommand*{\sphinxtableofcontents}{\tableofcontents} \providecommand*{\sphinxtableofcontents}{\tableofcontents}
\ltx@ifundefined{sphinxthebibliography} \ltx@ifundefined{sphinxthebibliography}
{\newenvironment {\newenvironment

View File

@ -53,7 +53,8 @@ def publish_msgstr(app, source, source_path, source_line, config, settings):
:rtype: docutils.nodes.document :rtype: docutils.nodes.document
""" """
from sphinx.io import SphinxI18nReader from sphinx.io import SphinxI18nReader
reader = SphinxI18nReader(app) reader = SphinxI18nReader()
reader.setup(app)
parser = app.registry.create_source_parser(app, 'restructuredtext') parser = app.registry.create_source_parser(app, 'restructuredtext')
doc = reader.read( doc = reader.read(
source=StringInput(source=source, source=StringInput(source=source,

View File

@ -220,7 +220,7 @@ def save_traceback(app: "Sphinx") -> str:
platform.python_version(), platform.python_version(),
platform.python_implementation(), platform.python_implementation(),
docutils.__version__, docutils.__version_details__, docutils.__version__, docutils.__version_details__,
jinja2.__version__, jinja2.__version__, # type: ignore
last_msgs)).encode()) last_msgs)).encode())
if app is not None: if app is not None:
for ext in app.extensions.values(): for ext in app.extensions.values():

View File

@ -50,13 +50,13 @@ additional_nodes = set() # type: Set[Type[nodes.Element]]
def docutils_namespace() -> Generator[None, None, None]: def docutils_namespace() -> Generator[None, None, None]:
"""Create namespace for reST parsers.""" """Create namespace for reST parsers."""
try: try:
_directives = copy(directives._directives) _directives = copy(directives._directives) # type: ignore
_roles = copy(roles._roles) _roles = copy(roles._roles) # type: ignore
yield yield
finally: finally:
directives._directives = _directives directives._directives = _directives # type: ignore
roles._roles = _roles roles._roles = _roles # type: ignore
for node in list(additional_nodes): for node in list(additional_nodes):
unregister_node(node) unregister_node(node)
@ -65,7 +65,7 @@ def docutils_namespace() -> Generator[None, None, None]:
def is_directive_registered(name: str) -> bool: def is_directive_registered(name: str) -> bool:
"""Check the *name* directive is already registered.""" """Check the *name* directive is already registered."""
return name in directives._directives return name in directives._directives # type: ignore
def register_directive(name: str, directive: "Type[Directive]") -> None: def register_directive(name: str, directive: "Type[Directive]") -> None:
@ -79,7 +79,7 @@ def register_directive(name: str, directive: "Type[Directive]") -> None:
def is_role_registered(name: str) -> bool: def is_role_registered(name: str) -> bool:
"""Check the *name* role is already registered.""" """Check the *name* role is already registered."""
return name in roles._roles return name in roles._roles # type: ignore
def register_role(name: str, role: RoleFunction) -> None: def register_role(name: str, role: RoleFunction) -> None:
@ -93,7 +93,7 @@ def register_role(name: str, role: RoleFunction) -> None:
def unregister_role(name: str) -> None: def unregister_role(name: str) -> None:
"""Unregister a role from docutils.""" """Unregister a role from docutils."""
roles._roles.pop(name, None) roles._roles.pop(name, None) # type: ignore
def is_node_registered(node: "Type[Element]") -> bool: def is_node_registered(node: "Type[Element]") -> bool:
@ -108,7 +108,7 @@ def register_node(node: "Type[Element]") -> None:
inside ``docutils_namespace()`` to prevent side-effects. inside ``docutils_namespace()`` to prevent side-effects.
""" """
if not hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__): if not hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__):
nodes._add_node_class_names([node.__name__]) nodes._add_node_class_names([node.__name__]) # type: ignore
additional_nodes.add(node) additional_nodes.add(node)

View File

@ -524,7 +524,7 @@ class Signature:
else: else:
qualname = repr(annotation) qualname = repr(annotation)
if (isinstance(annotation, typing.TupleMeta) and if (isinstance(annotation, typing.TupleMeta) and # type: ignore
not hasattr(annotation, '__tuple_params__')): # for Python 3.6 not hasattr(annotation, '__tuple_params__')): # for Python 3.6
params = annotation.__args__ params = annotation.__args__
if params: if params:
@ -550,7 +550,7 @@ class Signature:
param_str = ', '.join(self.format_annotation(p) for p in params) param_str = ', '.join(self.format_annotation(p) for p in params)
return '%s[%s]' % (qualname, param_str) return '%s[%s]' % (qualname, param_str)
elif (hasattr(typing, 'UnionMeta') and elif (hasattr(typing, 'UnionMeta') and
isinstance(annotation, typing.UnionMeta) and isinstance(annotation, typing.UnionMeta) and # type: ignore
hasattr(annotation, '__union_params__')): # for Python 3.5 hasattr(annotation, '__union_params__')): # for Python 3.5
params = annotation.__union_params__ params = annotation.__union_params__
if params is not None: if params is not None:
@ -568,7 +568,7 @@ class Signature:
else: else:
param_str = ', '.join(self.format_annotation(p) for p in params) param_str = ', '.join(self.format_annotation(p) for p in params)
return 'Union[%s]' % param_str return 'Union[%s]' % param_str
elif (isinstance(annotation, typing.CallableMeta) and elif (isinstance(annotation, typing.CallableMeta) and # type: ignore
getattr(annotation, '__args__', None) is not None and getattr(annotation, '__args__', None) is not None and
hasattr(annotation, '__result__')): # for Python 3.5 hasattr(annotation, '__result__')): # for Python 3.5
# Skipped in the case of plain typing.Callable # Skipped in the case of plain typing.Callable
@ -583,7 +583,7 @@ class Signature:
return '%s[%s, %s]' % (qualname, return '%s[%s, %s]' % (qualname,
args_str, args_str,
self.format_annotation(annotation.__result__)) self.format_annotation(annotation.__result__))
elif (isinstance(annotation, typing.TupleMeta) and elif (isinstance(annotation, typing.TupleMeta) and # type: ignore
hasattr(annotation, '__tuple_params__') and hasattr(annotation, '__tuple_params__') and
hasattr(annotation, '__tuple_use_ellipsis__')): # for Python 3.5 hasattr(annotation, '__tuple_use_ellipsis__')): # for Python 3.5
params = annotation.__tuple_params__ params = annotation.__tuple_params__

View File

@ -210,7 +210,7 @@ class TexinfoTranslator(SphinxTranslator):
for index in self.indices: for index in self.indices:
name, content = index name, content = index
pointers = tuple([name] + self.rellinks[name]) pointers = tuple([name] + self.rellinks[name])
self.body.append('\n@node %s,%s,%s,%s\n' % pointers) # type: ignore self.body.append('\n@node %s,%s,%s,%s\n' % pointers)
self.body.append('@unnumbered %s\n\n%s\n' % (name, content)) self.body.append('@unnumbered %s\n\n%s\n' % (name, content))
while self.referenced_ids: while self.referenced_ids:
@ -616,7 +616,7 @@ class TexinfoTranslator(SphinxTranslator):
node_name = node['node_name'] node_name = node['node_name']
pointers = tuple([node_name] + self.rellinks[node_name]) pointers = tuple([node_name] + self.rellinks[node_name])
self.body.append('\n@node %s,%s,%s,%s\n' % pointers) # type: ignore self.body.append('\n@node %s,%s,%s,%s\n' % pointers)
for id in sorted(self.next_section_ids): for id in sorted(self.next_section_ids):
self.add_anchor(id, node) self.add_anchor(id, node)