test_genericalias.py 17 KB

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