-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
test_typing.py
132 lines (98 loc) · 4.17 KB
/
test_typing.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import sys
from collections import namedtuple
from typing import Any, Callable as TypingCallable, Dict, List, NamedTuple, NewType, Union # noqa: F401
import pytest
from typing_extensions import Annotated # noqa: F401
from pydantic import Field # noqa: F401
from pydantic.typing import Literal, convert_generics, is_namedtuple, is_none_type, is_typeddict
try:
from typing import TypedDict as typing_TypedDict
except ImportError:
typing_TypedDict = None
try:
from typing_extensions import TypedDict as typing_extensions_TypedDict
except ImportError:
typing_extensions_TypedDict = None
try:
from mypy_extensions import TypedDict as mypy_extensions_TypedDict
except ImportError:
mypy_extensions_TypedDict = None
try:
from typing import ForwardRef
except ImportError:
# ForwardRef is only available in Python 3.6+
pass
ALL_TYPEDDICT_KINDS = (typing_TypedDict, typing_extensions_TypedDict, mypy_extensions_TypedDict)
def test_is_namedtuple():
class Employee(NamedTuple):
name: str
id: int = 3
assert is_namedtuple(namedtuple('Point', 'x y')) is True
assert is_namedtuple(Employee) is True
assert is_namedtuple(NamedTuple('Employee', [('name', str), ('id', int)])) is True
class Other(tuple):
name: str
id: int
assert is_namedtuple(Other) is False
@pytest.mark.parametrize('TypedDict', (t for t in ALL_TYPEDDICT_KINDS if t is not None))
def test_is_typeddict_typing(TypedDict):
class Employee(TypedDict):
name: str
id: int
assert is_typeddict(Employee) is True
assert is_typeddict(TypedDict('Employee', {'name': str, 'id': int})) is True
class Other(dict):
name: str
id: int
assert is_typeddict(Other) is False
def test_is_none_type():
assert is_none_type(Literal[None]) is True
assert is_none_type(None) is True
assert is_none_type(type(None)) is True
assert is_none_type(6) is False
assert is_none_type({}) is False
# WARNING: It's important to test `typing.Callable` not
# `collections.abc.Callable` (even with python >= 3.9) as they behave
# differently
assert is_none_type(TypingCallable) is False
class Hero:
pass
class Team:
pass
@pytest.mark.skipif(sys.version_info < (3, 9), reason='PEP585 generics only supported for python 3.9 and above.')
@pytest.mark.parametrize(
['type_', 'expectations'],
[
('int', 'int'),
('Union[list["Hero"], int]', 'Union[list[ForwardRef("Hero")], int]'),
('list["Hero"]', 'list[ForwardRef("Hero")]'),
('dict["Hero", "Team"]', 'dict[ForwardRef("Hero"), ForwardRef("Team")]'),
('dict["Hero", list["Team"]]', 'dict[ForwardRef("Hero"), list[ForwardRef("Team")]]'),
('dict["Hero", List["Team"]]', 'dict[ForwardRef("Hero"), List[ForwardRef("Team")]]'),
('Dict["Hero", list["Team"]]', 'Dict[ForwardRef("Hero"), list[ForwardRef("Team")]]'),
(
'Annotated[list["Hero"], Field(min_length=2)]',
'Annotated[list[ForwardRef("Hero")], Field(min_length=2)]',
),
],
)
def test_convert_generics(type_, expectations):
assert str(convert_generics(eval(type_))) == str(eval(expectations))
@pytest.mark.skipif(sys.version_info < (3, 10), reason='NewType class was added in python 3.10.')
def test_convert_generics_unsettable_args():
class User(NewType):
__origin__ = type(list[str])
__args__ = (list['Hero'],)
def __init__(self, name: str, tp: type) -> None:
super().__init__(name, tp)
def __setattr__(self, __name: str, __value: Any) -> None:
if __name == '__args__':
raise AttributeError # will be thrown during the generics conversion
return super().__setattr__(__name, __value)
# tests that convert_generics will not throw an exception even if __args__ isn't settable
assert convert_generics(User('MyUser', str)).__args__ == (list['Hero'],)
@pytest.mark.skipif(sys.version_info < (3, 10), reason='PEP604 unions only supported for python 3.10 and above.')
def test_convert_generics_pep604():
assert (
convert_generics(dict['Hero', list['Team']] | int) == dict[ForwardRef('Hero'), list[ForwardRef('Team')]] | int
)