blob: 0daaff099a868d7d23fdef7e79cd93a6b39049cc [file] [log] [blame]
Guido van Rossum48b069a2020-04-07 09:50:06 -07001"""Tests for C-implemented GenericAlias."""
2
3import unittest
4import pickle
Miss Islington (bot)de4c9c02021-09-15 12:35:16 -07005import copy
Guido van Rossum48b069a2020-04-07 09:50:06 -07006from collections import (
7 defaultdict, deque, OrderedDict, Counter, UserDict, UserList
8)
9from collections.abc import *
Batuhan Taşkaya03615562020-04-10 17:46:36 +030010from concurrent.futures import Future
11from concurrent.futures.thread import _WorkItem
Guido van Rossum48b069a2020-04-07 09:50:06 -070012from contextlib import AbstractContextManager, AbstractAsyncContextManager
Ethan Smithd01628e2020-04-14 16:14:15 -070013from contextvars import ContextVar, Token
14from dataclasses import Field
15from functools import partial, partialmethod, cached_property
16from mailbox import Mailbox, _PartialFile
Victor Stinnerf44693e2020-08-07 17:56:42 +020017try:
18 import ctypes
19except ImportError:
20 ctypes = None
Ethan Smithe3ec44d2020-04-09 21:47:31 -070021from difflib import SequenceMatcher
22from filecmp import dircmp
23from fileinput import FileInput
Ethan Smitha8403d02020-04-09 20:28:08 -070024from itertools import chain
Batuhan Taşkaya03615562020-04-10 17:46:36 +030025from http.cookies import Morsel
26from multiprocessing.managers import ValueProxy
27from multiprocessing.pool import ApplyResult
Chih-Hsuan Yen25a68332020-04-14 06:00:16 +080028try:
29 from multiprocessing.shared_memory import ShareableList
30except ImportError:
31 # multiprocessing.shared_memory is not available on e.g. Android
32 ShareableList = None
Saiyang Goub2c0a432020-10-09 13:00:15 -070033from multiprocessing.queues import SimpleQueue as MPSimpleQueue
Batuhan Taşkayaf9dd51e2020-04-08 00:37:19 +030034from os import DirEntry
Guido van Rossum48b069a2020-04-07 09:50:06 -070035from re import Pattern, Match
Ethan Smith7c4185d2020-04-09 21:25:53 -070036from types import GenericAlias, MappingProxyType, AsyncGeneratorType
Batuhan Taşkaya03615562020-04-10 17:46:36 +030037from tempfile import TemporaryDirectory, SpooledTemporaryFile
38from urllib.parse import SplitResult, ParseResult
39from unittest.case import _AssertRaisesContext
40from queue import Queue, SimpleQueue
Ethan Smith8ef87502020-04-13 21:54:40 -070041from weakref import WeakSet, ReferenceType, ref
Guido van Rossum48b069a2020-04-07 09:50:06 -070042import typing
43
44from typing import TypeVar
45T = TypeVar('T')
Serhiy Storchaka41a64582020-05-04 10:56:05 +030046K = TypeVar('K')
47V = TypeVar('V')
Guido van Rossum48b069a2020-04-07 09:50:06 -070048
49class BaseTest(unittest.TestCase):
50 """Test basics."""
kj384b7a42020-11-16 11:27:23 +080051 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,
kj384b7a42020-11-16 11:27:23 +080066 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))
Guido van Rossum48b069a2020-04-07 09:50:06 -070087
88 def test_subscriptable(self):
kj384b7a42020-11-16 11:27:23 +080089 for t in self.generic_types:
Chih-Hsuan Yen25a68332020-04-14 06:00:16 +080090 if t is None:
91 continue
Guido van Rossum48b069a2020-04-07 09:50:06 -070092 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):
Serhiy Storchaka41a64582020-05-04 10:56:05 +0300175 from typing import List, Dict, Callable
Guido van Rossum48b069a2020-04-07 09:50:06 -0700176 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,))
Serhiy Storchaka41a64582020-05-04 10:56:05 +0300197 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))
Guido van Rossum48b069a2020-04-07 09:50:06 -0700212
213 def test_parameter_chaining(self):
Serhiy Storchaka41a64582020-05-04 10:56:05 +0300214 from typing import List, Dict, Union, Callable
Guido van Rossum48b069a2020-04-07 09:50:06 -0700215 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])
Serhiy Storchaka41a64582020-05-04 10:56:05 +0300218 self.assertEqual(dict[K, V][str, int], dict[str, int])
Guido van Rossum48b069a2020-04-07 09:50:06 -0700219 self.assertEqual(dict[T, T][int], dict[int, int])
Serhiy Storchaka41a64582020-05-04 10:56:05 +0300220
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
Guido van Rossum48b069a2020-04-07 09:50:06 -0700234 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)
Miss Islington (bot)de4c9c02021-09-15 12:35:16 -0700274 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__)
Guido van Rossum48b069a2020-04-07 09:50:06 -0700298
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):
Guido van Rossum48b069a2020-04-07 09:50:06 -0700305 a = typing.Union[list[T], tuple[T, ...]]
306 self.assertEqual(a.__args__, (list[T], tuple[T, ...]))
307 self.assertEqual(a.__parameters__, (T,))
308
Batuhan Taskaya2e877742020-09-16 00:58:32 +0300309 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)
Guido van Rossum48b069a2020-04-07 09:50:06 -0700314
kj384b7a42020-11-16 11:27:23 +0800315 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
kj804d6892020-12-05 23:02:14 +0700324 def test_no_kwargs(self):
325 # bpo-42576
326 with self.assertRaises(TypeError):
327 GenericAlias(bad=float)
328
kj463c7d32020-12-14 02:38:24 +0800329 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
Ken Jin859577c2021-04-28 23:38:14 +0800340
Guido van Rossum48b069a2020-04-07 09:50:06 -0700341if __name__ == "__main__":
342 unittest.main()