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