blob: 535c2492574b3ca0a3eb89fe762b2e87e09939d3 [file] [log] [blame]
Guido van Rossum48b069a2020-04-07 09:50:06 -07001"""Tests for C-implemented GenericAlias."""
2
3import unittest
4import pickle
5from collections import (
6 defaultdict, deque, OrderedDict, Counter, UserDict, UserList
7)
8from collections.abc import *
9from contextlib import AbstractContextManager, AbstractAsyncContextManager
Batuhan Taşkaya2fa67df2020-04-10 07:04:54 +030010from ipaddress import IPv4Network, IPv4Interface, IPv6Network, IPv6Interface
Ethan Smitha8403d02020-04-09 20:28:08 -070011from itertools import chain
Batuhan Taşkayaf9dd51e2020-04-08 00:37:19 +030012from os import DirEntry
Guido van Rossum48b069a2020-04-07 09:50:06 -070013from re import Pattern, Match
14from types import GenericAlias, MappingProxyType
15import typing
16
17from typing import TypeVar
18T = TypeVar('T')
19
20class BaseTest(unittest.TestCase):
21 """Test basics."""
22
23 def test_subscriptable(self):
24 for t in (type, tuple, list, dict, set, frozenset,
25 defaultdict, deque,
26 OrderedDict, Counter, UserDict, UserList,
27 Pattern, Match,
28 AbstractContextManager, AbstractAsyncContextManager,
29 Awaitable, Coroutine,
30 AsyncIterable, AsyncIterator,
31 AsyncGenerator, Generator,
32 Iterable, Iterator,
33 Reversible,
34 Container, Collection,
35 Callable,
36 Set, MutableSet,
37 Mapping, MutableMapping, MappingView,
38 KeysView, ItemsView, ValuesView,
39 Sequence, MutableSequence,
Batuhan Taşkaya2fa67df2020-04-10 07:04:54 +030040 MappingProxyType,
41 DirEntry,
42 IPv4Network, IPv4Interface, IPv6Network, IPv6Interface,
Ethan Smitha8403d02020-04-09 20:28:08 -070043 MappingProxyType, DirEntry,
44 chain,
Guido van Rossum48b069a2020-04-07 09:50:06 -070045 ):
46 tname = t.__name__
47 with self.subTest(f"Testing {tname}"):
48 alias = t[int]
49 self.assertIs(alias.__origin__, t)
50 self.assertEqual(alias.__args__, (int,))
51 self.assertEqual(alias.__parameters__, ())
52
53 def test_unsubscriptable(self):
54 for t in int, str, float, Sized, Hashable:
55 tname = t.__name__
56 with self.subTest(f"Testing {tname}"):
57 with self.assertRaises(TypeError):
58 t[int]
59
60 def test_instantiate(self):
61 for t in tuple, list, dict, set, frozenset, defaultdict, deque:
62 tname = t.__name__
63 with self.subTest(f"Testing {tname}"):
64 alias = t[int]
65 self.assertEqual(alias(), t())
66 if t is dict:
67 self.assertEqual(alias(iter([('a', 1), ('b', 2)])), dict(a=1, b=2))
68 self.assertEqual(alias(a=1, b=2), dict(a=1, b=2))
69 elif t is defaultdict:
70 def default():
71 return 'value'
72 a = alias(default)
73 d = defaultdict(default)
74 self.assertEqual(a['test'], d['test'])
75 else:
76 self.assertEqual(alias(iter((1, 2, 3))), t((1, 2, 3)))
77
78 def test_unbound_methods(self):
79 t = list[int]
80 a = t()
81 t.append(a, 'foo')
82 self.assertEqual(a, ['foo'])
83 x = t.__getitem__(a, 0)
84 self.assertEqual(x, 'foo')
85 self.assertEqual(t.__len__(a), 1)
86
87 def test_subclassing(self):
88 class C(list[int]):
89 pass
90 self.assertEqual(C.__bases__, (list,))
91 self.assertEqual(C.__class__, type)
92
93 def test_class_methods(self):
94 t = dict[int, None]
95 self.assertEqual(dict.fromkeys(range(2)), {0: None, 1: None}) # This works
96 self.assertEqual(t.fromkeys(range(2)), {0: None, 1: None}) # Should be equivalent
97
98 def test_no_chaining(self):
99 t = list[int]
100 with self.assertRaises(TypeError):
101 t[int]
102
103 def test_generic_subclass(self):
104 class MyList(list):
105 pass
106 t = MyList[int]
107 self.assertIs(t.__origin__, MyList)
108 self.assertEqual(t.__args__, (int,))
109 self.assertEqual(t.__parameters__, ())
110
111 def test_repr(self):
112 class MyList(list):
113 pass
114 self.assertEqual(repr(list[str]), 'list[str]')
115 self.assertEqual(repr(list[()]), 'list[()]')
116 self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]')
117 self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr.<locals>.MyList[int]'))
118 self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr
119
120 def test_exposed_type(self):
121 import types
122 a = types.GenericAlias(list, int)
123 self.assertEqual(str(a), 'list[int]')
124 self.assertIs(a.__origin__, list)
125 self.assertEqual(a.__args__, (int,))
126 self.assertEqual(a.__parameters__, ())
127
128 def test_parameters(self):
129 from typing import TypeVar
130 T = TypeVar('T')
131 K = TypeVar('K')
132 V = TypeVar('V')
133 D0 = dict[str, int]
134 self.assertEqual(D0.__args__, (str, int))
135 self.assertEqual(D0.__parameters__, ())
136 D1a = dict[str, V]
137 self.assertEqual(D1a.__args__, (str, V))
138 self.assertEqual(D1a.__parameters__, (V,))
139 D1b = dict[K, int]
140 self.assertEqual(D1b.__args__, (K, int))
141 self.assertEqual(D1b.__parameters__, (K,))
142 D2a = dict[K, V]
143 self.assertEqual(D2a.__args__, (K, V))
144 self.assertEqual(D2a.__parameters__, (K, V))
145 D2b = dict[T, T]
146 self.assertEqual(D2b.__args__, (T, T))
147 self.assertEqual(D2b.__parameters__, (T,))
148 L0 = list[str]
149 self.assertEqual(L0.__args__, (str,))
150 self.assertEqual(L0.__parameters__, ())
151 L1 = list[T]
152 self.assertEqual(L1.__args__, (T,))
153 self.assertEqual(L1.__parameters__, (T,))
154
155 def test_parameter_chaining(self):
156 from typing import TypeVar
157 T = TypeVar('T')
158 self.assertEqual(list[T][int], list[int])
159 self.assertEqual(dict[str, T][int], dict[str, int])
160 self.assertEqual(dict[T, int][str], dict[str, int])
161 self.assertEqual(dict[T, T][int], dict[int, int])
162 with self.assertRaises(TypeError):
163 list[int][int]
164 dict[T, int][str, int]
165 dict[str, T][str, int]
166 dict[T, T][str, int]
167
168 def test_equality(self):
169 self.assertEqual(list[int], list[int])
170 self.assertEqual(dict[str, int], dict[str, int])
171 self.assertNotEqual(dict[str, int], dict[str, str])
172 self.assertNotEqual(list, list[int])
173 self.assertNotEqual(list[int], list)
174
175 def test_isinstance(self):
176 self.assertTrue(isinstance([], list))
177 with self.assertRaises(TypeError):
178 isinstance([], list[str])
179
180 def test_issubclass(self):
181 class L(list): ...
182 self.assertTrue(issubclass(L, list))
183 with self.assertRaises(TypeError):
184 issubclass(L, list[str])
185
186 def test_type_generic(self):
187 t = type[int]
188 Test = t('Test', (), {})
189 self.assertTrue(isinstance(Test, type))
190 test = Test()
191 self.assertEqual(t(test), Test)
192 self.assertEqual(t(0), int)
193
194 def test_type_subclass_generic(self):
195 class MyType(type):
196 pass
197 with self.assertRaises(TypeError):
198 MyType[int]
199
200 def test_pickle(self):
201 alias = GenericAlias(list, T)
202 s = pickle.dumps(alias)
203 loaded = pickle.loads(s)
204 self.assertEqual(alias.__origin__, loaded.__origin__)
205 self.assertEqual(alias.__args__, loaded.__args__)
206 self.assertEqual(alias.__parameters__, loaded.__parameters__)
207
208 def test_union(self):
209 a = typing.Union[list[int], list[str]]
210 self.assertEqual(a.__args__, (list[int], list[str]))
211 self.assertEqual(a.__parameters__, ())
212
213 def test_union_generic(self):
214 T = typing.TypeVar('T')
215 a = typing.Union[list[T], tuple[T, ...]]
216 self.assertEqual(a.__args__, (list[T], tuple[T, ...]))
217 self.assertEqual(a.__parameters__, (T,))
218
219
220if __name__ == "__main__":
221 unittest.main()