cpython/Lib/test/test_genericalias.py

216 lines
7.5 KiB
Python

"""Tests for C-implemented GenericAlias."""
import unittest
import pickle
from collections import (
defaultdict, deque, OrderedDict, Counter, UserDict, UserList
)
from collections.abc import *
from contextlib import AbstractContextManager, AbstractAsyncContextManager
from os import DirEntry
from re import Pattern, Match
from types import GenericAlias, MappingProxyType
import typing
from typing import TypeVar
T = TypeVar('T')
class BaseTest(unittest.TestCase):
"""Test basics."""
def test_subscriptable(self):
for t in (type, tuple, list, dict, set, frozenset,
defaultdict, deque,
OrderedDict, Counter, UserDict, UserList,
Pattern, Match,
AbstractContextManager, AbstractAsyncContextManager,
Awaitable, Coroutine,
AsyncIterable, AsyncIterator,
AsyncGenerator, Generator,
Iterable, Iterator,
Reversible,
Container, Collection,
Callable,
Set, MutableSet,
Mapping, MutableMapping, MappingView,
KeysView, ItemsView, ValuesView,
Sequence, MutableSequence,
MappingProxyType, DirEntry
):
tname = t.__name__
with self.subTest(f"Testing {tname}"):
alias = t[int]
self.assertIs(alias.__origin__, t)
self.assertEqual(alias.__args__, (int,))
self.assertEqual(alias.__parameters__, ())
def test_unsubscriptable(self):
for t in int, str, float, Sized, Hashable:
tname = t.__name__
with self.subTest(f"Testing {tname}"):
with self.assertRaises(TypeError):
t[int]
def test_instantiate(self):
for t in tuple, list, dict, set, frozenset, defaultdict, deque:
tname = t.__name__
with self.subTest(f"Testing {tname}"):
alias = t[int]
self.assertEqual(alias(), t())
if t is dict:
self.assertEqual(alias(iter([('a', 1), ('b', 2)])), dict(a=1, b=2))
self.assertEqual(alias(a=1, b=2), dict(a=1, b=2))
elif t is defaultdict:
def default():
return 'value'
a = alias(default)
d = defaultdict(default)
self.assertEqual(a['test'], d['test'])
else:
self.assertEqual(alias(iter((1, 2, 3))), t((1, 2, 3)))
def test_unbound_methods(self):
t = list[int]
a = t()
t.append(a, 'foo')
self.assertEqual(a, ['foo'])
x = t.__getitem__(a, 0)
self.assertEqual(x, 'foo')
self.assertEqual(t.__len__(a), 1)
def test_subclassing(self):
class C(list[int]):
pass
self.assertEqual(C.__bases__, (list,))
self.assertEqual(C.__class__, type)
def test_class_methods(self):
t = dict[int, None]
self.assertEqual(dict.fromkeys(range(2)), {0: None, 1: None}) # This works
self.assertEqual(t.fromkeys(range(2)), {0: None, 1: None}) # Should be equivalent
def test_no_chaining(self):
t = list[int]
with self.assertRaises(TypeError):
t[int]
def test_generic_subclass(self):
class MyList(list):
pass
t = MyList[int]
self.assertIs(t.__origin__, MyList)
self.assertEqual(t.__args__, (int,))
self.assertEqual(t.__parameters__, ())
def test_repr(self):
class MyList(list):
pass
self.assertEqual(repr(list[str]), 'list[str]')
self.assertEqual(repr(list[()]), 'list[()]')
self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]')
self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr.<locals>.MyList[int]'))
self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr
def test_exposed_type(self):
import types
a = types.GenericAlias(list, int)
self.assertEqual(str(a), 'list[int]')
self.assertIs(a.__origin__, list)
self.assertEqual(a.__args__, (int,))
self.assertEqual(a.__parameters__, ())
def test_parameters(self):
from typing import TypeVar
T = TypeVar('T')
K = TypeVar('K')
V = TypeVar('V')
D0 = dict[str, int]
self.assertEqual(D0.__args__, (str, int))
self.assertEqual(D0.__parameters__, ())
D1a = dict[str, V]
self.assertEqual(D1a.__args__, (str, V))
self.assertEqual(D1a.__parameters__, (V,))
D1b = dict[K, int]
self.assertEqual(D1b.__args__, (K, int))
self.assertEqual(D1b.__parameters__, (K,))
D2a = dict[K, V]
self.assertEqual(D2a.__args__, (K, V))
self.assertEqual(D2a.__parameters__, (K, V))
D2b = dict[T, T]
self.assertEqual(D2b.__args__, (T, T))
self.assertEqual(D2b.__parameters__, (T,))
L0 = list[str]
self.assertEqual(L0.__args__, (str,))
self.assertEqual(L0.__parameters__, ())
L1 = list[T]
self.assertEqual(L1.__args__, (T,))
self.assertEqual(L1.__parameters__, (T,))
def test_parameter_chaining(self):
from typing import TypeVar
T = TypeVar('T')
self.assertEqual(list[T][int], list[int])
self.assertEqual(dict[str, T][int], dict[str, int])
self.assertEqual(dict[T, int][str], dict[str, int])
self.assertEqual(dict[T, T][int], dict[int, int])
with self.assertRaises(TypeError):
list[int][int]
dict[T, int][str, int]
dict[str, T][str, int]
dict[T, T][str, int]
def test_equality(self):
self.assertEqual(list[int], list[int])
self.assertEqual(dict[str, int], dict[str, int])
self.assertNotEqual(dict[str, int], dict[str, str])
self.assertNotEqual(list, list[int])
self.assertNotEqual(list[int], list)
def test_isinstance(self):
self.assertTrue(isinstance([], list))
with self.assertRaises(TypeError):
isinstance([], list[str])
def test_issubclass(self):
class L(list): ...
self.assertTrue(issubclass(L, list))
with self.assertRaises(TypeError):
issubclass(L, list[str])
def test_type_generic(self):
t = type[int]
Test = t('Test', (), {})
self.assertTrue(isinstance(Test, type))
test = Test()
self.assertEqual(t(test), Test)
self.assertEqual(t(0), int)
def test_type_subclass_generic(self):
class MyType(type):
pass
with self.assertRaises(TypeError):
MyType[int]
def test_pickle(self):
alias = GenericAlias(list, T)
s = pickle.dumps(alias)
loaded = pickle.loads(s)
self.assertEqual(alias.__origin__, loaded.__origin__)
self.assertEqual(alias.__args__, loaded.__args__)
self.assertEqual(alias.__parameters__, loaded.__parameters__)
def test_union(self):
a = typing.Union[list[int], list[str]]
self.assertEqual(a.__args__, (list[int], list[str]))
self.assertEqual(a.__parameters__, ())
def test_union_generic(self):
T = typing.TypeVar('T')
a = typing.Union[list[T], tuple[T, ...]]
self.assertEqual(a.__args__, (list[T], tuple[T, ...]))
self.assertEqual(a.__parameters__, (T,))
if __name__ == "__main__":
unittest.main()