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