1"""Tests for C-implemented GenericAlias.""" 2 3import unittest 4import pickle 5import copy 6from collections import ( 7 defaultdict, deque, OrderedDict, Counter, UserDict, UserList 8) 9from collections.abc import * 10from concurrent.futures import Future 11from concurrent.futures.thread import _WorkItem 12from contextlib import AbstractContextManager, AbstractAsyncContextManager 13from contextvars import ContextVar, Token 14from dataclasses import Field 15from functools import partial, partialmethod, cached_property 16from graphlib import TopologicalSorter 17from logging import LoggerAdapter, StreamHandler 18from mailbox import Mailbox, _PartialFile 19try: 20 import ctypes 21except ImportError: 22 ctypes = None 23from difflib import SequenceMatcher 24from filecmp import dircmp 25from fileinput import FileInput 26from itertools import chain 27from http.cookies import Morsel 28try: 29 from multiprocessing.managers import ValueProxy 30 from multiprocessing.pool import ApplyResult 31 from multiprocessing.queues import SimpleQueue as MPSimpleQueue 32except ImportError: 33 # _multiprocessing module is optional 34 ValueProxy = None 35 ApplyResult = None 36 MPSimpleQueue = None 37try: 38 from multiprocessing.shared_memory import ShareableList 39except ImportError: 40 # multiprocessing.shared_memory is not available on e.g. Android 41 ShareableList = None 42from os import DirEntry 43from re import Pattern, Match 44from types import GenericAlias, MappingProxyType, AsyncGeneratorType 45from tempfile import TemporaryDirectory, SpooledTemporaryFile 46from urllib.parse import SplitResult, ParseResult 47from unittest.case import _AssertRaisesContext 48from queue import Queue, SimpleQueue 49from weakref import WeakSet, ReferenceType, ref 50import typing 51from typing import Unpack 52 53from typing import TypeVar 54T = TypeVar('T') 55K = TypeVar('K') 56V = 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 89class BaseTest(unittest.TestCase): 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 C(list[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 MyList(list): 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 MyList(list): 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 L(list): ... 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 MyType(type): 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 X(list): 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 SubClass(GenericAlias): ... 424 alias = SubClass(list, int) 425 class Bad(GenericAlias): 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 452class TypeIterationTests(unittest.TestCase): 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 472if __name__ == "__main__": 473 unittest.main() 474