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