1 """Tests for C-implemented GenericAlias."""
2
3 import unittest
4 import pickle
5 import copy
6 from collections import (
7 defaultdict, deque, OrderedDict, Counter, UserDict, UserList
8 )
9 from collections.abc import *
10 from concurrent.futures import Future
11 from concurrent.futures.thread import _WorkItem
12 from contextlib import AbstractContextManager, AbstractAsyncContextManager
13 from contextvars import ContextVar, Token
14 from dataclasses import Field
15 from functools import partial, partialmethod, cached_property
16 from graphlib import TopologicalSorter
17 from logging import LoggerAdapter, StreamHandler
18 from mailbox import Mailbox, _PartialFile
19 try:
20 import ctypes
21 except ImportError:
22 ctypes = None
23 from difflib import SequenceMatcher
24 from filecmp import dircmp
25 from fileinput import FileInput
26 from itertools import chain
27 from http.cookies import Morsel
28 try:
29 from multiprocessing.managers import ValueProxy
30 from multiprocessing.pool import ApplyResult
31 from multiprocessing.queues import SimpleQueue as MPSimpleQueue
32 except ImportError:
33 # _multiprocessing module is optional
34 ValueProxy = None
35 ApplyResult = None
36 MPSimpleQueue = None
37 try:
38 from multiprocessing.shared_memory import ShareableList
39 except ImportError:
40 # multiprocessing.shared_memory is not available on e.g. Android
41 ShareableList = None
42 from os import DirEntry
43 from re import Pattern, Match
44 from types import GenericAlias, MappingProxyType, AsyncGeneratorType
45 from tempfile import TemporaryDirectory, SpooledTemporaryFile
46 from urllib.parse import SplitResult, ParseResult
47 from unittest.case import _AssertRaisesContext
48 from queue import Queue, SimpleQueue
49 from weakref import WeakSet, ReferenceType, ref
50 import typing
51 from typing import Unpack
52
53 from typing import TypeVar
54 T = TypeVar('T')
55 K = TypeVar('K')
56 V = TypeVar('V')
57
58 _UNPACKED_TUPLES = [
59 # Unpacked tuple using `*`
60 (*tuple[int],)[0],
61 (*tuple[T],)[0],
62 (*tuple[int, str],)[0],
63 (*tuple[int, ...],)[0],
64 (*tuple[T, ...],)[0],
65 tuple[*tuple[int, ...]],
66 tuple[*tuple[T, ...]],
67 tuple[str, *tuple[int, ...]],
68 tuple[*tuple[int, ...], str],
69 tuple[float, *tuple[int, ...], str],
70 tuple[*tuple[*tuple[int, ...]]],
71 # Unpacked tuple using `Unpack`
72 Unpack[tuple[int]],
73 Unpack[tuple[T]],
74 Unpack[tuple[int, str]],
75 Unpack[tuple[int, ...]],
76 Unpack[tuple[T, ...]],
77 tuple[Unpack[tuple[int, ...]]],
78 tuple[Unpack[tuple[T, ...]]],
79 tuple[str, Unpack[tuple[int, ...]]],
80 tuple[Unpack[tuple[int, ...]], str],
81 tuple[float, Unpack[tuple[int, ...]], str],
82 tuple[Unpack[tuple[Unpack[tuple[int, ...]]]]],
83 # Unpacked tuple using `*` AND `Unpack`
84 tuple[Unpack[tuple[*tuple[int, ...]]]],
85 tuple[*tuple[Unpack[tuple[int, ...]]]],
86 ]
87
88
89 class ESC[4;38;5;81mBaseTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
90 """Test basics."""
91 generic_types = [type, tuple, list, dict, set, frozenset, enumerate,
92 defaultdict, deque,
93 SequenceMatcher,
94 dircmp,
95 FileInput,
96 OrderedDict, Counter, UserDict, UserList,
97 Pattern, Match,
98 partial, partialmethod, cached_property,
99 TopologicalSorter,
100 AbstractContextManager, AbstractAsyncContextManager,
101 Awaitable, Coroutine,
102 AsyncIterable, AsyncIterator,
103 AsyncGenerator, Generator,
104 Iterable, Iterator,
105 Reversible,
106 Container, Collection,
107 Mailbox, _PartialFile,
108 ContextVar, Token,
109 Field,
110 Set, MutableSet,
111 Mapping, MutableMapping, MappingView,
112 KeysView, ItemsView, ValuesView,
113 Sequence, MutableSequence,
114 MappingProxyType, AsyncGeneratorType,
115 DirEntry,
116 chain,
117 LoggerAdapter, StreamHandler,
118 TemporaryDirectory, SpooledTemporaryFile,
119 Queue, SimpleQueue,
120 _AssertRaisesContext,
121 SplitResult, ParseResult,
122 WeakSet, ReferenceType, ref,
123 ShareableList,
124 Future, _WorkItem,
125 Morsel]
126 if ctypes is not None:
127 generic_types.extend((ctypes.Array, ctypes.LibraryLoader))
128 if ValueProxy is not None:
129 generic_types.extend((ValueProxy, ApplyResult, MPSimpleQueue))
130
131 def test_subscriptable(self):
132 for t in self.generic_types:
133 if t is None:
134 continue
135 tname = t.__name__
136 with self.subTest(f"Testing {tname}"):
137 alias = t[int]
138 self.assertIs(alias.__origin__, t)
139 self.assertEqual(alias.__args__, (int,))
140 self.assertEqual(alias.__parameters__, ())
141
142 def test_unsubscriptable(self):
143 for t in int, str, float, Sized, Hashable:
144 tname = t.__name__
145 with self.subTest(f"Testing {tname}"):
146 with self.assertRaisesRegex(TypeError, tname):
147 t[int]
148
149 def test_instantiate(self):
150 for t in tuple, list, dict, set, frozenset, defaultdict, deque:
151 tname = t.__name__
152 with self.subTest(f"Testing {tname}"):
153 alias = t[int]
154 self.assertEqual(alias(), t())
155 if t is dict:
156 self.assertEqual(alias(iter([('a', 1), ('b', 2)])), dict(a=1, b=2))
157 self.assertEqual(alias(a=1, b=2), dict(a=1, b=2))
158 elif t is defaultdict:
159 def default():
160 return 'value'
161 a = alias(default)
162 d = defaultdict(default)
163 self.assertEqual(a['test'], d['test'])
164 else:
165 self.assertEqual(alias(iter((1, 2, 3))), t((1, 2, 3)))
166
167 def test_unbound_methods(self):
168 t = list[int]
169 a = t()
170 t.append(a, 'foo')
171 self.assertEqual(a, ['foo'])
172 x = t.__getitem__(a, 0)
173 self.assertEqual(x, 'foo')
174 self.assertEqual(t.__len__(a), 1)
175
176 def test_subclassing(self):
177 class ESC[4;38;5;81mC(ESC[4;38;5;149mlist[int]):
178 pass
179 self.assertEqual(C.__bases__, (list,))
180 self.assertEqual(C.__class__, type)
181
182 def test_class_methods(self):
183 t = dict[int, None]
184 self.assertEqual(dict.fromkeys(range(2)), {0: None, 1: None}) # This works
185 self.assertEqual(t.fromkeys(range(2)), {0: None, 1: None}) # Should be equivalent
186
187 def test_no_chaining(self):
188 t = list[int]
189 with self.assertRaises(TypeError):
190 t[int]
191
192 def test_generic_subclass(self):
193 class ESC[4;38;5;81mMyList(ESC[4;38;5;149mlist):
194 pass
195 t = MyList[int]
196 self.assertIs(t.__origin__, MyList)
197 self.assertEqual(t.__args__, (int,))
198 self.assertEqual(t.__parameters__, ())
199
200 def test_repr(self):
201 class ESC[4;38;5;81mMyList(ESC[4;38;5;149mlist):
202 pass
203 self.assertEqual(repr(list[str]), 'list[str]')
204 self.assertEqual(repr(list[()]), 'list[()]')
205 self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]')
206 x1 = tuple[*tuple[int]]
207 self.assertEqual(repr(x1), 'tuple[*tuple[int]]')
208 x2 = tuple[*tuple[int, str]]
209 self.assertEqual(repr(x2), 'tuple[*tuple[int, str]]')
210 x3 = tuple[*tuple[int, ...]]
211 self.assertEqual(repr(x3), 'tuple[*tuple[int, ...]]')
212 self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr.<locals>.MyList[int]'))
213 self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr
214
215 def test_exposed_type(self):
216 import types
217 a = types.GenericAlias(list, int)
218 self.assertEqual(str(a), 'list[int]')
219 self.assertIs(a.__origin__, list)
220 self.assertEqual(a.__args__, (int,))
221 self.assertEqual(a.__parameters__, ())
222
223 def test_parameters(self):
224 from typing import List, Dict, Callable
225
226 D0 = dict[str, int]
227 self.assertEqual(D0.__args__, (str, int))
228 self.assertEqual(D0.__parameters__, ())
229 D1a = dict[str, V]
230 self.assertEqual(D1a.__args__, (str, V))
231 self.assertEqual(D1a.__parameters__, (V,))
232 D1b = dict[K, int]
233 self.assertEqual(D1b.__args__, (K, int))
234 self.assertEqual(D1b.__parameters__, (K,))
235 D2a = dict[K, V]
236 self.assertEqual(D2a.__args__, (K, V))
237 self.assertEqual(D2a.__parameters__, (K, V))
238 D2b = dict[T, T]
239 self.assertEqual(D2b.__args__, (T, T))
240 self.assertEqual(D2b.__parameters__, (T,))
241
242 L0 = list[str]
243 self.assertEqual(L0.__args__, (str,))
244 self.assertEqual(L0.__parameters__, ())
245 L1 = list[T]
246 self.assertEqual(L1.__args__, (T,))
247 self.assertEqual(L1.__parameters__, (T,))
248 L2 = list[list[T]]
249 self.assertEqual(L2.__args__, (list[T],))
250 self.assertEqual(L2.__parameters__, (T,))
251 L3 = list[List[T]]
252 self.assertEqual(L3.__args__, (List[T],))
253 self.assertEqual(L3.__parameters__, (T,))
254 L4a = list[Dict[K, V]]
255 self.assertEqual(L4a.__args__, (Dict[K, V],))
256 self.assertEqual(L4a.__parameters__, (K, V))
257 L4b = list[Dict[T, int]]
258 self.assertEqual(L4b.__args__, (Dict[T, int],))
259 self.assertEqual(L4b.__parameters__, (T,))
260 L5 = list[Callable[[K, V], K]]
261 self.assertEqual(L5.__args__, (Callable[[K, V], K],))
262 self.assertEqual(L5.__parameters__, (K, V))
263
264 T1 = tuple[*tuple[int]]
265 self.assertEqual(
266 T1.__args__,
267 (*tuple[int],),
268 )
269 self.assertEqual(T1.__parameters__, ())
270
271 T2 = tuple[*tuple[T]]
272 self.assertEqual(
273 T2.__args__,
274 (*tuple[T],),
275 )
276 self.assertEqual(T2.__parameters__, (T,))
277
278 T4 = tuple[*tuple[int, str]]
279 self.assertEqual(
280 T4.__args__,
281 (*tuple[int, str],),
282 )
283 self.assertEqual(T4.__parameters__, ())
284
285 def test_parameter_chaining(self):
286 from typing import List, Dict, Union, Callable
287 self.assertEqual(list[T][int], list[int])
288 self.assertEqual(dict[str, T][int], dict[str, int])
289 self.assertEqual(dict[T, int][str], dict[str, int])
290 self.assertEqual(dict[K, V][str, int], dict[str, int])
291 self.assertEqual(dict[T, T][int], dict[int, int])
292
293 self.assertEqual(list[list[T]][int], list[list[int]])
294 self.assertEqual(list[dict[T, int]][str], list[dict[str, int]])
295 self.assertEqual(list[dict[str, T]][int], list[dict[str, int]])
296 self.assertEqual(list[dict[K, V]][str, int], list[dict[str, int]])
297 self.assertEqual(dict[T, list[int]][str], dict[str, list[int]])
298
299 self.assertEqual(list[List[T]][int], list[List[int]])
300 self.assertEqual(list[Dict[K, V]][str, int], list[Dict[str, int]])
301 self.assertEqual(list[Union[K, V]][str, int], list[Union[str, int]])
302 self.assertEqual(list[Callable[[K, V], K]][str, int],
303 list[Callable[[str, int], str]])
304 self.assertEqual(dict[T, List[int]][str], dict[str, List[int]])
305
306 with self.assertRaises(TypeError):
307 list[int][int]
308 with self.assertRaises(TypeError):
309 dict[T, int][str, int]
310 with self.assertRaises(TypeError):
311 dict[str, T][str, int]
312 with self.assertRaises(TypeError):
313 dict[T, T][str, int]
314
315 def test_equality(self):
316 self.assertEqual(list[int], list[int])
317 self.assertEqual(dict[str, int], dict[str, int])
318 self.assertEqual((*tuple[int],)[0], (*tuple[int],)[0])
319 self.assertEqual(tuple[*tuple[int]], tuple[*tuple[int]])
320 self.assertNotEqual(dict[str, int], dict[str, str])
321 self.assertNotEqual(list, list[int])
322 self.assertNotEqual(list[int], list)
323 self.assertNotEqual(list[int], tuple[int])
324 self.assertNotEqual((*tuple[int],)[0], tuple[int])
325
326 def test_isinstance(self):
327 self.assertTrue(isinstance([], list))
328 with self.assertRaises(TypeError):
329 isinstance([], list[str])
330
331 def test_issubclass(self):
332 class ESC[4;38;5;81mL(ESC[4;38;5;149mlist): ...
333 self.assertTrue(issubclass(L, list))
334 with self.assertRaises(TypeError):
335 issubclass(L, list[str])
336
337 def test_type_generic(self):
338 t = type[int]
339 Test = t('Test', (), {})
340 self.assertTrue(isinstance(Test, type))
341 test = Test()
342 self.assertEqual(t(test), Test)
343 self.assertEqual(t(0), int)
344
345 def test_type_subclass_generic(self):
346 class ESC[4;38;5;81mMyType(ESC[4;38;5;149mtype):
347 pass
348 with self.assertRaisesRegex(TypeError, 'MyType'):
349 MyType[int]
350
351 def test_pickle(self):
352 aliases = [GenericAlias(list, T)] + _UNPACKED_TUPLES
353 for alias in aliases:
354 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
355 with self.subTest(alias=alias, proto=proto):
356 s = pickle.dumps(alias, proto)
357 loaded = pickle.loads(s)
358 self.assertEqual(loaded.__origin__, alias.__origin__)
359 self.assertEqual(loaded.__args__, alias.__args__)
360 self.assertEqual(loaded.__parameters__, alias.__parameters__)
361 self.assertEqual(type(loaded), type(alias))
362
363 def test_copy(self):
364 class ESC[4;38;5;81mX(ESC[4;38;5;149mlist):
365 def __copy__(self):
366 return self
367 def __deepcopy__(self, memo):
368 return self
369
370 aliases = [
371 GenericAlias(list, T),
372 GenericAlias(deque, T),
373 GenericAlias(X, T)
374 ] + _UNPACKED_TUPLES
375 for alias in aliases:
376 with self.subTest(alias=alias):
377 copied = copy.copy(alias)
378 self.assertEqual(copied.__origin__, alias.__origin__)
379 self.assertEqual(copied.__args__, alias.__args__)
380 self.assertEqual(copied.__parameters__, alias.__parameters__)
381 copied = copy.deepcopy(alias)
382 self.assertEqual(copied.__origin__, alias.__origin__)
383 self.assertEqual(copied.__args__, alias.__args__)
384 self.assertEqual(copied.__parameters__, alias.__parameters__)
385
386 def test_unpack(self):
387 alias = tuple[str, ...]
388 self.assertIs(alias.__unpacked__, False)
389 unpacked = (*alias,)[0]
390 self.assertIs(unpacked.__unpacked__, True)
391
392 def test_union(self):
393 a = typing.Union[list[int], list[str]]
394 self.assertEqual(a.__args__, (list[int], list[str]))
395 self.assertEqual(a.__parameters__, ())
396
397 def test_union_generic(self):
398 a = typing.Union[list[T], tuple[T, ...]]
399 self.assertEqual(a.__args__, (list[T], tuple[T, ...]))
400 self.assertEqual(a.__parameters__, (T,))
401
402 def test_dir(self):
403 dir_of_gen_alias = set(dir(list[int]))
404 self.assertTrue(dir_of_gen_alias.issuperset(dir(list)))
405 for generic_alias_property in ("__origin__", "__args__", "__parameters__"):
406 self.assertIn(generic_alias_property, dir_of_gen_alias)
407
408 def test_weakref(self):
409 for t in self.generic_types:
410 if t is None:
411 continue
412 tname = t.__name__
413 with self.subTest(f"Testing {tname}"):
414 alias = t[int]
415 self.assertEqual(ref(alias)(), alias)
416
417 def test_no_kwargs(self):
418 # bpo-42576
419 with self.assertRaises(TypeError):
420 GenericAlias(bad=float)
421
422 def test_subclassing_types_genericalias(self):
423 class ESC[4;38;5;81mSubClass(ESC[4;38;5;149mGenericAlias): ...
424 alias = SubClass(list, int)
425 class ESC[4;38;5;81mBad(ESC[4;38;5;149mGenericAlias):
426 def __new__(cls, *args, **kwargs):
427 super().__new__(cls, *args, **kwargs)
428
429 self.assertEqual(alias, list[int])
430 with self.assertRaises(TypeError):
431 Bad(list, int, bad=int)
432
433 def test_iter_creates_starred_tuple(self):
434 t = tuple[int, str]
435 iter_t = iter(t)
436 x = next(iter_t)
437 self.assertEqual(repr(x), '*tuple[int, str]')
438
439 def test_calling_next_twice_raises_stopiteration(self):
440 t = tuple[int, str]
441 iter_t = iter(t)
442 next(iter_t)
443 with self.assertRaises(StopIteration):
444 next(iter_t)
445
446 def test_del_iter(self):
447 t = tuple[int, str]
448 iter_x = iter(t)
449 del iter_x
450
451
452 class ESC[4;38;5;81mTypeIterationTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
453 _UNITERABLE_TYPES = (list, tuple)
454
455 def test_cannot_iterate(self):
456 for test_type in self._UNITERABLE_TYPES:
457 with self.subTest(type=test_type):
458 expected_error_regex = "object is not iterable"
459 with self.assertRaisesRegex(TypeError, expected_error_regex):
460 iter(test_type)
461 with self.assertRaisesRegex(TypeError, expected_error_regex):
462 list(test_type)
463 with self.assertRaisesRegex(TypeError, expected_error_regex):
464 for _ in test_type:
465 pass
466
467 def test_is_not_instance_of_iterable(self):
468 for type_to_test in self._UNITERABLE_TYPES:
469 self.assertNotIsInstance(type_to_test, Iterable)
470
471
472 if __name__ == "__main__":
473 unittest.main()