mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '3.x' into 8200_typealias_break_type_annotation
This commit is contained in:
commit
d8cdad919b
12
CHANGES
12
CHANGES
@ -12,6 +12,8 @@ Deprecated
|
|||||||
|
|
||||||
* ``sphinx.builders.latex.LaTeXBuilder.usepackages``
|
* ``sphinx.builders.latex.LaTeXBuilder.usepackages``
|
||||||
* ``sphinx.builders.latex.LaTeXBuilder.usepackages_afger_hyperref``
|
* ``sphinx.builders.latex.LaTeXBuilder.usepackages_afger_hyperref``
|
||||||
|
* ``sphinx.ext.autodoc.SingledispatchFunctionDocumenter``
|
||||||
|
* ``sphinx.ext.autodoc.SingledispatchMethodDocumenter``
|
||||||
|
|
||||||
Features added
|
Features added
|
||||||
--------------
|
--------------
|
||||||
@ -22,11 +24,14 @@ Features added
|
|||||||
nested declarations.
|
nested declarations.
|
||||||
* #8081: LaTeX: Allow to add LaTeX package via ``app.add_latex_package()`` until
|
* #8081: LaTeX: Allow to add LaTeX package via ``app.add_latex_package()`` until
|
||||||
just before writing .tex file
|
just before writing .tex file
|
||||||
|
* #7996: manpage: Add :confval:`man_make_section_directory` to make a section
|
||||||
|
directory on build man page
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
* #8085: i18n: Add support for having single text domain
|
* #8085: i18n: Add support for having single text domain
|
||||||
|
* #6640: i18n: Failed to override system message translation
|
||||||
* #8143: autodoc: AttributeError is raised when False value is passed to
|
* #8143: autodoc: AttributeError is raised when False value is passed to
|
||||||
autodoc_default_options
|
autodoc_default_options
|
||||||
* #8103: autodoc: functools.cached_property is not considered as a property
|
* #8103: autodoc: functools.cached_property is not considered as a property
|
||||||
@ -34,15 +39,22 @@ Bugs fixed
|
|||||||
by string not ending with blank lines
|
by string not ending with blank lines
|
||||||
* #8142: autodoc: Wrong constructor signature for the class derived from
|
* #8142: autodoc: Wrong constructor signature for the class derived from
|
||||||
typing.Generic
|
typing.Generic
|
||||||
|
* #8157: autodoc: TypeError is raised when annotation has invalid __args__
|
||||||
|
* #7964: autodoc: Tuple in default value is wrongly rendered
|
||||||
* #8200: autodoc: type aliases break type formatting of autoattribute
|
* #8200: autodoc: type aliases break type formatting of autoattribute
|
||||||
* #8192: napoleon: description is disappeared when it contains inline literals
|
* #8192: napoleon: description is disappeared when it contains inline literals
|
||||||
* #8142: napoleon: Potential of regex denial of service in google style docs
|
* #8142: napoleon: Potential of regex denial of service in google style docs
|
||||||
* #8169: LaTeX: pxjahyper loaded even when latex_engine is not platex
|
* #8169: LaTeX: pxjahyper loaded even when latex_engine is not platex
|
||||||
* #8175: intersphinx: Potential of regex denial of service by broken inventory
|
* #8175: intersphinx: Potential of regex denial of service by broken inventory
|
||||||
|
* #8277: sphinx-build: missing and redundant spacing (and etc) for console
|
||||||
|
output on building
|
||||||
|
* #7973: imgconverter: Check availability of imagemagick many times
|
||||||
* #8093: The highlight warning has wrong location in some builders (LaTeX,
|
* #8093: The highlight warning has wrong location in some builders (LaTeX,
|
||||||
singlehtml and so on)
|
singlehtml and so on)
|
||||||
* #8239: Failed to refer a token in productionlist if it is indented
|
* #8239: Failed to refer a token in productionlist if it is indented
|
||||||
* #8268: linkcheck: Report HTTP errors when ``linkcheck_anchors`` is ``True``
|
* #8268: linkcheck: Report HTTP errors when ``linkcheck_anchors`` is ``True``
|
||||||
|
* #8245: linkcheck: take source directory into account for local files
|
||||||
|
* #6914: figure numbers are unexpectedly assigned to uncaptioned items
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
--------
|
--------
|
||||||
|
@ -36,6 +36,16 @@ The following is a list of deprecated interfaces.
|
|||||||
- 5.0
|
- 5.0
|
||||||
- N/A
|
- N/A
|
||||||
|
|
||||||
|
* - ``sphinx.ext.autodoc.SingledispatchFunctionDocumenter``
|
||||||
|
- 3.3
|
||||||
|
- 5.0
|
||||||
|
- ``sphinx.ext.autodoc.FunctionDocumenter``
|
||||||
|
|
||||||
|
* - ``sphinx.ext.autodoc.SingledispatchMethodDocumenter``
|
||||||
|
- 3.3
|
||||||
|
- 5.0
|
||||||
|
- ``sphinx.ext.autodoc.MethodDocumenter``
|
||||||
|
|
||||||
* - ``sphinx.ext.autodoc.members_set_option()``
|
* - ``sphinx.ext.autodoc.members_set_option()``
|
||||||
- 3.2
|
- 3.2
|
||||||
- 5.0
|
- 5.0
|
||||||
|
@ -2245,6 +2245,12 @@ These options influence manual page output.
|
|||||||
|
|
||||||
.. versionadded:: 1.1
|
.. versionadded:: 1.1
|
||||||
|
|
||||||
|
.. confval:: man_make_section_directory
|
||||||
|
|
||||||
|
If true, make a section directory on build man page. Default is False.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
.. _texinfo-options:
|
.. _texinfo-options:
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import warnings
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from os import path
|
from os import path
|
||||||
from typing import Any, Callable, Dict, IO, List, Tuple, Union
|
from typing import Any, Callable, Dict, IO, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.nodes import Element, TextElement
|
from docutils.nodes import Element, TextElement
|
||||||
@ -293,7 +293,10 @@ class Sphinx:
|
|||||||
if catalog.domain == 'sphinx' and catalog.is_outdated():
|
if catalog.domain == 'sphinx' and catalog.is_outdated():
|
||||||
catalog.write_mo(self.config.language)
|
catalog.write_mo(self.config.language)
|
||||||
|
|
||||||
locale_dirs = [None, path.join(package_dir, 'locale')] + list(repo.locale_dirs)
|
locale_dirs = [None] # type: List[Optional[str]]
|
||||||
|
locale_dirs += list(repo.locale_dirs)
|
||||||
|
locale_dirs += [path.join(package_dir, 'locale')]
|
||||||
|
|
||||||
self.translator, has_translation = locale.init(locale_dirs, self.config.language)
|
self.translator, has_translation = locale.init(locale_dirs, self.config.language)
|
||||||
if has_translation or self.config.language == 'en':
|
if has_translation or self.config.language == 'en':
|
||||||
# "en" never needs to be translated
|
# "en" never needs to be translated
|
||||||
|
@ -641,17 +641,17 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
def gen_additional_pages(self) -> None:
|
def gen_additional_pages(self) -> None:
|
||||||
# additional pages from conf.py
|
# additional pages from conf.py
|
||||||
for pagename, template in self.config.html_additional_pages.items():
|
for pagename, template in self.config.html_additional_pages.items():
|
||||||
logger.info(' ' + pagename, nonl=True)
|
logger.info(pagename + ' ', nonl=True)
|
||||||
self.handle_page(pagename, {}, template)
|
self.handle_page(pagename, {}, template)
|
||||||
|
|
||||||
# the search page
|
# the search page
|
||||||
if self.search:
|
if self.search:
|
||||||
logger.info(' search', nonl=True)
|
logger.info('search ', nonl=True)
|
||||||
self.handle_page('search', {}, 'search.html')
|
self.handle_page('search', {}, 'search.html')
|
||||||
|
|
||||||
# the opensearch xml file
|
# the opensearch xml file
|
||||||
if self.config.html_use_opensearch and self.search:
|
if self.config.html_use_opensearch and self.search:
|
||||||
logger.info(' opensearch', nonl=True)
|
logger.info('opensearch ', nonl=True)
|
||||||
fn = path.join(self.outdir, '_static', 'opensearch.xml')
|
fn = path.join(self.outdir, '_static', 'opensearch.xml')
|
||||||
self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn)
|
self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn)
|
||||||
|
|
||||||
@ -669,7 +669,7 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
'genindexcounts': indexcounts,
|
'genindexcounts': indexcounts,
|
||||||
'split_index': self.config.html_split_index,
|
'split_index': self.config.html_split_index,
|
||||||
}
|
}
|
||||||
logger.info(' genindex', nonl=True)
|
logger.info('genindex ', nonl=True)
|
||||||
|
|
||||||
if self.config.html_split_index:
|
if self.config.html_split_index:
|
||||||
self.handle_page('genindex', genindexcontext,
|
self.handle_page('genindex', genindexcontext,
|
||||||
@ -691,7 +691,7 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
'content': content,
|
'content': content,
|
||||||
'collapse_index': collapse,
|
'collapse_index': collapse,
|
||||||
}
|
}
|
||||||
logger.info(' ' + indexname, nonl=True)
|
logger.info(indexname + ' ', nonl=True)
|
||||||
self.handle_page(indexname, indexcontext, 'domainindex.html')
|
self.handle_page(indexname, indexcontext, 'domainindex.html')
|
||||||
|
|
||||||
def copy_image_files(self) -> None:
|
def copy_image_files(self) -> None:
|
||||||
@ -785,7 +785,7 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
|
|
||||||
def copy_static_files(self) -> None:
|
def copy_static_files(self) -> None:
|
||||||
try:
|
try:
|
||||||
with progress_message(__('copying static files... ')):
|
with progress_message(__('copying static files')):
|
||||||
ensuredir(path.join(self.outdir, '_static'))
|
ensuredir(path.join(self.outdir, '_static'))
|
||||||
|
|
||||||
# prepare context for templates
|
# prepare context for templates
|
||||||
|
@ -211,7 +211,7 @@ class CheckExternalLinksBuilder(Builder):
|
|||||||
else:
|
else:
|
||||||
return 'redirected', new_url, 0
|
return 'redirected', new_url, 0
|
||||||
|
|
||||||
def check() -> Tuple[str, str, int]:
|
def check(docname: str) -> Tuple[str, str, int]:
|
||||||
# check for various conditions without bothering the network
|
# check for various conditions without bothering the network
|
||||||
if len(uri) == 0 or uri.startswith(('#', 'mailto:')):
|
if len(uri) == 0 or uri.startswith(('#', 'mailto:')):
|
||||||
return 'unchecked', '', 0
|
return 'unchecked', '', 0
|
||||||
@ -220,7 +220,8 @@ class CheckExternalLinksBuilder(Builder):
|
|||||||
# non supported URI schemes (ex. ftp)
|
# non supported URI schemes (ex. ftp)
|
||||||
return 'unchecked', '', 0
|
return 'unchecked', '', 0
|
||||||
else:
|
else:
|
||||||
if path.exists(path.join(self.srcdir, uri)):
|
srcdir = path.dirname(self.env.doc2path(docname))
|
||||||
|
if path.exists(path.join(srcdir, uri)):
|
||||||
return 'working', '', 0
|
return 'working', '', 0
|
||||||
else:
|
else:
|
||||||
for rex in self.to_ignore:
|
for rex in self.to_ignore:
|
||||||
@ -257,7 +258,7 @@ class CheckExternalLinksBuilder(Builder):
|
|||||||
uri, docname, lineno = self.wqueue.get()
|
uri, docname, lineno = self.wqueue.get()
|
||||||
if uri is None:
|
if uri is None:
|
||||||
break
|
break
|
||||||
status, info, code = check()
|
status, info, code = check(docname)
|
||||||
self.rqueue.put((uri, docname, lineno, status, info, code))
|
self.rqueue.put((uri, docname, lineno, status, info, code))
|
||||||
|
|
||||||
def process_result(self, result: Tuple[str, str, int, str, str, int]) -> None:
|
def process_result(self, result: Tuple[str, str, int, str, str, int]) -> None:
|
||||||
|
@ -24,7 +24,7 @@ from sphinx.util import logging
|
|||||||
from sphinx.util import progress_message
|
from sphinx.util import progress_message
|
||||||
from sphinx.util.console import darkgreen # type: ignore
|
from sphinx.util.console import darkgreen # type: ignore
|
||||||
from sphinx.util.nodes import inline_all_toctrees
|
from sphinx.util.nodes import inline_all_toctrees
|
||||||
from sphinx.util.osutil import make_filename_from_project
|
from sphinx.util.osutil import ensuredir, make_filename_from_project
|
||||||
from sphinx.writers.manpage import ManualPageWriter, ManualPageTranslator
|
from sphinx.writers.manpage import ManualPageWriter, ManualPageTranslator
|
||||||
|
|
||||||
|
|
||||||
@ -80,7 +80,12 @@ class ManualPageBuilder(Builder):
|
|||||||
docsettings.authors = authors
|
docsettings.authors = authors
|
||||||
docsettings.section = section
|
docsettings.section = section
|
||||||
|
|
||||||
targetname = '%s.%s' % (name, section)
|
if self.config.man_make_section_directory:
|
||||||
|
ensuredir(path.join(self.outdir, str(section)))
|
||||||
|
targetname = '%s/%s.%s' % (section, name, section)
|
||||||
|
else:
|
||||||
|
targetname = '%s.%s' % (name, section)
|
||||||
|
|
||||||
logger.info(darkgreen(targetname) + ' { ', nonl=True)
|
logger.info(darkgreen(targetname) + ' { ', nonl=True)
|
||||||
destination = FileOutput(
|
destination = FileOutput(
|
||||||
destination_path=path.join(self.outdir, targetname),
|
destination_path=path.join(self.outdir, targetname),
|
||||||
@ -115,6 +120,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||||||
|
|
||||||
app.add_config_value('man_pages', default_man_pages, None)
|
app.add_config_value('man_pages', default_man_pages, None)
|
||||||
app.add_config_value('man_show_urls', False, None)
|
app.add_config_value('man_show_urls', False, None)
|
||||||
|
app.add_config_value('man_make_section_directory', False, None)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'version': 'builtin',
|
'version': 'builtin',
|
||||||
|
@ -224,6 +224,10 @@ class TocTreeCollector(EnvironmentCollector):
|
|||||||
def get_figtype(node: Node) -> str:
|
def get_figtype(node: Node) -> str:
|
||||||
for domain in env.domains.values():
|
for domain in env.domains.values():
|
||||||
figtype = domain.get_enumerable_node_type(node)
|
figtype = domain.get_enumerable_node_type(node)
|
||||||
|
if domain.name == 'std' and not domain.get_numfig_title(node): # type: ignore
|
||||||
|
# Skip if uncaptioned node
|
||||||
|
continue
|
||||||
|
|
||||||
if figtype:
|
if figtype:
|
||||||
return figtype
|
return figtype
|
||||||
|
|
||||||
|
@ -1302,6 +1302,11 @@ class SingledispatchFunctionDocumenter(FunctionDocumenter):
|
|||||||
Retained for backwards compatibility, now does the same as the FunctionDocumenter
|
Retained for backwards compatibility, now does the same as the FunctionDocumenter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
warnings.warn("%s is deprecated." % self.__class__.__name__,
|
||||||
|
RemovedInSphinx50Warning, stacklevel=2)
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class DecoratorDocumenter(FunctionDocumenter):
|
class DecoratorDocumenter(FunctionDocumenter):
|
||||||
"""
|
"""
|
||||||
@ -1938,6 +1943,11 @@ class SingledispatchMethodDocumenter(MethodDocumenter):
|
|||||||
Retained for backwards compatibility, now does the same as the MethodDocumenter
|
Retained for backwards compatibility, now does the same as the MethodDocumenter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
warnings.warn("%s is deprecated." % self.__class__.__name__,
|
||||||
|
RemovedInSphinx50Warning, stacklevel=2)
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore
|
class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore
|
||||||
"""
|
"""
|
||||||
|
@ -106,7 +106,7 @@ class _TranslationProxy(UserString):
|
|||||||
translators = defaultdict(NullTranslations) # type: Dict[Tuple[str, str], NullTranslations]
|
translators = defaultdict(NullTranslations) # type: Dict[Tuple[str, str], NullTranslations]
|
||||||
|
|
||||||
|
|
||||||
def init(locale_dirs: List[str], language: str,
|
def init(locale_dirs: List[Optional[str]], language: str,
|
||||||
catalog: str = 'sphinx', namespace: str = 'general') -> Tuple[NullTranslations, bool]:
|
catalog: str = 'sphinx', namespace: str = 'general') -> Tuple[NullTranslations, bool]:
|
||||||
"""Look for message catalogs in `locale_dirs` and *ensure* that there is at
|
"""Look for message catalogs in `locale_dirs` and *ensure* that there is at
|
||||||
least a NullTranslations catalog set in `translators`. If called multiple
|
least a NullTranslations catalog set in `translators`. If called multiple
|
||||||
|
@ -166,14 +166,28 @@ class _UnparseVisitor(ast.NodeVisitor):
|
|||||||
return "{" + ", ".join(self.visit(e) for e in node.elts) + "}"
|
return "{" + ", ".join(self.visit(e) for e in node.elts) + "}"
|
||||||
|
|
||||||
def visit_Subscript(self, node: ast.Subscript) -> str:
|
def visit_Subscript(self, node: ast.Subscript) -> str:
|
||||||
return "%s[%s]" % (self.visit(node.value), self.visit(node.slice))
|
def is_simple_tuple(value: ast.AST) -> bool:
|
||||||
|
return (
|
||||||
|
isinstance(value, ast.Tuple) and
|
||||||
|
bool(value.elts) and
|
||||||
|
not any(isinstance(elt, ast.Starred) for elt in value.elts)
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_simple_tuple(node.slice):
|
||||||
|
elts = ", ".join(self.visit(e) for e in node.slice.elts) # type: ignore
|
||||||
|
return "%s[%s]" % (self.visit(node.value), elts)
|
||||||
|
elif isinstance(node.slice, ast.Index) and is_simple_tuple(node.slice.value):
|
||||||
|
elts = ", ".join(self.visit(e) for e in node.slice.value.elts) # type: ignore
|
||||||
|
return "%s[%s]" % (self.visit(node.value), elts)
|
||||||
|
else:
|
||||||
|
return "%s[%s]" % (self.visit(node.value), self.visit(node.slice))
|
||||||
|
|
||||||
def visit_UnaryOp(self, node: ast.UnaryOp) -> str:
|
def visit_UnaryOp(self, node: ast.UnaryOp) -> str:
|
||||||
return "%s %s" % (self.visit(node.op), self.visit(node.operand))
|
return "%s %s" % (self.visit(node.op), self.visit(node.operand))
|
||||||
|
|
||||||
def visit_Tuple(self, node: ast.Tuple) -> str:
|
def visit_Tuple(self, node: ast.Tuple) -> str:
|
||||||
if node.elts:
|
if node.elts:
|
||||||
return ", ".join(self.visit(e) for e in node.elts)
|
return "(" + ", ".join(self.visit(e) for e in node.elts) + ")"
|
||||||
else:
|
else:
|
||||||
return "()"
|
return "()"
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from typing import Any, Dict, List, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
|
||||||
@ -175,6 +175,13 @@ class ImageConverter(BaseImageConverter):
|
|||||||
"""
|
"""
|
||||||
default_priority = 200
|
default_priority = 200
|
||||||
|
|
||||||
|
#: The converter is available or not. Will be filled at the first call of
|
||||||
|
#: the build. The result is shared in the same process.
|
||||||
|
#:
|
||||||
|
#: .. todo:: This should be refactored not to store the state without class
|
||||||
|
#: variable.
|
||||||
|
available = None # type: Optional[bool]
|
||||||
|
|
||||||
#: A conversion rules the image converter supports.
|
#: A conversion rules the image converter supports.
|
||||||
#: It is represented as a list of pair of source image format (mimetype) and
|
#: It is represented as a list of pair of source image format (mimetype) and
|
||||||
#: destination one::
|
#: destination one::
|
||||||
@ -187,16 +194,14 @@ class ImageConverter(BaseImageConverter):
|
|||||||
conversion_rules = [] # type: List[Tuple[str, str]]
|
conversion_rules = [] # type: List[Tuple[str, str]]
|
||||||
|
|
||||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
self.available = None # type: bool
|
|
||||||
# the converter is available or not.
|
|
||||||
# Will be checked at first conversion
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def match(self, node: nodes.image) -> bool:
|
def match(self, node: nodes.image) -> bool:
|
||||||
if not self.app.builder.supported_image_types:
|
if not self.app.builder.supported_image_types:
|
||||||
return False
|
return False
|
||||||
elif self.available is None:
|
elif self.available is None:
|
||||||
self.available = self.is_available()
|
# store the value to the class variable to share it during the build
|
||||||
|
self.__class__.available = self.is_available()
|
||||||
|
|
||||||
if not self.available:
|
if not self.available:
|
||||||
return False
|
return False
|
||||||
|
@ -109,7 +109,10 @@ def _stringify_py37(annotation: Any) -> str:
|
|||||||
return repr(annotation)
|
return repr(annotation)
|
||||||
|
|
||||||
if getattr(annotation, '__args__', None):
|
if getattr(annotation, '__args__', None):
|
||||||
if qualname == 'Union':
|
if not isinstance(annotation.__args__, (list, tuple)):
|
||||||
|
# broken __args__ found
|
||||||
|
pass
|
||||||
|
elif qualname == 'Union':
|
||||||
if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType:
|
if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType:
|
||||||
if len(annotation.__args__) > 2:
|
if len(annotation.__args__) > 2:
|
||||||
args = ', '.join(stringify(a) for a in annotation.__args__[:-1])
|
args = ', '.join(stringify(a) for a in annotation.__args__[:-1])
|
||||||
|
@ -30,6 +30,13 @@ def test_all(app, status, warning):
|
|||||||
assert 'Footnotes' not in content
|
assert 'Footnotes' not in content
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('man', testroot='basic',
|
||||||
|
confoverrides={'man_make_section_directory': True})
|
||||||
|
def test_man_make_section_directory(app, status, warning):
|
||||||
|
app.build()
|
||||||
|
assert (app.outdir / '1' / 'python.1').exists()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('man', testroot='directive-code')
|
@pytest.mark.sphinx('man', testroot='directive-code')
|
||||||
def test_captioned_code_block(app, status, warning):
|
def test_captioned_code_block(app, status, warning):
|
||||||
app.builder.build_all()
|
app.builder.build_all()
|
||||||
|
@ -14,8 +14,10 @@ import re
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from babel.messages import pofile, mofile
|
from babel.messages import pofile, mofile
|
||||||
|
from babel.messages.catalog import Catalog
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
|
||||||
|
from sphinx import locale
|
||||||
from sphinx.testing.util import (
|
from sphinx.testing.util import (
|
||||||
path, etree_parse, strip_escseq,
|
path, etree_parse, strip_escseq,
|
||||||
assert_re_search, assert_not_re_search, assert_startswith, assert_node
|
assert_re_search, assert_not_re_search, assert_startswith, assert_node
|
||||||
@ -1289,3 +1291,30 @@ def test_image_glob_intl_using_figure_language_filename(app):
|
|||||||
|
|
||||||
def getwarning(warnings):
|
def getwarning(warnings):
|
||||||
return strip_escseq(warnings.getvalue().replace(os.sep, '/'))
|
return strip_escseq(warnings.getvalue().replace(os.sep, '/'))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('html', testroot='basic', confoverrides={'language': 'de'})
|
||||||
|
def test_customize_system_message(make_app, app_params, sphinx_test_tempdir):
|
||||||
|
try:
|
||||||
|
# clear translators cache
|
||||||
|
locale.translators.clear()
|
||||||
|
|
||||||
|
# prepare message catalog (.po)
|
||||||
|
locale_dir = sphinx_test_tempdir / 'basic' / 'locales' / 'de' / 'LC_MESSAGES'
|
||||||
|
locale_dir.makedirs()
|
||||||
|
with (locale_dir / 'sphinx.po').open('wb') as f:
|
||||||
|
catalog = Catalog()
|
||||||
|
catalog.add('Quick search', 'QUICK SEARCH')
|
||||||
|
pofile.write_po(f, catalog)
|
||||||
|
|
||||||
|
# construct application and convert po file to .mo
|
||||||
|
args, kwargs = app_params
|
||||||
|
app = make_app(*args, **kwargs)
|
||||||
|
assert (locale_dir / 'sphinx.mo').exists()
|
||||||
|
assert app.translator.gettext('Quick search') == 'QUICK SEARCH'
|
||||||
|
|
||||||
|
app.build()
|
||||||
|
content = (app.outdir / 'index.html').read_text()
|
||||||
|
assert 'QUICK SEARCH' in content
|
||||||
|
finally:
|
||||||
|
locale.translators.clear()
|
||||||
|
@ -53,7 +53,7 @@ from sphinx.pycode import ast
|
|||||||
("+ a", "+ a"), # UAdd
|
("+ a", "+ a"), # UAdd
|
||||||
("- 1", "- 1"), # UnaryOp
|
("- 1", "- 1"), # UnaryOp
|
||||||
("- a", "- a"), # USub
|
("- a", "- a"), # USub
|
||||||
("(1, 2, 3)", "1, 2, 3"), # Tuple
|
("(1, 2, 3)", "(1, 2, 3)"), # Tuple
|
||||||
("()", "()"), # Tuple (empty)
|
("()", "()"), # Tuple (empty)
|
||||||
])
|
])
|
||||||
def test_unparse(source, expected):
|
def test_unparse(source, expected):
|
||||||
|
@ -32,6 +32,10 @@ class MyList(List[T]):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BrokenType:
|
||||||
|
__args__ = int
|
||||||
|
|
||||||
|
|
||||||
def test_stringify():
|
def test_stringify():
|
||||||
assert stringify(int) == "int"
|
assert stringify(int) == "int"
|
||||||
assert stringify(str) == "str"
|
assert stringify(str) == "str"
|
||||||
@ -113,3 +117,7 @@ def test_stringify_type_hints_alias():
|
|||||||
MyTuple = Tuple[str, str]
|
MyTuple = Tuple[str, str]
|
||||||
assert stringify(MyStr) == "str"
|
assert stringify(MyStr) == "str"
|
||||||
assert stringify(MyTuple) == "Tuple[str, str]" # type: ignore
|
assert stringify(MyTuple) == "Tuple[str, str]" # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
def test_stringify_broken_type_hints():
|
||||||
|
assert stringify(BrokenType) == 'test_util_typing.BrokenType'
|
||||||
|
Loading…
Reference in New Issue
Block a user