mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '4.x'
This commit is contained in:
commit
0e51ddef34
13
CHANGES
13
CHANGES
@ -41,6 +41,9 @@ Deprecated
|
|||||||
Features added
|
Features added
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
* #9075: autodoc: Add a config variable :confval:`autodoc_unqualified_typehints`
|
||||||
|
to suppress the leading module names of typehints of function signatures (ex.
|
||||||
|
``io.StringIO`` -> ``StringIO``)
|
||||||
* #9831: Autosummary now documents only the members specified in a module's
|
* #9831: Autosummary now documents only the members specified in a module's
|
||||||
``__all__`` attribute if :confval:`autosummary_ignore_module_all` is set to
|
``__all__`` attribute if :confval:`autosummary_ignore_module_all` is set to
|
||||||
``False``. The default behaviour is unchanged. Autogen also now supports
|
``False``. The default behaviour is unchanged. Autogen also now supports
|
||||||
@ -53,6 +56,11 @@ Features added
|
|||||||
``~``) as ``:type:`` option
|
``~``) as ``:type:`` option
|
||||||
* #9894: linkcheck: add option ``linkcheck_exclude_documents`` to disable link
|
* #9894: linkcheck: add option ``linkcheck_exclude_documents`` to disable link
|
||||||
checking in matched documents.
|
checking in matched documents.
|
||||||
|
* #9793: sphinx-build: Allow to use the parallel build feature in macOS on macOS
|
||||||
|
and Python3.8+
|
||||||
|
* #9391: texinfo: improve variable in ``samp`` role
|
||||||
|
* #9578: texinfo: Add :confval:`texinfo_cross_references` to disable cross
|
||||||
|
references for readability with standalone readers
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
@ -61,9 +69,14 @@ Bugs fixed
|
|||||||
* #9883: autodoc: doccomment for the alias to mocked object was ignored
|
* #9883: autodoc: doccomment for the alias to mocked object was ignored
|
||||||
* #9908: autodoc: debug message is shown on building document using NewTypes
|
* #9908: autodoc: debug message is shown on building document using NewTypes
|
||||||
with Python 3.10
|
with Python 3.10
|
||||||
|
* #9947: i18n: topic directive having a bullet list can't be translatable
|
||||||
* #9878: mathjax: MathJax configuration is placed after loading MathJax itself
|
* #9878: mathjax: MathJax configuration is placed after loading MathJax itself
|
||||||
* #9857: Generated RFC links use outdated base url
|
* #9857: Generated RFC links use outdated base url
|
||||||
* #9909: HTML, prevent line-wrapping in literal text.
|
* #9909: HTML, prevent line-wrapping in literal text.
|
||||||
|
* #9925: LaTeX: prohibit also with ``'xelatex'`` line splitting at dashes of
|
||||||
|
inline and parsed literals
|
||||||
|
* #9944: LaTeX: extra vertical whitespace for some nested declarations
|
||||||
|
* #9390: texinfo: Do not emit labels inside footnotes
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
--------
|
--------
|
||||||
|
4
doc/_static/conf.py.txt
vendored
4
doc/_static/conf.py.txt
vendored
@ -319,6 +319,10 @@ texinfo_documents = [
|
|||||||
#
|
#
|
||||||
# texinfo_no_detailmenu = False
|
# texinfo_no_detailmenu = False
|
||||||
|
|
||||||
|
# If false, do not generate in manual @ref nodes.
|
||||||
|
#
|
||||||
|
# texinfo_cross_references = False
|
||||||
|
|
||||||
# -- A random example -----------------------------------------------------
|
# -- A random example -----------------------------------------------------
|
||||||
|
|
||||||
import sys, os
|
import sys, os
|
||||||
|
2
doc/_themes/sphinx13/theme.conf
vendored
2
doc/_themes/sphinx13/theme.conf
vendored
@ -1,4 +1,4 @@
|
|||||||
[theme]
|
[theme]
|
||||||
inherit = basic
|
inherit = basic
|
||||||
stylesheet = sphinx13.css
|
stylesheet = sphinx13.css
|
||||||
pygments_style = trac
|
pygments_style = default
|
||||||
|
@ -299,6 +299,10 @@ appear in the source. Emacs, on the other-hand, will by default replace
|
|||||||
|
|
||||||
:ref:`texinfo-links`
|
:ref:`texinfo-links`
|
||||||
|
|
||||||
|
One can disable generation of the inline references in a document
|
||||||
|
with :confval:`texinfo_cross_references`. That makes
|
||||||
|
an info file more readable with stand-alone reader (``info``).
|
||||||
|
|
||||||
The exact behavior of how Emacs displays references is dependent on the variable
|
The exact behavior of how Emacs displays references is dependent on the variable
|
||||||
``Info-hide-note-references``. If set to the value of ``hide``, Emacs will hide
|
``Info-hide-note-references``. If set to the value of ``hide``, Emacs will hide
|
||||||
both the ``*note:`` part and the ``target-id``. This is generally the best way
|
both the ``*note:`` part and the ``target-id``. This is generally the best way
|
||||||
|
@ -2499,6 +2499,13 @@ These options influence Texinfo output.
|
|||||||
|
|
||||||
.. versionadded:: 1.1
|
.. versionadded:: 1.1
|
||||||
|
|
||||||
|
.. confval:: texinfo_cross_references
|
||||||
|
|
||||||
|
If false, do not generate inline references in a document. That makes
|
||||||
|
an info file more readable with stand-alone reader (``info``).
|
||||||
|
Default is ``True``.
|
||||||
|
|
||||||
|
.. versionadded:: 4.4
|
||||||
|
|
||||||
.. _qthelp-options:
|
.. _qthelp-options:
|
||||||
|
|
||||||
|
@ -662,6 +662,13 @@ There are also config values that you can set:
|
|||||||
.. __: https://mypy.readthedocs.io/en/latest/kinds_of_types.html#type-aliases
|
.. __: https://mypy.readthedocs.io/en/latest/kinds_of_types.html#type-aliases
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
.. confval:: autodoc_unqualified_typehints
|
||||||
|
|
||||||
|
If True, the leading module names of typehints of function signatures (ex.
|
||||||
|
``io.StringIO`` -> ``StringIO``). Defaults to False.
|
||||||
|
|
||||||
|
.. versionadded:: 4.4
|
||||||
|
|
||||||
.. confval:: autodoc_preserve_defaults
|
.. confval:: autodoc_preserve_defaults
|
||||||
|
|
||||||
If True, the default argument values of functions will be not evaluated on
|
If True, the default argument values of functions will be not evaluated on
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import pickle
|
import pickle
|
||||||
import platform
|
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from collections import deque
|
from collections import deque
|
||||||
@ -195,12 +194,6 @@ class Sphinx:
|
|||||||
# say hello to the world
|
# say hello to the world
|
||||||
logger.info(bold(__('Running Sphinx v%s') % sphinx.__display_version__))
|
logger.info(bold(__('Running Sphinx v%s') % sphinx.__display_version__))
|
||||||
|
|
||||||
# notice for parallel build on macOS and py38+
|
|
||||||
if sys.version_info > (3, 8) and platform.system() == 'Darwin' and parallel > 1:
|
|
||||||
logger.info(bold(__("For security reasons, parallel mode is disabled on macOS and "
|
|
||||||
"python3.8 and above. For more details, please read "
|
|
||||||
"https://github.com/sphinx-doc/sphinx/issues/6803")))
|
|
||||||
|
|
||||||
# status code for command-line application
|
# status code for command-line application
|
||||||
self.statuscode = 0
|
self.statuscode = 0
|
||||||
|
|
||||||
|
@ -211,6 +211,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||||||
app.add_config_value('texinfo_domain_indices', True, None, [list])
|
app.add_config_value('texinfo_domain_indices', True, None, [list])
|
||||||
app.add_config_value('texinfo_show_urls', 'footnote', None)
|
app.add_config_value('texinfo_show_urls', 'footnote', None)
|
||||||
app.add_config_value('texinfo_no_detailmenu', False, None)
|
app.add_config_value('texinfo_no_detailmenu', False, None)
|
||||||
|
app.add_config_value('texinfo_cross_references', True, None)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'version': 'builtin',
|
'version': 'builtin',
|
||||||
|
@ -80,7 +80,8 @@ class ModuleEntry(NamedTuple):
|
|||||||
deprecated: bool
|
deprecated: bool
|
||||||
|
|
||||||
|
|
||||||
def type_to_xref(target: str, env: BuildEnvironment = None) -> addnodes.pending_xref:
|
def type_to_xref(target: str, env: BuildEnvironment = None, suppress_prefix: bool = False
|
||||||
|
) -> addnodes.pending_xref:
|
||||||
"""Convert a type string to a cross reference node."""
|
"""Convert a type string to a cross reference node."""
|
||||||
if target == 'None':
|
if target == 'None':
|
||||||
reftype = 'obj'
|
reftype = 'obj'
|
||||||
@ -101,6 +102,8 @@ def type_to_xref(target: str, env: BuildEnvironment = None) -> addnodes.pending_
|
|||||||
elif target.startswith('~'):
|
elif target.startswith('~'):
|
||||||
target = target[1:]
|
target = target[1:]
|
||||||
text = target.split('.')[-1]
|
text = target.split('.')[-1]
|
||||||
|
elif suppress_prefix:
|
||||||
|
text = target.split('.')[-1]
|
||||||
else:
|
else:
|
||||||
text = target
|
text = target
|
||||||
|
|
||||||
@ -150,6 +153,8 @@ def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Nod
|
|||||||
return unparse(node.value)
|
return unparse(node.value)
|
||||||
elif isinstance(node, ast.Index):
|
elif isinstance(node, ast.Index):
|
||||||
return unparse(node.value)
|
return unparse(node.value)
|
||||||
|
elif isinstance(node, ast.Invert):
|
||||||
|
return [addnodes.desc_sig_punctuation('', '~')]
|
||||||
elif isinstance(node, ast.List):
|
elif isinstance(node, ast.List):
|
||||||
result = [addnodes.desc_sig_punctuation('', '[')]
|
result = [addnodes.desc_sig_punctuation('', '[')]
|
||||||
if node.elts:
|
if node.elts:
|
||||||
@ -180,6 +185,8 @@ def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Nod
|
|||||||
if isinstance(subnode, nodes.Text):
|
if isinstance(subnode, nodes.Text):
|
||||||
result[i] = nodes.literal('', '', subnode)
|
result[i] = nodes.literal('', '', subnode)
|
||||||
return result
|
return result
|
||||||
|
elif isinstance(node, ast.UnaryOp):
|
||||||
|
return unparse(node.op) + unparse(node.operand)
|
||||||
elif isinstance(node, ast.Tuple):
|
elif isinstance(node, ast.Tuple):
|
||||||
if node.elts:
|
if node.elts:
|
||||||
result = []
|
result = []
|
||||||
@ -209,12 +216,19 @@ def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Nod
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
tree = ast_parse(annotation)
|
tree = ast_parse(annotation)
|
||||||
result = unparse(tree)
|
result: List[Node] = []
|
||||||
for i, node in enumerate(result):
|
for node in unparse(tree):
|
||||||
if isinstance(node, nodes.literal):
|
if isinstance(node, nodes.literal):
|
||||||
result[i] = node[0]
|
result.append(node[0])
|
||||||
elif isinstance(node, nodes.Text) and node.strip():
|
elif isinstance(node, nodes.Text) and node.strip():
|
||||||
result[i] = type_to_xref(str(node), env)
|
if (result and isinstance(result[-1], addnodes.desc_sig_punctuation) and
|
||||||
|
result[-1].astext() == '~'):
|
||||||
|
result.pop()
|
||||||
|
result.append(type_to_xref(str(node), env, suppress_prefix=True))
|
||||||
|
else:
|
||||||
|
result.append(type_to_xref(str(node), env))
|
||||||
|
else:
|
||||||
|
result.append(node)
|
||||||
return result
|
return result
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
return [type_to_xref(annotation, env)]
|
return [type_to_xref(annotation, env)]
|
||||||
|
@ -1295,6 +1295,8 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|||||||
def format_args(self, **kwargs: Any) -> str:
|
def format_args(self, **kwargs: Any) -> str:
|
||||||
if self.config.autodoc_typehints in ('none', 'description'):
|
if self.config.autodoc_typehints in ('none', 'description'):
|
||||||
kwargs.setdefault('show_annotation', False)
|
kwargs.setdefault('show_annotation', False)
|
||||||
|
if self.config.autodoc_unqualified_typehints:
|
||||||
|
kwargs.setdefault('unqualified_typehints', True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.env.app.emit('autodoc-before-process-signature', self.object, False)
|
self.env.app.emit('autodoc-before-process-signature', self.object, False)
|
||||||
@ -1323,6 +1325,9 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
|
|||||||
self.add_line(' :async:', sourcename)
|
self.add_line(' :async:', sourcename)
|
||||||
|
|
||||||
def format_signature(self, **kwargs: Any) -> str:
|
def format_signature(self, **kwargs: Any) -> str:
|
||||||
|
if self.config.autodoc_unqualified_typehints:
|
||||||
|
kwargs.setdefault('unqualified_typehints', True)
|
||||||
|
|
||||||
sigs = []
|
sigs = []
|
||||||
if (self.analyzer and
|
if (self.analyzer and
|
||||||
'.'.join(self.objpath) in self.analyzer.overloads and
|
'.'.join(self.objpath) in self.analyzer.overloads and
|
||||||
@ -1561,6 +1566,8 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|||||||
def format_args(self, **kwargs: Any) -> str:
|
def format_args(self, **kwargs: Any) -> str:
|
||||||
if self.config.autodoc_typehints in ('none', 'description'):
|
if self.config.autodoc_typehints in ('none', 'description'):
|
||||||
kwargs.setdefault('show_annotation', False)
|
kwargs.setdefault('show_annotation', False)
|
||||||
|
if self.config.autodoc_unqualified_typehints:
|
||||||
|
kwargs.setdefault('unqualified_typehints', True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._signature_class, self._signature_method_name, sig = self._get_signature()
|
self._signature_class, self._signature_method_name, sig = self._get_signature()
|
||||||
@ -1582,6 +1589,9 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
|||||||
# do not show signatures
|
# do not show signatures
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
if self.config.autodoc_unqualified_typehints:
|
||||||
|
kwargs.setdefault('unqualified_typehints', True)
|
||||||
|
|
||||||
sig = super().format_signature()
|
sig = super().format_signature()
|
||||||
sigs = []
|
sigs = []
|
||||||
|
|
||||||
@ -2110,6 +2120,8 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|||||||
def format_args(self, **kwargs: Any) -> str:
|
def format_args(self, **kwargs: Any) -> str:
|
||||||
if self.config.autodoc_typehints in ('none', 'description'):
|
if self.config.autodoc_typehints in ('none', 'description'):
|
||||||
kwargs.setdefault('show_annotation', False)
|
kwargs.setdefault('show_annotation', False)
|
||||||
|
if self.config.autodoc_unqualified_typehints:
|
||||||
|
kwargs.setdefault('unqualified_typehints', True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.object == object.__init__ and self.parent != object:
|
if self.object == object.__init__ and self.parent != object:
|
||||||
@ -2160,6 +2172,9 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def format_signature(self, **kwargs: Any) -> str:
|
def format_signature(self, **kwargs: Any) -> str:
|
||||||
|
if self.config.autodoc_unqualified_typehints:
|
||||||
|
kwargs.setdefault('unqualified_typehints', True)
|
||||||
|
|
||||||
sigs = []
|
sigs = []
|
||||||
if (self.analyzer and
|
if (self.analyzer and
|
||||||
'.'.join(self.objpath) in self.analyzer.overloads and
|
'.'.join(self.objpath) in self.analyzer.overloads and
|
||||||
@ -2833,6 +2848,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||||||
app.add_config_value('autodoc_typehints_description_target', 'all', True,
|
app.add_config_value('autodoc_typehints_description_target', 'all', True,
|
||||||
ENUM('all', 'documented'))
|
ENUM('all', 'documented'))
|
||||||
app.add_config_value('autodoc_type_aliases', {}, True)
|
app.add_config_value('autodoc_type_aliases', {}, True)
|
||||||
|
app.add_config_value('autodoc_unqualified_typehints', False, 'env')
|
||||||
app.add_config_value('autodoc_warningiserror', True, True)
|
app.add_config_value('autodoc_warningiserror', True, True)
|
||||||
app.add_config_value('autodoc_inherit_docstrings', True, True)
|
app.add_config_value('autodoc_inherit_docstrings', True, True)
|
||||||
app.add_event('autodoc-before-process-signature')
|
app.add_event('autodoc-before-process-signature')
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
%% LITERAL BLOCKS
|
%% LITERAL BLOCKS
|
||||||
%
|
%
|
||||||
% change this info string if making any custom modification
|
% change this info string if making any custom modification
|
||||||
\ProvidesFile{sphinxlatexliterals.sty}[2021/01/27 code-blocks and parsed literals]
|
\ProvidesFile{sphinxlatexliterals.sty}[2021/12/06 code-blocks and parsed literals]
|
||||||
|
|
||||||
% Provides support for this output mark-up from Sphinx latex writer:
|
% Provides support for this output mark-up from Sphinx latex writer:
|
||||||
%
|
%
|
||||||
@ -704,6 +704,10 @@
|
|||||||
% the \catcode13=5\relax (deactivate end of input lines) is left to callers
|
% the \catcode13=5\relax (deactivate end of input lines) is left to callers
|
||||||
\newcommand*{\sphinxunactivateextrasandspace}{\catcode32=10\relax
|
\newcommand*{\sphinxunactivateextrasandspace}{\catcode32=10\relax
|
||||||
\sphinxunactivateextras}%
|
\sphinxunactivateextras}%
|
||||||
|
% alltt uses a monospace font and linebreaks at dashes (which are escaped
|
||||||
|
% to \sphinxhyphen{} which expands to -\kern\z@) are inhibited with pdflatex.
|
||||||
|
% Not with xelatex (cf \defaultfontfeatures in latex writer), so:
|
||||||
|
\newcommand*{\sphinxhypheninparsedliteral}{\sphinxhyphennobreak}
|
||||||
% now for the modified alltt environment
|
% now for the modified alltt environment
|
||||||
\newenvironment{sphinxalltt}
|
\newenvironment{sphinxalltt}
|
||||||
{% at start of next line to workaround Emacs/AUCTeX issue with this file
|
{% at start of next line to workaround Emacs/AUCTeX issue with this file
|
||||||
@ -711,6 +715,7 @@
|
|||||||
\ifspx@opt@parsedliteralwraps
|
\ifspx@opt@parsedliteralwraps
|
||||||
\sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}%
|
\sbox\sphinxcontinuationbox {\spx@opt@verbatimcontinued}%
|
||||||
\sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}%
|
\sbox\sphinxvisiblespacebox {\spx@opt@verbatimvisiblespace}%
|
||||||
|
\let\sphinxhyphen\sphinxhypheninparsedliteral
|
||||||
\sphinxbreaksattexescapedchars
|
\sphinxbreaksattexescapedchars
|
||||||
\sphinxbreaksviaactiveinparsedliteral
|
\sphinxbreaksviaactiveinparsedliteral
|
||||||
\sphinxbreaksatspaceinparsedliteral
|
\sphinxbreaksatspaceinparsedliteral
|
||||||
@ -757,10 +762,14 @@
|
|||||||
\protected\def\sphinxtextbackslashbreakafter
|
\protected\def\sphinxtextbackslashbreakafter
|
||||||
{\discretionary{\sphinx@textbackslash}{\sphinxafterbreak}{\sphinx@textbackslash}}
|
{\discretionary{\sphinx@textbackslash}{\sphinxafterbreak}{\sphinx@textbackslash}}
|
||||||
\let\sphinxtextbackslash\sphinxtextbackslashbreakafter
|
\let\sphinxtextbackslash\sphinxtextbackslashbreakafter
|
||||||
|
% - is escaped to \sphinxhyphen{} and this default ensures no linebreak
|
||||||
|
% behaviour (also with a non monospace font, or with xelatex)
|
||||||
|
\newcommand*{\sphinxhyphenininlineliteral}{\sphinxhyphennobreak}
|
||||||
% the macro must be protected if it ends up used in moving arguments,
|
% the macro must be protected if it ends up used in moving arguments,
|
||||||
% in 'alltt' \@noligs is done already, and the \scantokens must be avoided.
|
% in 'alltt' \@noligs is done already, and the \scantokens must be avoided.
|
||||||
\protected\def\sphinxupquote#1{{\def\@tempa{alltt}%
|
\protected\def\sphinxupquote#1{{\def\@tempa{alltt}%
|
||||||
\ifx\@tempa\@currenvir\else
|
\ifx\@tempa\@currenvir\else
|
||||||
|
\let\sphinxhyphen\sphinxhyphenininlineliteral
|
||||||
\ifspx@opt@inlineliteralwraps
|
\ifspx@opt@inlineliteralwraps
|
||||||
% break at . , ; ? ! /
|
% break at . , ; ? ! /
|
||||||
\sphinxbreaksviaactive
|
\sphinxbreaksviaactive
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
%% TEXT STYLING
|
%% TEXT STYLING
|
||||||
%
|
%
|
||||||
% change this info string if making any custom modification
|
% change this info string if making any custom modification
|
||||||
\ProvidesFile{sphinxlatexstyletext.sty}[2021/01/27 text styling]
|
\ProvidesFile{sphinxlatexstyletext.sty}[2021/12/06 text styling]
|
||||||
|
|
||||||
% Basically everything here consists of macros which are part of the latex
|
% Basically everything here consists of macros which are part of the latex
|
||||||
% markup produced by the Sphinx latex writer
|
% markup produced by the Sphinx latex writer
|
||||||
@ -72,12 +72,20 @@
|
|||||||
|
|
||||||
% Special characters
|
% Special characters
|
||||||
%
|
%
|
||||||
% This definition prevents en-dash and em-dash TeX ligatures.
|
% The \kern\z@ is to prevent en-dash and em-dash TeX ligatures.
|
||||||
|
% A linebreak can occur after the dash in regular text (this is
|
||||||
|
% normal behaviour of "-" in TeX, it is not related to \kern\z@).
|
||||||
%
|
%
|
||||||
% It inserts a potential breakpoint after the hyphen. This is to keep in sync
|
% Parsed-literals and inline literals also use the \sphinxhyphen
|
||||||
% with behavior in code-blocks, parsed and inline literals. For a breakpoint
|
% but linebreaks there are prevented due to monospace font family.
|
||||||
% before the hyphen use \leavevmode\kern\z@- (within \makeatletter/\makeatother)
|
% (xelatex needs a special addition, cf. sphinxlatexliterals.sty)
|
||||||
|
%
|
||||||
|
% Inside code-blocks, dashes are escaped via another macro, from
|
||||||
|
% Pygments latex output (search for \PYGZhy in sphinxlatexliterals.sty),
|
||||||
|
% and are configured to allow linebreaks despite the monospace font.
|
||||||
|
% (the #1 swallows the {} from \sphinxhyphen{} mark-up)
|
||||||
\protected\def\sphinxhyphen#1{-\kern\z@}
|
\protected\def\sphinxhyphen#1{-\kern\z@}
|
||||||
|
\protected\def\sphinxhyphennobreak#1{\mbox{-}}
|
||||||
% The {} from texescape mark-up is kept, else -- gives en-dash in PDF bookmark
|
% The {} from texescape mark-up is kept, else -- gives en-dash in PDF bookmark
|
||||||
\def\sphinxhyphenforbookmarks{-}
|
\def\sphinxhyphenforbookmarks{-}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ class ApplySourceWorkaround(SphinxTransform):
|
|||||||
|
|
||||||
def apply(self, **kwargs: Any) -> None:
|
def apply(self, **kwargs: Any) -> None:
|
||||||
for node in self.document.traverse(): # type: Node
|
for node in self.document.traverse(): # type: Node
|
||||||
if isinstance(node, (nodes.TextElement, nodes.image)):
|
if isinstance(node, (nodes.TextElement, nodes.image, nodes.topic)):
|
||||||
apply_source_workaround(node)
|
apply_source_workaround(node)
|
||||||
|
|
||||||
|
|
||||||
|
@ -744,10 +744,13 @@ def evaluate_signature(sig: inspect.Signature, globalns: Dict = None, localns: D
|
|||||||
|
|
||||||
|
|
||||||
def stringify_signature(sig: inspect.Signature, show_annotation: bool = True,
|
def stringify_signature(sig: inspect.Signature, show_annotation: bool = True,
|
||||||
show_return_annotation: bool = True) -> str:
|
show_return_annotation: bool = True,
|
||||||
|
unqualified_typehints: bool = False) -> str:
|
||||||
"""Stringify a Signature object.
|
"""Stringify a Signature object.
|
||||||
|
|
||||||
:param show_annotation: Show annotation in result
|
:param show_annotation: Show annotation in result
|
||||||
|
:param unqualified_typehints: Show annotations as unqualified
|
||||||
|
(ex. io.StringIO -> StringIO)
|
||||||
"""
|
"""
|
||||||
args = []
|
args = []
|
||||||
last_kind = None
|
last_kind = None
|
||||||
@ -771,7 +774,7 @@ def stringify_signature(sig: inspect.Signature, show_annotation: bool = True,
|
|||||||
|
|
||||||
if show_annotation and param.annotation is not param.empty:
|
if show_annotation and param.annotation is not param.empty:
|
||||||
arg.write(': ')
|
arg.write(': ')
|
||||||
arg.write(stringify_annotation(param.annotation))
|
arg.write(stringify_annotation(param.annotation, unqualified_typehints))
|
||||||
if param.default is not param.empty:
|
if param.default is not param.empty:
|
||||||
if show_annotation and param.annotation is not param.empty:
|
if show_annotation and param.annotation is not param.empty:
|
||||||
arg.write(' = ')
|
arg.write(' = ')
|
||||||
@ -791,7 +794,7 @@ def stringify_signature(sig: inspect.Signature, show_annotation: bool = True,
|
|||||||
show_return_annotation is False):
|
show_return_annotation is False):
|
||||||
return '(%s)' % ', '.join(args)
|
return '(%s)' % ', '.join(args)
|
||||||
else:
|
else:
|
||||||
annotation = stringify_annotation(sig.return_annotation)
|
annotation = stringify_annotation(sig.return_annotation, unqualified_typehints)
|
||||||
return '(%s) -> %s' % (', '.join(args), annotation)
|
return '(%s) -> %s' % (', '.join(args), annotation)
|
||||||
|
|
||||||
|
|
||||||
|
@ -150,6 +150,11 @@ def apply_source_workaround(node: Element) -> None:
|
|||||||
for classifier in reversed(list(node.parent.traverse(nodes.classifier))):
|
for classifier in reversed(list(node.parent.traverse(nodes.classifier))):
|
||||||
node.rawsource = re.sub(r'\s*:\s*%s' % re.escape(classifier.astext()),
|
node.rawsource = re.sub(r'\s*:\s*%s' % re.escape(classifier.astext()),
|
||||||
'', node.rawsource)
|
'', node.rawsource)
|
||||||
|
if isinstance(node, nodes.topic) and node.source is None:
|
||||||
|
# docutils-0.18 does not fill the source attribute of topic
|
||||||
|
logger.debug('[i18n] PATCH: %r to have source, line: %s',
|
||||||
|
get_full_module_name(node), repr_domxml(node))
|
||||||
|
node.source, node.line = node.parent.source, node.parent.line
|
||||||
|
|
||||||
# workaround: literal_block under bullet list (#4913)
|
# workaround: literal_block under bullet list (#4913)
|
||||||
if isinstance(node, nodes.literal_block) and node.source is None:
|
if isinstance(node, nodes.literal_block) and node.source is None:
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from math import sqrt
|
from math import sqrt
|
||||||
@ -28,12 +26,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
# our parallel functionality only works for the forking Process
|
# our parallel functionality only works for the forking Process
|
||||||
#
|
parallel_available = multiprocessing and os.name == 'posix'
|
||||||
# Note: "fork" is not recommended on macOS and py38+.
|
|
||||||
# see https://bugs.python.org/issue33725
|
|
||||||
parallel_available = (multiprocessing and
|
|
||||||
(os.name == 'posix') and
|
|
||||||
not (sys.version_info > (3, 8) and platform.system() == 'Darwin'))
|
|
||||||
|
|
||||||
|
|
||||||
class SerialTasks:
|
class SerialTasks:
|
||||||
@ -64,7 +57,7 @@ class ParallelTasks:
|
|||||||
# task arguments
|
# task arguments
|
||||||
self._args: Dict[int, Optional[List[Any]]] = {}
|
self._args: Dict[int, Optional[List[Any]]] = {}
|
||||||
# list of subprocesses (both started and waiting)
|
# list of subprocesses (both started and waiting)
|
||||||
self._procs: Dict[int, multiprocessing.Process] = {}
|
self._procs: Dict[int, multiprocessing.context.ForkProcess] = {}
|
||||||
# list of receiving pipe connections of running subprocesses
|
# list of receiving pipe connections of running subprocesses
|
||||||
self._precvs: Dict[int, Any] = {}
|
self._precvs: Dict[int, Any] = {}
|
||||||
# list of receiving pipe connections of waiting subprocesses
|
# list of receiving pipe connections of waiting subprocesses
|
||||||
@ -96,8 +89,8 @@ class ParallelTasks:
|
|||||||
self._result_funcs[tid] = result_func or (lambda arg, result: None)
|
self._result_funcs[tid] = result_func or (lambda arg, result: None)
|
||||||
self._args[tid] = arg
|
self._args[tid] = arg
|
||||||
precv, psend = multiprocessing.Pipe(False)
|
precv, psend = multiprocessing.Pipe(False)
|
||||||
proc = multiprocessing.Process(target=self._process,
|
context = multiprocessing.get_context('fork')
|
||||||
args=(psend, task_func, arg))
|
proc = context.Process(target=self._process, args=(psend, task_func, arg))
|
||||||
self._procs[tid] = proc
|
self._procs[tid] = proc
|
||||||
self._precvsWaiting[tid] = precv
|
self._precvsWaiting[tid] = precv
|
||||||
self._join_one()
|
self._join_one()
|
||||||
|
@ -299,10 +299,19 @@ def _restify_py36(cls: Optional[Type]) -> str:
|
|||||||
return ':py:obj:`%s.%s`' % (cls.__module__, qualname)
|
return ':py:obj:`%s.%s`' % (cls.__module__, qualname)
|
||||||
|
|
||||||
|
|
||||||
def stringify(annotation: Any) -> str:
|
def stringify(annotation: Any, smartref: bool = False) -> str:
|
||||||
"""Stringify type annotation object."""
|
"""Stringify type annotation object.
|
||||||
|
|
||||||
|
:param smartref: If true, add "~" prefix to the result to remove the leading
|
||||||
|
module and class names from the reference text
|
||||||
|
"""
|
||||||
from sphinx.util import inspect # lazy loading
|
from sphinx.util import inspect # lazy loading
|
||||||
|
|
||||||
|
if smartref:
|
||||||
|
prefix = '~'
|
||||||
|
else:
|
||||||
|
prefix = ''
|
||||||
|
|
||||||
if isinstance(annotation, str):
|
if isinstance(annotation, str):
|
||||||
if annotation.startswith("'") and annotation.endswith("'"):
|
if annotation.startswith("'") and annotation.endswith("'"):
|
||||||
# might be a double Forward-ref'ed type. Go unquoting.
|
# might be a double Forward-ref'ed type. Go unquoting.
|
||||||
@ -313,11 +322,11 @@ def stringify(annotation: Any) -> str:
|
|||||||
if annotation.__module__ == 'typing':
|
if annotation.__module__ == 'typing':
|
||||||
return annotation.__name__
|
return annotation.__name__
|
||||||
else:
|
else:
|
||||||
return '.'.join([annotation.__module__, annotation.__name__])
|
return prefix + '.'.join([annotation.__module__, annotation.__name__])
|
||||||
elif inspect.isNewType(annotation):
|
elif inspect.isNewType(annotation):
|
||||||
if sys.version_info > (3, 10):
|
if sys.version_info > (3, 10):
|
||||||
# newtypes have correct module info since Python 3.10+
|
# newtypes have correct module info since Python 3.10+
|
||||||
return '%s.%s' % (annotation.__module__, annotation.__name__)
|
return prefix + '%s.%s' % (annotation.__module__, annotation.__name__)
|
||||||
else:
|
else:
|
||||||
return annotation.__name__
|
return annotation.__name__
|
||||||
elif not annotation:
|
elif not annotation:
|
||||||
@ -325,7 +334,7 @@ def stringify(annotation: Any) -> str:
|
|||||||
elif annotation is NoneType:
|
elif annotation is NoneType:
|
||||||
return 'None'
|
return 'None'
|
||||||
elif annotation in INVALID_BUILTIN_CLASSES:
|
elif annotation in INVALID_BUILTIN_CLASSES:
|
||||||
return INVALID_BUILTIN_CLASSES[annotation]
|
return prefix + INVALID_BUILTIN_CLASSES[annotation]
|
||||||
elif str(annotation).startswith('typing.Annotated'): # for py310+
|
elif str(annotation).startswith('typing.Annotated'): # for py310+
|
||||||
pass
|
pass
|
||||||
elif (getattr(annotation, '__module__', None) == 'builtins' and
|
elif (getattr(annotation, '__module__', None) == 'builtins' and
|
||||||
@ -338,28 +347,36 @@ def stringify(annotation: Any) -> str:
|
|||||||
return '...'
|
return '...'
|
||||||
|
|
||||||
if sys.version_info >= (3, 7): # py37+
|
if sys.version_info >= (3, 7): # py37+
|
||||||
return _stringify_py37(annotation)
|
return _stringify_py37(annotation, smartref)
|
||||||
else:
|
else:
|
||||||
return _stringify_py36(annotation)
|
return _stringify_py36(annotation, smartref)
|
||||||
|
|
||||||
|
|
||||||
def _stringify_py37(annotation: Any) -> str:
|
def _stringify_py37(annotation: Any, smartref: bool = False) -> str:
|
||||||
"""stringify() for py37+."""
|
"""stringify() for py37+."""
|
||||||
module = getattr(annotation, '__module__', None)
|
module = getattr(annotation, '__module__', None)
|
||||||
if module == 'typing':
|
modprefix = ''
|
||||||
|
if module == 'typing' and getattr(annotation, '__forward_arg__', None):
|
||||||
|
qualname = annotation.__forward_arg__
|
||||||
|
elif module == 'typing':
|
||||||
if getattr(annotation, '_name', None):
|
if getattr(annotation, '_name', None):
|
||||||
qualname = annotation._name
|
qualname = annotation._name
|
||||||
elif getattr(annotation, '__qualname__', None):
|
elif getattr(annotation, '__qualname__', None):
|
||||||
qualname = annotation.__qualname__
|
qualname = annotation.__qualname__
|
||||||
elif getattr(annotation, '__forward_arg__', None):
|
|
||||||
qualname = annotation.__forward_arg__
|
|
||||||
else:
|
else:
|
||||||
qualname = stringify(annotation.__origin__) # ex. Union
|
qualname = stringify(annotation.__origin__) # ex. Union
|
||||||
|
|
||||||
|
if smartref:
|
||||||
|
modprefix = '~%s.' % module
|
||||||
elif hasattr(annotation, '__qualname__'):
|
elif hasattr(annotation, '__qualname__'):
|
||||||
qualname = '%s.%s' % (module, annotation.__qualname__)
|
if smartref:
|
||||||
|
modprefix = '~%s.' % module
|
||||||
|
else:
|
||||||
|
modprefix = '%s.' % module
|
||||||
|
qualname = annotation.__qualname__
|
||||||
elif hasattr(annotation, '__origin__'):
|
elif hasattr(annotation, '__origin__'):
|
||||||
# instantiated generic provided by a user
|
# instantiated generic provided by a user
|
||||||
qualname = stringify(annotation.__origin__)
|
qualname = stringify(annotation.__origin__, smartref)
|
||||||
elif UnionType and isinstance(annotation, UnionType): # types.Union (for py3.10+)
|
elif UnionType and isinstance(annotation, UnionType): # types.Union (for py3.10+)
|
||||||
qualname = 'types.Union'
|
qualname = 'types.Union'
|
||||||
else:
|
else:
|
||||||
@ -374,54 +391,63 @@ def _stringify_py37(annotation: Any) -> str:
|
|||||||
elif qualname in ('Optional', 'Union'):
|
elif qualname in ('Optional', '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, smartref) for a in annotation.__args__[:-1])
|
||||||
return 'Optional[Union[%s]]' % args
|
return '%sOptional[%sUnion[%s]]' % (modprefix, modprefix, args)
|
||||||
else:
|
else:
|
||||||
return 'Optional[%s]' % stringify(annotation.__args__[0])
|
return '%sOptional[%s]' % (modprefix,
|
||||||
|
stringify(annotation.__args__[0], smartref))
|
||||||
else:
|
else:
|
||||||
args = ', '.join(stringify(a) for a in annotation.__args__)
|
args = ', '.join(stringify(a, smartref) for a in annotation.__args__)
|
||||||
return 'Union[%s]' % args
|
return '%sUnion[%s]' % (modprefix, args)
|
||||||
elif qualname == 'types.Union':
|
elif qualname == 'types.Union':
|
||||||
if len(annotation.__args__) > 1 and None in annotation.__args__:
|
if len(annotation.__args__) > 1 and None in annotation.__args__:
|
||||||
args = ' | '.join(stringify(a) for a in annotation.__args__ if a)
|
args = ' | '.join(stringify(a) for a in annotation.__args__ if a)
|
||||||
return 'Optional[%s]' % args
|
return '%sOptional[%s]' % (modprefix, args)
|
||||||
else:
|
else:
|
||||||
return ' | '.join(stringify(a) for a in annotation.__args__)
|
return ' | '.join(stringify(a) for a in annotation.__args__)
|
||||||
elif qualname == 'Callable':
|
elif qualname == 'Callable':
|
||||||
args = ', '.join(stringify(a) for a in annotation.__args__[:-1])
|
args = ', '.join(stringify(a, smartref) for a in annotation.__args__[:-1])
|
||||||
returns = stringify(annotation.__args__[-1])
|
returns = stringify(annotation.__args__[-1], smartref)
|
||||||
return '%s[[%s], %s]' % (qualname, args, returns)
|
return '%s%s[[%s], %s]' % (modprefix, qualname, args, returns)
|
||||||
elif qualname == 'Literal':
|
elif qualname == 'Literal':
|
||||||
args = ', '.join(repr(a) for a in annotation.__args__)
|
args = ', '.join(repr(a) for a in annotation.__args__)
|
||||||
return '%s[%s]' % (qualname, args)
|
return '%s%s[%s]' % (modprefix, qualname, args)
|
||||||
elif str(annotation).startswith('typing.Annotated'): # for py39+
|
elif str(annotation).startswith('typing.Annotated'): # for py39+
|
||||||
return stringify(annotation.__args__[0])
|
return stringify(annotation.__args__[0], smartref)
|
||||||
elif all(is_system_TypeVar(a) for a in annotation.__args__):
|
elif all(is_system_TypeVar(a) for a in annotation.__args__):
|
||||||
# Suppress arguments if all system defined TypeVars (ex. Dict[KT, VT])
|
# Suppress arguments if all system defined TypeVars (ex. Dict[KT, VT])
|
||||||
return qualname
|
return modprefix + qualname
|
||||||
else:
|
else:
|
||||||
args = ', '.join(stringify(a) for a in annotation.__args__)
|
args = ', '.join(stringify(a, smartref) for a in annotation.__args__)
|
||||||
return '%s[%s]' % (qualname, args)
|
return '%s%s[%s]' % (modprefix, qualname, args)
|
||||||
|
|
||||||
return qualname
|
return modprefix + qualname
|
||||||
|
|
||||||
|
|
||||||
def _stringify_py36(annotation: Any) -> str:
|
def _stringify_py36(annotation: Any, smartref: bool = False) -> str:
|
||||||
"""stringify() for py36."""
|
"""stringify() for py36."""
|
||||||
module = getattr(annotation, '__module__', None)
|
module = getattr(annotation, '__module__', None)
|
||||||
if module == 'typing':
|
modprefix = ''
|
||||||
|
if module == 'typing' and getattr(annotation, '__forward_arg__', None):
|
||||||
|
qualname = annotation.__forward_arg__
|
||||||
|
elif module == 'typing':
|
||||||
if getattr(annotation, '_name', None):
|
if getattr(annotation, '_name', None):
|
||||||
qualname = annotation._name
|
qualname = annotation._name
|
||||||
elif getattr(annotation, '__qualname__', None):
|
elif getattr(annotation, '__qualname__', None):
|
||||||
qualname = annotation.__qualname__
|
qualname = annotation.__qualname__
|
||||||
elif getattr(annotation, '__forward_arg__', None):
|
|
||||||
qualname = annotation.__forward_arg__
|
|
||||||
elif getattr(annotation, '__origin__', None):
|
elif getattr(annotation, '__origin__', None):
|
||||||
qualname = stringify(annotation.__origin__) # ex. Union
|
qualname = stringify(annotation.__origin__) # ex. Union
|
||||||
else:
|
else:
|
||||||
qualname = repr(annotation).replace('typing.', '')
|
qualname = repr(annotation).replace('typing.', '')
|
||||||
|
|
||||||
|
if smartref:
|
||||||
|
modprefix = '~%s.' % module
|
||||||
elif hasattr(annotation, '__qualname__'):
|
elif hasattr(annotation, '__qualname__'):
|
||||||
qualname = '%s.%s' % (module, annotation.__qualname__)
|
if smartref:
|
||||||
|
modprefix = '~%s.' % module
|
||||||
|
else:
|
||||||
|
modprefix = '%s.' % module
|
||||||
|
qualname = annotation.__qualname__
|
||||||
else:
|
else:
|
||||||
qualname = repr(annotation)
|
qualname = repr(annotation)
|
||||||
|
|
||||||
@ -429,10 +455,10 @@ def _stringify_py36(annotation: Any) -> str:
|
|||||||
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:
|
||||||
param_str = ', '.join(stringify(p) for p in params)
|
param_str = ', '.join(stringify(p, smartref) for p in params)
|
||||||
return '%s[%s]' % (qualname, param_str)
|
return '%s%s[%s]' % (modprefix, qualname, param_str)
|
||||||
else:
|
else:
|
||||||
return qualname
|
return modprefix + qualname
|
||||||
elif isinstance(annotation, typing.GenericMeta):
|
elif isinstance(annotation, typing.GenericMeta):
|
||||||
params = None
|
params = None
|
||||||
if annotation.__args__ is None or len(annotation.__args__) <= 2: # type: ignore # NOQA
|
if annotation.__args__ is None or len(annotation.__args__) <= 2: # type: ignore # NOQA
|
||||||
@ -440,28 +466,28 @@ def _stringify_py36(annotation: Any) -> str:
|
|||||||
elif annotation.__origin__ == Generator: # type: ignore
|
elif annotation.__origin__ == Generator: # type: ignore
|
||||||
params = annotation.__args__ # type: ignore
|
params = annotation.__args__ # type: ignore
|
||||||
else: # typing.Callable
|
else: # typing.Callable
|
||||||
args = ', '.join(stringify(arg) for arg
|
args = ', '.join(stringify(arg, smartref) for arg
|
||||||
in annotation.__args__[:-1]) # type: ignore
|
in annotation.__args__[:-1]) # type: ignore
|
||||||
result = stringify(annotation.__args__[-1]) # type: ignore
|
result = stringify(annotation.__args__[-1]) # type: ignore
|
||||||
return '%s[[%s], %s]' % (qualname, args, result)
|
return '%s%s[[%s], %s]' % (modprefix, qualname, args, result)
|
||||||
if params is not None:
|
if params is not None:
|
||||||
param_str = ', '.join(stringify(p) for p in params)
|
param_str = ', '.join(stringify(p, smartref) for p in params)
|
||||||
return '%s[%s]' % (qualname, param_str)
|
return '%s%s[%s]' % (modprefix, qualname, param_str)
|
||||||
elif (hasattr(annotation, '__origin__') and
|
elif (hasattr(annotation, '__origin__') and
|
||||||
annotation.__origin__ is typing.Union):
|
annotation.__origin__ is typing.Union):
|
||||||
params = annotation.__args__
|
params = annotation.__args__
|
||||||
if params is not None:
|
if params is not None:
|
||||||
if len(params) > 1 and params[-1] is NoneType:
|
if len(params) > 1 and params[-1] is NoneType:
|
||||||
if len(params) > 2:
|
if len(params) > 2:
|
||||||
param_str = ", ".join(stringify(p) for p in params[:-1])
|
param_str = ", ".join(stringify(p, smartref) for p in params[:-1])
|
||||||
return 'Optional[Union[%s]]' % param_str
|
return '%sOptional[%sUnion[%s]]' % (modprefix, modprefix, param_str)
|
||||||
else:
|
else:
|
||||||
return 'Optional[%s]' % stringify(params[0])
|
return '%sOptional[%s]' % (modprefix, stringify(params[0]))
|
||||||
else:
|
else:
|
||||||
param_str = ', '.join(stringify(p) for p in params)
|
param_str = ', '.join(stringify(p, smartref) for p in params)
|
||||||
return 'Union[%s]' % param_str
|
return '%sUnion[%s]' % (modprefix, param_str)
|
||||||
|
|
||||||
return qualname
|
return modprefix + qualname
|
||||||
|
|
||||||
|
|
||||||
deprecated_alias('sphinx.util.typing',
|
deprecated_alias('sphinx.util.typing',
|
||||||
|
@ -757,9 +757,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|||||||
self._depart_signature_line(node)
|
self._depart_signature_line(node)
|
||||||
|
|
||||||
def visit_desc_content(self, node: Element) -> None:
|
def visit_desc_content(self, node: Element) -> None:
|
||||||
if node.children and not isinstance(node.children[0], nodes.paragraph):
|
pass
|
||||||
# avoid empty desc environment which causes a formatting bug
|
|
||||||
self.body.append('~')
|
|
||||||
|
|
||||||
def depart_desc_content(self, node: Element) -> None:
|
def depart_desc_content(self, node: Element) -> None:
|
||||||
pass
|
pass
|
||||||
|
@ -194,6 +194,7 @@ class TexinfoTranslator(SphinxTranslator):
|
|||||||
self.curfilestack: List[str] = []
|
self.curfilestack: List[str] = []
|
||||||
self.footnotestack: List[Dict[str, List[Union[collected_footnote, bool]]]] = [] # NOQA
|
self.footnotestack: List[Dict[str, List[Union[collected_footnote, bool]]]] = [] # NOQA
|
||||||
self.in_footnote = 0
|
self.in_footnote = 0
|
||||||
|
self.in_samp = 0
|
||||||
self.handled_abbrs: Set[str] = set()
|
self.handled_abbrs: Set[str] = set()
|
||||||
self.colwidths: List[int] = None
|
self.colwidths: List[int] = None
|
||||||
|
|
||||||
@ -545,9 +546,12 @@ class TexinfoTranslator(SphinxTranslator):
|
|||||||
def add_xref(self, id: str, name: str, node: Node) -> None:
|
def add_xref(self, id: str, name: str, node: Node) -> None:
|
||||||
name = self.escape_menu(name)
|
name = self.escape_menu(name)
|
||||||
sid = self.get_short_id(id)
|
sid = self.get_short_id(id)
|
||||||
self.body.append('@ref{%s,,%s}' % (sid, name))
|
if self.config.texinfo_cross_references:
|
||||||
self.referenced_ids.add(sid)
|
self.body.append('@ref{%s,,%s}' % (sid, name))
|
||||||
self.referenced_ids.add(self.escape_id(id))
|
self.referenced_ids.add(sid)
|
||||||
|
self.referenced_ids.add(self.escape_id(id))
|
||||||
|
else:
|
||||||
|
self.body.append(name)
|
||||||
|
|
||||||
# -- Visiting
|
# -- Visiting
|
||||||
|
|
||||||
@ -809,15 +813,23 @@ class TexinfoTranslator(SphinxTranslator):
|
|||||||
self.body.append('}')
|
self.body.append('}')
|
||||||
|
|
||||||
def visit_emphasis(self, node: Element) -> None:
|
def visit_emphasis(self, node: Element) -> None:
|
||||||
self.body.append('@emph{')
|
element = 'emph' if not self.in_samp else 'var'
|
||||||
|
self.body.append('@%s{' % element)
|
||||||
|
|
||||||
def depart_emphasis(self, node: Element) -> None:
|
def depart_emphasis(self, node: Element) -> None:
|
||||||
self.body.append('}')
|
self.body.append('}')
|
||||||
|
|
||||||
|
def is_samp(self, node: Element) -> bool:
|
||||||
|
return 'samp' in node['classes']
|
||||||
|
|
||||||
def visit_literal(self, node: Element) -> None:
|
def visit_literal(self, node: Element) -> None:
|
||||||
|
if self.is_samp(node):
|
||||||
|
self.in_samp += 1
|
||||||
self.body.append('@code{')
|
self.body.append('@code{')
|
||||||
|
|
||||||
def depart_literal(self, node: Element) -> None:
|
def depart_literal(self, node: Element) -> None:
|
||||||
|
if self.is_samp(node):
|
||||||
|
self.in_samp -= 1
|
||||||
self.body.append('}')
|
self.body.append('}')
|
||||||
|
|
||||||
def visit_superscript(self, node: Element) -> None:
|
def visit_superscript(self, node: Element) -> None:
|
||||||
@ -1223,7 +1235,11 @@ class TexinfoTranslator(SphinxTranslator):
|
|||||||
self.depart_topic(node)
|
self.depart_topic(node)
|
||||||
|
|
||||||
def visit_label(self, node: Element) -> None:
|
def visit_label(self, node: Element) -> None:
|
||||||
self.body.append('@w{(')
|
# label numbering is automatically generated by Texinfo
|
||||||
|
if self.in_footnote:
|
||||||
|
raise nodes.SkipNode
|
||||||
|
else:
|
||||||
|
self.body.append('@w{(')
|
||||||
|
|
||||||
def depart_label(self, node: Element) -> None:
|
def depart_label(self, node: Element) -> None:
|
||||||
self.body.append(')} ')
|
self.body.append(')} ')
|
||||||
|
@ -112,3 +112,36 @@ def test_texinfo_escape_id(app, status, warning):
|
|||||||
assert translator.escape_id('Hello(world)') == 'Hello world'
|
assert translator.escape_id('Hello(world)') == 'Hello world'
|
||||||
assert translator.escape_id('Hello world.') == 'Hello world'
|
assert translator.escape_id('Hello world.') == 'Hello world'
|
||||||
assert translator.escape_id('.') == '.'
|
assert translator.escape_id('.') == '.'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('texinfo', testroot='footnotes')
|
||||||
|
def test_texinfo_footnote(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
|
||||||
|
output = (app.outdir / 'python.texi').read_text()
|
||||||
|
assert 'First footnote: @footnote{\nFirst\n}' in output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('texinfo')
|
||||||
|
def test_texinfo_xrefs(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
output = (app.outdir / 'sphinxtests.texi').read_text()
|
||||||
|
assert re.search(r'@ref{\w+,,--plugin\.option}', output)
|
||||||
|
|
||||||
|
# Now rebuild it without xrefs
|
||||||
|
app.config.texinfo_cross_references = False
|
||||||
|
app.builder.build_all()
|
||||||
|
output = (app.outdir / 'sphinxtests.texi').read_text()
|
||||||
|
assert not re.search(r'@ref{\w+,,--plugin\.option}', output)
|
||||||
|
assert 'Link to perl +p, --ObjC++, --plugin.option, create-auth-token, arg and -j' in output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('texinfo', testroot='root')
|
||||||
|
def test_texinfo_samp_with_variable(app, status, warning):
|
||||||
|
app.build()
|
||||||
|
|
||||||
|
output = (app.outdir / 'sphinxtests.texi').read_text()
|
||||||
|
|
||||||
|
assert '@code{@var{variable_only}}' in output
|
||||||
|
assert '@code{@var{variable} and text}' in output
|
||||||
|
assert '@code{Show @var{variable} in the middle}' in output
|
||||||
|
@ -350,6 +350,18 @@ def test_parse_annotation(app):
|
|||||||
assert_node(doctree[0], pending_xref, refdomain="py", reftype="obj", reftarget="None")
|
assert_node(doctree[0], pending_xref, refdomain="py", reftype="obj", reftarget="None")
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_annotation_suppress(app):
|
||||||
|
doctree = _parse_annotation("~typing.Dict[str, str]", app.env)
|
||||||
|
assert_node(doctree, ([pending_xref, "Dict"],
|
||||||
|
[desc_sig_punctuation, "["],
|
||||||
|
[pending_xref, "str"],
|
||||||
|
[desc_sig_punctuation, ","],
|
||||||
|
desc_sig_space,
|
||||||
|
[pending_xref, "str"],
|
||||||
|
[desc_sig_punctuation, "]"]))
|
||||||
|
assert_node(doctree[0], pending_xref, refdomain="py", reftype="class", reftarget="typing.Dict")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
||||||
def test_parse_annotation_Literal(app):
|
def test_parse_annotation_Literal(app):
|
||||||
doctree = _parse_annotation("Literal[True, False]", app.env)
|
doctree = _parse_annotation("Literal[True, False]", app.env)
|
||||||
|
@ -1142,6 +1142,99 @@ def test_autodoc_typehints_description_and_type_aliases(app):
|
|||||||
' myint\n' == context)
|
' myint\n' == context)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('html', testroot='ext-autodoc',
|
||||||
|
confoverrides={'autodoc_unqualified_typehints': True})
|
||||||
|
def test_autodoc_unqualified_typehints(app):
|
||||||
|
if sys.version_info < (3, 7):
|
||||||
|
Any = 'Any'
|
||||||
|
else:
|
||||||
|
Any = '~typing.Any'
|
||||||
|
|
||||||
|
options = {"members": None,
|
||||||
|
"undoc-members": None}
|
||||||
|
actual = do_autodoc(app, 'module', 'target.typehints', options)
|
||||||
|
assert list(actual) == [
|
||||||
|
'',
|
||||||
|
'.. py:module:: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:data:: CONST1',
|
||||||
|
' :module: target.typehints',
|
||||||
|
' :type: int',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:class:: Math(s: str, o: ~typing.Optional[%s] = None)' % Any,
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
' .. py:attribute:: Math.CONST1',
|
||||||
|
' :module: target.typehints',
|
||||||
|
' :type: int',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
' .. py:attribute:: Math.CONST2',
|
||||||
|
' :module: target.typehints',
|
||||||
|
' :type: int',
|
||||||
|
' :value: 1',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
' .. py:method:: Math.decr(a: int, b: int = 1) -> int',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
' .. py:method:: Math.horse(a: str, b: int) -> None',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
' .. py:method:: Math.incr(a: int, b: int = 1) -> int',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
' .. py:method:: Math.nothing() -> None',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
' .. py:property:: Math.prop',
|
||||||
|
' :module: target.typehints',
|
||||||
|
' :type: int',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:class:: NewAnnotation(i: int)',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:class:: NewComment(i: int)',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:class:: SignatureFromMetaclass(a: int)',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:function:: complex_func(arg1: str, arg2: List[int], arg3: Tuple[int, '
|
||||||
|
'Union[str, Unknown]] = None, *args: str, **kwargs: str) -> None',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:function:: decr(a: int, b: int = 1) -> int',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:function:: incr(a: int, b: int = 1) -> int',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:function:: missing_attr(c, a: str, b: Optional[str] = None) -> str',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'.. py:function:: tuple_args(x: ~typing.Tuple[int, ~typing.Union[int, str]]) '
|
||||||
|
'-> ~typing.Tuple[int, int]',
|
||||||
|
' :module: target.typehints',
|
||||||
|
'',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||||
def test_autodoc_default_options(app):
|
def test_autodoc_default_options(app):
|
||||||
# no settings
|
# no settings
|
||||||
|
@ -259,6 +259,10 @@ def test_signature_annotations():
|
|||||||
sig = inspect.signature(f7)
|
sig = inspect.signature(f7)
|
||||||
assert stringify_signature(sig, show_return_annotation=False) == '(x: Optional[int] = None, y: dict = {})'
|
assert stringify_signature(sig, show_return_annotation=False) == '(x: Optional[int] = None, y: dict = {})'
|
||||||
|
|
||||||
|
# unqualified_typehints is True
|
||||||
|
sig = inspect.signature(f7)
|
||||||
|
assert stringify_signature(sig, unqualified_typehints=True) == '(x: ~typing.Optional[int] = None, y: dict = {}) -> None'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
||||||
@pytest.mark.sphinx(testroot='ext-autodoc')
|
@pytest.mark.sphinx(testroot='ext-autodoc')
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
@ -318,8 +316,6 @@ def test_colored_logs(app, status, warning):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail(os.name != 'posix', reason="Not working on windows")
|
@pytest.mark.xfail(os.name != 'posix', reason="Not working on windows")
|
||||||
@pytest.mark.xfail(platform.system() == 'Darwin' and sys.version_info > (3, 8),
|
|
||||||
reason="Not working on macOS and py38")
|
|
||||||
def test_logging_in_ParallelTasks(app, status, warning):
|
def test_logging_in_ParallelTasks(app, status, warning):
|
||||||
logging.setup(app, status, warning)
|
logging.setup(app, status, warning)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -178,78 +178,156 @@ def test_restify_mock():
|
|||||||
|
|
||||||
|
|
||||||
def test_stringify():
|
def test_stringify():
|
||||||
assert stringify(int) == "int"
|
assert stringify(int, False) == "int"
|
||||||
assert stringify(str) == "str"
|
assert stringify(int, True) == "int"
|
||||||
assert stringify(None) == "None"
|
|
||||||
assert stringify(Integral) == "numbers.Integral"
|
assert stringify(str, False) == "str"
|
||||||
assert stringify(Struct) == "struct.Struct"
|
assert stringify(str, True) == "str"
|
||||||
assert stringify(TracebackType) == "types.TracebackType"
|
|
||||||
assert stringify(Any) == "Any"
|
assert stringify(None, False) == "None"
|
||||||
|
assert stringify(None, True) == "None"
|
||||||
|
|
||||||
|
assert stringify(Integral, False) == "numbers.Integral"
|
||||||
|
assert stringify(Integral, True) == "~numbers.Integral"
|
||||||
|
|
||||||
|
assert stringify(Struct, False) == "struct.Struct"
|
||||||
|
assert stringify(Struct, True) == "~struct.Struct"
|
||||||
|
|
||||||
|
assert stringify(TracebackType, False) == "types.TracebackType"
|
||||||
|
assert stringify(TracebackType, True) == "~types.TracebackType"
|
||||||
|
|
||||||
|
assert stringify(Any, False) == "Any"
|
||||||
|
assert stringify(Any, True) == "~typing.Any"
|
||||||
|
|
||||||
|
|
||||||
def test_stringify_type_hints_containers():
|
def test_stringify_type_hints_containers():
|
||||||
assert stringify(List) == "List"
|
assert stringify(List, False) == "List"
|
||||||
assert stringify(Dict) == "Dict"
|
assert stringify(List, True) == "~typing.List"
|
||||||
assert stringify(List[int]) == "List[int]"
|
|
||||||
assert stringify(List[str]) == "List[str]"
|
assert stringify(Dict, False) == "Dict"
|
||||||
assert stringify(Dict[str, float]) == "Dict[str, float]"
|
assert stringify(Dict, True) == "~typing.Dict"
|
||||||
assert stringify(Tuple[str, str, str]) == "Tuple[str, str, str]"
|
|
||||||
assert stringify(Tuple[str, ...]) == "Tuple[str, ...]"
|
assert stringify(List[int], False) == "List[int]"
|
||||||
assert stringify(Tuple[()]) == "Tuple[()]"
|
assert stringify(List[int], True) == "~typing.List[int]"
|
||||||
assert stringify(List[Dict[str, Tuple]]) == "List[Dict[str, Tuple]]"
|
|
||||||
assert stringify(MyList[Tuple[int, int]]) == "tests.test_util_typing.MyList[Tuple[int, int]]"
|
assert stringify(List[str], False) == "List[str]"
|
||||||
assert stringify(Generator[None, None, None]) == "Generator[None, None, None]"
|
assert stringify(List[str], True) == "~typing.List[str]"
|
||||||
|
|
||||||
|
assert stringify(Dict[str, float], False) == "Dict[str, float]"
|
||||||
|
assert stringify(Dict[str, float], True) == "~typing.Dict[str, float]"
|
||||||
|
|
||||||
|
assert stringify(Tuple[str, str, str], False) == "Tuple[str, str, str]"
|
||||||
|
assert stringify(Tuple[str, str, str], True) == "~typing.Tuple[str, str, str]"
|
||||||
|
|
||||||
|
assert stringify(Tuple[str, ...], False) == "Tuple[str, ...]"
|
||||||
|
assert stringify(Tuple[str, ...], True) == "~typing.Tuple[str, ...]"
|
||||||
|
|
||||||
|
assert stringify(Tuple[()], False) == "Tuple[()]"
|
||||||
|
assert stringify(Tuple[()], True) == "~typing.Tuple[()]"
|
||||||
|
|
||||||
|
assert stringify(List[Dict[str, Tuple]], False) == "List[Dict[str, Tuple]]"
|
||||||
|
assert stringify(List[Dict[str, Tuple]], True) == "~typing.List[~typing.Dict[str, ~typing.Tuple]]"
|
||||||
|
|
||||||
|
assert stringify(MyList[Tuple[int, int]], False) == "tests.test_util_typing.MyList[Tuple[int, int]]"
|
||||||
|
assert stringify(MyList[Tuple[int, int]], True) == "~tests.test_util_typing.MyList[~typing.Tuple[int, int]]"
|
||||||
|
|
||||||
|
assert stringify(Generator[None, None, None], False) == "Generator[None, None, None]"
|
||||||
|
assert stringify(Generator[None, None, None], True) == "~typing.Generator[None, None, None]"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info < (3, 9), reason='python 3.9+ is required.')
|
@pytest.mark.skipif(sys.version_info < (3, 9), reason='python 3.9+ is required.')
|
||||||
def test_stringify_type_hints_pep_585():
|
def test_stringify_type_hints_pep_585():
|
||||||
assert stringify(list[int]) == "list[int]"
|
assert stringify(list[int], False) == "list[int]"
|
||||||
assert stringify(list[str]) == "list[str]"
|
assert stringify(list[int], True) == "list[int]"
|
||||||
assert stringify(dict[str, float]) == "dict[str, float]"
|
|
||||||
assert stringify(tuple[str, str, str]) == "tuple[str, str, str]"
|
assert stringify(list[str], False) == "list[str]"
|
||||||
assert stringify(tuple[str, ...]) == "tuple[str, ...]"
|
assert stringify(list[str], True) == "list[str]"
|
||||||
assert stringify(tuple[()]) == "tuple[()]"
|
|
||||||
assert stringify(list[dict[str, tuple]]) == "list[dict[str, tuple]]"
|
assert stringify(dict[str, float], False) == "dict[str, float]"
|
||||||
assert stringify(type[int]) == "type[int]"
|
assert stringify(dict[str, float], True) == "dict[str, float]"
|
||||||
|
|
||||||
|
assert stringify(tuple[str, str, str], False) == "tuple[str, str, str]"
|
||||||
|
assert stringify(tuple[str, str, str], True) == "tuple[str, str, str]"
|
||||||
|
|
||||||
|
assert stringify(tuple[str, ...], False) == "tuple[str, ...]"
|
||||||
|
assert stringify(tuple[str, ...], True) == "tuple[str, ...]"
|
||||||
|
|
||||||
|
assert stringify(tuple[()], False) == "tuple[()]"
|
||||||
|
assert stringify(tuple[()], True) == "tuple[()]"
|
||||||
|
|
||||||
|
assert stringify(list[dict[str, tuple]], False) == "list[dict[str, tuple]]"
|
||||||
|
assert stringify(list[dict[str, tuple]], True) == "list[dict[str, tuple]]"
|
||||||
|
|
||||||
|
assert stringify(type[int], False) == "type[int]"
|
||||||
|
assert stringify(type[int], True) == "type[int]"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info < (3, 9), reason='python 3.9+ is required.')
|
@pytest.mark.skipif(sys.version_info < (3, 9), reason='python 3.9+ is required.')
|
||||||
def test_stringify_Annotated():
|
def test_stringify_Annotated():
|
||||||
from typing import Annotated # type: ignore
|
from typing import Annotated # type: ignore
|
||||||
assert stringify(Annotated[str, "foo", "bar"]) == "str" # NOQA
|
assert stringify(Annotated[str, "foo", "bar"], False) == "str" # NOQA
|
||||||
|
assert stringify(Annotated[str, "foo", "bar"], True) == "str" # NOQA
|
||||||
|
|
||||||
|
|
||||||
def test_stringify_type_hints_string():
|
def test_stringify_type_hints_string():
|
||||||
assert stringify("int") == "int"
|
assert stringify("int", False) == "int"
|
||||||
assert stringify("str") == "str"
|
assert stringify("int", True) == "int"
|
||||||
assert stringify(List["int"]) == "List[int]"
|
|
||||||
assert stringify("Tuple[str]") == "Tuple[str]"
|
assert stringify("str", False) == "str"
|
||||||
assert stringify("unknown") == "unknown"
|
assert stringify("str", True) == "str"
|
||||||
|
|
||||||
|
assert stringify(List["int"], False) == "List[int]"
|
||||||
|
assert stringify(List["int"], True) == "~typing.List[int]"
|
||||||
|
|
||||||
|
assert stringify("Tuple[str]", False) == "Tuple[str]"
|
||||||
|
assert stringify("Tuple[str]", True) == "Tuple[str]"
|
||||||
|
|
||||||
|
assert stringify("unknown", False) == "unknown"
|
||||||
|
assert stringify("unknown", True) == "unknown"
|
||||||
|
|
||||||
|
|
||||||
def test_stringify_type_hints_Callable():
|
def test_stringify_type_hints_Callable():
|
||||||
assert stringify(Callable) == "Callable"
|
assert stringify(Callable, False) == "Callable"
|
||||||
|
assert stringify(Callable, True) == "~typing.Callable"
|
||||||
|
|
||||||
if sys.version_info >= (3, 7):
|
if sys.version_info >= (3, 7):
|
||||||
assert stringify(Callable[[str], int]) == "Callable[[str], int]"
|
assert stringify(Callable[[str], int], False) == "Callable[[str], int]"
|
||||||
assert stringify(Callable[..., int]) == "Callable[[...], int]"
|
assert stringify(Callable[[str], int], True) == "~typing.Callable[[str], int]"
|
||||||
|
|
||||||
|
assert stringify(Callable[..., int], False) == "Callable[[...], int]"
|
||||||
|
assert stringify(Callable[..., int], True) == "~typing.Callable[[...], int]"
|
||||||
else:
|
else:
|
||||||
assert stringify(Callable[[str], int]) == "Callable[str, int]"
|
assert stringify(Callable[[str], int], False) == "Callable[str, int]"
|
||||||
assert stringify(Callable[..., int]) == "Callable[..., int]"
|
assert stringify(Callable[[str], int], True) == "~typing.Callable[str, int]"
|
||||||
|
|
||||||
|
assert stringify(Callable[..., int], False) == "Callable[..., int]"
|
||||||
|
assert stringify(Callable[..., int], True) == "~typing.Callable[..., int]"
|
||||||
|
|
||||||
|
|
||||||
def test_stringify_type_hints_Union():
|
def test_stringify_type_hints_Union():
|
||||||
assert stringify(Optional[int]) == "Optional[int]"
|
assert stringify(Optional[int], False) == "Optional[int]"
|
||||||
assert stringify(Union[str, None]) == "Optional[str]"
|
assert stringify(Optional[int], True) == "~typing.Optional[int]"
|
||||||
assert stringify(Union[int, str]) == "Union[int, str]"
|
|
||||||
|
assert stringify(Union[str, None], False) == "Optional[str]"
|
||||||
|
assert stringify(Union[str, None], True) == "~typing.Optional[str]"
|
||||||
|
|
||||||
|
assert stringify(Union[int, str], False) == "Union[int, str]"
|
||||||
|
assert stringify(Union[int, str], True) == "~typing.Union[int, str]"
|
||||||
|
|
||||||
if sys.version_info >= (3, 7):
|
if sys.version_info >= (3, 7):
|
||||||
assert stringify(Union[int, Integral]) == "Union[int, numbers.Integral]"
|
assert stringify(Union[int, Integral], False) == "Union[int, numbers.Integral]"
|
||||||
assert (stringify(Union[MyClass1, MyClass2]) ==
|
assert stringify(Union[int, Integral], True) == "~typing.Union[int, ~numbers.Integral]"
|
||||||
|
|
||||||
|
assert (stringify(Union[MyClass1, MyClass2], False) ==
|
||||||
"Union[tests.test_util_typing.MyClass1, tests.test_util_typing.<MyClass2>]")
|
"Union[tests.test_util_typing.MyClass1, tests.test_util_typing.<MyClass2>]")
|
||||||
|
assert (stringify(Union[MyClass1, MyClass2], True) ==
|
||||||
|
"~typing.Union[~tests.test_util_typing.MyClass1, ~tests.test_util_typing.<MyClass2>]")
|
||||||
else:
|
else:
|
||||||
assert stringify(Union[int, Integral]) == "numbers.Integral"
|
assert stringify(Union[int, Integral], False) == "numbers.Integral"
|
||||||
assert stringify(Union[MyClass1, MyClass2]) == "tests.test_util_typing.MyClass1"
|
assert stringify(Union[int, Integral], True) == "~numbers.Integral"
|
||||||
|
|
||||||
|
assert stringify(Union[MyClass1, MyClass2], False) == "tests.test_util_typing.MyClass1"
|
||||||
|
assert stringify(Union[MyClass1, MyClass2], True) == "~tests.test_util_typing.MyClass1"
|
||||||
|
|
||||||
|
|
||||||
def test_stringify_type_hints_typevars():
|
def test_stringify_type_hints_typevars():
|
||||||
@ -258,52 +336,83 @@ def test_stringify_type_hints_typevars():
|
|||||||
T_contra = TypeVar('T_contra', contravariant=True)
|
T_contra = TypeVar('T_contra', contravariant=True)
|
||||||
|
|
||||||
if sys.version_info < (3, 7):
|
if sys.version_info < (3, 7):
|
||||||
assert stringify(T) == "T"
|
assert stringify(T, False) == "T"
|
||||||
assert stringify(T_co) == "T_co"
|
assert stringify(T, True) == "T"
|
||||||
assert stringify(T_contra) == "T_contra"
|
|
||||||
assert stringify(List[T]) == "List[T]"
|
assert stringify(T_co, False) == "T_co"
|
||||||
|
assert stringify(T_co, True) == "T_co"
|
||||||
|
|
||||||
|
assert stringify(T_contra, False) == "T_contra"
|
||||||
|
assert stringify(T_contra, True) == "T_contra"
|
||||||
|
|
||||||
|
assert stringify(List[T], False) == "List[T]"
|
||||||
|
assert stringify(List[T], True) == "~typing.List[T]"
|
||||||
else:
|
else:
|
||||||
assert stringify(T) == "tests.test_util_typing.T"
|
assert stringify(T, False) == "tests.test_util_typing.T"
|
||||||
assert stringify(T_co) == "tests.test_util_typing.T_co"
|
assert stringify(T, True) == "~tests.test_util_typing.T"
|
||||||
assert stringify(T_contra) == "tests.test_util_typing.T_contra"
|
|
||||||
assert stringify(List[T]) == "List[tests.test_util_typing.T]"
|
assert stringify(T_co, False) == "tests.test_util_typing.T_co"
|
||||||
|
assert stringify(T_co, True) == "~tests.test_util_typing.T_co"
|
||||||
|
|
||||||
|
assert stringify(T_contra, False) == "tests.test_util_typing.T_contra"
|
||||||
|
assert stringify(T_contra, True) == "~tests.test_util_typing.T_contra"
|
||||||
|
|
||||||
|
assert stringify(List[T], False) == "List[tests.test_util_typing.T]"
|
||||||
|
assert stringify(List[T], True) == "~typing.List[~tests.test_util_typing.T]"
|
||||||
|
|
||||||
if sys.version_info >= (3, 10):
|
if sys.version_info >= (3, 10):
|
||||||
assert stringify(MyInt) == "tests.test_util_typing.MyInt"
|
assert stringify(MyInt, False) == "tests.test_util_typing.MyInt"
|
||||||
|
assert stringify(MyInt, True) == "~tests.test_util_typing.MyInt"
|
||||||
else:
|
else:
|
||||||
assert stringify(MyInt) == "MyInt"
|
assert stringify(MyInt, False) == "MyInt"
|
||||||
|
assert stringify(MyInt, True) == "MyInt"
|
||||||
|
|
||||||
|
|
||||||
def test_stringify_type_hints_custom_class():
|
def test_stringify_type_hints_custom_class():
|
||||||
assert stringify(MyClass1) == "tests.test_util_typing.MyClass1"
|
assert stringify(MyClass1, False) == "tests.test_util_typing.MyClass1"
|
||||||
assert stringify(MyClass2) == "tests.test_util_typing.<MyClass2>"
|
assert stringify(MyClass1, True) == "~tests.test_util_typing.MyClass1"
|
||||||
|
|
||||||
|
assert stringify(MyClass2, False) == "tests.test_util_typing.<MyClass2>"
|
||||||
|
assert stringify(MyClass2, True) == "~tests.test_util_typing.<MyClass2>"
|
||||||
|
|
||||||
|
|
||||||
def test_stringify_type_hints_alias():
|
def test_stringify_type_hints_alias():
|
||||||
MyStr = str
|
MyStr = str
|
||||||
MyTuple = Tuple[str, str]
|
MyTuple = Tuple[str, str]
|
||||||
assert stringify(MyStr) == "str"
|
|
||||||
assert stringify(MyTuple) == "Tuple[str, str]" # type: ignore
|
assert stringify(MyStr, False) == "str"
|
||||||
|
assert stringify(MyStr, True) == "str"
|
||||||
|
|
||||||
|
assert stringify(MyTuple, False) == "Tuple[str, str]" # type: ignore
|
||||||
|
assert stringify(MyTuple, True) == "~typing.Tuple[str, str]" # type: ignore
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
@pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.')
|
||||||
def test_stringify_type_Literal():
|
def test_stringify_type_Literal():
|
||||||
from typing import Literal # type: ignore
|
from typing import Literal # type: ignore
|
||||||
assert stringify(Literal[1, "2", "\r"]) == "Literal[1, '2', '\\r']"
|
assert stringify(Literal[1, "2", "\r"], False) == "Literal[1, '2', '\\r']"
|
||||||
|
assert stringify(Literal[1, "2", "\r"], True) == "~typing.Literal[1, '2', '\\r']"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info < (3, 10), reason='python 3.10+ is required.')
|
@pytest.mark.skipif(sys.version_info < (3, 10), reason='python 3.10+ is required.')
|
||||||
def test_stringify_type_union_operator():
|
def test_stringify_type_union_operator():
|
||||||
assert stringify(int | None) == "int | None" # type: ignore
|
assert stringify(int | None, False) == "int | None" # type: ignore
|
||||||
assert stringify(int | str) == "int | str" # type: ignore
|
assert stringify(int | None, True) == "int | None" # type: ignore
|
||||||
assert stringify(int | str | None) == "int | str | None" # type: ignore
|
|
||||||
|
assert stringify(int | str, False) == "int | str" # type: ignore
|
||||||
|
assert stringify(int | str, True) == "int | str" # type: ignore
|
||||||
|
|
||||||
|
assert stringify(int | str | None, False) == "int | str | None" # type: ignore
|
||||||
|
assert stringify(int | str | None, True) == "int | str | None" # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def test_stringify_broken_type_hints():
|
def test_stringify_broken_type_hints():
|
||||||
assert stringify(BrokenType) == 'tests.test_util_typing.BrokenType'
|
assert stringify(BrokenType, False) == 'tests.test_util_typing.BrokenType'
|
||||||
|
assert stringify(BrokenType, True) == '~tests.test_util_typing.BrokenType'
|
||||||
|
|
||||||
|
|
||||||
def test_stringify_mock():
|
def test_stringify_mock():
|
||||||
with mock(['unknown']):
|
with mock(['unknown']):
|
||||||
import unknown
|
import unknown
|
||||||
assert stringify(unknown.secret.Class) == 'unknown.secret.Class'
|
assert stringify(unknown.secret.Class, False) == 'unknown.secret.Class'
|
||||||
|
assert stringify(unknown.secret.Class, True) == 'unknown.secret.Class'
|
||||||
|
2
tox.ini
2
tox.ini
@ -64,7 +64,7 @@ basepython = python3
|
|||||||
description =
|
description =
|
||||||
Run code coverage checks.
|
Run code coverage checks.
|
||||||
setenv =
|
setenv =
|
||||||
PYTEST_ADDOPTS = --cov sphinx --cov-config {toxinidir}/setup.cfg
|
PYTEST_ADDOPTS = --cov sphinx --cov-config "{toxinidir}/setup.cfg"
|
||||||
commands =
|
commands =
|
||||||
{[testenv]commands}
|
{[testenv]commands}
|
||||||
coverage report
|
coverage report
|
||||||
|
Loading…
Reference in New Issue
Block a user