| import contextlib |
| import collections |
| import pickle |
| import re |
| import sys |
| from unittest import TestCase, main, skipUnless, SkipTest |
| from copy import copy, deepcopy |
| |
| from typing import Any |
| from typing import TypeVar, AnyStr |
| from typing import T, KT, VT # Not in __all__. |
| from typing import Union, Optional |
| from typing import Tuple, List, MutableMapping |
| from typing import Callable |
| from typing import Generic, ClassVar, GenericMeta |
| from typing import cast |
| from typing import get_type_hints |
| from typing import no_type_check, no_type_check_decorator |
| from typing import Type |
| from typing import NewType |
| from typing import NamedTuple |
| from typing import IO, TextIO, BinaryIO |
| from typing import Pattern, Match |
| import abc |
| import typing |
| import weakref |
| try: |
| import collections.abc as collections_abc |
| except ImportError: |
| import collections as collections_abc # Fallback for PY3.2. |
| |
| |
| class BaseTestCase(TestCase): |
| |
| def assertIsSubclass(self, cls, class_or_tuple, msg=None): |
| if not issubclass(cls, class_or_tuple): |
| message = '%r is not a subclass of %r' % (cls, class_or_tuple) |
| if msg is not None: |
| message += ' : %s' % msg |
| raise self.failureException(message) |
| |
| def assertNotIsSubclass(self, cls, class_or_tuple, msg=None): |
| if issubclass(cls, class_or_tuple): |
| message = '%r is a subclass of %r' % (cls, class_or_tuple) |
| if msg is not None: |
| message += ' : %s' % msg |
| raise self.failureException(message) |
| |
| def clear_caches(self): |
| for f in typing._cleanups: |
| f() |
| |
| |
| class Employee: |
| pass |
| |
| |
| class Manager(Employee): |
| pass |
| |
| |
| class Founder(Employee): |
| pass |
| |
| |
| class ManagingFounder(Manager, Founder): |
| pass |
| |
| |
| class AnyTests(BaseTestCase): |
| |
| def test_any_instance_type_error(self): |
| with self.assertRaises(TypeError): |
| isinstance(42, Any) |
| |
| def test_any_subclass_type_error(self): |
| with self.assertRaises(TypeError): |
| issubclass(Employee, Any) |
| with self.assertRaises(TypeError): |
| issubclass(Any, Employee) |
| |
| def test_repr(self): |
| self.assertEqual(repr(Any), 'typing.Any') |
| |
| def test_errors(self): |
| with self.assertRaises(TypeError): |
| issubclass(42, Any) |
| with self.assertRaises(TypeError): |
| Any[int] # Any is not a generic type. |
| |
| def test_cannot_subclass(self): |
| with self.assertRaises(TypeError): |
| class A(Any): |
| pass |
| with self.assertRaises(TypeError): |
| class A(type(Any)): |
| pass |
| |
| def test_cannot_instantiate(self): |
| with self.assertRaises(TypeError): |
| Any() |
| with self.assertRaises(TypeError): |
| type(Any)() |
| |
| def test_cannot_subscript(self): |
| with self.assertRaises(TypeError): |
| Any[int] |
| |
| def test_any_works_with_alias(self): |
| # These expressions must simply not fail. |
| typing.Match[Any] |
| typing.Pattern[Any] |
| typing.IO[Any] |
| |
| |
| class TypeVarTests(BaseTestCase): |
| |
| def test_basic_plain(self): |
| T = TypeVar('T') |
| # T equals itself. |
| self.assertEqual(T, T) |
| # T is an instance of TypeVar |
| self.assertIsInstance(T, TypeVar) |
| |
| def test_typevar_instance_type_error(self): |
| T = TypeVar('T') |
| with self.assertRaises(TypeError): |
| isinstance(42, T) |
| |
| def test_typevar_subclass_type_error(self): |
| T = TypeVar('T') |
| with self.assertRaises(TypeError): |
| issubclass(int, T) |
| with self.assertRaises(TypeError): |
| issubclass(T, int) |
| |
| def test_constrained_error(self): |
| with self.assertRaises(TypeError): |
| X = TypeVar('X', int) |
| X |
| |
| def test_union_unique(self): |
| X = TypeVar('X') |
| Y = TypeVar('Y') |
| self.assertNotEqual(X, Y) |
| self.assertEqual(Union[X], X) |
| self.assertNotEqual(Union[X], Union[X, Y]) |
| self.assertEqual(Union[X, X], X) |
| self.assertNotEqual(Union[X, int], Union[X]) |
| self.assertNotEqual(Union[X, int], Union[int]) |
| self.assertEqual(Union[X, int].__args__, (X, int)) |
| self.assertEqual(Union[X, int].__parameters__, (X,)) |
| self.assertIs(Union[X, int].__origin__, Union) |
| |
| def test_union_constrained(self): |
| A = TypeVar('A', str, bytes) |
| self.assertNotEqual(Union[A, str], Union[A]) |
| |
| def test_repr(self): |
| self.assertEqual(repr(T), '~T') |
| self.assertEqual(repr(KT), '~KT') |
| self.assertEqual(repr(VT), '~VT') |
| self.assertEqual(repr(AnyStr), '~AnyStr') |
| T_co = TypeVar('T_co', covariant=True) |
| self.assertEqual(repr(T_co), '+T_co') |
| T_contra = TypeVar('T_contra', contravariant=True) |
| self.assertEqual(repr(T_contra), '-T_contra') |
| |
| def test_no_redefinition(self): |
| self.assertNotEqual(TypeVar('T'), TypeVar('T')) |
| self.assertNotEqual(TypeVar('T', int, str), TypeVar('T', int, str)) |
| |
| def test_cannot_subclass_vars(self): |
| with self.assertRaises(TypeError): |
| class V(TypeVar('T')): |
| pass |
| |
| def test_cannot_subclass_var_itself(self): |
| with self.assertRaises(TypeError): |
| class V(TypeVar): |
| pass |
| |
| def test_cannot_instantiate_vars(self): |
| with self.assertRaises(TypeError): |
| TypeVar('A')() |
| |
| def test_bound_errors(self): |
| with self.assertRaises(TypeError): |
| TypeVar('X', bound=42) |
| with self.assertRaises(TypeError): |
| TypeVar('X', str, float, bound=Employee) |
| |
| |
| class UnionTests(BaseTestCase): |
| |
| def test_basics(self): |
| u = Union[int, float] |
| self.assertNotEqual(u, Union) |
| |
| def test_subclass_error(self): |
| with self.assertRaises(TypeError): |
| issubclass(int, Union) |
| with self.assertRaises(TypeError): |
| issubclass(Union, int) |
| with self.assertRaises(TypeError): |
| issubclass(int, Union[int, str]) |
| with self.assertRaises(TypeError): |
| issubclass(Union[int, str], int) |
| |
| def test_union_any(self): |
| u = Union[Any] |
| self.assertEqual(u, Any) |
| u1 = Union[int, Any] |
| u2 = Union[Any, int] |
| u3 = Union[Any, object] |
| self.assertEqual(u1, u2) |
| self.assertNotEqual(u1, Any) |
| self.assertNotEqual(u2, Any) |
| self.assertNotEqual(u3, Any) |
| |
| def test_union_object(self): |
| u = Union[object] |
| self.assertEqual(u, object) |
| u = Union[int, object] |
| self.assertEqual(u, object) |
| u = Union[object, int] |
| self.assertEqual(u, object) |
| |
| def test_unordered(self): |
| u1 = Union[int, float] |
| u2 = Union[float, int] |
| self.assertEqual(u1, u2) |
| |
| def test_single_class_disappears(self): |
| t = Union[Employee] |
| self.assertIs(t, Employee) |
| |
| def test_base_class_disappears(self): |
| u = Union[Employee, Manager, int] |
| self.assertEqual(u, Union[int, Employee]) |
| u = Union[Manager, int, Employee] |
| self.assertEqual(u, Union[int, Employee]) |
| u = Union[Employee, Manager] |
| self.assertIs(u, Employee) |
| |
| def test_union_union(self): |
| u = Union[int, float] |
| v = Union[u, Employee] |
| self.assertEqual(v, Union[int, float, Employee]) |
| |
| def test_repr(self): |
| self.assertEqual(repr(Union), 'typing.Union') |
| u = Union[Employee, int] |
| self.assertEqual(repr(u), 'typing.Union[%s.Employee, int]' % __name__) |
| u = Union[int, Employee] |
| self.assertEqual(repr(u), 'typing.Union[int, %s.Employee]' % __name__) |
| |
| def test_cannot_subclass(self): |
| with self.assertRaises(TypeError): |
| class C(Union): |
| pass |
| with self.assertRaises(TypeError): |
| class C(type(Union)): |
| pass |
| with self.assertRaises(TypeError): |
| class C(Union[int, str]): |
| pass |
| |
| def test_cannot_instantiate(self): |
| with self.assertRaises(TypeError): |
| Union() |
| with self.assertRaises(TypeError): |
| type(Union)() |
| u = Union[int, float] |
| with self.assertRaises(TypeError): |
| u() |
| with self.assertRaises(TypeError): |
| type(u)() |
| |
| def test_union_generalization(self): |
| self.assertFalse(Union[str, typing.Iterable[int]] == str) |
| self.assertFalse(Union[str, typing.Iterable[int]] == typing.Iterable[int]) |
| self.assertTrue(Union[str, typing.Iterable] == typing.Iterable) |
| |
| def test_union_compare_other(self): |
| self.assertNotEqual(Union, object) |
| self.assertNotEqual(Union, Any) |
| self.assertNotEqual(ClassVar, Union) |
| self.assertNotEqual(Optional, Union) |
| self.assertNotEqual([None], Optional) |
| self.assertNotEqual(Optional, typing.Mapping) |
| self.assertNotEqual(Optional[typing.MutableMapping], Union) |
| |
| def test_optional(self): |
| o = Optional[int] |
| u = Union[int, None] |
| self.assertEqual(o, u) |
| |
| def test_empty(self): |
| with self.assertRaises(TypeError): |
| Union[()] |
| |
| def test_union_instance_type_error(self): |
| with self.assertRaises(TypeError): |
| isinstance(42, Union[int, str]) |
| |
| def test_union_str_pattern(self): |
| # Shouldn't crash; see http://bugs.python.org/issue25390 |
| A = Union[str, Pattern] |
| A |
| |
| def test_etree(self): |
| # See https://github.com/python/typing/issues/229 |
| # (Only relevant for Python 2.) |
| try: |
| from xml.etree.cElementTree import Element |
| except ImportError: |
| raise SkipTest("cElementTree not found") |
| Union[Element, str] # Shouldn't crash |
| |
| def Elem(*args): |
| return Element(*args) |
| |
| Union[Elem, str] # Nor should this |
| |
| |
| class TupleTests(BaseTestCase): |
| |
| def test_basics(self): |
| with self.assertRaises(TypeError): |
| issubclass(Tuple, Tuple[int, str]) |
| with self.assertRaises(TypeError): |
| issubclass(tuple, Tuple[int, str]) |
| |
| class TP(tuple): ... |
| self.assertTrue(issubclass(tuple, Tuple)) |
| self.assertTrue(issubclass(TP, Tuple)) |
| |
| def test_equality(self): |
| self.assertEqual(Tuple[int], Tuple[int]) |
| self.assertEqual(Tuple[int, ...], Tuple[int, ...]) |
| self.assertNotEqual(Tuple[int], Tuple[int, int]) |
| self.assertNotEqual(Tuple[int], Tuple[int, ...]) |
| |
| def test_tuple_subclass(self): |
| class MyTuple(tuple): |
| pass |
| self.assertTrue(issubclass(MyTuple, Tuple)) |
| |
| def test_tuple_instance_type_error(self): |
| with self.assertRaises(TypeError): |
| isinstance((0, 0), Tuple[int, int]) |
| self.assertIsInstance((0, 0), Tuple) |
| |
| def test_repr(self): |
| self.assertEqual(repr(Tuple), 'typing.Tuple') |
| self.assertEqual(repr(Tuple[()]), 'typing.Tuple[()]') |
| self.assertEqual(repr(Tuple[int, float]), 'typing.Tuple[int, float]') |
| self.assertEqual(repr(Tuple[int, ...]), 'typing.Tuple[int, ...]') |
| |
| def test_errors(self): |
| with self.assertRaises(TypeError): |
| issubclass(42, Tuple) |
| with self.assertRaises(TypeError): |
| issubclass(42, Tuple[int]) |
| |
| |
| class CallableTests(BaseTestCase): |
| |
| def test_self_subclass(self): |
| with self.assertRaises(TypeError): |
| self.assertTrue(issubclass(type(lambda x: x), Callable[[int], int])) |
| self.assertTrue(issubclass(type(lambda x: x), Callable)) |
| |
| def test_eq_hash(self): |
| self.assertEqual(Callable[[int], int], Callable[[int], int]) |
| self.assertEqual(len({Callable[[int], int], Callable[[int], int]}), 1) |
| self.assertNotEqual(Callable[[int], int], Callable[[int], str]) |
| self.assertNotEqual(Callable[[int], int], Callable[[str], int]) |
| self.assertNotEqual(Callable[[int], int], Callable[[int, int], int]) |
| self.assertNotEqual(Callable[[int], int], Callable[[], int]) |
| self.assertNotEqual(Callable[[int], int], Callable) |
| |
| def test_cannot_instantiate(self): |
| with self.assertRaises(TypeError): |
| Callable() |
| with self.assertRaises(TypeError): |
| type(Callable)() |
| c = Callable[[int], str] |
| with self.assertRaises(TypeError): |
| c() |
| with self.assertRaises(TypeError): |
| type(c)() |
| |
| def test_callable_wrong_forms(self): |
| with self.assertRaises(TypeError): |
| Callable[[...], int] |
| with self.assertRaises(TypeError): |
| Callable[(), int] |
| with self.assertRaises(TypeError): |
| Callable[[()], int] |
| with self.assertRaises(TypeError): |
| Callable[[int, 1], 2] |
| |
| def test_callable_instance_works(self): |
| def f(): |
| pass |
| self.assertIsInstance(f, Callable) |
| self.assertNotIsInstance(None, Callable) |
| |
| def test_callable_instance_type_error(self): |
| def f(): |
| pass |
| with self.assertRaises(TypeError): |
| self.assertIsInstance(f, Callable[[], None]) |
| with self.assertRaises(TypeError): |
| self.assertIsInstance(f, Callable[[], Any]) |
| with self.assertRaises(TypeError): |
| self.assertNotIsInstance(None, Callable[[], None]) |
| with self.assertRaises(TypeError): |
| self.assertNotIsInstance(None, Callable[[], Any]) |
| |
| def test_repr(self): |
| ct0 = Callable[[], bool] |
| self.assertEqual(repr(ct0), 'typing.Callable[[], bool]') |
| ct2 = Callable[[str, float], int] |
| self.assertEqual(repr(ct2), 'typing.Callable[[str, float], int]') |
| ctv = Callable[..., str] |
| self.assertEqual(repr(ctv), 'typing.Callable[..., str]') |
| |
| def test_callable_with_ellipsis(self): |
| |
| def foo(a: Callable[..., T]): |
| pass |
| |
| self.assertEqual(get_type_hints(foo, globals(), locals()), |
| {'a': Callable[..., T]}) |
| |
| def test_ellipsis_in_generic(self): |
| # Shouldn't crash; see https://github.com/python/typing/issues/259 |
| typing.List[Callable[..., str]] |
| |
| |
| XK = TypeVar('XK', str, bytes) |
| XV = TypeVar('XV') |
| |
| |
| class SimpleMapping(Generic[XK, XV]): |
| |
| def __getitem__(self, key: XK) -> XV: |
| ... |
| |
| def __setitem__(self, key: XK, value: XV): |
| ... |
| |
| def get(self, key: XK, default: XV = None) -> XV: |
| ... |
| |
| |
| class MySimpleMapping(SimpleMapping[XK, XV]): |
| |
| def __init__(self): |
| self.store = {} |
| |
| def __getitem__(self, key: str): |
| return self.store[key] |
| |
| def __setitem__(self, key: str, value): |
| self.store[key] = value |
| |
| def get(self, key: str, default=None): |
| try: |
| return self.store[key] |
| except KeyError: |
| return default |
| |
| |
| class ProtocolTests(BaseTestCase): |
| |
| def test_supports_int(self): |
| self.assertIsSubclass(int, typing.SupportsInt) |
| self.assertNotIsSubclass(str, typing.SupportsInt) |
| |
| def test_supports_float(self): |
| self.assertIsSubclass(float, typing.SupportsFloat) |
| self.assertNotIsSubclass(str, typing.SupportsFloat) |
| |
| def test_supports_complex(self): |
| |
| # Note: complex itself doesn't have __complex__. |
| class C: |
| def __complex__(self): |
| return 0j |
| |
| self.assertIsSubclass(C, typing.SupportsComplex) |
| self.assertNotIsSubclass(str, typing.SupportsComplex) |
| |
| def test_supports_bytes(self): |
| |
| # Note: bytes itself doesn't have __bytes__. |
| class B: |
| def __bytes__(self): |
| return b'' |
| |
| self.assertIsSubclass(B, typing.SupportsBytes) |
| self.assertNotIsSubclass(str, typing.SupportsBytes) |
| |
| def test_supports_abs(self): |
| self.assertIsSubclass(float, typing.SupportsAbs) |
| self.assertIsSubclass(int, typing.SupportsAbs) |
| self.assertNotIsSubclass(str, typing.SupportsAbs) |
| |
| def test_supports_round(self): |
| issubclass(float, typing.SupportsRound) |
| self.assertIsSubclass(float, typing.SupportsRound) |
| self.assertIsSubclass(int, typing.SupportsRound) |
| self.assertNotIsSubclass(str, typing.SupportsRound) |
| |
| def test_reversible(self): |
| self.assertIsSubclass(list, typing.Reversible) |
| self.assertNotIsSubclass(int, typing.Reversible) |
| |
| def test_protocol_instance_type_error(self): |
| with self.assertRaises(TypeError): |
| isinstance(0, typing.SupportsAbs) |
| class C1(typing.SupportsInt): |
| def __int__(self) -> int: |
| return 42 |
| class C2(C1): |
| pass |
| c = C2() |
| self.assertIsInstance(c, C1) |
| |
| |
| class GenericTests(BaseTestCase): |
| |
| def test_basics(self): |
| X = SimpleMapping[str, Any] |
| self.assertEqual(X.__parameters__, ()) |
| with self.assertRaises(TypeError): |
| X[str] |
| with self.assertRaises(TypeError): |
| X[str, str] |
| Y = SimpleMapping[XK, str] |
| self.assertEqual(Y.__parameters__, (XK,)) |
| Y[str] |
| with self.assertRaises(TypeError): |
| Y[str, str] |
| |
| def test_generic_errors(self): |
| T = TypeVar('T') |
| with self.assertRaises(TypeError): |
| Generic[T]() |
| with self.assertRaises(TypeError): |
| isinstance([], List[int]) |
| with self.assertRaises(TypeError): |
| issubclass(list, List[int]) |
| |
| def test_init(self): |
| T = TypeVar('T') |
| S = TypeVar('S') |
| with self.assertRaises(TypeError): |
| Generic[T, T] |
| with self.assertRaises(TypeError): |
| Generic[T, S, T] |
| |
| def test_repr(self): |
| self.assertEqual(repr(SimpleMapping), |
| __name__ + '.' + 'SimpleMapping') |
| self.assertEqual(repr(MySimpleMapping), |
| __name__ + '.' + 'MySimpleMapping') |
| |
| def test_chain_repr(self): |
| T = TypeVar('T') |
| S = TypeVar('S') |
| |
| class C(Generic[T]): |
| pass |
| |
| X = C[Tuple[S, T]] |
| self.assertEqual(X, C[Tuple[S, T]]) |
| self.assertNotEqual(X, C[Tuple[T, S]]) |
| |
| Y = X[T, int] |
| self.assertEqual(Y, X[T, int]) |
| self.assertNotEqual(Y, X[S, int]) |
| self.assertNotEqual(Y, X[T, str]) |
| |
| Z = Y[str] |
| self.assertEqual(Z, Y[str]) |
| self.assertNotEqual(Z, Y[int]) |
| self.assertNotEqual(Z, Y[T]) |
| |
| self.assertTrue(str(Z).endswith( |
| '.C[typing.Tuple[str, int]]')) |
| |
| def test_new_repr(self): |
| T = TypeVar('T') |
| U = TypeVar('U', covariant=True) |
| S = TypeVar('S') |
| |
| self.assertEqual(repr(List), 'typing.List') |
| self.assertEqual(repr(List[T]), 'typing.List[~T]') |
| self.assertEqual(repr(List[U]), 'typing.List[+U]') |
| self.assertEqual(repr(List[S][T][int]), 'typing.List[int]') |
| self.assertEqual(repr(List[int]), 'typing.List[int]') |
| |
| def test_new_repr_complex(self): |
| T = TypeVar('T') |
| TS = TypeVar('TS') |
| |
| self.assertEqual(repr(typing.Mapping[T, TS][TS, T]), 'typing.Mapping[~TS, ~T]') |
| self.assertEqual(repr(List[Tuple[T, TS]][int, T]), |
| 'typing.List[typing.Tuple[int, ~T]]') |
| self.assertEqual( |
| repr(List[Tuple[T, T]][List[int]]), |
| 'typing.List[typing.Tuple[typing.List[int], typing.List[int]]]' |
| ) |
| |
| def test_new_repr_bare(self): |
| T = TypeVar('T') |
| self.assertEqual(repr(Generic[T]), 'typing.Generic[~T]') |
| self.assertEqual(repr(typing._Protocol[T]), 'typing.Protocol[~T]') |
| class C(typing.Dict[Any, Any]): ... |
| # this line should just work |
| repr(C.__mro__) |
| |
| def test_dict(self): |
| T = TypeVar('T') |
| |
| class B(Generic[T]): |
| pass |
| |
| b = B() |
| b.foo = 42 |
| self.assertEqual(b.__dict__, {'foo': 42}) |
| |
| class C(B[int]): |
| pass |
| |
| c = C() |
| c.bar = 'abc' |
| self.assertEqual(c.__dict__, {'bar': 'abc'}) |
| |
| def test_false_subclasses(self): |
| class MyMapping(MutableMapping[str, str]): pass |
| self.assertNotIsInstance({}, MyMapping) |
| self.assertNotIsSubclass(dict, MyMapping) |
| |
| def test_abc_bases(self): |
| class MM(MutableMapping[str, str]): |
| def __getitem__(self, k): |
| return None |
| def __setitem__(self, k, v): |
| pass |
| def __delitem__(self, k): |
| pass |
| def __iter__(self): |
| return iter(()) |
| def __len__(self): |
| return 0 |
| # this should just work |
| MM().update() |
| self.assertIsInstance(MM(), collections_abc.MutableMapping) |
| self.assertIsInstance(MM(), MutableMapping) |
| self.assertNotIsInstance(MM(), List) |
| self.assertNotIsInstance({}, MM) |
| |
| def test_multiple_bases(self): |
| class MM1(MutableMapping[str, str], collections_abc.MutableMapping): |
| pass |
| with self.assertRaises(TypeError): |
| # consistent MRO not possible |
| class MM2(collections_abc.MutableMapping, MutableMapping[str, str]): |
| pass |
| |
| def test_orig_bases(self): |
| T = TypeVar('T') |
| class C(typing.Dict[str, T]): ... |
| self.assertEqual(C.__orig_bases__, (typing.Dict[str, T],)) |
| |
| def test_naive_runtime_checks(self): |
| def naive_dict_check(obj, tp): |
| # Check if a dictionary conforms to Dict type |
| if len(tp.__parameters__) > 0: |
| raise NotImplementedError |
| if tp.__args__: |
| KT, VT = tp.__args__ |
| return all( |
| isinstance(k, KT) and isinstance(v, VT) |
| for k, v in obj.items() |
| ) |
| self.assertTrue(naive_dict_check({'x': 1}, typing.Dict[str, int])) |
| self.assertFalse(naive_dict_check({1: 'x'}, typing.Dict[str, int])) |
| with self.assertRaises(NotImplementedError): |
| naive_dict_check({1: 'x'}, typing.Dict[str, T]) |
| |
| def naive_generic_check(obj, tp): |
| # Check if an instance conforms to the generic class |
| if not hasattr(obj, '__orig_class__'): |
| raise NotImplementedError |
| return obj.__orig_class__ == tp |
| class Node(Generic[T]): ... |
| self.assertTrue(naive_generic_check(Node[int](), Node[int])) |
| self.assertFalse(naive_generic_check(Node[str](), Node[int])) |
| self.assertFalse(naive_generic_check(Node[str](), List)) |
| with self.assertRaises(NotImplementedError): |
| naive_generic_check([1, 2, 3], Node[int]) |
| |
| def naive_list_base_check(obj, tp): |
| # Check if list conforms to a List subclass |
| return all(isinstance(x, tp.__orig_bases__[0].__args__[0]) |
| for x in obj) |
| class C(List[int]): ... |
| self.assertTrue(naive_list_base_check([1, 2, 3], C)) |
| self.assertFalse(naive_list_base_check(['a', 'b'], C)) |
| |
| def test_multi_subscr_base(self): |
| T = TypeVar('T') |
| U = TypeVar('U') |
| V = TypeVar('V') |
| class C(List[T][U][V]): ... |
| class D(C, List[T][U][V]): ... |
| self.assertEqual(C.__parameters__, (V,)) |
| self.assertEqual(D.__parameters__, (V,)) |
| self.assertEqual(C[int].__parameters__, ()) |
| self.assertEqual(D[int].__parameters__, ()) |
| self.assertEqual(C[int].__args__, (int,)) |
| self.assertEqual(D[int].__args__, (int,)) |
| self.assertEqual(C.__bases__, (List,)) |
| self.assertEqual(D.__bases__, (C, List)) |
| self.assertEqual(C.__orig_bases__, (List[T][U][V],)) |
| self.assertEqual(D.__orig_bases__, (C, List[T][U][V])) |
| |
| def test_subscript_meta(self): |
| T = TypeVar('T') |
| self.assertEqual(Type[GenericMeta], Type[GenericMeta]) |
| self.assertEqual(Union[T, int][GenericMeta], Union[GenericMeta, int]) |
| self.assertEqual(Callable[..., GenericMeta].__args__, (Ellipsis, GenericMeta)) |
| |
| def test_extended_generic_rules_eq(self): |
| T = TypeVar('T') |
| U = TypeVar('U') |
| self.assertEqual(Tuple[T, T][int], Tuple[int, int]) |
| self.assertEqual(typing.Iterable[Tuple[T, T]][T], typing.Iterable[Tuple[T, T]]) |
| with self.assertRaises(TypeError): |
| Tuple[T, int][()] |
| with self.assertRaises(TypeError): |
| Tuple[T, U][T, ...] |
| |
| self.assertEqual(Union[T, int][int], int) |
| self.assertEqual(Union[T, U][int, Union[int, str]], Union[int, str]) |
| class Base: ... |
| class Derived(Base): ... |
| self.assertEqual(Union[T, Base][Derived], Base) |
| with self.assertRaises(TypeError): |
| Union[T, int][1] |
| |
| self.assertEqual(Callable[[T], T][KT], Callable[[KT], KT]) |
| self.assertEqual(Callable[..., List[T]][int], Callable[..., List[int]]) |
| with self.assertRaises(TypeError): |
| Callable[[T], U][..., int] |
| with self.assertRaises(TypeError): |
| Callable[[T], U][[], int] |
| |
| def test_extended_generic_rules_repr(self): |
| T = TypeVar('T') |
| self.assertEqual(repr(Union[Tuple, Callable]).replace('typing.', ''), |
| 'Union[Tuple, Callable]') |
| self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''), |
| 'Tuple') |
| self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''), |
| 'Callable[..., Union[int, NoneType]]') |
| self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''), |
| 'Callable[[], List[int]]') |
| |
| def test_generic_forward_ref(self): |
| def foobar(x: List[List['CC']]): ... |
| class CC: ... |
| self.assertEqual( |
| get_type_hints(foobar, globals(), locals()), |
| {'x': List[List[CC]]} |
| ) |
| T = TypeVar('T') |
| AT = Tuple[T, ...] |
| def barfoo(x: AT): ... |
| self.assertIs(get_type_hints(barfoo, globals(), locals())['x'], AT) |
| CT = Callable[..., List[T]] |
| def barfoo2(x: CT): ... |
| self.assertIs(get_type_hints(barfoo2, globals(), locals())['x'], CT) |
| |
| def test_extended_generic_rules_subclassing(self): |
| class T1(Tuple[T, KT]): ... |
| class T2(Tuple[T, ...]): ... |
| class C1(Callable[[T], T]): ... |
| class C2(Callable[..., int]): |
| def __call__(self): |
| return None |
| |
| self.assertEqual(T1.__parameters__, (T, KT)) |
| self.assertEqual(T1[int, str].__args__, (int, str)) |
| self.assertEqual(T1[int, T].__origin__, T1) |
| |
| self.assertEqual(T2.__parameters__, (T,)) |
| with self.assertRaises(TypeError): |
| T1[int] |
| with self.assertRaises(TypeError): |
| T2[int, str] |
| |
| self.assertEqual(repr(C1[int]).split('.')[-1], 'C1[int]') |
| self.assertEqual(C2.__parameters__, ()) |
| self.assertIsInstance(C2(), collections_abc.Callable) |
| self.assertIsSubclass(C2, collections_abc.Callable) |
| self.assertIsSubclass(C1, collections_abc.Callable) |
| self.assertIsInstance(T1(), tuple) |
| self.assertIsSubclass(T2, tuple) |
| self.assertIsSubclass(Tuple[int, ...], typing.Sequence) |
| self.assertIsSubclass(Tuple[int, ...], typing.Iterable) |
| |
| def test_fail_with_bare_union(self): |
| with self.assertRaises(TypeError): |
| List[Union] |
| with self.assertRaises(TypeError): |
| Tuple[Optional] |
| with self.assertRaises(TypeError): |
| ClassVar[ClassVar] |
| with self.assertRaises(TypeError): |
| List[ClassVar[int]] |
| |
| def test_fail_with_bare_generic(self): |
| T = TypeVar('T') |
| with self.assertRaises(TypeError): |
| List[Generic] |
| with self.assertRaises(TypeError): |
| Tuple[Generic[T]] |
| with self.assertRaises(TypeError): |
| List[typing._Protocol] |
| |
| def test_type_erasure_special(self): |
| T = TypeVar('T') |
| # this is the only test that checks type caching |
| self.clear_caches() |
| class MyTup(Tuple[T, T]): ... |
| self.assertIs(MyTup[int]().__class__, MyTup) |
| self.assertIs(MyTup[int]().__orig_class__, MyTup[int]) |
| class MyCall(Callable[..., T]): |
| def __call__(self): return None |
| self.assertIs(MyCall[T]().__class__, MyCall) |
| self.assertIs(MyCall[T]().__orig_class__, MyCall[T]) |
| class MyDict(typing.Dict[T, T]): ... |
| self.assertIs(MyDict[int]().__class__, MyDict) |
| self.assertIs(MyDict[int]().__orig_class__, MyDict[int]) |
| class MyDef(typing.DefaultDict[str, T]): ... |
| self.assertIs(MyDef[int]().__class__, MyDef) |
| self.assertIs(MyDef[int]().__orig_class__, MyDef[int]) |
| |
| def test_all_repr_eq_any(self): |
| objs = (getattr(typing, el) for el in typing.__all__) |
| for obj in objs: |
| self.assertNotEqual(repr(obj), '') |
| self.assertEqual(obj, obj) |
| if getattr(obj, '__parameters__', None) and len(obj.__parameters__) == 1: |
| self.assertEqual(obj[Any].__args__, (Any,)) |
| if isinstance(obj, type): |
| for base in obj.__mro__: |
| self.assertNotEqual(repr(base), '') |
| self.assertEqual(base, base) |
| |
| def test_substitution_helper(self): |
| T = TypeVar('T') |
| KT = TypeVar('KT') |
| VT = TypeVar('VT') |
| class Map(Generic[KT, VT]): |
| def meth(self, k: KT, v: VT): ... |
| StrMap = Map[str, T] |
| obj = StrMap[int]() |
| |
| new_args = typing._subs_tree(obj.__orig_class__) |
| new_annots = {k: typing._replace_arg(v, type(obj).__parameters__, new_args) |
| for k, v in obj.meth.__annotations__.items()} |
| |
| self.assertEqual(new_annots, {'k': str, 'v': int}) |
| |
| def test_pickle(self): |
| global C # pickle wants to reference the class by name |
| T = TypeVar('T') |
| |
| class B(Generic[T]): |
| pass |
| |
| class C(B[int]): |
| pass |
| |
| c = C() |
| c.foo = 42 |
| c.bar = 'abc' |
| for proto in range(pickle.HIGHEST_PROTOCOL + 1): |
| z = pickle.dumps(c, proto) |
| x = pickle.loads(z) |
| self.assertEqual(x.foo, 42) |
| self.assertEqual(x.bar, 'abc') |
| self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'}) |
| simples = [Any, Union, Tuple, Callable, ClassVar, List, typing.Iterable] |
| for s in simples: |
| for proto in range(pickle.HIGHEST_PROTOCOL + 1): |
| z = pickle.dumps(s, proto) |
| x = pickle.loads(z) |
| self.assertEqual(s, x) |
| |
| def test_copy_and_deepcopy(self): |
| T = TypeVar('T') |
| class Node(Generic[T]): ... |
| things = [Union[T, int], Tuple[T, int], Callable[..., T], Callable[[int], int], |
| Tuple[Any, Any], Node[T], Node[int], Node[Any], typing.Iterable[T], |
| typing.Iterable[Any], typing.Iterable[int], typing.Dict[int, str], |
| typing.Dict[T, Any], ClassVar[int], ClassVar[List[T]], Tuple['T', 'T'], |
| Union['T', int], List['T'], typing.Mapping['T', int]] |
| for t in things + [Any]: |
| self.assertEqual(t, copy(t)) |
| self.assertEqual(t, deepcopy(t)) |
| |
| def test_weakref_all(self): |
| T = TypeVar('T') |
| things = [Any, Union[T, int], Callable[..., T], Tuple[Any, Any], |
| Optional[List[int]], typing.Mapping[int, str], |
| typing.re.Match[bytes], typing.Iterable['whatever']] |
| for t in things: |
| self.assertEqual(weakref.ref(t)(), t) |
| |
| def test_parameterized_slots(self): |
| T = TypeVar('T') |
| class C(Generic[T]): |
| __slots__ = ('potato',) |
| |
| c = C() |
| c_int = C[int]() |
| self.assertEqual(C.__slots__, C[str].__slots__) |
| |
| c.potato = 0 |
| c_int.potato = 0 |
| with self.assertRaises(AttributeError): |
| c.tomato = 0 |
| with self.assertRaises(AttributeError): |
| c_int.tomato = 0 |
| |
| def foo(x: C['C']): ... |
| self.assertEqual(get_type_hints(foo, globals(), locals())['x'], C[C]) |
| self.assertEqual(get_type_hints(foo, globals(), locals())['x'].__slots__, |
| C.__slots__) |
| self.assertEqual(copy(C[int]), deepcopy(C[int])) |
| |
| def test_parameterized_slots_dict(self): |
| T = TypeVar('T') |
| class D(Generic[T]): |
| __slots__ = {'banana': 42} |
| |
| d = D() |
| d_int = D[int]() |
| self.assertEqual(D.__slots__, D[str].__slots__) |
| |
| d.banana = 'yes' |
| d_int.banana = 'yes' |
| with self.assertRaises(AttributeError): |
| d.foobar = 'no' |
| with self.assertRaises(AttributeError): |
| d_int.foobar = 'no' |
| |
| def test_errors(self): |
| with self.assertRaises(TypeError): |
| B = SimpleMapping[XK, Any] |
| |
| class C(Generic[B]): |
| pass |
| |
| def test_repr_2(self): |
| PY32 = sys.version_info[:2] < (3, 3) |
| |
| class C(Generic[T]): |
| pass |
| |
| self.assertEqual(C.__module__, __name__) |
| if not PY32: |
| self.assertEqual(C.__qualname__, |
| 'GenericTests.test_repr_2.<locals>.C') |
| self.assertEqual(repr(C).split('.')[-1], 'C') |
| X = C[int] |
| self.assertEqual(X.__module__, __name__) |
| if not PY32: |
| self.assertTrue(X.__qualname__.endswith('.<locals>.C')) |
| self.assertEqual(repr(X).split('.')[-1], 'C[int]') |
| |
| class Y(C[int]): |
| pass |
| |
| self.assertEqual(Y.__module__, __name__) |
| if not PY32: |
| self.assertEqual(Y.__qualname__, |
| 'GenericTests.test_repr_2.<locals>.Y') |
| self.assertEqual(repr(Y).split('.')[-1], 'Y') |
| |
| def test_eq_1(self): |
| self.assertEqual(Generic, Generic) |
| self.assertEqual(Generic[T], Generic[T]) |
| self.assertNotEqual(Generic[KT], Generic[VT]) |
| |
| def test_eq_2(self): |
| |
| class A(Generic[T]): |
| pass |
| |
| class B(Generic[T]): |
| pass |
| |
| self.assertEqual(A, A) |
| self.assertNotEqual(A, B) |
| self.assertEqual(A[T], A[T]) |
| self.assertNotEqual(A[T], B[T]) |
| |
| def test_multiple_inheritance(self): |
| |
| class A(Generic[T, VT]): |
| pass |
| |
| class B(Generic[KT, T]): |
| pass |
| |
| class C(A[T, VT], Generic[VT, T, KT], B[KT, T]): |
| pass |
| |
| self.assertEqual(C.__parameters__, (VT, T, KT)) |
| |
| def test_nested(self): |
| |
| G = Generic |
| |
| class Visitor(G[T]): |
| |
| a = None |
| |
| def set(self, a: T): |
| self.a = a |
| |
| def get(self): |
| return self.a |
| |
| def visit(self) -> T: |
| return self.a |
| |
| V = Visitor[typing.List[int]] |
| |
| class IntListVisitor(V): |
| |
| def append(self, x: int): |
| self.a.append(x) |
| |
| a = IntListVisitor() |
| a.set([]) |
| a.append(1) |
| a.append(42) |
| self.assertEqual(a.get(), [1, 42]) |
| |
| def test_type_erasure(self): |
| T = TypeVar('T') |
| |
| class Node(Generic[T]): |
| def __init__(self, label: T, |
| left: 'Node[T]' = None, |
| right: 'Node[T]' = None): |
| self.label = label # type: T |
| self.left = left # type: Optional[Node[T]] |
| self.right = right # type: Optional[Node[T]] |
| |
| def foo(x: T): |
| a = Node(x) |
| b = Node[T](x) |
| c = Node[Any](x) |
| self.assertIs(type(a), Node) |
| self.assertIs(type(b), Node) |
| self.assertIs(type(c), Node) |
| self.assertEqual(a.label, x) |
| self.assertEqual(b.label, x) |
| self.assertEqual(c.label, x) |
| |
| foo(42) |
| |
| def test_implicit_any(self): |
| T = TypeVar('T') |
| |
| class C(Generic[T]): |
| pass |
| |
| class D(C): |
| pass |
| |
| self.assertEqual(D.__parameters__, ()) |
| |
| with self.assertRaises(Exception): |
| D[int] |
| with self.assertRaises(Exception): |
| D[Any] |
| with self.assertRaises(Exception): |
| D[T] |
| |
| |
| class ClassVarTests(BaseTestCase): |
| |
| def test_basics(self): |
| with self.assertRaises(TypeError): |
| ClassVar[1] |
| with self.assertRaises(TypeError): |
| ClassVar[int, str] |
| with self.assertRaises(TypeError): |
| ClassVar[int][str] |
| |
| def test_repr(self): |
| self.assertEqual(repr(ClassVar), 'typing.ClassVar') |
| cv = ClassVar[int] |
| self.assertEqual(repr(cv), 'typing.ClassVar[int]') |
| cv = ClassVar[Employee] |
| self.assertEqual(repr(cv), 'typing.ClassVar[%s.Employee]' % __name__) |
| |
| def test_cannot_subclass(self): |
| with self.assertRaises(TypeError): |
| class C(type(ClassVar)): |
| pass |
| with self.assertRaises(TypeError): |
| class C(type(ClassVar[int])): |
| pass |
| |
| def test_cannot_init(self): |
| with self.assertRaises(TypeError): |
| ClassVar() |
| with self.assertRaises(TypeError): |
| type(ClassVar)() |
| with self.assertRaises(TypeError): |
| type(ClassVar[Optional[int]])() |
| |
| def test_no_isinstance(self): |
| with self.assertRaises(TypeError): |
| isinstance(1, ClassVar[int]) |
| with self.assertRaises(TypeError): |
| issubclass(int, ClassVar) |
| |
| |
| class CastTests(BaseTestCase): |
| |
| def test_basics(self): |
| self.assertEqual(cast(int, 42), 42) |
| self.assertEqual(cast(float, 42), 42) |
| self.assertIs(type(cast(float, 42)), int) |
| self.assertEqual(cast(Any, 42), 42) |
| self.assertEqual(cast(list, 42), 42) |
| self.assertEqual(cast(Union[str, float], 42), 42) |
| self.assertEqual(cast(AnyStr, 42), 42) |
| self.assertEqual(cast(None, 42), 42) |
| |
| def test_errors(self): |
| # Bogus calls are not expected to fail. |
| cast(42, 42) |
| cast('hello', 42) |
| |
| |
| class ForwardRefTests(BaseTestCase): |
| |
| def test_basics(self): |
| |
| class Node(Generic[T]): |
| |
| def __init__(self, label: T): |
| self.label = label |
| self.left = self.right = None |
| |
| def add_both(self, |
| left: 'Optional[Node[T]]', |
| right: 'Node[T]' = None, |
| stuff: int = None, |
| blah=None): |
| self.left = left |
| self.right = right |
| |
| def add_left(self, node: Optional['Node[T]']): |
| self.add_both(node, None) |
| |
| def add_right(self, node: 'Node[T]' = None): |
| self.add_both(None, node) |
| |
| t = Node[int] |
| both_hints = get_type_hints(t.add_both, globals(), locals()) |
| self.assertEqual(both_hints['left'], Optional[Node[T]]) |
| self.assertEqual(both_hints['right'], Optional[Node[T]]) |
| self.assertEqual(both_hints['left'], both_hints['right']) |
| self.assertEqual(both_hints['stuff'], Optional[int]) |
| self.assertNotIn('blah', both_hints) |
| |
| left_hints = get_type_hints(t.add_left, globals(), locals()) |
| self.assertEqual(left_hints['node'], Optional[Node[T]]) |
| |
| right_hints = get_type_hints(t.add_right, globals(), locals()) |
| self.assertEqual(right_hints['node'], Optional[Node[T]]) |
| |
| def test_forwardref_instance_type_error(self): |
| fr = typing._ForwardRef('int') |
| with self.assertRaises(TypeError): |
| isinstance(42, fr) |
| |
| def test_union_forward(self): |
| |
| def foo(a: Union['T']): |
| pass |
| |
| self.assertEqual(get_type_hints(foo, globals(), locals()), |
| {'a': Union[T]}) |
| |
| def test_tuple_forward(self): |
| |
| def foo(a: Tuple['T']): |
| pass |
| |
| self.assertEqual(get_type_hints(foo, globals(), locals()), |
| {'a': Tuple[T]}) |
| |
| def test_callable_forward(self): |
| |
| def foo(a: Callable[['T'], 'T']): |
| pass |
| |
| self.assertEqual(get_type_hints(foo, globals(), locals()), |
| {'a': Callable[[T], T]}) |
| |
| def test_callable_with_ellipsis_forward(self): |
| |
| def foo(a: 'Callable[..., T]'): |
| pass |
| |
| self.assertEqual(get_type_hints(foo, globals(), locals()), |
| {'a': Callable[..., T]}) |
| |
| def test_syntax_error(self): |
| |
| with self.assertRaises(SyntaxError): |
| Generic['/T'] |
| |
| def test_delayed_syntax_error(self): |
| |
| def foo(a: 'Node[T'): |
| pass |
| |
| with self.assertRaises(SyntaxError): |
| get_type_hints(foo) |
| |
| def test_type_error(self): |
| |
| def foo(a: Tuple['42']): |
| pass |
| |
| with self.assertRaises(TypeError): |
| get_type_hints(foo) |
| |
| def test_name_error(self): |
| |
| def foo(a: 'Noode[T]'): |
| pass |
| |
| with self.assertRaises(NameError): |
| get_type_hints(foo, locals()) |
| |
| def test_no_type_check(self): |
| |
| @no_type_check |
| def foo(a: 'whatevers') -> {}: |
| pass |
| |
| th = get_type_hints(foo) |
| self.assertEqual(th, {}) |
| |
| def test_no_type_check_class(self): |
| |
| @no_type_check |
| class C: |
| def foo(a: 'whatevers') -> {}: |
| pass |
| |
| cth = get_type_hints(C.foo) |
| self.assertEqual(cth, {}) |
| ith = get_type_hints(C().foo) |
| self.assertEqual(ith, {}) |
| |
| def test_meta_no_type_check(self): |
| |
| @no_type_check_decorator |
| def magic_decorator(deco): |
| return deco |
| |
| self.assertEqual(magic_decorator.__name__, 'magic_decorator') |
| |
| @magic_decorator |
| def foo(a: 'whatevers') -> {}: |
| pass |
| |
| @magic_decorator |
| class C: |
| def foo(a: 'whatevers') -> {}: |
| pass |
| |
| self.assertEqual(foo.__name__, 'foo') |
| th = get_type_hints(foo) |
| self.assertEqual(th, {}) |
| cth = get_type_hints(C.foo) |
| self.assertEqual(cth, {}) |
| ith = get_type_hints(C().foo) |
| self.assertEqual(ith, {}) |
| |
| def test_default_globals(self): |
| code = ("class C:\n" |
| " def foo(self, a: 'C') -> 'D': pass\n" |
| "class D:\n" |
| " def bar(self, b: 'D') -> C: pass\n" |
| ) |
| ns = {} |
| exec(code, ns) |
| hints = get_type_hints(ns['C'].foo) |
| self.assertEqual(hints, {'a': ns['C'], 'return': ns['D']}) |
| |
| |
| class OverloadTests(BaseTestCase): |
| |
| def test_overload_fails(self): |
| from typing import overload |
| |
| with self.assertRaises(RuntimeError): |
| |
| @overload |
| def blah(): |
| pass |
| |
| blah() |
| |
| def test_overload_succeeds(self): |
| from typing import overload |
| |
| @overload |
| def blah(): |
| pass |
| |
| def blah(): |
| pass |
| |
| blah() |
| |
| |
| ASYNCIO = sys.version_info[:2] >= (3, 5) |
| |
| ASYNCIO_TESTS = """ |
| import asyncio |
| |
| T_a = TypeVar('T_a') |
| |
| class AwaitableWrapper(typing.Awaitable[T_a]): |
| |
| def __init__(self, value): |
| self.value = value |
| |
| def __await__(self) -> typing.Iterator[T_a]: |
| yield |
| return self.value |
| |
| class AsyncIteratorWrapper(typing.AsyncIterator[T_a]): |
| |
| def __init__(self, value: typing.Iterable[T_a]): |
| self.value = value |
| |
| def __aiter__(self) -> typing.AsyncIterator[T_a]: |
| return self |
| |
| @asyncio.coroutine |
| def __anext__(self) -> T_a: |
| data = yield from self.value |
| if data: |
| return data |
| else: |
| raise StopAsyncIteration |
| """ |
| |
| if ASYNCIO: |
| try: |
| exec(ASYNCIO_TESTS) |
| except ImportError: |
| ASYNCIO = False |
| else: |
| # fake names for the sake of static analysis |
| asyncio = None |
| AwaitableWrapper = AsyncIteratorWrapper = object |
| |
| PY36 = sys.version_info[:2] >= (3, 6) |
| |
| PY36_TESTS = """ |
| from test import ann_module, ann_module2, ann_module3 |
| |
| class A: |
| y: float |
| class B(A): |
| x: ClassVar[Optional['B']] = None |
| y: int |
| class CSub(B): |
| z: ClassVar['CSub'] = B() |
| class G(Generic[T]): |
| lst: ClassVar[List[T]] = [] |
| |
| class CoolEmployee(NamedTuple): |
| name: str |
| cool: int |
| |
| class CoolEmployeeWithDefault(NamedTuple): |
| name: str |
| cool: int = 0 |
| |
| class XMeth(NamedTuple): |
| x: int |
| def double(self): |
| return 2 * self.x |
| |
| class XMethBad(NamedTuple): |
| x: int |
| def _fields(self): |
| return 'no chance for this' |
| """ |
| |
| if PY36: |
| exec(PY36_TESTS) |
| else: |
| # fake names for the sake of static analysis |
| ann_module = ann_module2 = ann_module3 = None |
| A = B = CSub = G = CoolEmployee = CoolEmployeeWithDefault = object |
| XMeth = XMethBad = object |
| |
| gth = get_type_hints |
| |
| |
| class GetTypeHintTests(BaseTestCase): |
| def test_get_type_hints_from_various_objects(self): |
| # For invalid objects should fail with TypeError (not AttributeError etc). |
| with self.assertRaises(TypeError): |
| gth(123) |
| with self.assertRaises(TypeError): |
| gth('abc') |
| with self.assertRaises(TypeError): |
| gth(None) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_get_type_hints_modules(self): |
| ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str} |
| self.assertEqual(gth(ann_module), ann_module_type_hints) |
| self.assertEqual(gth(ann_module2), {}) |
| self.assertEqual(gth(ann_module3), {}) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_get_type_hints_classes(self): |
| self.assertEqual(gth(ann_module.C, ann_module.__dict__), |
| {'y': Optional[ann_module.C]}) |
| self.assertIsInstance(gth(ann_module.j_class), dict) |
| self.assertEqual(gth(ann_module.M), {'123': 123, 'o': type}) |
| self.assertEqual(gth(ann_module.D), |
| {'j': str, 'k': str, 'y': Optional[ann_module.C]}) |
| self.assertEqual(gth(ann_module.Y), {'z': int}) |
| self.assertEqual(gth(ann_module.h_class), |
| {'y': Optional[ann_module.C]}) |
| self.assertEqual(gth(ann_module.S), {'x': str, 'y': str}) |
| self.assertEqual(gth(ann_module.foo), {'x': int}) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_respect_no_type_check(self): |
| @no_type_check |
| class NoTpCheck: |
| class Inn: |
| def __init__(self, x: 'not a type'): ... |
| self.assertTrue(NoTpCheck.__no_type_check__) |
| self.assertTrue(NoTpCheck.Inn.__init__.__no_type_check__) |
| self.assertEqual(gth(ann_module2.NTC.meth), {}) |
| class ABase(Generic[T]): |
| def meth(x: int): ... |
| @no_type_check |
| class Der(ABase): ... |
| self.assertEqual(gth(ABase.meth), {'x': int}) |
| |
| def test_get_type_hints_for_builins(self): |
| # Should not fail for built-in classes and functions. |
| self.assertEqual(gth(int), {}) |
| self.assertEqual(gth(type), {}) |
| self.assertEqual(gth(dir), {}) |
| self.assertEqual(gth(len), {}) |
| |
| def test_previous_behavior(self): |
| def testf(x, y): ... |
| testf.__annotations__['x'] = 'int' |
| self.assertEqual(gth(testf), {'x': int}) |
| |
| def test_get_type_hints_for_object_with_annotations(self): |
| class A: ... |
| class B: ... |
| b = B() |
| b.__annotations__ = {'x': 'A'} |
| self.assertEqual(gth(b, locals()), {'x': A}) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_get_type_hints_ClassVar(self): |
| self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__), |
| {'var': typing.ClassVar[ann_module2.CV]}) |
| self.assertEqual(gth(B, globals()), |
| {'y': int, 'x': ClassVar[Optional[B]]}) |
| self.assertEqual(gth(CSub, globals()), |
| {'z': ClassVar[CSub], 'y': int, 'x': ClassVar[Optional[B]]}) |
| self.assertEqual(gth(G), {'lst': ClassVar[List[T]]}) |
| |
| |
| class CollectionsAbcTests(BaseTestCase): |
| |
| def test_hashable(self): |
| self.assertIsInstance(42, typing.Hashable) |
| self.assertNotIsInstance([], typing.Hashable) |
| |
| def test_iterable(self): |
| self.assertIsInstance([], typing.Iterable) |
| # Due to ABC caching, the second time takes a separate code |
| # path and could fail. So call this a few times. |
| self.assertIsInstance([], typing.Iterable) |
| self.assertIsInstance([], typing.Iterable) |
| self.assertNotIsInstance(42, typing.Iterable) |
| # Just in case, also test issubclass() a few times. |
| self.assertIsSubclass(list, typing.Iterable) |
| self.assertIsSubclass(list, typing.Iterable) |
| |
| def test_iterator(self): |
| it = iter([]) |
| self.assertIsInstance(it, typing.Iterator) |
| self.assertNotIsInstance(42, typing.Iterator) |
| |
| @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') |
| def test_awaitable(self): |
| ns = {} |
| exec( |
| "async def foo() -> typing.Awaitable[int]:\n" |
| " return await AwaitableWrapper(42)\n", |
| globals(), ns) |
| foo = ns['foo'] |
| g = foo() |
| self.assertIsInstance(g, typing.Awaitable) |
| self.assertNotIsInstance(foo, typing.Awaitable) |
| g.send(None) # Run foo() till completion, to avoid warning. |
| |
| @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') |
| def test_coroutine(self): |
| ns = {} |
| exec( |
| "async def foo():\n" |
| " return\n", |
| globals(), ns) |
| foo = ns['foo'] |
| g = foo() |
| self.assertIsInstance(g, typing.Coroutine) |
| with self.assertRaises(TypeError): |
| isinstance(g, typing.Coroutine[int]) |
| self.assertNotIsInstance(foo, typing.Coroutine) |
| try: |
| g.send(None) |
| except StopIteration: |
| pass |
| |
| @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') |
| def test_async_iterable(self): |
| base_it = range(10) # type: Iterator[int] |
| it = AsyncIteratorWrapper(base_it) |
| self.assertIsInstance(it, typing.AsyncIterable) |
| self.assertIsInstance(it, typing.AsyncIterable) |
| self.assertNotIsInstance(42, typing.AsyncIterable) |
| |
| @skipUnless(ASYNCIO, 'Python 3.5 and multithreading required') |
| def test_async_iterator(self): |
| base_it = range(10) # type: Iterator[int] |
| it = AsyncIteratorWrapper(base_it) |
| self.assertIsInstance(it, typing.AsyncIterator) |
| self.assertNotIsInstance(42, typing.AsyncIterator) |
| |
| def test_sized(self): |
| self.assertIsInstance([], typing.Sized) |
| self.assertNotIsInstance(42, typing.Sized) |
| |
| def test_container(self): |
| self.assertIsInstance([], typing.Container) |
| self.assertNotIsInstance(42, typing.Container) |
| |
| def test_collection(self): |
| if hasattr(typing, 'Collection'): |
| self.assertIsInstance(tuple(), typing.Collection) |
| self.assertIsInstance(frozenset(), typing.Collection) |
| self.assertIsSubclass(dict, typing.Collection) |
| self.assertNotIsInstance(42, typing.Collection) |
| |
| def test_abstractset(self): |
| self.assertIsInstance(set(), typing.AbstractSet) |
| self.assertNotIsInstance(42, typing.AbstractSet) |
| |
| def test_mutableset(self): |
| self.assertIsInstance(set(), typing.MutableSet) |
| self.assertNotIsInstance(frozenset(), typing.MutableSet) |
| |
| def test_mapping(self): |
| self.assertIsInstance({}, typing.Mapping) |
| self.assertNotIsInstance(42, typing.Mapping) |
| |
| def test_mutablemapping(self): |
| self.assertIsInstance({}, typing.MutableMapping) |
| self.assertNotIsInstance(42, typing.MutableMapping) |
| |
| def test_sequence(self): |
| self.assertIsInstance([], typing.Sequence) |
| self.assertNotIsInstance(42, typing.Sequence) |
| |
| def test_mutablesequence(self): |
| self.assertIsInstance([], typing.MutableSequence) |
| self.assertNotIsInstance((), typing.MutableSequence) |
| |
| def test_bytestring(self): |
| self.assertIsInstance(b'', typing.ByteString) |
| self.assertIsInstance(bytearray(b''), typing.ByteString) |
| |
| def test_list(self): |
| self.assertIsSubclass(list, typing.List) |
| |
| def test_deque(self): |
| self.assertIsSubclass(collections.deque, typing.Deque) |
| |
| def test_set(self): |
| self.assertIsSubclass(set, typing.Set) |
| self.assertNotIsSubclass(frozenset, typing.Set) |
| |
| def test_frozenset(self): |
| self.assertIsSubclass(frozenset, typing.FrozenSet) |
| self.assertNotIsSubclass(set, typing.FrozenSet) |
| |
| def test_dict(self): |
| self.assertIsSubclass(dict, typing.Dict) |
| |
| def test_no_list_instantiation(self): |
| with self.assertRaises(TypeError): |
| typing.List() |
| with self.assertRaises(TypeError): |
| typing.List[T]() |
| with self.assertRaises(TypeError): |
| typing.List[int]() |
| |
| def test_list_subclass(self): |
| |
| class MyList(typing.List[int]): |
| pass |
| |
| a = MyList() |
| self.assertIsInstance(a, MyList) |
| self.assertIsInstance(a, typing.Sequence) |
| |
| self.assertIsSubclass(MyList, list) |
| self.assertNotIsSubclass(list, MyList) |
| |
| def test_no_dict_instantiation(self): |
| with self.assertRaises(TypeError): |
| typing.Dict() |
| with self.assertRaises(TypeError): |
| typing.Dict[KT, VT]() |
| with self.assertRaises(TypeError): |
| typing.Dict[str, int]() |
| |
| def test_dict_subclass(self): |
| |
| class MyDict(typing.Dict[str, int]): |
| pass |
| |
| d = MyDict() |
| self.assertIsInstance(d, MyDict) |
| self.assertIsInstance(d, typing.MutableMapping) |
| |
| self.assertIsSubclass(MyDict, dict) |
| self.assertNotIsSubclass(dict, MyDict) |
| |
| def test_no_defaultdict_instantiation(self): |
| with self.assertRaises(TypeError): |
| typing.DefaultDict() |
| with self.assertRaises(TypeError): |
| typing.DefaultDict[KT, VT]() |
| with self.assertRaises(TypeError): |
| typing.DefaultDict[str, int]() |
| |
| def test_defaultdict_subclass(self): |
| |
| class MyDefDict(typing.DefaultDict[str, int]): |
| pass |
| |
| dd = MyDefDict() |
| self.assertIsInstance(dd, MyDefDict) |
| |
| self.assertIsSubclass(MyDefDict, collections.defaultdict) |
| self.assertNotIsSubclass(collections.defaultdict, MyDefDict) |
| |
| def test_no_deque_instantiation(self): |
| with self.assertRaises(TypeError): |
| typing.Deque() |
| with self.assertRaises(TypeError): |
| typing.Deque[T]() |
| with self.assertRaises(TypeError): |
| typing.Deque[int]() |
| |
| def test_no_set_instantiation(self): |
| with self.assertRaises(TypeError): |
| typing.Set() |
| with self.assertRaises(TypeError): |
| typing.Set[T]() |
| with self.assertRaises(TypeError): |
| typing.Set[int]() |
| |
| def test_set_subclass_instantiation(self): |
| |
| class MySet(typing.Set[int]): |
| pass |
| |
| d = MySet() |
| self.assertIsInstance(d, MySet) |
| |
| def test_no_frozenset_instantiation(self): |
| with self.assertRaises(TypeError): |
| typing.FrozenSet() |
| with self.assertRaises(TypeError): |
| typing.FrozenSet[T]() |
| with self.assertRaises(TypeError): |
| typing.FrozenSet[int]() |
| |
| def test_frozenset_subclass_instantiation(self): |
| |
| class MyFrozenSet(typing.FrozenSet[int]): |
| pass |
| |
| d = MyFrozenSet() |
| self.assertIsInstance(d, MyFrozenSet) |
| |
| def test_no_tuple_instantiation(self): |
| with self.assertRaises(TypeError): |
| Tuple() |
| with self.assertRaises(TypeError): |
| Tuple[T]() |
| with self.assertRaises(TypeError): |
| Tuple[int]() |
| |
| def test_generator(self): |
| def foo(): |
| yield 42 |
| g = foo() |
| self.assertIsSubclass(type(g), typing.Generator) |
| |
| def test_no_generator_instantiation(self): |
| with self.assertRaises(TypeError): |
| typing.Generator() |
| with self.assertRaises(TypeError): |
| typing.Generator[T, T, T]() |
| with self.assertRaises(TypeError): |
| typing.Generator[int, int, int]() |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_async_generator(self): |
| ns = {} |
| exec("async def f():\n" |
| " yield 42\n", globals(), ns) |
| g = ns['f']() |
| self.assertIsSubclass(type(g), typing.AsyncGenerator) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_no_async_generator_instantiation(self): |
| with self.assertRaises(TypeError): |
| typing.AsyncGenerator() |
| with self.assertRaises(TypeError): |
| typing.AsyncGenerator[T, T]() |
| with self.assertRaises(TypeError): |
| typing.AsyncGenerator[int, int]() |
| |
| def test_subclassing(self): |
| |
| class MMA(typing.MutableMapping): |
| pass |
| |
| with self.assertRaises(TypeError): # It's abstract |
| MMA() |
| |
| class MMC(MMA): |
| def __getitem__(self, k): |
| return None |
| def __setitem__(self, k, v): |
| pass |
| def __delitem__(self, k): |
| pass |
| def __iter__(self): |
| return iter(()) |
| def __len__(self): |
| return 0 |
| |
| self.assertEqual(len(MMC()), 0) |
| assert callable(MMC.update) |
| self.assertIsInstance(MMC(), typing.Mapping) |
| |
| class MMB(typing.MutableMapping[KT, VT]): |
| def __getitem__(self, k): |
| return None |
| def __setitem__(self, k, v): |
| pass |
| def __delitem__(self, k): |
| pass |
| def __iter__(self): |
| return iter(()) |
| def __len__(self): |
| return 0 |
| |
| self.assertEqual(len(MMB()), 0) |
| self.assertEqual(len(MMB[str, str]()), 0) |
| self.assertEqual(len(MMB[KT, VT]()), 0) |
| |
| self.assertNotIsSubclass(dict, MMA) |
| self.assertNotIsSubclass(dict, MMB) |
| |
| self.assertIsSubclass(MMA, typing.Mapping) |
| self.assertIsSubclass(MMB, typing.Mapping) |
| self.assertIsSubclass(MMC, typing.Mapping) |
| |
| self.assertIsInstance(MMB[KT, VT](), typing.Mapping) |
| self.assertIsInstance(MMB[KT, VT](), collections.Mapping) |
| |
| self.assertIsSubclass(MMA, collections.Mapping) |
| self.assertIsSubclass(MMB, collections.Mapping) |
| self.assertIsSubclass(MMC, collections.Mapping) |
| |
| self.assertIsSubclass(MMB[str, str], typing.Mapping) |
| self.assertIsSubclass(MMC, MMA) |
| |
| class I(typing.Iterable): ... |
| self.assertNotIsSubclass(list, I) |
| |
| class G(typing.Generator[int, int, int]): ... |
| def g(): yield 0 |
| self.assertIsSubclass(G, typing.Generator) |
| self.assertIsSubclass(G, typing.Iterable) |
| if hasattr(collections, 'Generator'): |
| self.assertIsSubclass(G, collections.Generator) |
| self.assertIsSubclass(G, collections.Iterable) |
| self.assertNotIsSubclass(type(g), G) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_subclassing_async_generator(self): |
| class G(typing.AsyncGenerator[int, int]): |
| def asend(self, value): |
| pass |
| def athrow(self, typ, val=None, tb=None): |
| pass |
| |
| ns = {} |
| exec('async def g(): yield 0', globals(), ns) |
| g = ns['g'] |
| self.assertIsSubclass(G, typing.AsyncGenerator) |
| self.assertIsSubclass(G, typing.AsyncIterable) |
| self.assertIsSubclass(G, collections.AsyncGenerator) |
| self.assertIsSubclass(G, collections.AsyncIterable) |
| self.assertNotIsSubclass(type(g), G) |
| |
| instance = G() |
| self.assertIsInstance(instance, typing.AsyncGenerator) |
| self.assertIsInstance(instance, typing.AsyncIterable) |
| self.assertIsInstance(instance, collections.AsyncGenerator) |
| self.assertIsInstance(instance, collections.AsyncIterable) |
| self.assertNotIsInstance(type(g), G) |
| self.assertNotIsInstance(g, G) |
| |
| def test_subclassing_subclasshook(self): |
| |
| class Base(typing.Iterable): |
| @classmethod |
| def __subclasshook__(cls, other): |
| if other.__name__ == 'Foo': |
| return True |
| else: |
| return False |
| |
| class C(Base): ... |
| class Foo: ... |
| class Bar: ... |
| self.assertIsSubclass(Foo, Base) |
| self.assertIsSubclass(Foo, C) |
| self.assertNotIsSubclass(Bar, C) |
| |
| def test_subclassing_register(self): |
| |
| class A(typing.Container): ... |
| class B(A): ... |
| |
| class C: ... |
| A.register(C) |
| self.assertIsSubclass(C, A) |
| self.assertNotIsSubclass(C, B) |
| |
| class D: ... |
| B.register(D) |
| self.assertIsSubclass(D, A) |
| self.assertIsSubclass(D, B) |
| |
| class M(): ... |
| collections.MutableMapping.register(M) |
| self.assertIsSubclass(M, typing.Mapping) |
| |
| def test_collections_as_base(self): |
| |
| class M(collections.Mapping): ... |
| self.assertIsSubclass(M, typing.Mapping) |
| self.assertIsSubclass(M, typing.Iterable) |
| |
| class S(collections.MutableSequence): ... |
| self.assertIsSubclass(S, typing.MutableSequence) |
| self.assertIsSubclass(S, typing.Iterable) |
| |
| class I(collections.Iterable): ... |
| self.assertIsSubclass(I, typing.Iterable) |
| |
| class A(collections.Mapping, metaclass=abc.ABCMeta): ... |
| class B: ... |
| A.register(B) |
| self.assertIsSubclass(B, typing.Mapping) |
| |
| |
| class OtherABCTests(BaseTestCase): |
| |
| @skipUnless(hasattr(typing, 'ContextManager'), |
| 'requires typing.ContextManager') |
| def test_contextmanager(self): |
| @contextlib.contextmanager |
| def manager(): |
| yield 42 |
| |
| cm = manager() |
| self.assertIsInstance(cm, typing.ContextManager) |
| self.assertNotIsInstance(42, typing.ContextManager) |
| |
| |
| class TypeTests(BaseTestCase): |
| |
| def test_type_basic(self): |
| |
| class User: pass |
| class BasicUser(User): pass |
| class ProUser(User): pass |
| |
| def new_user(user_class: Type[User]) -> User: |
| return user_class() |
| |
| new_user(BasicUser) |
| |
| def test_type_typevar(self): |
| |
| class User: pass |
| class BasicUser(User): pass |
| class ProUser(User): pass |
| |
| U = TypeVar('U', bound=User) |
| |
| def new_user(user_class: Type[U]) -> U: |
| return user_class() |
| |
| new_user(BasicUser) |
| |
| def test_type_optional(self): |
| A = Optional[Type[BaseException]] |
| |
| def foo(a: A) -> Optional[BaseException]: |
| if a is None: |
| return None |
| else: |
| return a() |
| |
| assert isinstance(foo(KeyboardInterrupt), KeyboardInterrupt) |
| assert foo(None) is None |
| |
| |
| class NewTypeTests(BaseTestCase): |
| |
| def test_basic(self): |
| UserId = NewType('UserId', int) |
| UserName = NewType('UserName', str) |
| self.assertIsInstance(UserId(5), int) |
| self.assertIsInstance(UserName('Joe'), str) |
| self.assertEqual(UserId(5) + 1, 6) |
| |
| def test_errors(self): |
| UserId = NewType('UserId', int) |
| UserName = NewType('UserName', str) |
| with self.assertRaises(TypeError): |
| issubclass(UserId, int) |
| with self.assertRaises(TypeError): |
| class D(UserName): |
| pass |
| |
| |
| class NamedTupleTests(BaseTestCase): |
| |
| def test_basics(self): |
| Emp = NamedTuple('Emp', [('name', str), ('id', int)]) |
| self.assertIsSubclass(Emp, tuple) |
| joe = Emp('Joe', 42) |
| jim = Emp(name='Jim', id=1) |
| self.assertIsInstance(joe, Emp) |
| self.assertIsInstance(joe, tuple) |
| self.assertEqual(joe.name, 'Joe') |
| self.assertEqual(joe.id, 42) |
| self.assertEqual(jim.name, 'Jim') |
| self.assertEqual(jim.id, 1) |
| self.assertEqual(Emp.__name__, 'Emp') |
| self.assertEqual(Emp._fields, ('name', 'id')) |
| self.assertEqual(Emp.__annotations__, |
| collections.OrderedDict([('name', str), ('id', int)])) |
| self.assertIs(Emp._field_types, Emp.__annotations__) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_annotation_usage(self): |
| tim = CoolEmployee('Tim', 9000) |
| self.assertIsInstance(tim, CoolEmployee) |
| self.assertIsInstance(tim, tuple) |
| self.assertEqual(tim.name, 'Tim') |
| self.assertEqual(tim.cool, 9000) |
| self.assertEqual(CoolEmployee.__name__, 'CoolEmployee') |
| self.assertEqual(CoolEmployee._fields, ('name', 'cool')) |
| self.assertEqual(CoolEmployee.__annotations__, |
| collections.OrderedDict(name=str, cool=int)) |
| self.assertIs(CoolEmployee._field_types, CoolEmployee.__annotations__) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_annotation_usage_with_default(self): |
| jelle = CoolEmployeeWithDefault('Jelle') |
| self.assertIsInstance(jelle, CoolEmployeeWithDefault) |
| self.assertIsInstance(jelle, tuple) |
| self.assertEqual(jelle.name, 'Jelle') |
| self.assertEqual(jelle.cool, 0) |
| cooler_employee = CoolEmployeeWithDefault('Sjoerd', 1) |
| self.assertEqual(cooler_employee.cool, 1) |
| |
| self.assertEqual(CoolEmployeeWithDefault.__name__, 'CoolEmployeeWithDefault') |
| self.assertEqual(CoolEmployeeWithDefault._fields, ('name', 'cool')) |
| self.assertEqual(CoolEmployeeWithDefault._field_types, dict(name=str, cool=int)) |
| self.assertEqual(CoolEmployeeWithDefault._field_defaults, dict(cool=0)) |
| |
| with self.assertRaises(TypeError): |
| exec(""" |
| class NonDefaultAfterDefault(NamedTuple): |
| x: int = 3 |
| y: int |
| """) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_annotation_usage_with_methods(self): |
| self.assertEquals(XMeth(1).double(), 2) |
| self.assertEquals(XMeth(42).x, XMeth(42)[0]) |
| self.assertEquals(XMethBad(1)._fields, ('x',)) |
| self.assertEquals(XMethBad(1).__annotations__, {'x': int}) |
| |
| @skipUnless(PY36, 'Python 3.6 required') |
| def test_namedtuple_keyword_usage(self): |
| LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int) |
| nick = LocalEmployee('Nick', 25) |
| self.assertIsInstance(nick, tuple) |
| self.assertEqual(nick.name, 'Nick') |
| self.assertEqual(LocalEmployee.__name__, 'LocalEmployee') |
| self.assertEqual(LocalEmployee._fields, ('name', 'age')) |
| self.assertEqual(LocalEmployee.__annotations__, dict(name=str, age=int)) |
| self.assertIs(LocalEmployee._field_types, LocalEmployee.__annotations__) |
| with self.assertRaises(TypeError): |
| NamedTuple('Name', [('x', int)], y=str) |
| with self.assertRaises(TypeError): |
| NamedTuple('Name', x=1, y='a') |
| |
| def test_pickle(self): |
| global Emp # pickle wants to reference the class by name |
| Emp = NamedTuple('Emp', [('name', str), ('id', int)]) |
| jane = Emp('jane', 37) |
| for proto in range(pickle.HIGHEST_PROTOCOL + 1): |
| z = pickle.dumps(jane, proto) |
| jane2 = pickle.loads(z) |
| self.assertEqual(jane2, jane) |
| |
| |
| class IOTests(BaseTestCase): |
| |
| def test_io(self): |
| |
| def stuff(a: IO) -> AnyStr: |
| return a.readline() |
| |
| a = stuff.__annotations__['a'] |
| self.assertEqual(a.__parameters__, (AnyStr,)) |
| |
| def test_textio(self): |
| |
| def stuff(a: TextIO) -> str: |
| return a.readline() |
| |
| a = stuff.__annotations__['a'] |
| self.assertEqual(a.__parameters__, ()) |
| |
| def test_binaryio(self): |
| |
| def stuff(a: BinaryIO) -> bytes: |
| return a.readline() |
| |
| a = stuff.__annotations__['a'] |
| self.assertEqual(a.__parameters__, ()) |
| |
| def test_io_submodule(self): |
| from typing.io import IO, TextIO, BinaryIO, __all__, __name__ |
| self.assertIs(IO, typing.IO) |
| self.assertIs(TextIO, typing.TextIO) |
| self.assertIs(BinaryIO, typing.BinaryIO) |
| self.assertEqual(set(__all__), set(['IO', 'TextIO', 'BinaryIO'])) |
| self.assertEqual(__name__, 'typing.io') |
| |
| |
| class RETests(BaseTestCase): |
| # Much of this is really testing _TypeAlias. |
| |
| def test_basics(self): |
| pat = re.compile('[a-z]+', re.I) |
| self.assertIsSubclass(pat.__class__, Pattern) |
| self.assertIsSubclass(type(pat), Pattern) |
| self.assertIsInstance(pat, Pattern) |
| |
| mat = pat.search('12345abcde.....') |
| self.assertIsSubclass(mat.__class__, Match) |
| self.assertIsSubclass(type(mat), Match) |
| self.assertIsInstance(mat, Match) |
| |
| # these should just work |
| Pattern[Union[str, bytes]] |
| Match[Union[bytes, str]] |
| |
| def test_errors(self): |
| with self.assertRaises(TypeError): |
| # Doesn't fit AnyStr. |
| Pattern[int] |
| with self.assertRaises(TypeError): |
| # Can't change type vars? |
| Match[T] |
| m = Match[Union[str, bytes]] |
| with self.assertRaises(TypeError): |
| # Too complicated? |
| m[str] |
| with self.assertRaises(TypeError): |
| # We don't support isinstance(). |
| isinstance(42, Pattern[str]) |
| |
| def test_repr(self): |
| self.assertEqual(repr(Pattern), 'Pattern[~AnyStr]') |
| self.assertEqual(repr(Pattern[str]), 'Pattern[str]') |
| self.assertEqual(repr(Pattern[bytes]), 'Pattern[bytes]') |
| self.assertEqual(repr(Match), 'Match[~AnyStr]') |
| self.assertEqual(repr(Match[str]), 'Match[str]') |
| self.assertEqual(repr(Match[bytes]), 'Match[bytes]') |
| |
| def test_re_submodule(self): |
| from typing.re import Match, Pattern, __all__, __name__ |
| self.assertIs(Match, typing.Match) |
| self.assertIs(Pattern, typing.Pattern) |
| self.assertEqual(set(__all__), set(['Match', 'Pattern'])) |
| self.assertEqual(__name__, 'typing.re') |
| |
| def test_cannot_subclass(self): |
| with self.assertRaises(TypeError) as ex: |
| |
| class A(typing.Match): |
| pass |
| |
| self.assertEqual(str(ex.exception), |
| "Cannot subclass typing._TypeAlias") |
| |
| |
| class AllTests(BaseTestCase): |
| """Tests for __all__.""" |
| |
| def test_all(self): |
| from typing import __all__ as a |
| # Just spot-check the first and last of every category. |
| self.assertIn('AbstractSet', a) |
| self.assertIn('ValuesView', a) |
| self.assertIn('cast', a) |
| self.assertIn('overload', a) |
| if hasattr(contextlib, 'AbstractContextManager'): |
| self.assertIn('ContextManager', a) |
| # Check that io and re are not exported. |
| self.assertNotIn('io', a) |
| self.assertNotIn('re', a) |
| # Spot-check that stdlib modules aren't exported. |
| self.assertNotIn('os', a) |
| self.assertNotIn('sys', a) |
| # Check that Text is defined. |
| self.assertIn('Text', a) |
| |
| |
| if __name__ == '__main__': |
| main() |