mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Use PEP 604 display for `typing.Optional and typing.Union` (#11072)
This commit is contained in:
@@ -22,6 +22,11 @@ The following is a list of deprecated interfaces.
|
||||
- Removed
|
||||
- Alternatives
|
||||
|
||||
* - ``sphinx.util.typing.stringify``
|
||||
- 6.1
|
||||
- 8.0
|
||||
- ``sphinx.util.typing.stringify_annotation``
|
||||
|
||||
* - HTML 4 support
|
||||
- 5.2
|
||||
- 7.0
|
||||
|
||||
@@ -176,6 +176,8 @@ def _parse_annotation(annotation: str, env: BuildEnvironment) -> list[Node]:
|
||||
elif isinstance(node, ast.Name):
|
||||
return [nodes.Text(node.id)]
|
||||
elif isinstance(node, ast.Subscript):
|
||||
if getattr(node.value, 'id', '') in {'Optional', 'Union'}:
|
||||
return _unparse_pep_604_annotation(node)
|
||||
result = unparse(node.value)
|
||||
result.append(addnodes.desc_sig_punctuation('', '['))
|
||||
result.extend(unparse(node.slice))
|
||||
@@ -206,6 +208,28 @@ def _parse_annotation(annotation: str, env: BuildEnvironment) -> list[Node]:
|
||||
else:
|
||||
raise SyntaxError # unsupported syntax
|
||||
|
||||
def _unparse_pep_604_annotation(node: ast.Subscript) -> list[Node]:
|
||||
subscript = node.slice
|
||||
if isinstance(subscript, ast.Index):
|
||||
# py38 only
|
||||
subscript = subscript.value # type: ignore[assignment]
|
||||
|
||||
flattened: list[Node] = []
|
||||
if isinstance(subscript, ast.Tuple):
|
||||
flattened.extend(unparse(subscript.elts[0]))
|
||||
for elt in subscript.elts[1:]:
|
||||
flattened.extend(unparse(ast.BitOr()))
|
||||
flattened.extend(unparse(elt))
|
||||
else:
|
||||
# e.g. a Union[] inside an Optional[]
|
||||
flattened.extend(unparse(subscript))
|
||||
|
||||
if getattr(node.value, 'id', '') == 'Optional':
|
||||
flattened.extend(unparse(ast.BitOr()))
|
||||
flattened.append(nodes.Text('None'))
|
||||
|
||||
return flattened
|
||||
|
||||
try:
|
||||
tree = ast.parse(annotation, type_comments=True)
|
||||
result: list[Node] = []
|
||||
|
||||
@@ -27,8 +27,7 @@ from sphinx.util import inspect, logging
|
||||
from sphinx.util.docstrings import prepare_docstring, separate_metadata
|
||||
from sphinx.util.inspect import (evaluate_signature, getdoc, object_description, safe_getattr,
|
||||
stringify_signature)
|
||||
from sphinx.util.typing import OptionSpec, get_type_hints, restify
|
||||
from sphinx.util.typing import stringify as stringify_typehint
|
||||
from sphinx.util.typing import OptionSpec, get_type_hints, restify, stringify_annotation
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.ext.autodoc.directive import DocumenterBridge
|
||||
@@ -1902,9 +1901,10 @@ class TypeVarMixin(DataDocumenterMixinBase):
|
||||
attrs = [repr(self.object.__name__)]
|
||||
for constraint in self.object.__constraints__:
|
||||
if self.config.autodoc_typehints_format == "short":
|
||||
attrs.append(stringify_typehint(constraint, "smart"))
|
||||
attrs.append(stringify_annotation(constraint, "smart"))
|
||||
else:
|
||||
attrs.append(stringify_typehint(constraint))
|
||||
attrs.append(stringify_annotation(constraint,
|
||||
"fully-qualified-except-typing"))
|
||||
if self.object.__bound__:
|
||||
if self.config.autodoc_typehints_format == "short":
|
||||
bound = restify(self.object.__bound__, "smart")
|
||||
@@ -2027,10 +2027,11 @@ class DataDocumenter(GenericAliasMixin, NewTypeMixin, TypeVarMixin,
|
||||
self.config.autodoc_type_aliases)
|
||||
if self.objpath[-1] in annotations:
|
||||
if self.config.autodoc_typehints_format == "short":
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]),
|
||||
"smart")
|
||||
objrepr = stringify_annotation(annotations.get(self.objpath[-1]),
|
||||
"smart")
|
||||
else:
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]))
|
||||
objrepr = stringify_annotation(annotations.get(self.objpath[-1]),
|
||||
"fully-qualified-except-typing")
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
|
||||
try:
|
||||
@@ -2616,10 +2617,11 @@ class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type:
|
||||
self.config.autodoc_type_aliases)
|
||||
if self.objpath[-1] in annotations:
|
||||
if self.config.autodoc_typehints_format == "short":
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]),
|
||||
"smart")
|
||||
objrepr = stringify_annotation(annotations.get(self.objpath[-1]),
|
||||
"smart")
|
||||
else:
|
||||
objrepr = stringify_typehint(annotations.get(self.objpath[-1]))
|
||||
objrepr = stringify_annotation(annotations.get(self.objpath[-1]),
|
||||
"fully-qualified-except-typing")
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
|
||||
try:
|
||||
@@ -2744,9 +2746,10 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
|
||||
type_aliases=self.config.autodoc_type_aliases)
|
||||
if signature.return_annotation is not Parameter.empty:
|
||||
if self.config.autodoc_typehints_format == "short":
|
||||
objrepr = stringify_typehint(signature.return_annotation, "smart")
|
||||
objrepr = stringify_annotation(signature.return_annotation, "smart")
|
||||
else:
|
||||
objrepr = stringify_typehint(signature.return_annotation)
|
||||
objrepr = stringify_annotation(signature.return_annotation,
|
||||
"fully-qualified-except-typing")
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
except TypeError as exc:
|
||||
logger.warning(__("Failed to get a function signature for %s: %s"),
|
||||
|
||||
@@ -12,7 +12,8 @@ from docutils.nodes import Element
|
||||
import sphinx
|
||||
from sphinx import addnodes
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.util import inspect, typing
|
||||
from sphinx.util import inspect
|
||||
from sphinx.util.typing import stringify_annotation
|
||||
|
||||
|
||||
def record_typehints(app: Sphinx, objtype: str, name: str, obj: Any,
|
||||
@@ -30,9 +31,9 @@ def record_typehints(app: Sphinx, objtype: str, name: str, obj: Any,
|
||||
sig = inspect.signature(obj, type_aliases=app.config.autodoc_type_aliases)
|
||||
for param in sig.parameters.values():
|
||||
if param.annotation is not param.empty:
|
||||
annotation[param.name] = typing.stringify(param.annotation, mode)
|
||||
annotation[param.name] = stringify_annotation(param.annotation, mode)
|
||||
if sig.return_annotation is not sig.empty:
|
||||
annotation['return'] = typing.stringify(sig.return_annotation, mode)
|
||||
annotation['return'] = stringify_annotation(sig.return_annotation, mode)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ from sphinx.application import Sphinx
|
||||
from sphinx.config import Config as SphinxConfig
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.inspect import stringify_annotation
|
||||
from sphinx.util.typing import get_type_hints
|
||||
from sphinx.util.typing import get_type_hints, stringify_annotation
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -876,7 +875,8 @@ class GoogleDocstring:
|
||||
) or {})
|
||||
self._annotations = get_type_hints(self._obj, None, localns)
|
||||
if _name in self._annotations:
|
||||
return stringify_annotation(self._annotations[_name])
|
||||
return stringify_annotation(self._annotations[_name],
|
||||
'fully-qualified-except-typing')
|
||||
# No annotation found
|
||||
return ""
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ from typing import Any, Callable, Dict, Mapping, Sequence, cast
|
||||
|
||||
from sphinx.pycode.ast import unparse as ast_unparse
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.typing import ForwardRef
|
||||
from sphinx.util.typing import stringify as stringify_annotation
|
||||
from sphinx.util.typing import ForwardRef, stringify_annotation
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ from typing import Any, Callable, Dict, ForwardRef, List, Tuple, TypeVar, Union
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.states import Inliner
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx80Warning, deprecated_alias
|
||||
|
||||
try:
|
||||
from types import UnionType # type: ignore # python 3.10 or above
|
||||
except ImportError:
|
||||
@@ -205,9 +207,14 @@ def restify(cls: type | None, mode: str = 'fully-qualified-except-typing') -> st
|
||||
return inspect.object_description(cls)
|
||||
|
||||
|
||||
def stringify(annotation: Any, mode: str = 'fully-qualified-except-typing') -> str:
|
||||
def stringify_annotation(
|
||||
annotation: Any,
|
||||
/,
|
||||
mode: str = 'fully-qualified-except-typing',
|
||||
) -> str:
|
||||
"""Stringify type annotation object.
|
||||
|
||||
:param annotation: The annotation to stringified.
|
||||
:param mode: Specify a method how annotations will be stringified.
|
||||
|
||||
'fully-qualified-except-typing'
|
||||
@@ -219,12 +226,20 @@ def stringify(annotation: Any, mode: str = 'fully-qualified-except-typing') -> s
|
||||
Show the module name and qualified name of the annotation.
|
||||
"""
|
||||
from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading
|
||||
from sphinx.util import inspect # lazy loading
|
||||
from sphinx.util.inspect import isNewType # lazy loading
|
||||
|
||||
if mode not in {'fully-qualified-except-typing', 'fully-qualified', 'smart'}:
|
||||
raise ValueError("'mode' must be one of 'fully-qualified-except-typing', "
|
||||
f"'fully-qualified', or 'smart'; got {mode!r}.")
|
||||
|
||||
if mode == 'smart':
|
||||
modprefix = '~'
|
||||
module_prefix = '~'
|
||||
else:
|
||||
modprefix = ''
|
||||
module_prefix = ''
|
||||
|
||||
annotation_qualname = getattr(annotation, '__qualname__', '')
|
||||
annotation_module = getattr(annotation, '__module__', '')
|
||||
annotation_name = getattr(annotation, '__name__', '')
|
||||
|
||||
if isinstance(annotation, str):
|
||||
if annotation.startswith("'") and annotation.endswith("'"):
|
||||
@@ -233,104 +248,105 @@ def stringify(annotation: Any, mode: str = 'fully-qualified-except-typing') -> s
|
||||
else:
|
||||
return annotation
|
||||
elif isinstance(annotation, TypeVar):
|
||||
if (annotation.__module__ == 'typing' and
|
||||
mode in ('fully-qualified-except-typing', 'smart')):
|
||||
return annotation.__name__
|
||||
if (annotation_module == 'typing'
|
||||
and mode in {'fully-qualified-except-typing', 'smart'}):
|
||||
return annotation_name
|
||||
else:
|
||||
return modprefix + '.'.join([annotation.__module__, annotation.__name__])
|
||||
elif inspect.isNewType(annotation):
|
||||
return module_prefix + f'{annotation_module}.{annotation_name}'
|
||||
elif isNewType(annotation):
|
||||
if sys.version_info[:2] >= (3, 10):
|
||||
# newtypes have correct module info since Python 3.10+
|
||||
return modprefix + f'{annotation.__module__}.{annotation.__name__}'
|
||||
return module_prefix + f'{annotation_module}.{annotation_name}'
|
||||
else:
|
||||
return annotation.__name__
|
||||
return annotation_name
|
||||
elif not annotation:
|
||||
return repr(annotation)
|
||||
elif annotation is NoneType:
|
||||
return 'None'
|
||||
elif ismockmodule(annotation):
|
||||
return modprefix + annotation.__name__
|
||||
return module_prefix + annotation_name
|
||||
elif ismock(annotation):
|
||||
return modprefix + f'{annotation.__module__}.{annotation.__name__}'
|
||||
return module_prefix + f'{annotation_module}.{annotation_name}'
|
||||
elif is_invalid_builtin_class(annotation):
|
||||
return modprefix + INVALID_BUILTIN_CLASSES[annotation]
|
||||
return module_prefix + INVALID_BUILTIN_CLASSES[annotation]
|
||||
elif str(annotation).startswith('typing.Annotated'): # for py310+
|
||||
pass
|
||||
elif (getattr(annotation, '__module__', None) == 'builtins' and
|
||||
getattr(annotation, '__qualname__', None)):
|
||||
elif annotation_module == 'builtins' and annotation_qualname:
|
||||
if hasattr(annotation, '__args__'): # PEP 585 generic
|
||||
return repr(annotation)
|
||||
else:
|
||||
return annotation.__qualname__
|
||||
return annotation_qualname
|
||||
elif annotation is Ellipsis:
|
||||
return '...'
|
||||
|
||||
module = getattr(annotation, '__module__', None)
|
||||
modprefix = ''
|
||||
if module == 'typing' and getattr(annotation, '__forward_arg__', None):
|
||||
qualname = annotation.__forward_arg__
|
||||
elif module == 'typing':
|
||||
if getattr(annotation, '_name', None):
|
||||
qualname = annotation._name
|
||||
elif getattr(annotation, '__qualname__', None):
|
||||
qualname = annotation.__qualname__
|
||||
else:
|
||||
qualname = stringify(annotation.__origin__).replace('typing.', '') # ex. Union
|
||||
|
||||
module_prefix = ''
|
||||
annotation_forward_arg = getattr(annotation, '__forward_arg__', None)
|
||||
if (annotation_qualname
|
||||
or (annotation_module == 'typing' and not annotation_forward_arg)):
|
||||
if mode == 'smart':
|
||||
modprefix = '~%s.' % module
|
||||
module_prefix = f'~{annotation_module}.'
|
||||
elif mode == 'fully-qualified':
|
||||
modprefix = '%s.' % module
|
||||
elif hasattr(annotation, '__qualname__'):
|
||||
if mode == 'smart':
|
||||
modprefix = '~%s.' % module
|
||||
module_prefix = f'{annotation_module}.'
|
||||
elif annotation_module != 'typing' and mode == 'fully-qualified-except-typing':
|
||||
module_prefix = f'{annotation_module}.'
|
||||
|
||||
if annotation_module == 'typing':
|
||||
if annotation_forward_arg:
|
||||
# handle ForwardRefs
|
||||
qualname = annotation_forward_arg
|
||||
else:
|
||||
modprefix = '%s.' % module
|
||||
qualname = annotation.__qualname__
|
||||
_name = getattr(annotation, '_name', '')
|
||||
if _name:
|
||||
qualname = _name
|
||||
elif annotation_qualname:
|
||||
qualname = annotation_qualname
|
||||
else:
|
||||
qualname = stringify_annotation(
|
||||
annotation.__origin__, 'fully-qualified-except-typing'
|
||||
).replace('typing.', '') # ex. Union
|
||||
elif annotation_qualname:
|
||||
qualname = annotation_qualname
|
||||
elif hasattr(annotation, '__origin__'):
|
||||
# instantiated generic provided by a user
|
||||
qualname = stringify(annotation.__origin__, mode)
|
||||
elif UnionType and isinstance(annotation, UnionType): # types.Union (for py3.10+)
|
||||
qualname = 'types.Union'
|
||||
qualname = stringify_annotation(annotation.__origin__, mode)
|
||||
elif UnionType and isinstance(annotation, UnionType): # types.UnionType (for py3.10+)
|
||||
qualname = 'types.UnionType'
|
||||
else:
|
||||
# we weren't able to extract the base type, appending arguments would
|
||||
# only make them appear twice
|
||||
return repr(annotation)
|
||||
|
||||
if getattr(annotation, '__args__', None):
|
||||
if not isinstance(annotation.__args__, (list, tuple)):
|
||||
annotation_args = getattr(annotation, '__args__', None)
|
||||
if annotation_args:
|
||||
if not isinstance(annotation_args, (list, tuple)):
|
||||
# broken __args__ found
|
||||
pass
|
||||
elif qualname in ('Optional', 'Union'):
|
||||
if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType:
|
||||
if len(annotation.__args__) > 2:
|
||||
args = ', '.join(stringify(a, mode) for a in annotation.__args__[:-1])
|
||||
return f'{modprefix}Optional[{modprefix}Union[{args}]]'
|
||||
else:
|
||||
return f'{modprefix}Optional[{stringify(annotation.__args__[0], mode)}]'
|
||||
else:
|
||||
args = ', '.join(stringify(a, mode) for a in annotation.__args__)
|
||||
return f'{modprefix}Union[{args}]'
|
||||
elif qualname == 'types.Union':
|
||||
if len(annotation.__args__) > 1 and None in annotation.__args__:
|
||||
args = ' | '.join(stringify(a) for a in annotation.__args__ if a)
|
||||
return f'{modprefix}Optional[{args}]'
|
||||
else:
|
||||
return ' | '.join(stringify(a) for a in annotation.__args__)
|
||||
elif qualname in {'Optional', 'Union', 'types.UnionType'}:
|
||||
return ' | '.join(stringify_annotation(a, mode) for a in annotation_args)
|
||||
elif qualname == 'Callable':
|
||||
args = ', '.join(stringify(a, mode) for a in annotation.__args__[:-1])
|
||||
returns = stringify(annotation.__args__[-1], mode)
|
||||
return f'{modprefix}{qualname}[[{args}], {returns}]'
|
||||
args = ', '.join(stringify_annotation(a, mode) for a in annotation_args[:-1])
|
||||
returns = stringify_annotation(annotation_args[-1], mode)
|
||||
return f'{module_prefix}Callable[[{args}], {returns}]'
|
||||
elif qualname == 'Literal':
|
||||
args = ', '.join(repr(a) for a in annotation.__args__)
|
||||
return f'{modprefix}{qualname}[{args}]'
|
||||
args = ', '.join(repr(a) for a in annotation_args)
|
||||
return f'{module_prefix}Literal[{args}]'
|
||||
elif str(annotation).startswith('typing.Annotated'): # for py39+
|
||||
return stringify(annotation.__args__[0], mode)
|
||||
elif all(is_system_TypeVar(a) for a in annotation.__args__):
|
||||
return stringify_annotation(annotation_args[0], mode)
|
||||
elif all(is_system_TypeVar(a) for a in annotation_args):
|
||||
# Suppress arguments if all system defined TypeVars (ex. Dict[KT, VT])
|
||||
return modprefix + qualname
|
||||
return module_prefix + qualname
|
||||
else:
|
||||
args = ', '.join(stringify(a, mode) for a in annotation.__args__)
|
||||
return f'{modprefix}{qualname}[{args}]'
|
||||
args = ', '.join(stringify_annotation(a, mode) for a in annotation_args)
|
||||
return f'{module_prefix}{qualname}[{args}]'
|
||||
|
||||
return modprefix + qualname
|
||||
return module_prefix + qualname
|
||||
|
||||
|
||||
deprecated_alias(__name__,
|
||||
{
|
||||
'stringify': stringify_annotation,
|
||||
},
|
||||
RemovedInSphinx80Warning,
|
||||
{
|
||||
'stringify': 'sphinx.util.typing.stringify_annotation',
|
||||
})
|
||||
|
||||
@@ -866,10 +866,11 @@ def test_pyattribute(app):
|
||||
assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "attr"],
|
||||
[desc_annotation, ([desc_sig_punctuation, ':'],
|
||||
desc_sig_space,
|
||||
[pending_xref, "Optional"],
|
||||
[desc_sig_punctuation, "["],
|
||||
[pending_xref, "str"],
|
||||
[desc_sig_punctuation, "]"])],
|
||||
desc_sig_space,
|
||||
[desc_sig_punctuation, "|"],
|
||||
desc_sig_space,
|
||||
[pending_xref, "None"])],
|
||||
[desc_annotation, (desc_sig_space,
|
||||
[desc_sig_punctuation, '='],
|
||||
desc_sig_space,
|
||||
@@ -877,7 +878,7 @@ def test_pyattribute(app):
|
||||
)],
|
||||
[desc_content, ()]))
|
||||
assert_node(doctree[1][1][1][0][1][2], pending_xref, **{"py:class": "Class"})
|
||||
assert_node(doctree[1][1][1][0][1][4], pending_xref, **{"py:class": "Class"})
|
||||
assert_node(doctree[1][1][1][0][1][6], pending_xref, **{"py:class": "Class"})
|
||||
assert 'Class.attr' in domain.objects
|
||||
assert domain.objects['Class.attr'] == ('index', 'Class.attr', 'attribute', False)
|
||||
|
||||
|
||||
@@ -808,7 +808,7 @@ def test_autodoc_imported_members(app):
|
||||
"imported-members": None,
|
||||
"ignore-module-all": None}
|
||||
actual = do_autodoc(app, 'module', 'target', options)
|
||||
assert '.. py:function:: function_to_be_imported(app: ~typing.Optional[Sphinx]) -> str' in actual
|
||||
assert '.. py:function:: function_to_be_imported(app: Sphinx | None) -> str' in actual
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
|
||||
@@ -662,7 +662,7 @@ def test_mocked_module_imports(app, warning):
|
||||
confoverrides={'autodoc_typehints': "signature"})
|
||||
def test_autodoc_typehints_signature(app):
|
||||
if sys.version_info[:2] <= (3, 10):
|
||||
type_o = "~typing.Optional[~typing.Any]"
|
||||
type_o = "~typing.Any | None"
|
||||
else:
|
||||
type_o = "~typing.Any"
|
||||
|
||||
@@ -1304,7 +1304,7 @@ def test_autodoc_type_aliases(app):
|
||||
'',
|
||||
'.. py:data:: variable3',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: ~typing.Optional[int]',
|
||||
' :type: int | None',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
@@ -1375,7 +1375,7 @@ def test_autodoc_type_aliases(app):
|
||||
'',
|
||||
'.. py:data:: variable3',
|
||||
' :module: target.autodoc_type_aliases',
|
||||
' :type: ~typing.Optional[myint]',
|
||||
' :type: myint | None',
|
||||
'',
|
||||
' docstring',
|
||||
'',
|
||||
@@ -1409,7 +1409,7 @@ def test_autodoc_typehints_description_and_type_aliases(app):
|
||||
confoverrides={'autodoc_typehints_format': "fully-qualified"})
|
||||
def test_autodoc_typehints_format_fully_qualified(app):
|
||||
if sys.version_info[:2] <= (3, 10):
|
||||
type_o = "typing.Optional[typing.Any]"
|
||||
type_o = "typing.Any | None"
|
||||
else:
|
||||
type_o = "typing.Any"
|
||||
|
||||
|
||||
@@ -15,15 +15,15 @@ import pytest
|
||||
|
||||
from sphinx.util import inspect
|
||||
from sphinx.util.inspect import TypeAliasForwardRef, TypeAliasNamespace, stringify_signature
|
||||
from sphinx.util.typing import stringify
|
||||
from sphinx.util.typing import stringify_annotation
|
||||
|
||||
|
||||
def test_TypeAliasForwardRef():
|
||||
alias = TypeAliasForwardRef('example')
|
||||
assert stringify(alias) == 'example'
|
||||
assert stringify_annotation(alias, 'fully-qualified-except-typing') == 'example'
|
||||
|
||||
alias = Optional[alias]
|
||||
assert stringify(alias) == 'Optional[example]'
|
||||
assert stringify_annotation(alias, 'fully-qualified-except-typing') == 'example | None'
|
||||
|
||||
|
||||
def test_TypeAliasNamespace():
|
||||
@@ -173,7 +173,7 @@ def test_signature_annotations():
|
||||
|
||||
# Union types
|
||||
sig = inspect.signature(f3)
|
||||
assert stringify_signature(sig) == '(x: typing.Union[str, numbers.Integral]) -> None'
|
||||
assert stringify_signature(sig) == '(x: str | numbers.Integral) -> None'
|
||||
|
||||
# Quoted annotations
|
||||
sig = inspect.signature(f4)
|
||||
@@ -190,7 +190,7 @@ def test_signature_annotations():
|
||||
# Space around '=' for defaults
|
||||
sig = inspect.signature(f7)
|
||||
if sys.version_info[:2] <= (3, 10):
|
||||
assert stringify_signature(sig) == '(x: typing.Optional[int] = None, y: dict = {}) -> None'
|
||||
assert stringify_signature(sig) == '(x: int | None = None, y: dict = {}) -> None'
|
||||
else:
|
||||
assert stringify_signature(sig) == '(x: int = None, y: dict = {}) -> None'
|
||||
|
||||
@@ -215,12 +215,12 @@ def test_signature_annotations():
|
||||
|
||||
# optional
|
||||
sig = inspect.signature(f13)
|
||||
assert stringify_signature(sig) == '() -> typing.Optional[str]'
|
||||
assert stringify_signature(sig) == '() -> str | None'
|
||||
|
||||
# optional union
|
||||
sig = inspect.signature(f20)
|
||||
assert stringify_signature(sig) in ('() -> typing.Optional[typing.Union[int, str]]',
|
||||
'() -> typing.Optional[typing.Union[str, int]]')
|
||||
assert stringify_signature(sig) in ('() -> int | str | None',
|
||||
'() -> str | int | None')
|
||||
|
||||
# Any
|
||||
sig = inspect.signature(f14)
|
||||
@@ -239,7 +239,7 @@ def test_signature_annotations():
|
||||
assert stringify_signature(sig) == '(*, arg3, arg4)'
|
||||
|
||||
sig = inspect.signature(f18)
|
||||
assert stringify_signature(sig) == ('(self, arg1: typing.Union[int, typing.Tuple] = 10) -> '
|
||||
assert stringify_signature(sig) == ('(self, arg1: int | typing.Tuple = 10) -> '
|
||||
'typing.List[typing.Dict]')
|
||||
|
||||
# annotations for variadic and keyword parameters
|
||||
@@ -255,7 +255,7 @@ def test_signature_annotations():
|
||||
assert stringify_signature(sig) == '(self) -> typing.List[tests.typing_test_data.Node]'
|
||||
|
||||
sig = inspect.signature(Node.__init__)
|
||||
assert stringify_signature(sig) == '(self, parent: typing.Optional[tests.typing_test_data.Node]) -> None'
|
||||
assert stringify_signature(sig) == '(self, parent: tests.typing_test_data.Node | None) -> None'
|
||||
|
||||
# show_annotation is False
|
||||
sig = inspect.signature(f7)
|
||||
@@ -264,14 +264,14 @@ def test_signature_annotations():
|
||||
# show_return_annotation is False
|
||||
sig = inspect.signature(f7)
|
||||
if sys.version_info[:2] <= (3, 10):
|
||||
assert stringify_signature(sig, show_return_annotation=False) == '(x: typing.Optional[int] = None, y: dict = {})'
|
||||
assert stringify_signature(sig, show_return_annotation=False) == '(x: int | None = None, y: dict = {})'
|
||||
else:
|
||||
assert stringify_signature(sig, show_return_annotation=False) == '(x: int = None, y: dict = {})'
|
||||
|
||||
# unqualified_typehints is True
|
||||
sig = inspect.signature(f7)
|
||||
if sys.version_info[:2] <= (3, 10):
|
||||
assert stringify_signature(sig, unqualified_typehints=True) == '(x: ~typing.Optional[int] = None, y: dict = {}) -> None'
|
||||
assert stringify_signature(sig, unqualified_typehints=True) == '(x: int | None = None, y: dict = {}) -> None'
|
||||
else:
|
||||
assert stringify_signature(sig, unqualified_typehints=True) == '(x: int = None, y: dict = {}) -> None'
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from typing import (Any, Callable, Dict, Generator, List, NewType, Optional, Tup
|
||||
import pytest
|
||||
|
||||
from sphinx.ext.autodoc import mock
|
||||
from sphinx.util.typing import restify, stringify
|
||||
from sphinx.util.typing import restify, stringify_annotation
|
||||
|
||||
|
||||
class MyClass1:
|
||||
@@ -198,169 +198,174 @@ def test_restify_mock():
|
||||
assert restify(unknown.secret.Class, "smart") == ':py:class:`~unknown.secret.Class`'
|
||||
|
||||
|
||||
def test_stringify():
|
||||
assert stringify(int) == "int"
|
||||
assert stringify(int, "smart") == "int"
|
||||
def test_stringify_annotation():
|
||||
assert stringify_annotation(int, 'fully-qualified-except-typing') == "int"
|
||||
assert stringify_annotation(int, "smart") == "int"
|
||||
|
||||
assert stringify(str) == "str"
|
||||
assert stringify(str, "smart") == "str"
|
||||
assert stringify_annotation(str, 'fully-qualified-except-typing') == "str"
|
||||
assert stringify_annotation(str, "smart") == "str"
|
||||
|
||||
assert stringify(None) == "None"
|
||||
assert stringify(None, "smart") == "None"
|
||||
assert stringify_annotation(None, 'fully-qualified-except-typing') == "None"
|
||||
assert stringify_annotation(None, "smart") == "None"
|
||||
|
||||
assert stringify(Integral) == "numbers.Integral"
|
||||
assert stringify(Integral, "smart") == "~numbers.Integral"
|
||||
assert stringify_annotation(Integral, 'fully-qualified-except-typing') == "numbers.Integral"
|
||||
assert stringify_annotation(Integral, "smart") == "~numbers.Integral"
|
||||
|
||||
assert stringify(Struct) == "struct.Struct"
|
||||
assert stringify(Struct, "smart") == "~struct.Struct"
|
||||
assert stringify_annotation(Struct, 'fully-qualified-except-typing') == "struct.Struct"
|
||||
assert stringify_annotation(Struct, "smart") == "~struct.Struct"
|
||||
|
||||
assert stringify(TracebackType) == "types.TracebackType"
|
||||
assert stringify(TracebackType, "smart") == "~types.TracebackType"
|
||||
assert stringify_annotation(TracebackType, 'fully-qualified-except-typing') == "types.TracebackType"
|
||||
assert stringify_annotation(TracebackType, "smart") == "~types.TracebackType"
|
||||
|
||||
assert stringify(Any) == "Any"
|
||||
assert stringify(Any, "fully-qualified") == "typing.Any"
|
||||
assert stringify(Any, "smart") == "~typing.Any"
|
||||
assert stringify_annotation(Any, 'fully-qualified-except-typing') == "Any"
|
||||
assert stringify_annotation(Any, "fully-qualified") == "typing.Any"
|
||||
assert stringify_annotation(Any, "smart") == "~typing.Any"
|
||||
|
||||
|
||||
def test_stringify_type_hints_containers():
|
||||
assert stringify(List) == "List"
|
||||
assert stringify(List, "fully-qualified") == "typing.List"
|
||||
assert stringify(List, "smart") == "~typing.List"
|
||||
assert stringify_annotation(List, 'fully-qualified-except-typing') == "List"
|
||||
assert stringify_annotation(List, "fully-qualified") == "typing.List"
|
||||
assert stringify_annotation(List, "smart") == "~typing.List"
|
||||
|
||||
assert stringify(Dict) == "Dict"
|
||||
assert stringify(Dict, "fully-qualified") == "typing.Dict"
|
||||
assert stringify(Dict, "smart") == "~typing.Dict"
|
||||
assert stringify_annotation(Dict, 'fully-qualified-except-typing') == "Dict"
|
||||
assert stringify_annotation(Dict, "fully-qualified") == "typing.Dict"
|
||||
assert stringify_annotation(Dict, "smart") == "~typing.Dict"
|
||||
|
||||
assert stringify(List[int]) == "List[int]"
|
||||
assert stringify(List[int], "fully-qualified") == "typing.List[int]"
|
||||
assert stringify(List[int], "smart") == "~typing.List[int]"
|
||||
assert stringify_annotation(List[int], 'fully-qualified-except-typing') == "List[int]"
|
||||
assert stringify_annotation(List[int], "fully-qualified") == "typing.List[int]"
|
||||
assert stringify_annotation(List[int], "smart") == "~typing.List[int]"
|
||||
|
||||
assert stringify(List[str]) == "List[str]"
|
||||
assert stringify(List[str], "fully-qualified") == "typing.List[str]"
|
||||
assert stringify(List[str], "smart") == "~typing.List[str]"
|
||||
assert stringify_annotation(List[str], 'fully-qualified-except-typing') == "List[str]"
|
||||
assert stringify_annotation(List[str], "fully-qualified") == "typing.List[str]"
|
||||
assert stringify_annotation(List[str], "smart") == "~typing.List[str]"
|
||||
|
||||
assert stringify(Dict[str, float]) == "Dict[str, float]"
|
||||
assert stringify(Dict[str, float], "fully-qualified") == "typing.Dict[str, float]"
|
||||
assert stringify(Dict[str, float], "smart") == "~typing.Dict[str, float]"
|
||||
assert stringify_annotation(Dict[str, float], 'fully-qualified-except-typing') == "Dict[str, float]"
|
||||
assert stringify_annotation(Dict[str, float], "fully-qualified") == "typing.Dict[str, float]"
|
||||
assert stringify_annotation(Dict[str, float], "smart") == "~typing.Dict[str, float]"
|
||||
|
||||
assert stringify(Tuple[str, str, str]) == "Tuple[str, str, str]"
|
||||
assert stringify(Tuple[str, str, str], "fully-qualified") == "typing.Tuple[str, str, str]"
|
||||
assert stringify(Tuple[str, str, str], "smart") == "~typing.Tuple[str, str, str]"
|
||||
assert stringify_annotation(Tuple[str, str, str], 'fully-qualified-except-typing') == "Tuple[str, str, str]"
|
||||
assert stringify_annotation(Tuple[str, str, str], "fully-qualified") == "typing.Tuple[str, str, str]"
|
||||
assert stringify_annotation(Tuple[str, str, str], "smart") == "~typing.Tuple[str, str, str]"
|
||||
|
||||
assert stringify(Tuple[str, ...]) == "Tuple[str, ...]"
|
||||
assert stringify(Tuple[str, ...], "fully-qualified") == "typing.Tuple[str, ...]"
|
||||
assert stringify(Tuple[str, ...], "smart") == "~typing.Tuple[str, ...]"
|
||||
assert stringify_annotation(Tuple[str, ...], 'fully-qualified-except-typing') == "Tuple[str, ...]"
|
||||
assert stringify_annotation(Tuple[str, ...], "fully-qualified") == "typing.Tuple[str, ...]"
|
||||
assert stringify_annotation(Tuple[str, ...], "smart") == "~typing.Tuple[str, ...]"
|
||||
|
||||
if sys.version_info[:2] <= (3, 10):
|
||||
assert stringify(Tuple[()]) == "Tuple[()]"
|
||||
assert stringify(Tuple[()], "fully-qualified") == "typing.Tuple[()]"
|
||||
assert stringify(Tuple[()], "smart") == "~typing.Tuple[()]"
|
||||
assert stringify_annotation(Tuple[()], 'fully-qualified-except-typing') == "Tuple[()]"
|
||||
assert stringify_annotation(Tuple[()], "fully-qualified") == "typing.Tuple[()]"
|
||||
assert stringify_annotation(Tuple[()], "smart") == "~typing.Tuple[()]"
|
||||
else:
|
||||
assert stringify(Tuple[()]) == "Tuple"
|
||||
assert stringify(Tuple[()], "fully-qualified") == "typing.Tuple"
|
||||
assert stringify(Tuple[()], "smart") == "~typing.Tuple"
|
||||
assert stringify_annotation(Tuple[()], 'fully-qualified-except-typing') == "Tuple"
|
||||
assert stringify_annotation(Tuple[()], "fully-qualified") == "typing.Tuple"
|
||||
assert stringify_annotation(Tuple[()], "smart") == "~typing.Tuple"
|
||||
|
||||
assert stringify(List[Dict[str, Tuple]]) == "List[Dict[str, Tuple]]"
|
||||
assert stringify(List[Dict[str, Tuple]], "fully-qualified") == "typing.List[typing.Dict[str, typing.Tuple]]"
|
||||
assert stringify(List[Dict[str, Tuple]], "smart") == "~typing.List[~typing.Dict[str, ~typing.Tuple]]"
|
||||
assert stringify_annotation(List[Dict[str, Tuple]], 'fully-qualified-except-typing') == "List[Dict[str, Tuple]]"
|
||||
assert stringify_annotation(List[Dict[str, Tuple]], "fully-qualified") == "typing.List[typing.Dict[str, typing.Tuple]]"
|
||||
assert stringify_annotation(List[Dict[str, Tuple]], "smart") == "~typing.List[~typing.Dict[str, ~typing.Tuple]]"
|
||||
|
||||
assert stringify(MyList[Tuple[int, int]]) == "tests.test_util_typing.MyList[Tuple[int, int]]"
|
||||
assert stringify(MyList[Tuple[int, int]], "fully-qualified") == "tests.test_util_typing.MyList[typing.Tuple[int, int]]"
|
||||
assert stringify(MyList[Tuple[int, int]], "smart") == "~tests.test_util_typing.MyList[~typing.Tuple[int, int]]"
|
||||
assert stringify_annotation(MyList[Tuple[int, int]], 'fully-qualified-except-typing') == "tests.test_util_typing.MyList[Tuple[int, int]]"
|
||||
assert stringify_annotation(MyList[Tuple[int, int]], "fully-qualified") == "tests.test_util_typing.MyList[typing.Tuple[int, int]]"
|
||||
assert stringify_annotation(MyList[Tuple[int, int]], "smart") == "~tests.test_util_typing.MyList[~typing.Tuple[int, int]]"
|
||||
|
||||
assert stringify(Generator[None, None, None]) == "Generator[None, None, None]"
|
||||
assert stringify(Generator[None, None, None], "fully-qualified") == "typing.Generator[None, None, None]"
|
||||
assert stringify(Generator[None, None, None], "smart") == "~typing.Generator[None, None, None]"
|
||||
assert stringify_annotation(Generator[None, None, None], 'fully-qualified-except-typing') == "Generator[None, None, None]"
|
||||
assert stringify_annotation(Generator[None, None, None], "fully-qualified") == "typing.Generator[None, None, None]"
|
||||
assert stringify_annotation(Generator[None, None, None], "smart") == "~typing.Generator[None, None, None]"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[:2] <= (3, 8), reason='python 3.9+ is required.')
|
||||
def test_stringify_type_hints_pep_585():
|
||||
assert stringify(list[int]) == "list[int]"
|
||||
assert stringify(list[int], "smart") == "list[int]"
|
||||
assert stringify_annotation(list[int], 'fully-qualified-except-typing') == "list[int]"
|
||||
assert stringify_annotation(list[int], "smart") == "list[int]"
|
||||
|
||||
assert stringify(list[str]) == "list[str]"
|
||||
assert stringify(list[str], "smart") == "list[str]"
|
||||
assert stringify_annotation(list[str], 'fully-qualified-except-typing') == "list[str]"
|
||||
assert stringify_annotation(list[str], "smart") == "list[str]"
|
||||
|
||||
assert stringify(dict[str, float]) == "dict[str, float]"
|
||||
assert stringify(dict[str, float], "smart") == "dict[str, float]"
|
||||
assert stringify_annotation(dict[str, float], 'fully-qualified-except-typing') == "dict[str, float]"
|
||||
assert stringify_annotation(dict[str, float], "smart") == "dict[str, float]"
|
||||
|
||||
assert stringify(tuple[str, str, str]) == "tuple[str, str, str]"
|
||||
assert stringify(tuple[str, str, str], "smart") == "tuple[str, str, str]"
|
||||
assert stringify_annotation(tuple[str, str, str], 'fully-qualified-except-typing') == "tuple[str, str, str]"
|
||||
assert stringify_annotation(tuple[str, str, str], "smart") == "tuple[str, str, str]"
|
||||
|
||||
assert stringify(tuple[str, ...]) == "tuple[str, ...]"
|
||||
assert stringify(tuple[str, ...], "smart") == "tuple[str, ...]"
|
||||
assert stringify_annotation(tuple[str, ...], 'fully-qualified-except-typing') == "tuple[str, ...]"
|
||||
assert stringify_annotation(tuple[str, ...], "smart") == "tuple[str, ...]"
|
||||
|
||||
assert stringify(tuple[()]) == "tuple[()]"
|
||||
assert stringify(tuple[()], "smart") == "tuple[()]"
|
||||
assert stringify_annotation(tuple[()], 'fully-qualified-except-typing') == "tuple[()]"
|
||||
assert stringify_annotation(tuple[()], "smart") == "tuple[()]"
|
||||
|
||||
assert stringify(list[dict[str, tuple]]) == "list[dict[str, tuple]]"
|
||||
assert stringify(list[dict[str, tuple]], "smart") == "list[dict[str, tuple]]"
|
||||
assert stringify_annotation(list[dict[str, tuple]], 'fully-qualified-except-typing') == "list[dict[str, tuple]]"
|
||||
assert stringify_annotation(list[dict[str, tuple]], "smart") == "list[dict[str, tuple]]"
|
||||
|
||||
assert stringify(type[int]) == "type[int]"
|
||||
assert stringify(type[int], "smart") == "type[int]"
|
||||
assert stringify_annotation(type[int], 'fully-qualified-except-typing') == "type[int]"
|
||||
assert stringify_annotation(type[int], "smart") == "type[int]"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[:2] <= (3, 8), reason='python 3.9+ is required.')
|
||||
def test_stringify_Annotated():
|
||||
from typing import Annotated # type: ignore
|
||||
assert stringify(Annotated[str, "foo", "bar"]) == "str"
|
||||
assert stringify(Annotated[str, "foo", "bar"], "smart") == "str"
|
||||
assert stringify_annotation(Annotated[str, "foo", "bar"], 'fully-qualified-except-typing') == "str"
|
||||
assert stringify_annotation(Annotated[str, "foo", "bar"], "smart") == "str"
|
||||
|
||||
|
||||
def test_stringify_type_hints_string():
|
||||
assert stringify("int") == "int"
|
||||
assert stringify("int", "smart") == "int"
|
||||
assert stringify_annotation("int", 'fully-qualified-except-typing') == "int"
|
||||
assert stringify_annotation("int", 'fully-qualified') == "int"
|
||||
assert stringify_annotation("int", "smart") == "int"
|
||||
|
||||
assert stringify("str") == "str"
|
||||
assert stringify("str", "smart") == "str"
|
||||
assert stringify_annotation("str", 'fully-qualified-except-typing') == "str"
|
||||
assert stringify_annotation("str", 'fully-qualified') == "str"
|
||||
assert stringify_annotation("str", "smart") == "str"
|
||||
|
||||
assert stringify(List["int"]) == "List[int]"
|
||||
assert stringify(List["int"], "smart") == "~typing.List[int]"
|
||||
assert stringify_annotation(List["int"], 'fully-qualified-except-typing') == "List[int]"
|
||||
assert stringify_annotation(List["int"], 'fully-qualified') == "typing.List[int]"
|
||||
assert stringify_annotation(List["int"], "smart") == "~typing.List[int]"
|
||||
|
||||
assert stringify("Tuple[str]") == "Tuple[str]"
|
||||
assert stringify("Tuple[str]", "smart") == "Tuple[str]"
|
||||
assert stringify_annotation("Tuple[str]", 'fully-qualified-except-typing') == "Tuple[str]"
|
||||
assert stringify_annotation("Tuple[str]", 'fully-qualified') == "Tuple[str]"
|
||||
assert stringify_annotation("Tuple[str]", "smart") == "Tuple[str]"
|
||||
|
||||
assert stringify("unknown") == "unknown"
|
||||
assert stringify("unknown", "smart") == "unknown"
|
||||
assert stringify_annotation("unknown", 'fully-qualified-except-typing') == "unknown"
|
||||
assert stringify_annotation("unknown", 'fully-qualified') == "unknown"
|
||||
assert stringify_annotation("unknown", "smart") == "unknown"
|
||||
|
||||
|
||||
def test_stringify_type_hints_Callable():
|
||||
assert stringify(Callable) == "Callable"
|
||||
assert stringify(Callable, "fully-qualified") == "typing.Callable"
|
||||
assert stringify(Callable, "smart") == "~typing.Callable"
|
||||
assert stringify_annotation(Callable, 'fully-qualified-except-typing') == "Callable"
|
||||
assert stringify_annotation(Callable, "fully-qualified") == "typing.Callable"
|
||||
assert stringify_annotation(Callable, "smart") == "~typing.Callable"
|
||||
|
||||
assert stringify(Callable[[str], int]) == "Callable[[str], int]"
|
||||
assert stringify(Callable[[str], int], "fully-qualified") == "typing.Callable[[str], int]"
|
||||
assert stringify(Callable[[str], int], "smart") == "~typing.Callable[[str], int]"
|
||||
assert stringify_annotation(Callable[[str], int], 'fully-qualified-except-typing') == "Callable[[str], int]"
|
||||
assert stringify_annotation(Callable[[str], int], "fully-qualified") == "typing.Callable[[str], int]"
|
||||
assert stringify_annotation(Callable[[str], int], "smart") == "~typing.Callable[[str], int]"
|
||||
|
||||
assert stringify(Callable[..., int]) == "Callable[[...], int]"
|
||||
assert stringify(Callable[..., int], "fully-qualified") == "typing.Callable[[...], int]"
|
||||
assert stringify(Callable[..., int], "smart") == "~typing.Callable[[...], int]"
|
||||
assert stringify_annotation(Callable[..., int], 'fully-qualified-except-typing') == "Callable[[...], int]"
|
||||
assert stringify_annotation(Callable[..., int], "fully-qualified") == "typing.Callable[[...], int]"
|
||||
assert stringify_annotation(Callable[..., int], "smart") == "~typing.Callable[[...], int]"
|
||||
|
||||
|
||||
def test_stringify_type_hints_Union():
|
||||
assert stringify(Optional[int]) == "Optional[int]"
|
||||
assert stringify(Optional[int], "fully-qualified") == "typing.Optional[int]"
|
||||
assert stringify(Optional[int], "smart") == "~typing.Optional[int]"
|
||||
assert stringify_annotation(Optional[int], 'fully-qualified-except-typing') == "int | None"
|
||||
assert stringify_annotation(Optional[int], "fully-qualified") == "int | None"
|
||||
assert stringify_annotation(Optional[int], "smart") == "int | None"
|
||||
|
||||
assert stringify(Union[str, None]) == "Optional[str]"
|
||||
assert stringify(Union[str, None], "fully-qualified") == "typing.Optional[str]"
|
||||
assert stringify(Union[str, None], "smart") == "~typing.Optional[str]"
|
||||
assert stringify_annotation(Union[str, None], 'fully-qualified-except-typing') == "str | None"
|
||||
assert stringify_annotation(Union[str, None], "fully-qualified") == "str | None"
|
||||
assert stringify_annotation(Union[str, None], "smart") == "str | None"
|
||||
|
||||
assert stringify(Union[int, str]) == "Union[int, str]"
|
||||
assert stringify(Union[int, str], "fully-qualified") == "typing.Union[int, str]"
|
||||
assert stringify(Union[int, str], "smart") == "~typing.Union[int, str]"
|
||||
assert stringify_annotation(Union[int, str], 'fully-qualified-except-typing') == "int | str"
|
||||
assert stringify_annotation(Union[int, str], "fully-qualified") == "int | str"
|
||||
assert stringify_annotation(Union[int, str], "smart") == "int | str"
|
||||
|
||||
assert stringify(Union[int, Integral]) == "Union[int, numbers.Integral]"
|
||||
assert stringify(Union[int, Integral], "fully-qualified") == "typing.Union[int, numbers.Integral]"
|
||||
assert stringify(Union[int, Integral], "smart") == "~typing.Union[int, ~numbers.Integral]"
|
||||
assert stringify_annotation(Union[int, Integral], 'fully-qualified-except-typing') == "int | numbers.Integral"
|
||||
assert stringify_annotation(Union[int, Integral], "fully-qualified") == "int | numbers.Integral"
|
||||
assert stringify_annotation(Union[int, Integral], "smart") == "int | ~numbers.Integral"
|
||||
|
||||
assert (stringify(Union[MyClass1, MyClass2]) ==
|
||||
"Union[tests.test_util_typing.MyClass1, tests.test_util_typing.<MyClass2>]")
|
||||
assert (stringify(Union[MyClass1, MyClass2], "fully-qualified") ==
|
||||
"typing.Union[tests.test_util_typing.MyClass1, tests.test_util_typing.<MyClass2>]")
|
||||
assert (stringify(Union[MyClass1, MyClass2], "smart") ==
|
||||
"~typing.Union[~tests.test_util_typing.MyClass1, ~tests.test_util_typing.<MyClass2>]")
|
||||
assert (stringify_annotation(Union[MyClass1, MyClass2], 'fully-qualified-except-typing') ==
|
||||
"tests.test_util_typing.MyClass1 | tests.test_util_typing.<MyClass2>")
|
||||
assert (stringify_annotation(Union[MyClass1, MyClass2], "fully-qualified") ==
|
||||
"tests.test_util_typing.MyClass1 | tests.test_util_typing.<MyClass2>")
|
||||
assert (stringify_annotation(Union[MyClass1, MyClass2], "smart") ==
|
||||
"~tests.test_util_typing.MyClass1 | ~tests.test_util_typing.<MyClass2>")
|
||||
|
||||
|
||||
def test_stringify_type_hints_typevars():
|
||||
@@ -368,72 +373,72 @@ def test_stringify_type_hints_typevars():
|
||||
T_co = TypeVar('T_co', covariant=True)
|
||||
T_contra = TypeVar('T_contra', contravariant=True)
|
||||
|
||||
assert stringify(T) == "tests.test_util_typing.T"
|
||||
assert stringify(T, "smart") == "~tests.test_util_typing.T"
|
||||
assert stringify_annotation(T, 'fully-qualified-except-typing') == "tests.test_util_typing.T"
|
||||
assert stringify_annotation(T, "smart") == "~tests.test_util_typing.T"
|
||||
|
||||
assert stringify(T_co) == "tests.test_util_typing.T_co"
|
||||
assert stringify(T_co, "smart") == "~tests.test_util_typing.T_co"
|
||||
assert stringify_annotation(T_co, 'fully-qualified-except-typing') == "tests.test_util_typing.T_co"
|
||||
assert stringify_annotation(T_co, "smart") == "~tests.test_util_typing.T_co"
|
||||
|
||||
assert stringify(T_contra) == "tests.test_util_typing.T_contra"
|
||||
assert stringify(T_contra, "smart") == "~tests.test_util_typing.T_contra"
|
||||
assert stringify_annotation(T_contra, 'fully-qualified-except-typing') == "tests.test_util_typing.T_contra"
|
||||
assert stringify_annotation(T_contra, "smart") == "~tests.test_util_typing.T_contra"
|
||||
|
||||
assert stringify(List[T]) == "List[tests.test_util_typing.T]"
|
||||
assert stringify(List[T], "smart") == "~typing.List[~tests.test_util_typing.T]"
|
||||
assert stringify_annotation(List[T], 'fully-qualified-except-typing') == "List[tests.test_util_typing.T]"
|
||||
assert stringify_annotation(List[T], "smart") == "~typing.List[~tests.test_util_typing.T]"
|
||||
|
||||
if sys.version_info[:2] >= (3, 10):
|
||||
assert stringify(MyInt) == "tests.test_util_typing.MyInt"
|
||||
assert stringify(MyInt, "smart") == "~tests.test_util_typing.MyInt"
|
||||
assert stringify_annotation(MyInt, 'fully-qualified-except-typing') == "tests.test_util_typing.MyInt"
|
||||
assert stringify_annotation(MyInt, "smart") == "~tests.test_util_typing.MyInt"
|
||||
else:
|
||||
assert stringify(MyInt) == "MyInt"
|
||||
assert stringify(MyInt, "smart") == "MyInt"
|
||||
assert stringify_annotation(MyInt, 'fully-qualified-except-typing') == "MyInt"
|
||||
assert stringify_annotation(MyInt, "smart") == "MyInt"
|
||||
|
||||
|
||||
def test_stringify_type_hints_custom_class():
|
||||
assert stringify(MyClass1) == "tests.test_util_typing.MyClass1"
|
||||
assert stringify(MyClass1, "smart") == "~tests.test_util_typing.MyClass1"
|
||||
assert stringify_annotation(MyClass1, 'fully-qualified-except-typing') == "tests.test_util_typing.MyClass1"
|
||||
assert stringify_annotation(MyClass1, "smart") == "~tests.test_util_typing.MyClass1"
|
||||
|
||||
assert stringify(MyClass2) == "tests.test_util_typing.<MyClass2>"
|
||||
assert stringify(MyClass2, "smart") == "~tests.test_util_typing.<MyClass2>"
|
||||
assert stringify_annotation(MyClass2, 'fully-qualified-except-typing') == "tests.test_util_typing.<MyClass2>"
|
||||
assert stringify_annotation(MyClass2, "smart") == "~tests.test_util_typing.<MyClass2>"
|
||||
|
||||
|
||||
def test_stringify_type_hints_alias():
|
||||
MyStr = str
|
||||
MyTuple = Tuple[str, str]
|
||||
|
||||
assert stringify(MyStr) == "str"
|
||||
assert stringify(MyStr, "smart") == "str"
|
||||
assert stringify_annotation(MyStr, 'fully-qualified-except-typing') == "str"
|
||||
assert stringify_annotation(MyStr, "smart") == "str"
|
||||
|
||||
assert stringify(MyTuple) == "Tuple[str, str]" # type: ignore
|
||||
assert stringify(MyTuple, "smart") == "~typing.Tuple[str, str]" # type: ignore
|
||||
assert stringify_annotation(MyTuple) == "Tuple[str, str]" # type: ignore
|
||||
assert stringify_annotation(MyTuple, "smart") == "~typing.Tuple[str, str]" # type: ignore
|
||||
|
||||
|
||||
def test_stringify_type_Literal():
|
||||
from typing import Literal # type: ignore
|
||||
assert stringify(Literal[1, "2", "\r"]) == "Literal[1, '2', '\\r']"
|
||||
assert stringify(Literal[1, "2", "\r"], "fully-qualified") == "typing.Literal[1, '2', '\\r']"
|
||||
assert stringify(Literal[1, "2", "\r"], "smart") == "~typing.Literal[1, '2', '\\r']"
|
||||
assert stringify_annotation(Literal[1, "2", "\r"], 'fully-qualified-except-typing') == "Literal[1, '2', '\\r']"
|
||||
assert stringify_annotation(Literal[1, "2", "\r"], "fully-qualified") == "typing.Literal[1, '2', '\\r']"
|
||||
assert stringify_annotation(Literal[1, "2", "\r"], "smart") == "~typing.Literal[1, '2', '\\r']"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[:2] <= (3, 9), reason='python 3.10+ is required.')
|
||||
def test_stringify_type_union_operator():
|
||||
assert stringify(int | None) == "int | None" # type: ignore
|
||||
assert stringify(int | None, "smart") == "int | None" # type: ignore
|
||||
assert stringify_annotation(int | None) == "int | None" # type: ignore
|
||||
assert stringify_annotation(int | None, "smart") == "int | None" # type: ignore
|
||||
|
||||
assert stringify(int | str) == "int | str" # type: ignore
|
||||
assert stringify(int | str, "smart") == "int | str" # type: ignore
|
||||
assert stringify_annotation(int | str) == "int | str" # type: ignore
|
||||
assert stringify_annotation(int | str, "smart") == "int | str" # type: ignore
|
||||
|
||||
assert stringify(int | str | None) == "int | str | None" # type: ignore
|
||||
assert stringify(int | str | None, "smart") == "int | str | None" # type: ignore
|
||||
assert stringify_annotation(int | str | None) == "int | str | None" # type: ignore
|
||||
assert stringify_annotation(int | str | None, "smart") == "int | str | None" # type: ignore
|
||||
|
||||
|
||||
def test_stringify_broken_type_hints():
|
||||
assert stringify(BrokenType) == 'tests.test_util_typing.BrokenType'
|
||||
assert stringify(BrokenType, "smart") == '~tests.test_util_typing.BrokenType'
|
||||
assert stringify_annotation(BrokenType, 'fully-qualified-except-typing') == 'tests.test_util_typing.BrokenType'
|
||||
assert stringify_annotation(BrokenType, "smart") == '~tests.test_util_typing.BrokenType'
|
||||
|
||||
|
||||
def test_stringify_mock():
|
||||
with mock(['unknown']):
|
||||
import unknown
|
||||
assert stringify(unknown) == 'unknown'
|
||||
assert stringify(unknown.secret.Class) == 'unknown.secret.Class'
|
||||
assert stringify(unknown.secret.Class, "smart") == 'unknown.secret.Class'
|
||||
assert stringify_annotation(unknown, 'fully-qualified-except-typing') == 'unknown'
|
||||
assert stringify_annotation(unknown.secret.Class, 'fully-qualified-except-typing') == 'unknown.secret.Class'
|
||||
assert stringify_annotation(unknown.secret.Class, "smart") == 'unknown.secret.Class'
|
||||
|
||||
Reference in New Issue
Block a user