1"""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 concurrent.futures import Future 10from concurrent.futures.thread import _WorkItem 11from contextlib import AbstractContextManager, AbstractAsyncContextManager 12from contextvars import ContextVar, Token 13from dataclasses import Field 14from functools import partial, partialmethod, cached_property 15from mailbox import Mailbox, _PartialFile 16try: 17 import ctypes 18except ImportError: 19 ctypes = None 20from difflib import SequenceMatcher 21from filecmp import dircmp 22from fileinput import FileInput 23from itertools import chain 24from http.cookies import Morsel 25from multiprocessing.managers import ValueProxy 26from multiprocessing.pool import ApplyResult 27try: 28 from multiprocessing.shared_memory import ShareableList 29except ImportError: 30 # multiprocessing.shared_memory is not available on e.g. Android 31 ShareableList = None 32from multiprocessing.queues import SimpleQueue as MPSimpleQueue 33from os import DirEntry 34from re import Pattern, Match 35from types import GenericAlias, MappingProxyType, AsyncGeneratorType 36from tempfile import TemporaryDirectory, SpooledTemporaryFile 37from urllib.parse import SplitResult, ParseResult 38from unittest.case import _AssertRaisesContext 39from queue import Queue, SimpleQueue 40from weakref import WeakSet, ReferenceType, ref 41import typing 42 43from typing import TypeVar 44T = TypeVar('T') 45K = TypeVar('K') 46V = TypeVar('V') 47 48class BaseTest(unittest.TestCase): 49 """Test basics.""" 50 generic_types = [type, tuple, list, dict, set, frozenset, enumerate, 51 defaultdict, deque, 52 SequenceMatcher, 53 dircmp, 54 FileInput, 55 OrderedDict, Counter, UserDict, UserList, 56 Pattern, Match, 57 partial, partialmethod, cached_property, 58 AbstractContextManager, AbstractAsyncContextManager, 59 Awaitable, Coroutine, 60 AsyncIterable, AsyncIterator, 61 AsyncGenerator, Generator, 62 Iterable, Iterator, 63 Reversible, 64 Container, Collection, 65 Mailbox, _PartialFile, 66 ContextVar, Token, 67 Field, 68 Set, MutableSet, 69 Mapping, MutableMapping, MappingView, 70 KeysView, ItemsView, ValuesView, 71 Sequence, MutableSequence, 72 MappingProxyType, AsyncGeneratorType, 73 DirEntry, 74 chain, 75 TemporaryDirectory, SpooledTemporaryFile, 76 Queue, SimpleQueue, 77 _AssertRaisesContext, 78 SplitResult, ParseResult, 79 ValueProxy, ApplyResult, 80 WeakSet, ReferenceType, ref, 81 ShareableList, MPSimpleQueue, 82 Future, _WorkItem, 83 Morsel] 84 if ctypes is not None: 85 generic_types.extend((ctypes.Array, ctypes.LibraryLoader)) 86 87 def test_subscriptable(self): 88 for t in self.generic_types: 89 if t is None: 90 continue 91 tname = t.__name__ 92 with self.subTest(f"Testing {tname}"): 93 alias = t[int] 94 self.assertIs(alias.__origin__, t) 95 self.assertEqual(alias.__args__, (int,)) 96 self.assertEqual(alias.__parameters__, ()) 97 98 def test_unsubscriptable(self): 99 for t in int, str, float, Sized, Hashable: 100 tname = t.__name__ 101 with self.subTest(f"Testing {tname}"): 102 with self.assertRaises(TypeError): 103 t[int] 104 105 def test_instantiate(self): 106 for t in tuple, list, dict, set, frozenset, defaultdict, deque: 107 tname = t.__name__ 108 with self.subTest(f"Testing {tname}"): 109 alias = t[int] 110 self.assertEqual(alias(), t()) 111 if t is dict: 112 self.assertEqual(alias(iter([('a', 1), ('b', 2)])), dict(a=1, b=2)) 113 self.assertEqual(alias(a=1, b=2), dict(a=1, b=2)) 114 elif t is defaultdict: 115 def default(): 116 return 'value' 117 a = alias(default) 118 d = defaultdict(default) 119 self.assertEqual(a['test'], d['test']) 120 else: 121 self.assertEqual(alias(iter((1, 2, 3))), t((1, 2, 3))) 122 123 def test_unbound_methods(self): 124 t = list[int] 125 a = t() 126 t.append(a, 'foo') 127 self.assertEqual(a, ['foo']) 128 x = t.__getitem__(a, 0) 129 self.assertEqual(x, 'foo') 130 self.assertEqual(t.__len__(a), 1) 131 132 def test_subclassing(self): 133 class C(list[int]): 134 pass 135 self.assertEqual(C.__bases__, (list,)) 136 self.assertEqual(C.__class__, type) 137 138 def test_class_methods(self): 139 t = dict[int, None] 140 self.assertEqual(dict.fromkeys(range(2)), {0: None, 1: None}) # This works 141 self.assertEqual(t.fromkeys(range(2)), {0: None, 1: None}) # Should be equivalent 142 143 def test_no_chaining(self): 144 t = list[int] 145 with self.assertRaises(TypeError): 146 t[int] 147 148 def test_generic_subclass(self): 149 class MyList(list): 150 pass 151 t = MyList[int] 152 self.assertIs(t.__origin__, MyList) 153 self.assertEqual(t.__args__, (int,)) 154 self.assertEqual(t.__parameters__, ()) 155 156 def test_repr(self): 157 class MyList(list): 158 pass 159 self.assertEqual(repr(list[str]), 'list[str]') 160 self.assertEqual(repr(list[()]), 'list[()]') 161 self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]') 162 self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr.<locals>.MyList[int]')) 163 self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr 164 165 def test_exposed_type(self): 166 import types 167 a = types.GenericAlias(list, int) 168 self.assertEqual(str(a), 'list[int]') 169 self.assertIs(a.__origin__, list) 170 self.assertEqual(a.__args__, (int,)) 171 self.assertEqual(a.__parameters__, ()) 172 173 def test_parameters(self): 174 from typing import List, Dict, Callable 175 D0 = dict[str, int] 176 self.assertEqual(D0.__args__, (str, int)) 177 self.assertEqual(D0.__parameters__, ()) 178 D1a = dict[str, V] 179 self.assertEqual(D1a.__args__, (str, V)) 180 self.assertEqual(D1a.__parameters__, (V,)) 181 D1b = dict[K, int] 182 self.assertEqual(D1b.__args__, (K, int)) 183 self.assertEqual(D1b.__parameters__, (K,)) 184 D2a = dict[K, V] 185 self.assertEqual(D2a.__args__, (K, V)) 186 self.assertEqual(D2a.__parameters__, (K, V)) 187 D2b = dict[T, T] 188 self.assertEqual(D2b.__args__, (T, T)) 189 self.assertEqual(D2b.__parameters__, (T,)) 190 L0 = list[str] 191 self.assertEqual(L0.__args__, (str,)) 192 self.assertEqual(L0.__parameters__, ()) 193 L1 = list[T] 194 self.assertEqual(L1.__args__, (T,)) 195 self.assertEqual(L1.__parameters__, (T,)) 196 L2 = list[list[T]] 197 self.assertEqual(L2.__args__, (list[T],)) 198 self.assertEqual(L2.__parameters__, (T,)) 199 L3 = list[List[T]] 200 self.assertEqual(L3.__args__, (List[T],)) 201 self.assertEqual(L3.__parameters__, (T,)) 202 L4a = list[Dict[K, V]] 203 self.assertEqual(L4a.__args__, (Dict[K, V],)) 204 self.assertEqual(L4a.__parameters__, (K, V)) 205 L4b = list[Dict[T, int]] 206 self.assertEqual(L4b.__args__, (Dict[T, int],)) 207 self.assertEqual(L4b.__parameters__, (T,)) 208 L5 = list[Callable[[K, V], K]] 209 self.assertEqual(L5.__args__, (Callable[[K, V], K],)) 210 self.assertEqual(L5.__parameters__, (K, V)) 211 212 def test_parameter_chaining(self): 213 from typing import List, Dict, Union, Callable 214 self.assertEqual(list[T][int], list[int]) 215 self.assertEqual(dict[str, T][int], dict[str, int]) 216 self.assertEqual(dict[T, int][str], dict[str, int]) 217 self.assertEqual(dict[K, V][str, int], dict[str, int]) 218 self.assertEqual(dict[T, T][int], dict[int, int]) 219 220 self.assertEqual(list[list[T]][int], list[list[int]]) 221 self.assertEqual(list[dict[T, int]][str], list[dict[str, int]]) 222 self.assertEqual(list[dict[str, T]][int], list[dict[str, int]]) 223 self.assertEqual(list[dict[K, V]][str, int], list[dict[str, int]]) 224 self.assertEqual(dict[T, list[int]][str], dict[str, list[int]]) 225 226 self.assertEqual(list[List[T]][int], list[List[int]]) 227 self.assertEqual(list[Dict[K, V]][str, int], list[Dict[str, int]]) 228 self.assertEqual(list[Union[K, V]][str, int], list[Union[str, int]]) 229 self.assertEqual(list[Callable[[K, V], K]][str, int], 230 list[Callable[[str, int], str]]) 231 self.assertEqual(dict[T, List[int]][str], dict[str, List[int]]) 232 233 with self.assertRaises(TypeError): 234 list[int][int] 235 dict[T, int][str, int] 236 dict[str, T][str, int] 237 dict[T, T][str, int] 238 239 def test_equality(self): 240 self.assertEqual(list[int], list[int]) 241 self.assertEqual(dict[str, int], dict[str, int]) 242 self.assertNotEqual(dict[str, int], dict[str, str]) 243 self.assertNotEqual(list, list[int]) 244 self.assertNotEqual(list[int], list) 245 246 def test_isinstance(self): 247 self.assertTrue(isinstance([], list)) 248 with self.assertRaises(TypeError): 249 isinstance([], list[str]) 250 251 def test_issubclass(self): 252 class L(list): ... 253 self.assertTrue(issubclass(L, list)) 254 with self.assertRaises(TypeError): 255 issubclass(L, list[str]) 256 257 def test_type_generic(self): 258 t = type[int] 259 Test = t('Test', (), {}) 260 self.assertTrue(isinstance(Test, type)) 261 test = Test() 262 self.assertEqual(t(test), Test) 263 self.assertEqual(t(0), int) 264 265 def test_type_subclass_generic(self): 266 class MyType(type): 267 pass 268 with self.assertRaises(TypeError): 269 MyType[int] 270 271 def test_pickle(self): 272 alias = GenericAlias(list, T) 273 s = pickle.dumps(alias) 274 loaded = pickle.loads(s) 275 self.assertEqual(alias.__origin__, loaded.__origin__) 276 self.assertEqual(alias.__args__, loaded.__args__) 277 self.assertEqual(alias.__parameters__, loaded.__parameters__) 278 279 def test_union(self): 280 a = typing.Union[list[int], list[str]] 281 self.assertEqual(a.__args__, (list[int], list[str])) 282 self.assertEqual(a.__parameters__, ()) 283 284 def test_union_generic(self): 285 a = typing.Union[list[T], tuple[T, ...]] 286 self.assertEqual(a.__args__, (list[T], tuple[T, ...])) 287 self.assertEqual(a.__parameters__, (T,)) 288 289 def test_dir(self): 290 dir_of_gen_alias = set(dir(list[int])) 291 self.assertTrue(dir_of_gen_alias.issuperset(dir(list))) 292 for generic_alias_property in ("__origin__", "__args__", "__parameters__"): 293 self.assertIn(generic_alias_property, dir_of_gen_alias) 294 295 def test_weakref(self): 296 for t in self.generic_types: 297 if t is None: 298 continue 299 tname = t.__name__ 300 with self.subTest(f"Testing {tname}"): 301 alias = t[int] 302 self.assertEqual(ref(alias)(), alias) 303 304 def test_no_kwargs(self): 305 # bpo-42576 306 with self.assertRaises(TypeError): 307 GenericAlias(bad=float) 308 309 def test_subclassing_types_genericalias(self): 310 class SubClass(GenericAlias): ... 311 alias = SubClass(list, int) 312 class Bad(GenericAlias): 313 def __new__(cls, *args, **kwargs): 314 super().__new__(cls, *args, **kwargs) 315 316 self.assertEqual(alias, list[int]) 317 with self.assertRaises(TypeError): 318 Bad(list, int, bad=int) 319 320 def test_abc_callable(self): 321 # A separate test is needed for Callable since it uses a subclass of 322 # GenericAlias. 323 alias = Callable[[int, str], float] 324 with self.subTest("Testing subscription"): 325 self.assertIs(alias.__origin__, Callable) 326 self.assertEqual(alias.__args__, (int, str, float)) 327 self.assertEqual(alias.__parameters__, ()) 328 329 with self.subTest("Testing instance checks"): 330 self.assertIsInstance(alias, GenericAlias) 331 332 with self.subTest("Testing weakref"): 333 self.assertEqual(ref(alias)(), alias) 334 335 with self.subTest("Testing pickling"): 336 s = pickle.dumps(alias) 337 loaded = pickle.loads(s) 338 self.assertEqual(alias.__origin__, loaded.__origin__) 339 self.assertEqual(alias.__args__, loaded.__args__) 340 self.assertEqual(alias.__parameters__, loaded.__parameters__) 341 342 with self.subTest("Testing TypeVar substitution"): 343 C1 = Callable[[int, T], T] 344 C2 = Callable[[K, T], V] 345 C3 = Callable[..., T] 346 self.assertEqual(C1[str], Callable[[int, str], str]) 347 self.assertEqual(C2[int, float, str], Callable[[int, float], str]) 348 self.assertEqual(C3[int], Callable[..., int]) 349 350 # multi chaining 351 C4 = C2[int, V, str] 352 self.assertEqual(repr(C4).split(".")[-1], "Callable[[int, ~V], str]") 353 self.assertEqual(repr(C4[dict]).split(".")[-1], "Callable[[int, dict], str]") 354 self.assertEqual(C4[dict], Callable[[int, dict], str]) 355 356 with self.subTest("Testing type erasure"): 357 class C1(Callable): 358 def __call__(self): 359 return None 360 a = C1[[int], T] 361 self.assertIs(a().__class__, C1) 362 self.assertEqual(a().__orig_class__, C1[[int], T]) 363 364 # bpo-42195 365 with self.subTest("Testing collections.abc.Callable's consistency " 366 "with typing.Callable"): 367 c1 = typing.Callable[[int, str], dict] 368 c2 = Callable[[int, str], dict] 369 self.assertEqual(c1.__args__, c2.__args__) 370 self.assertEqual(hash(c1.__args__), hash(c2.__args__)) 371 372 373if __name__ == "__main__": 374 unittest.main() 375