summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2016-09-27 22:22:40 (GMT)
committerGuido van Rossum <guido@python.org>2016-09-27 22:22:40 (GMT)
commit6703e042fa0005dbf76578ddf24c7c170a715061 (patch)
treea881957f878e6e42cc7bf64f4e8dc997bd45a8d5
parent49d2c389a375db596ab5ae82d644e894f373a1d9 (diff)
parent4cefe74aef34a86a9eb60cea9d7a775fc288004c (diff)
downloadcpython-6703e042fa0005dbf76578ddf24c7c170a715061.zip
cpython-6703e042fa0005dbf76578ddf24c7c170a715061.tar.gz
cpython-6703e042fa0005dbf76578ddf24c7c170a715061.tar.bz2
Update typing.py and test_typing.py from upstream (https://github.com/python/typing) (merge 3.5->3.6)
-rw-r--r--Lib/test/test_typing.py337
-rw-r--r--Lib/typing.py641
2 files changed, 416 insertions, 562 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 3b99060..6543005 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -9,7 +9,7 @@ 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
+from typing import Tuple, List, MutableMapping
from typing import Callable
from typing import Generic, ClassVar
from typing import cast
@@ -21,6 +21,10 @@ from typing import NamedTuple
from typing import IO, TextIO, BinaryIO
from typing import Pattern, Match
import typing
+try:
+ import collections.abc as collections_abc
+except ImportError:
+ import collections as collections_abc # Fallback for PY3.2.
class BaseTestCase(TestCase):
@@ -62,18 +66,11 @@ class AnyTests(BaseTestCase):
with self.assertRaises(TypeError):
isinstance(42, Any)
- def test_any_subclass(self):
- self.assertTrue(issubclass(Employee, Any))
- self.assertTrue(issubclass(int, Any))
- self.assertTrue(issubclass(type(None), Any))
- self.assertTrue(issubclass(object, Any))
-
- def test_others_any(self):
- self.assertFalse(issubclass(Any, Employee))
- self.assertFalse(issubclass(Any, int))
- self.assertFalse(issubclass(Any, type(None)))
- # However, Any is a subclass of object (this can't be helped).
- self.assertTrue(issubclass(Any, object))
+ 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')
@@ -88,32 +85,21 @@ class AnyTests(BaseTestCase):
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_is_subclass(self):
- # Any should be considered a subclass of everything.
- self.assertIsSubclass(Any, Any)
- self.assertIsSubclass(Any, typing.List)
- self.assertIsSubclass(Any, typing.List[int])
- self.assertIsSubclass(Any, typing.List[T])
- self.assertIsSubclass(Any, typing.Mapping)
- self.assertIsSubclass(Any, typing.Mapping[str, int])
- self.assertIsSubclass(Any, typing.Mapping[KT, VT])
- self.assertIsSubclass(Any, Generic)
- self.assertIsSubclass(Any, Generic[T])
- self.assertIsSubclass(Any, Generic[KT, VT])
- self.assertIsSubclass(Any, AnyStr)
- self.assertIsSubclass(Any, Union)
- self.assertIsSubclass(Any, Union[int, str])
- self.assertIsSubclass(Any, typing.Match)
- self.assertIsSubclass(Any, typing.Match[str])
+ def test_any_works_with_alias(self):
# These expressions must simply not fail.
typing.Match[Any]
typing.Pattern[Any]
@@ -124,13 +110,8 @@ class TypeVarTests(BaseTestCase):
def test_basic_plain(self):
T = TypeVar('T')
- # Every class is a subclass of T.
- self.assertIsSubclass(int, T)
- self.assertIsSubclass(str, T)
# T equals itself.
self.assertEqual(T, T)
- # T is a subclass of itself.
- self.assertIsSubclass(T, T)
# T is an instance of TypeVar
self.assertIsInstance(T, TypeVar)
@@ -139,16 +120,12 @@ class TypeVarTests(BaseTestCase):
with self.assertRaises(TypeError):
isinstance(42, T)
- def test_basic_constrained(self):
- A = TypeVar('A', str, bytes)
- # Only str and bytes are subclasses of A.
- self.assertIsSubclass(str, A)
- self.assertIsSubclass(bytes, A)
- self.assertNotIsSubclass(int, A)
- # A equals itself.
- self.assertEqual(A, A)
- # A is a subclass of itself.
- self.assertIsSubclass(A, A)
+ 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):
@@ -185,19 +162,6 @@ class TypeVarTests(BaseTestCase):
self.assertNotEqual(TypeVar('T'), TypeVar('T'))
self.assertNotEqual(TypeVar('T', int, str), TypeVar('T', int, str))
- def test_subclass_as_unions(self):
- # None of these are true -- each type var is its own world.
- self.assertFalse(issubclass(TypeVar('T', int, str),
- TypeVar('T', int, str)))
- self.assertFalse(issubclass(TypeVar('T', int, float),
- TypeVar('T', int, float, str)))
- self.assertFalse(issubclass(TypeVar('T', int, str),
- TypeVar('T', str, int)))
- A = TypeVar('A', int, str)
- B = TypeVar('B', int, str, float)
- self.assertFalse(issubclass(A, B))
- self.assertFalse(issubclass(B, A))
-
def test_cannot_subclass_vars(self):
with self.assertRaises(TypeError):
class V(TypeVar('T')):
@@ -212,12 +176,6 @@ class TypeVarTests(BaseTestCase):
with self.assertRaises(TypeError):
TypeVar('A')()
- def test_bound(self):
- X = TypeVar('X', bound=Employee)
- self.assertIsSubclass(Employee, X)
- self.assertIsSubclass(Manager, X)
- self.assertNotIsSubclass(int, X)
-
def test_bound_errors(self):
with self.assertRaises(TypeError):
TypeVar('X', bound=42)
@@ -230,8 +188,16 @@ class UnionTests(BaseTestCase):
def test_basics(self):
u = Union[int, float]
self.assertNotEqual(u, Union)
- self.assertTrue(issubclass(int, u))
- self.assertTrue(issubclass(float, u))
+
+ 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]
@@ -260,18 +226,6 @@ class UnionTests(BaseTestCase):
u2 = Union[float, int]
self.assertEqual(u1, u2)
- def test_subclass(self):
- u = Union[int, Employee]
- self.assertTrue(issubclass(Manager, u))
-
- def test_self_subclass(self):
- self.assertTrue(issubclass(Union[KT, VT], Union))
- self.assertFalse(issubclass(Union, Union[KT, VT]))
-
- def test_multiple_inheritance(self):
- u = Union[int, Employee]
- self.assertTrue(issubclass(ManagingFounder, u))
-
def test_single_class_disappears(self):
t = Union[Employee]
self.assertIs(t, Employee)
@@ -284,13 +238,6 @@ class UnionTests(BaseTestCase):
u = Union[Employee, Manager]
self.assertIs(u, Employee)
- def test_weird_subclasses(self):
- u = Union[Employee, int, float]
- v = Union[int, float]
- self.assertTrue(issubclass(v, u))
- w = Union[int, Manager]
- self.assertTrue(issubclass(w, u))
-
def test_union_union(self):
u = Union[int, float]
v = Union[u, Employee]
@@ -308,15 +255,27 @@ class UnionTests(BaseTestCase):
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_optional(self):
o = Optional[int]
@@ -327,10 +286,6 @@ class UnionTests(BaseTestCase):
with self.assertRaises(TypeError):
Union[()]
- def test_issubclass_union(self):
- self.assertIsSubclass(Union[int, str], Union)
- self.assertNotIsSubclass(int, Union)
-
def test_union_instance_type_error(self):
with self.assertRaises(TypeError):
isinstance(42, Union[int, str])
@@ -355,43 +310,19 @@ class UnionTests(BaseTestCase):
Union[Elem, str] # Nor should this
-class TypeVarUnionTests(BaseTestCase):
-
- def test_simpler(self):
- A = TypeVar('A', int, str, float)
- B = TypeVar('B', int, str)
- self.assertIsSubclass(A, A)
- self.assertIsSubclass(B, B)
- self.assertNotIsSubclass(B, A)
- self.assertIsSubclass(A, Union[int, str, float])
- self.assertNotIsSubclass(Union[int, str, float], A)
- self.assertNotIsSubclass(Union[int, str], B)
- self.assertIsSubclass(B, Union[int, str])
- self.assertNotIsSubclass(A, B)
- self.assertNotIsSubclass(Union[int, str, float], B)
- self.assertNotIsSubclass(A, Union[int, str])
-
- def test_var_union_subclass(self):
- self.assertTrue(issubclass(T, Union[int, T]))
- self.assertTrue(issubclass(KT, Union[KT, VT]))
-
- def test_var_union(self):
- TU = TypeVar('TU', Union[int, float], None)
- self.assertIsSubclass(int, TU)
- self.assertIsSubclass(float, TU)
-
-
class TupleTests(BaseTestCase):
def test_basics(self):
- self.assertTrue(issubclass(Tuple[int, str], Tuple))
- self.assertTrue(issubclass(Tuple[int, str], Tuple[int, str]))
- self.assertFalse(issubclass(int, Tuple))
- self.assertFalse(issubclass(Tuple[float, str], Tuple[int, str]))
- self.assertFalse(issubclass(Tuple[int, str, int], Tuple[int, str]))
- self.assertFalse(issubclass(Tuple[int, str], Tuple[int, str, int]))
+ with self.assertRaises(TypeError):
+ issubclass(Tuple[int, str], Tuple)
+ 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.assertFalse(issubclass(Tuple, tuple)) # Can't have it both ways.
+ self.assertTrue(issubclass(TP, Tuple))
def test_equality(self):
self.assertEqual(Tuple[int], Tuple[int])
@@ -407,21 +338,7 @@ class TupleTests(BaseTestCase):
def test_tuple_instance_type_error(self):
with self.assertRaises(TypeError):
isinstance((0, 0), Tuple[int, int])
- with self.assertRaises(TypeError):
- isinstance((0, 0), Tuple)
-
- def test_tuple_ellipsis_subclass(self):
-
- class B:
- pass
-
- class C(B):
- pass
-
- self.assertNotIsSubclass(Tuple[B], Tuple[B, ...])
- self.assertIsSubclass(Tuple[C, ...], Tuple[B, ...])
- self.assertNotIsSubclass(Tuple[C, ...], Tuple[B])
- self.assertNotIsSubclass(Tuple[C], Tuple[B, ...])
+ self.assertIsInstance((0, 0), Tuple)
def test_repr(self):
self.assertEqual(repr(Tuple), 'typing.Tuple')
@@ -439,17 +356,9 @@ class TupleTests(BaseTestCase):
class CallableTests(BaseTestCase):
def test_self_subclass(self):
- self.assertTrue(issubclass(Callable[[int], int], Callable))
- self.assertFalse(issubclass(Callable, Callable[[int], int]))
- self.assertTrue(issubclass(Callable[[int], int], Callable[[int], int]))
- self.assertFalse(issubclass(Callable[[Employee], int],
- Callable[[Manager], int]))
- self.assertFalse(issubclass(Callable[[Manager], int],
- Callable[[Employee], int]))
- self.assertFalse(issubclass(Callable[[int], Employee],
- Callable[[int], Manager]))
- self.assertFalse(issubclass(Callable[[int], Manager],
- Callable[[int], Employee]))
+ 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])
@@ -468,15 +377,24 @@ class CallableTests(BaseTestCase):
with self.assertRaises(TypeError):
+ class C(type(Callable)):
+ pass
+
+ with self.assertRaises(TypeError):
+
class C(Callable[[int], int]):
pass
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_instance_works(self):
def f():
@@ -616,6 +534,12 @@ class GenericTests(BaseTestCase):
with self.assertRaises(TypeError):
Y[str, str]
+ def test_generic_errors(self):
+ 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')
@@ -671,6 +595,42 @@ class GenericTests(BaseTestCase):
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_multiple_abc_bases(self):
+ class MM1(MutableMapping[str, str], collections_abc.MutableMapping):
+ 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
+ class MM2(collections_abc.MutableMapping, 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
+ # these two should just work
+ MM1().update()
+ MM2().update()
+ self.assertIsInstance(MM1(), collections_abc.MutableMapping)
+ self.assertIsInstance(MM1(), MutableMapping)
+ self.assertIsInstance(MM2(), collections_abc.MutableMapping)
+ self.assertIsInstance(MM2(), MutableMapping)
+
def test_pickle(self):
global C # pickle wants to reference the class by name
T = TypeVar('T')
@@ -854,6 +814,8 @@ class ClassVarTests(BaseTestCase):
def test_cannot_init(self):
with self.assertRaises(TypeError):
+ ClassVar()
+ with self.assertRaises(TypeError):
type(ClassVar)()
with self.assertRaises(TypeError):
type(ClassVar[Optional[int]])()
@@ -865,52 +827,6 @@ class ClassVarTests(BaseTestCase):
issubclass(int, ClassVar)
-class VarianceTests(BaseTestCase):
-
- def test_invariance(self):
- # Because of invariance, List[subclass of X] is not a subclass
- # of List[X], and ditto for MutableSequence.
- self.assertNotIsSubclass(typing.List[Manager], typing.List[Employee])
- self.assertNotIsSubclass(typing.MutableSequence[Manager],
- typing.MutableSequence[Employee])
- # It's still reflexive.
- self.assertIsSubclass(typing.List[Employee], typing.List[Employee])
- self.assertIsSubclass(typing.MutableSequence[Employee],
- typing.MutableSequence[Employee])
-
- def test_covariance_tuple(self):
- # Check covariace for Tuple (which are really special cases).
- self.assertIsSubclass(Tuple[Manager], Tuple[Employee])
- self.assertNotIsSubclass(Tuple[Employee], Tuple[Manager])
- # And pairwise.
- self.assertIsSubclass(Tuple[Manager, Manager],
- Tuple[Employee, Employee])
- self.assertNotIsSubclass(Tuple[Employee, Employee],
- Tuple[Manager, Employee])
- # And using ellipsis.
- self.assertIsSubclass(Tuple[Manager, ...], Tuple[Employee, ...])
- self.assertNotIsSubclass(Tuple[Employee, ...], Tuple[Manager, ...])
-
- def test_covariance_sequence(self):
- # Check covariance for Sequence (which is just a generic class
- # for this purpose, but using a type variable with covariant=True).
- self.assertIsSubclass(typing.Sequence[Manager],
- typing.Sequence[Employee])
- self.assertNotIsSubclass(typing.Sequence[Employee],
- typing.Sequence[Manager])
-
- def test_covariance_mapping(self):
- # Ditto for Mapping (covariant in the value, invariant in the key).
- self.assertIsSubclass(typing.Mapping[Employee, Manager],
- typing.Mapping[Employee, Employee])
- self.assertNotIsSubclass(typing.Mapping[Manager, Employee],
- typing.Mapping[Employee, Employee])
- self.assertNotIsSubclass(typing.Mapping[Employee, Manager],
- typing.Mapping[Manager, Manager])
- self.assertNotIsSubclass(typing.Mapping[Manager, Employee],
- typing.Mapping[Manager, Manager])
-
-
class CastTests(BaseTestCase):
def test_basics(self):
@@ -1247,7 +1163,6 @@ class CollectionsAbcTests(BaseTestCase):
# path and could fail. So call this a few times.
self.assertIsInstance([], typing.Iterable)
self.assertIsInstance([], typing.Iterable)
- self.assertIsInstance([], typing.Iterable[int])
self.assertNotIsInstance(42, typing.Iterable)
# Just in case, also test issubclass() a few times.
self.assertIsSubclass(list, typing.Iterable)
@@ -1256,7 +1171,6 @@ class CollectionsAbcTests(BaseTestCase):
def test_iterator(self):
it = iter([])
self.assertIsInstance(it, typing.Iterator)
- self.assertIsInstance(it, typing.Iterator[int])
self.assertNotIsInstance(42, typing.Iterator)
@skipUnless(PY35, 'Python 3.5 required')
@@ -1268,13 +1182,8 @@ class CollectionsAbcTests(BaseTestCase):
globals(), ns)
foo = ns['foo']
g = foo()
- self.assertIsSubclass(type(g), typing.Awaitable[int])
self.assertIsInstance(g, typing.Awaitable)
self.assertNotIsInstance(foo, typing.Awaitable)
- self.assertIsSubclass(typing.Awaitable[Manager],
- typing.Awaitable[Employee])
- self.assertNotIsSubclass(typing.Awaitable[Employee],
- typing.Awaitable[Manager])
g.send(None) # Run foo() till completion, to avoid warning.
@skipUnless(PY35, 'Python 3.5 required')
@@ -1283,8 +1192,6 @@ class CollectionsAbcTests(BaseTestCase):
it = AsyncIteratorWrapper(base_it)
self.assertIsInstance(it, typing.AsyncIterable)
self.assertIsInstance(it, typing.AsyncIterable)
- self.assertIsSubclass(typing.AsyncIterable[Manager],
- typing.AsyncIterable[Employee])
self.assertNotIsInstance(42, typing.AsyncIterable)
@skipUnless(PY35, 'Python 3.5 required')
@@ -1292,8 +1199,6 @@ class CollectionsAbcTests(BaseTestCase):
base_it = range(10) # type: Iterator[int]
it = AsyncIteratorWrapper(base_it)
self.assertIsInstance(it, typing.AsyncIterator)
- self.assertIsSubclass(typing.AsyncIterator[Manager],
- typing.AsyncIterator[Employee])
self.assertNotIsInstance(42, typing.AsyncIterator)
def test_sized(self):
@@ -1457,10 +1362,6 @@ class CollectionsAbcTests(BaseTestCase):
yield 42
g = foo()
self.assertIsSubclass(type(g), typing.Generator)
- self.assertIsSubclass(typing.Generator[Manager, Employee, Manager],
- typing.Generator[Employee, Manager, Employee])
- self.assertNotIsSubclass(typing.Generator[Manager, Manager, Manager],
- typing.Generator[Employee, Employee, Employee])
def test_no_generator_instantiation(self):
with self.assertRaises(TypeError):
@@ -1511,7 +1412,6 @@ class OtherABCTests(BaseTestCase):
cm = manager()
self.assertIsInstance(cm, typing.ContextManager)
- self.assertIsInstance(cm, typing.ContextManager[int])
self.assertNotIsInstance(42, typing.ContextManager)
@@ -1653,22 +1553,16 @@ class RETests(BaseTestCase):
pat = re.compile('[a-z]+', re.I)
self.assertIsSubclass(pat.__class__, Pattern)
self.assertIsSubclass(type(pat), Pattern)
- self.assertIsSubclass(type(pat), Pattern[str])
+ self.assertIsInstance(pat, Pattern)
mat = pat.search('12345abcde.....')
self.assertIsSubclass(mat.__class__, Match)
- self.assertIsSubclass(mat.__class__, Match[str])
- self.assertIsSubclass(mat.__class__, Match[bytes]) # Sad but true.
self.assertIsSubclass(type(mat), Match)
- self.assertIsSubclass(type(mat), Match[str])
+ self.assertIsInstance(mat, Match)
+ # these should just work
p = Pattern[Union[str, bytes]]
- self.assertIsSubclass(Pattern[str], Pattern)
- self.assertIsSubclass(Pattern[str], p)
-
m = Match[Union[bytes, str]]
- self.assertIsSubclass(Match[bytes], Match)
- self.assertIsSubclass(Match[bytes], m)
def test_errors(self):
with self.assertRaises(TypeError):
@@ -1683,9 +1577,6 @@ class RETests(BaseTestCase):
m[str]
with self.assertRaises(TypeError):
# We don't support isinstance().
- isinstance(42, Pattern)
- with self.assertRaises(TypeError):
- # We don't support isinstance().
isinstance(42, Pattern[str])
def test_repr(self):
@@ -1710,7 +1601,7 @@ class RETests(BaseTestCase):
pass
self.assertEqual(str(ex.exception),
- "A type alias cannot be subclassed")
+ "Cannot subclass typing._TypeAlias")
class AllTests(BaseTestCase):
diff --git a/Lib/typing.py b/Lib/typing.py
index 4676d28..925d9e4 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -89,6 +89,13 @@ def _qualname(x):
return x.__name__
+def _trim_name(nm):
+ if nm.startswith('_') and nm not in ('_TypeAlias',
+ '_ForwardRef', '_TypingBase', '_FinalTypingBase'):
+ nm = nm[1:]
+ return nm
+
+
class TypingMeta(type):
"""Metaclass for every type defined below.
@@ -127,22 +134,69 @@ class TypingMeta(type):
pass
def __repr__(self):
- return '%s.%s' % (self.__module__, _qualname(self))
+ qname = _trim_name(_qualname(self))
+ return '%s.%s' % (self.__module__, qname)
+
+
+class _TypingBase(metaclass=TypingMeta, _root=True):
+ """Indicator of special typing constructs."""
+
+ __slots__ = ()
+
+
+ def __init__(self, *args, **kwds):
+ pass
+
+ def __new__(cls, *args, **kwds):
+ """Constructor.
+
+ This only exists to give a better error message in case
+ someone tries to subclass a special typing object (not a good idea).
+ """
+ if (len(args) == 3 and
+ isinstance(args[0], str) and
+ isinstance(args[1], tuple)):
+ # Close enough.
+ raise TypeError("Cannot subclass %r" % cls)
+ return object.__new__(cls)
+
+ # Things that are not classes also need these.
+ def _eval_type(self, globalns, localns):
+ return self
+
+ def _get_type_vars(self, tvars):
+ pass
+
+ def __repr__(self):
+ cls = type(self)
+ qname = _trim_name(_qualname(cls))
+ return '%s.%s' % (cls.__module__, qname)
+ def __call__(self, *args, **kwds):
+ raise TypeError("Cannot instantiate %r" % type(self))
-class Final:
+
+class _FinalTypingBase(_TypingBase, _root=True):
"""Mix-in class to prevent instantiation."""
__slots__ = ()
- def __new__(self, *args, **kwds):
- raise TypeError("Cannot instantiate %r" % self.__class__)
+ def __new__(cls, *args, _root=False, **kwds):
+ self = super().__new__(cls, *args, **kwds)
+ if _root is True:
+ return self
+ raise TypeError("Cannot instantiate %r" % cls)
-class _ForwardRef(TypingMeta):
+class _ForwardRef(_TypingBase, _root=True):
"""Wrapper to hold a forward reference."""
- def __new__(cls, arg):
+ __slots__ = ('__forward_arg__', '__forward_code__',
+ '__forward_evaluated__', '__forward_value__',
+ '__forward_frame__')
+
+ def __init__(self, arg):
+ super().__init__(arg)
if not isinstance(arg, str):
raise TypeError('ForwardRef must be a string -- got %r' % (arg,))
try:
@@ -150,7 +204,6 @@ class _ForwardRef(TypingMeta):
except SyntaxError:
raise SyntaxError('ForwardRef must be an expression -- got %r' %
(arg,))
- self = super().__new__(cls, arg, (), {}, _root=True)
self.__forward_arg__ = arg
self.__forward_code__ = code
self.__forward_evaluated__ = False
@@ -161,7 +214,6 @@ class _ForwardRef(TypingMeta):
frame = frame.f_back
assert frame is not None
self.__forward_frame__ = frame
- return self
def _eval_type(self, globalns, localns):
if not self.__forward_evaluated__:
@@ -177,49 +229,36 @@ class _ForwardRef(TypingMeta):
self.__forward_evaluated__ = True
return self.__forward_value__
+ def __eq__(self, other):
+ if not isinstance(other, _ForwardRef):
+ return NotImplemented
+ return (self.__forward_arg__ == other.__forward_arg__ and
+ self.__forward_frame__ == other.__forward_frame__)
+
+ def __hash__(self):
+ return hash((self.__forward_arg__, self.__forward_frame__))
+
def __instancecheck__(self, obj):
raise TypeError("Forward references cannot be used with isinstance().")
def __subclasscheck__(self, cls):
- if not self.__forward_evaluated__:
- globalns = self.__forward_frame__.f_globals
- localns = self.__forward_frame__.f_locals
- try:
- self._eval_type(globalns, localns)
- except NameError:
- return False # Too early.
- return issubclass(cls, self.__forward_value__)
+ raise TypeError("Forward references cannot be used with issubclass().")
def __repr__(self):
return '_ForwardRef(%r)' % (self.__forward_arg__,)
-class _TypeAlias:
+class _TypeAlias(_TypingBase, _root=True):
"""Internal helper class for defining generic variants of concrete types.
- Note that this is not a type; let's call it a pseudo-type. It can
- be used in instance and subclass checks, e.g. isinstance(m, Match)
- or issubclass(type(m), Match). However, it cannot be itself the
- target of an issubclass() call; e.g. issubclass(Match, C) (for
- some arbitrary class C) raises TypeError rather than returning
- False.
+ Note that this is not a type; let's call it a pseudo-type. It cannot
+ be used in instance and subclass checks in parameterized form, i.e.
+ ``isinstance(42, Match[str])`` raises ``TypeError`` instead of returning
+ ``False``.
"""
__slots__ = ('name', 'type_var', 'impl_type', 'type_checker')
- def __new__(cls, *args, **kwds):
- """Constructor.
-
- This only exists to give a better error message in case
- someone tries to subclass a type alias (not a good idea).
- """
- if (len(args) == 3 and
- isinstance(args[0], str) and
- isinstance(args[1], tuple)):
- # Close enough.
- raise TypeError("A type alias cannot be subclassed")
- return object.__new__(cls)
-
def __init__(self, name, type_var, impl_type, type_checker):
"""Initializer.
@@ -232,9 +271,9 @@ class _TypeAlias:
and returns a value that should be a type_var instance.
"""
assert isinstance(name, str), repr(name)
- assert isinstance(type_var, type), repr(type_var)
assert isinstance(impl_type, type), repr(impl_type)
assert not isinstance(impl_type, TypingMeta), repr(impl_type)
+ assert isinstance(type_var, (type, _TypingBase))
self.name = name
self.type_var = type_var
self.impl_type = impl_type
@@ -244,36 +283,41 @@ class _TypeAlias:
return "%s[%s]" % (self.name, _type_repr(self.type_var))
def __getitem__(self, parameter):
- assert isinstance(parameter, type), repr(parameter)
if not isinstance(self.type_var, TypeVar):
raise TypeError("%s cannot be further parameterized." % self)
- if self.type_var.__constraints__:
- if not issubclass(parameter, Union[self.type_var.__constraints__]):
+ if self.type_var.__constraints__ and isinstance(parameter, type):
+ if not issubclass(parameter, self.type_var.__constraints__):
raise TypeError("%s is not a valid substitution for %s." %
(parameter, self.type_var))
+ if isinstance(parameter, TypeVar):
+ raise TypeError("%s cannot be re-parameterized." % self.type_var)
return self.__class__(self.name, parameter,
self.impl_type, self.type_checker)
+ def __eq__(self, other):
+ if not isinstance(other, _TypeAlias):
+ return NotImplemented
+ return self.name == other.name and self.type_var == other.type_var
+
+ def __hash__(self):
+ return hash((self.name, self.type_var))
+
def __instancecheck__(self, obj):
- raise TypeError("Type aliases cannot be used with isinstance().")
+ if not isinstance(self.type_var, TypeVar):
+ raise TypeError("Parameterized type aliases cannot be used "
+ "with isinstance().")
+ return isinstance(obj, self.impl_type)
def __subclasscheck__(self, cls):
- if cls is Any:
- return True
- if isinstance(cls, _TypeAlias):
- # Covariance. For now, we compare by name.
- return (cls.name == self.name and
- issubclass(cls.type_var, self.type_var))
- else:
- # Note that this is too lenient, because the
- # implementation type doesn't carry information about
- # whether it is about bytes or str (for example).
- return issubclass(cls, self.impl_type)
+ if not isinstance(self.type_var, TypeVar):
+ raise TypeError("Parameterized type aliases cannot be used "
+ "with issubclass().")
+ return issubclass(cls, self.impl_type)
def _get_type_vars(types, tvars):
for t in types:
- if isinstance(t, TypingMeta) or isinstance(t, _ClassVar):
+ if isinstance(t, TypingMeta) or isinstance(t, _TypingBase):
t._get_type_vars(tvars)
@@ -284,7 +328,7 @@ def _type_vars(types):
def _eval_type(t, globalns, localns):
- if isinstance(t, TypingMeta) or isinstance(t, _ClassVar):
+ if isinstance(t, TypingMeta) or isinstance(t, _TypingBase):
return t._eval_type(globalns, localns)
else:
return t
@@ -306,7 +350,7 @@ def _type_check(arg, msg):
return type(None)
if isinstance(arg, str):
arg = _ForwardRef(arg)
- if not isinstance(arg, (type, _TypeAlias)) and not callable(arg):
+ if not isinstance(arg, (type, _TypingBase)) and not callable(arg):
raise TypeError(msg + " Got %.100r." % (arg,))
return arg
@@ -328,23 +372,7 @@ def _type_repr(obj):
return repr(obj)
-class AnyMeta(TypingMeta):
- """Metaclass for Any."""
-
- def __new__(cls, name, bases, namespace, _root=False):
- self = super().__new__(cls, name, bases, namespace, _root=_root)
- return self
-
- def __instancecheck__(self, obj):
- raise TypeError("Any cannot be used with isinstance().")
-
- def __subclasscheck__(self, cls):
- if not isinstance(cls, type):
- return super().__subclasscheck__(cls) # To TypeError.
- return True
-
-
-class Any(Final, metaclass=AnyMeta, _root=True):
+class _Any(_FinalTypingBase, _root=True):
"""Special type indicating an unconstrained type.
- Any object is an instance of Any.
@@ -354,8 +382,17 @@ class Any(Final, metaclass=AnyMeta, _root=True):
__slots__ = ()
+ def __instancecheck__(self, obj):
+ raise TypeError("Any cannot be used with isinstance().")
+
+ def __subclasscheck__(self, cls):
+ raise TypeError("Any cannot be used with issubclass().")
+
+
+Any = _Any(_root=True)
-class TypeVar(TypingMeta, metaclass=TypingMeta, _root=True):
+
+class TypeVar(_TypingBase, _root=True):
"""Type variable.
Usage::
@@ -400,9 +437,14 @@ class TypeVar(TypingMeta, metaclass=TypingMeta, _root=True):
A.__constraints__ == (str, bytes)
"""
- def __new__(cls, name, *constraints, bound=None,
+ __slots__ = ('__name__', '__bound__', '__constraints__',
+ '__covariant__', '__contravariant__')
+
+ def __init__(self, name, *constraints, bound=None,
covariant=False, contravariant=False):
- self = super().__new__(cls, name, (Final,), {}, _root=True)
+ super().__init__(name, *constraints, bound=bound,
+ covariant=covariant, contravariant=contravariant)
+ self.__name__ = name
if covariant and contravariant:
raise ValueError("Bivariant types are not supported.")
self.__covariant__ = bool(covariant)
@@ -417,7 +459,6 @@ class TypeVar(TypingMeta, metaclass=TypingMeta, _root=True):
self.__bound__ = _type_check(bound, "Bound must be a type.")
else:
self.__bound__ = None
- return self
def _get_type_vars(self, tvars):
if self not in tvars:
@@ -436,16 +477,7 @@ class TypeVar(TypingMeta, metaclass=TypingMeta, _root=True):
raise TypeError("Type variables cannot be used with isinstance().")
def __subclasscheck__(self, cls):
- # TODO: Make this raise TypeError too?
- if cls is self:
- return True
- if cls is Any:
- return True
- if self.__bound__ is not None:
- return issubclass(cls, self.__bound__)
- if self.__constraints__:
- return any(issubclass(cls, c) for c in self.__constraints__)
- return True
+ raise TypeError("Type variables cannot be used with issubclass().")
# Some unconstrained type variables. These are used by the container types.
@@ -463,19 +495,85 @@ T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant.
AnyStr = TypeVar('AnyStr', bytes, str)
-class UnionMeta(TypingMeta):
- """Metaclass for Union."""
+def _tp_cache(func):
+ cached = functools.lru_cache()(func)
+ @functools.wraps(func)
+ def inner(*args, **kwds):
+ try:
+ return cached(*args, **kwds)
+ except TypeError:
+ pass # Do not duplicate real errors.
+ return func(*args, **kwds)
+ return inner
+
+
+class _Union(_FinalTypingBase, _root=True):
+ """Union type; Union[X, Y] means either X or Y.
+
+ To define a union, use e.g. Union[int, str]. Details:
+
+ - The arguments must be types and there must be at least one.
+
+ - None as an argument is a special case and is replaced by
+ type(None).
+
+ - Unions of unions are flattened, e.g.::
+
+ Union[Union[int, str], float] == Union[int, str, float]
+
+ - Unions of a single argument vanish, e.g.::
+
+ Union[int] == int # The constructor actually returns int
+
+ - Redundant arguments are skipped, e.g.::
+
+ Union[int, str, int] == Union[int, str]
+
+ - When comparing unions, the argument order is ignored, e.g.::
- def __new__(cls, name, bases, namespace, parameters=None, _root=False):
+ Union[int, str] == Union[str, int]
+
+ - When two arguments have a subclass relationship, the least
+ derived argument is kept, e.g.::
+
+ class Employee: pass
+ class Manager(Employee): pass
+ Union[int, Employee, Manager] == Union[int, Employee]
+ Union[Manager, int, Employee] == Union[int, Employee]
+ Union[Employee, Manager] == Employee
+
+ - Corollary: if Any is present it is the sole survivor, e.g.::
+
+ Union[int, Any] == Any
+
+ - Similar for object::
+
+ Union[int, object] == object
+
+ - To cut a tie: Union[object, Any] == Union[Any, object] == Any.
+
+ - You cannot subclass or instantiate a union.
+
+ - You cannot write Union[X][Y] (what would it mean?).
+
+ - You can use Optional[X] as a shorthand for Union[X, None].
+ """
+
+ __slots__ = ('__union_params__', '__union_set_params__')
+
+ def __new__(cls, parameters=None, *args, _root=False):
+ self = super().__new__(cls, parameters, *args, _root=_root)
if parameters is None:
- return super().__new__(cls, name, bases, namespace, _root=_root)
+ self.__union_params__ = None
+ self.__union_set_params__ = None
+ return self
if not isinstance(parameters, tuple):
raise TypeError("Expected parameters=<tuple>")
# Flatten out Union[Union[...], ...] and type-check non-Union args.
params = []
msg = "Union[arg, ...]: each arg must be a type."
for p in parameters:
- if isinstance(p, UnionMeta):
+ if isinstance(p, _Union):
params.extend(p.__union_params__)
else:
params.append(_type_check(p, msg))
@@ -499,22 +597,16 @@ class UnionMeta(TypingMeta):
for t1 in params:
if t1 is Any:
return Any
- if isinstance(t1, TypeVar):
- continue
- if isinstance(t1, _TypeAlias):
- # _TypeAlias is not a real class.
- continue
if not isinstance(t1, type):
- assert callable(t1) # A callable might sneak through.
continue
if any(isinstance(t2, type) and issubclass(t1, t2)
- for t2 in all_params - {t1} if not isinstance(t2, TypeVar)):
+ for t2 in all_params - {t1}
+ if not (isinstance(t2, GenericMeta) and
+ t2.__origin__ is not None)):
all_params.remove(t1)
# It's not a union if there's only one type left.
if len(all_params) == 1:
return all_params.pop()
- # Create a new class with these params.
- self = super().__new__(cls, name, bases, {}, _root=True)
self.__union_params__ = tuple(t for t in params if t in all_params)
self.__union_set_params__ = frozenset(self.__union_params__)
return self
@@ -525,8 +617,7 @@ class UnionMeta(TypingMeta):
if p == self.__union_params__:
return self
else:
- return self.__class__(self.__name__, self.__bases__, {},
- p, _root=True)
+ return self.__class__(p, _root=True)
def _get_type_vars(self, tvars):
if self.__union_params__:
@@ -539,6 +630,7 @@ class UnionMeta(TypingMeta):
for t in self.__union_params__))
return r
+ @_tp_cache
def __getitem__(self, parameters):
if self.__union_params__ is not None:
raise TypeError(
@@ -547,11 +639,10 @@ class UnionMeta(TypingMeta):
raise TypeError("Cannot take a Union of no types.")
if not isinstance(parameters, tuple):
parameters = (parameters,)
- return self.__class__(self.__name__, self.__bases__,
- dict(self.__dict__), parameters, _root=True)
+ return self.__class__(parameters, _root=True)
def __eq__(self, other):
- if not isinstance(other, UnionMeta):
+ if not isinstance(other, _Union):
return NotImplemented
return self.__union_set_params__ == other.__union_set_params__
@@ -562,110 +653,45 @@ class UnionMeta(TypingMeta):
raise TypeError("Unions cannot be used with isinstance().")
def __subclasscheck__(self, cls):
- if cls is Any:
- return True
- if self.__union_params__ is None:
- return isinstance(cls, UnionMeta)
- elif isinstance(cls, UnionMeta):
- if cls.__union_params__ is None:
- return False
- return all(issubclass(c, self) for c in (cls.__union_params__))
- elif isinstance(cls, TypeVar):
- if cls in self.__union_params__:
- return True
- if cls.__constraints__:
- return issubclass(Union[cls.__constraints__], self)
- return False
- else:
- return any(issubclass(cls, t) for t in self.__union_params__)
+ raise TypeError("Unions cannot be used with issubclass().")
-class Union(Final, metaclass=UnionMeta, _root=True):
- """Union type; Union[X, Y] means either X or Y.
-
- To define a union, use e.g. Union[int, str]. Details:
-
- - The arguments must be types and there must be at least one.
-
- - None as an argument is a special case and is replaced by
- type(None).
-
- - Unions of unions are flattened, e.g.::
-
- Union[Union[int, str], float] == Union[int, str, float]
-
- - Unions of a single argument vanish, e.g.::
-
- Union[int] == int # The constructor actually returns int
-
- - Redundant arguments are skipped, e.g.::
-
- Union[int, str, int] == Union[int, str]
-
- - When comparing unions, the argument order is ignored, e.g.::
-
- Union[int, str] == Union[str, int]
-
- - When two arguments have a subclass relationship, the least
- derived argument is kept, e.g.::
-
- class Employee: pass
- class Manager(Employee): pass
- Union[int, Employee, Manager] == Union[int, Employee]
- Union[Manager, int, Employee] == Union[int, Employee]
- Union[Employee, Manager] == Employee
-
- - Corollary: if Any is present it is the sole survivor, e.g.::
-
- Union[int, Any] == Any
+Union = _Union(_root=True)
- - Similar for object::
- Union[int, object] == object
-
- - To cut a tie: Union[object, Any] == Union[Any, object] == Any.
-
- - You cannot subclass or instantiate a union.
-
- - You cannot write Union[X][Y] (what would it mean?).
+class _Optional(_FinalTypingBase, _root=True):
+ """Optional type.
- - You can use Optional[X] as a shorthand for Union[X, None].
+ Optional[X] is equivalent to Union[X, type(None)].
"""
- # Unsubscripted Union type has params set to None.
- __union_params__ = None
- __union_set_params__ = None
-
-
-class OptionalMeta(TypingMeta):
- """Metaclass for Optional."""
-
- def __new__(cls, name, bases, namespace, _root=False):
- return super().__new__(cls, name, bases, namespace, _root=_root)
+ __slots__ = ()
+ @_tp_cache
def __getitem__(self, arg):
arg = _type_check(arg, "Optional[t] requires a single type.")
return Union[arg, type(None)]
-class Optional(Final, metaclass=OptionalMeta, _root=True):
- """Optional type.
+Optional = _Optional(_root=True)
- Optional[X] is equivalent to Union[X, type(None)].
- """
- __slots__ = ()
+class _Tuple(_FinalTypingBase, _root=True):
+ """Tuple type; Tuple[X, Y] is the cross-product type of X and Y.
+ Example: Tuple[T1, T2] is a tuple of two elements corresponding
+ to type variables T1 and T2. Tuple[int, float, str] is a tuple
+ of an int, a float and a string.
+
+ To specify a variable-length tuple of homogeneous type, use Tuple[T, ...].
+ """
-class TupleMeta(TypingMeta):
- """Metaclass for Tuple."""
+ __slots__ = ('__tuple_params__', '__tuple_use_ellipsis__')
- def __new__(cls, name, bases, namespace, parameters=None,
+ def __init__(self, parameters=None,
use_ellipsis=False, _root=False):
- self = super().__new__(cls, name, bases, namespace, _root=_root)
self.__tuple_params__ = parameters
self.__tuple_use_ellipsis__ = use_ellipsis
- return self
def _get_type_vars(self, tvars):
if self.__tuple_params__:
@@ -679,8 +705,7 @@ class TupleMeta(TypingMeta):
if p == self.__tuple_params__:
return self
else:
- return self.__class__(self.__name__, self.__bases__, {},
- p, _root=True)
+ return self.__class__(p, _root=True)
def __repr__(self):
r = super().__repr__()
@@ -694,6 +719,7 @@ class TupleMeta(TypingMeta):
', '.join(params))
return r
+ @_tp_cache
def __getitem__(self, parameters):
if self.__tuple_params__ is not None:
raise TypeError("Cannot re-parameterize %r" % (self,))
@@ -707,64 +733,50 @@ class TupleMeta(TypingMeta):
use_ellipsis = False
msg = "Tuple[t0, t1, ...]: each t must be a type."
parameters = tuple(_type_check(p, msg) for p in parameters)
- return self.__class__(self.__name__, self.__bases__,
- dict(self.__dict__), parameters,
+ return self.__class__(parameters,
use_ellipsis=use_ellipsis, _root=True)
def __eq__(self, other):
- if not isinstance(other, TupleMeta):
+ if not isinstance(other, _Tuple):
return NotImplemented
return (self.__tuple_params__ == other.__tuple_params__ and
self.__tuple_use_ellipsis__ == other.__tuple_use_ellipsis__)
def __hash__(self):
- return hash(self.__tuple_params__)
+ return hash((self.__tuple_params__, self.__tuple_use_ellipsis__))
def __instancecheck__(self, obj):
- raise TypeError("Tuples cannot be used with isinstance().")
+ if self.__tuple_params__ == None:
+ return isinstance(obj, tuple)
+ raise TypeError("Parameterized Tuple cannot be used "
+ "with isinstance().")
def __subclasscheck__(self, cls):
- if cls is Any:
- return True
- if not isinstance(cls, type):
- return super().__subclasscheck__(cls) # To TypeError.
- if issubclass(cls, tuple):
- return True # Special case.
- if not isinstance(cls, TupleMeta):
- return super().__subclasscheck__(cls) # False.
- if self.__tuple_params__ is None:
- return True
- if cls.__tuple_params__ is None:
- return False # ???
- if cls.__tuple_use_ellipsis__ != self.__tuple_use_ellipsis__:
- return False
- # Covariance.
- return (len(self.__tuple_params__) == len(cls.__tuple_params__) and
- all(issubclass(x, p)
- for x, p in zip(cls.__tuple_params__,
- self.__tuple_params__)))
-
-
-class Tuple(Final, metaclass=TupleMeta, _root=True):
- """Tuple type; Tuple[X, Y] is the cross-product type of X and Y.
+ if self.__tuple_params__ == None:
+ return issubclass(cls, tuple)
+ raise TypeError("Parameterized Tuple cannot be used "
+ "with issubclass().")
- Example: Tuple[T1, T2] is a tuple of two elements corresponding
- to type variables T1 and T2. Tuple[int, float, str] is a tuple
- of an int, a float and a string.
- To specify a variable-length tuple of homogeneous type, use Sequence[T].
- """
+Tuple = _Tuple(_root=True)
- __slots__ = ()
+class _Callable(_FinalTypingBase, _root=True):
+ """Callable type; Callable[[int], str] is a function of (int) -> str.
-class CallableMeta(TypingMeta):
- """Metaclass for Callable."""
+ The subscription syntax must always be used with exactly two
+ values: the argument list and the return type. The argument list
+ must be a list of types; the return type must be a single type.
- def __new__(cls, name, bases, namespace, _root=False,
- args=None, result=None):
+ There is no syntax to indicate optional or keyword arguments,
+ such function types are rarely used as callback types.
+ """
+
+ __slots__ = ('__args__', '__result__')
+
+ def __init__(self, args=None, result=None, _root=False):
if args is None and result is None:
- pass # Must be 'class Callable'.
+ pass
else:
if args is not Ellipsis:
if not isinstance(args, list):
@@ -775,10 +787,8 @@ class CallableMeta(TypingMeta):
args = tuple(_type_check(arg, msg) for arg in args)
msg = "Callable[args, result]: result must be a type."
result = _type_check(result, msg)
- self = super().__new__(cls, name, bases, namespace, _root=_root)
self.__args__ = args
self.__result__ = result
- return self
def _get_type_vars(self, tvars):
if self.__args__ and self.__args__ is not Ellipsis:
@@ -795,8 +805,7 @@ class CallableMeta(TypingMeta):
if args == self.__args__ and result == self.__result__:
return self
else:
- return self.__class__(self.__name__, self.__bases__, {},
- args=args, result=result, _root=True)
+ return self.__class__(args, result, _root=True)
def __repr__(self):
r = super().__repr__()
@@ -816,12 +825,10 @@ class CallableMeta(TypingMeta):
raise TypeError(
"Callable must be used as Callable[[arg, ...], result].")
args, result = parameters
- return self.__class__(self.__name__, self.__bases__,
- dict(self.__dict__), _root=True,
- args=args, result=result)
+ return self.__class__(args, result, _root=True)
def __eq__(self, other):
- if not isinstance(other, CallableMeta):
+ if not isinstance(other, _Callable):
return NotImplemented
return (self.__args__ == other.__args__ and
self.__result__ == other.__result__)
@@ -836,31 +843,18 @@ class CallableMeta(TypingMeta):
if self.__args__ is None and self.__result__ is None:
return isinstance(obj, collections_abc.Callable)
else:
- raise TypeError("Callable[] cannot be used with isinstance().")
+ raise TypeError("Parameterized Callable cannot be used "
+ "with isinstance().")
def __subclasscheck__(self, cls):
- if cls is Any:
- return True
- if not isinstance(cls, CallableMeta):
- return super().__subclasscheck__(cls)
if self.__args__ is None and self.__result__ is None:
- return True
- # We're not doing covariance or contravariance -- this is *invariance*.
- return self == cls
-
-
-class Callable(Final, metaclass=CallableMeta, _root=True):
- """Callable type; Callable[[int], str] is a function of (int) -> str.
-
- The subscription syntax must always be used with exactly two
- values: the argument list and the return type. The argument list
- must be a list of types; the return type must be a single type.
+ return issubclass(cls, collections_abc.Callable)
+ else:
+ raise TypeError("Parameterized Callable cannot be used "
+ "with issubclass().")
- There is no syntax to indicate optional or keyword arguments,
- such function types are rarely used as callback types.
- """
- __slots__ = ()
+Callable = _Callable(_root=True)
def _gorg(a):
@@ -985,6 +979,7 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
def __hash__(self):
return hash((self.__name__, self.__parameters__))
+ @_tp_cache
def __getitem__(self, params):
if not isinstance(params, tuple):
params = (params,)
@@ -1040,44 +1035,18 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
return self.__subclasscheck__(instance.__class__)
def __subclasscheck__(self, cls):
- if cls is Any:
- return True
- if isinstance(cls, GenericMeta):
- # For a covariant class C(Generic[T]),
- # C[X] is a subclass of C[Y] iff X is a subclass of Y.
- origin = self.__origin__
- if origin is not None and origin is cls.__origin__:
- assert len(self.__args__) == len(origin.__parameters__)
- assert len(cls.__args__) == len(origin.__parameters__)
- for p_self, p_cls, p_origin in zip(self.__args__,
- cls.__args__,
- origin.__parameters__):
- if isinstance(p_origin, TypeVar):
- if p_origin.__covariant__:
- # Covariant -- p_cls must be a subclass of p_self.
- if not issubclass(p_cls, p_self):
- break
- elif p_origin.__contravariant__:
- # Contravariant. I think it's the opposite. :-)
- if not issubclass(p_self, p_cls):
- break
- else:
- # Invariant -- p_cls and p_self must equal.
- if p_self != p_cls:
- break
- else:
- # If the origin's parameter is not a typevar,
- # insist on invariance.
- if p_self != p_cls:
- break
- else:
- return True
- # If we break out of the loop, the superclass gets a chance.
+ if self is Generic:
+ raise TypeError("Class %r cannot be used with class "
+ "or instance checks" % self)
+ if (self.__origin__ is not None and
+ sys._getframe(1).f_globals['__name__'] != 'abc'):
+ raise TypeError("Parameterized generics cannot be used with class "
+ "or instance checks")
if super().__subclasscheck__(cls):
return True
- if self.__extra__ is None or isinstance(cls, GenericMeta):
- return False
- return issubclass(cls, self.__extra__)
+ if self.__extra__ is not None:
+ return issubclass(cls, self.__extra__)
+ return False
# Prevent checks for Generic to crash when defining Generic.
@@ -1117,7 +1086,7 @@ class Generic(metaclass=GenericMeta):
return obj
-class _ClassVar(metaclass=TypingMeta, _root=True):
+class _ClassVar(_FinalTypingBase, _root=True):
"""Special type construct to mark class variables.
An annotation wrapped in ClassVar indicates that a given
@@ -1134,36 +1103,35 @@ class _ClassVar(metaclass=TypingMeta, _root=True):
be used with isinstance() or issubclass().
"""
- def __init__(self, tp=None, _root=False):
- cls = type(self)
- if _root:
- self.__type__ = tp
- else:
- raise TypeError('Cannot initialize {}'.format(cls.__name__[1:]))
+ __slots__ = ('__type__',)
+
+ def __init__(self, tp=None, **kwds):
+ self.__type__ = tp
def __getitem__(self, item):
cls = type(self)
if self.__type__ is None:
return cls(_type_check(item,
- '{} accepts only types.'.format(cls.__name__[1:])),
+ '{} accepts only single type.'.format(cls.__name__[1:])),
_root=True)
raise TypeError('{} cannot be further subscripted'
.format(cls.__name__[1:]))
def _eval_type(self, globalns, localns):
- return type(self)(_eval_type(self.__type__, globalns, localns),
- _root=True)
+ new_tp = _eval_type(self.__type__, globalns, localns)
+ if new_tp == self.__type__:
+ return self
+ return type(self)(new_tp, _root=True)
def _get_type_vars(self, tvars):
if self.__type__:
_get_type_vars(self.__type__, tvars)
def __repr__(self):
- cls = type(self)
- if not self.__type__:
- return '{}.{}'.format(cls.__module__, cls.__name__[1:])
- return '{}.{}[{}]'.format(cls.__module__, cls.__name__[1:],
- _type_repr(self.__type__))
+ r = super().__repr__()
+ if self.__type__ is not None:
+ r += '[{}]'.format(_type_repr(self.__type__))
+ return r
def __hash__(self):
return hash((type(self).__name__, self.__type__))
@@ -1614,52 +1582,52 @@ if hasattr(collections_abc, 'Collection'):
if hasattr(collections_abc, 'Collection'):
class AbstractSet(Collection[T_co],
extra=collections_abc.Set):
- pass
+ __slots__ = ()
else:
class AbstractSet(Sized, Iterable[T_co], Container[T_co],
extra=collections_abc.Set):
- pass
+ __slots__ = ()
class MutableSet(AbstractSet[T], extra=collections_abc.MutableSet):
- pass
+ __slots__ = ()
# NOTE: It is only covariant in the value type.
if hasattr(collections_abc, 'Collection'):
class Mapping(Collection[KT], Generic[KT, VT_co],
extra=collections_abc.Mapping):
- pass
+ __slots__ = ()
else:
class Mapping(Sized, Iterable[KT], Container[KT], Generic[KT, VT_co],
extra=collections_abc.Mapping):
- pass
+ __slots__ = ()
class MutableMapping(Mapping[KT, VT], extra=collections_abc.MutableMapping):
- pass
+ __slots__ = ()
if hasattr(collections_abc, 'Reversible'):
if hasattr(collections_abc, 'Collection'):
class Sequence(Reversible[T_co], Collection[T_co],
extra=collections_abc.Sequence):
- pass
+ __slots__ = ()
else:
class Sequence(Sized, Reversible[T_co], Container[T_co],
extra=collections_abc.Sequence):
- pass
+ __slots__ = ()
else:
class Sequence(Sized, Iterable[T_co], Container[T_co],
extra=collections_abc.Sequence):
- pass
+ __slots__ = ()
class MutableSequence(Sequence[T], extra=collections_abc.MutableSequence):
- pass
+ __slots__ = ()
class ByteString(Sequence[int], extra=collections_abc.ByteString):
- pass
+ __slots__ = ()
ByteString.register(type(memoryview(b'')))
@@ -1667,6 +1635,8 @@ ByteString.register(type(memoryview(b'')))
class List(list, MutableSequence[T], extra=list):
+ __slots__ = ()
+
def __new__(cls, *args, **kwds):
if _geqv(cls, List):
raise TypeError("Type List cannot be instantiated; "
@@ -1676,6 +1646,8 @@ class List(list, MutableSequence[T], extra=list):
class Set(set, MutableSet[T], extra=set):
+ __slots__ = ()
+
def __new__(cls, *args, **kwds):
if _geqv(cls, Set):
raise TypeError("Type Set cannot be instantiated; "
@@ -1683,22 +1655,7 @@ class Set(set, MutableSet[T], extra=set):
return set.__new__(cls, *args, **kwds)
-class _FrozenSetMeta(GenericMeta):
- """This metaclass ensures set is not a subclass of FrozenSet.
-
- Without this metaclass, set would be considered a subclass of
- FrozenSet, because FrozenSet.__extra__ is collections.abc.Set, and
- set is a subclass of that.
- """
-
- def __subclasscheck__(self, cls):
- if issubclass(cls, Set):
- return False
- return super().__subclasscheck__(cls)
-
-
-class FrozenSet(frozenset, AbstractSet[T_co], metaclass=_FrozenSetMeta,
- extra=frozenset):
+class FrozenSet(frozenset, AbstractSet[T_co], extra=frozenset):
__slots__ = ()
def __new__(cls, *args, **kwds):
@@ -1709,23 +1666,23 @@ class FrozenSet(frozenset, AbstractSet[T_co], metaclass=_FrozenSetMeta,
class MappingView(Sized, Iterable[T_co], extra=collections_abc.MappingView):
- pass
+ __slots__ = ()
class KeysView(MappingView[KT], AbstractSet[KT],
extra=collections_abc.KeysView):
- pass
+ __slots__ = ()
class ItemsView(MappingView[Tuple[KT, VT_co]],
AbstractSet[Tuple[KT, VT_co]],
Generic[KT, VT_co],
extra=collections_abc.ItemsView):
- pass
+ __slots__ = ()
class ValuesView(MappingView[VT_co], extra=collections_abc.ValuesView):
- pass
+ __slots__ = ()
if hasattr(contextlib, 'AbstractContextManager'):
@@ -1736,6 +1693,8 @@ if hasattr(contextlib, 'AbstractContextManager'):
class Dict(dict, MutableMapping[KT, VT], extra=dict):
+ __slots__ = ()
+
def __new__(cls, *args, **kwds):
if _geqv(cls, Dict):
raise TypeError("Type Dict cannot be instantiated; "
@@ -1745,6 +1704,8 @@ class Dict(dict, MutableMapping[KT, VT], extra=dict):
class DefaultDict(collections.defaultdict, MutableMapping[KT, VT],
extra=collections.defaultdict):
+ __slots__ = ()
+
def __new__(cls, *args, **kwds):
if _geqv(cls, DefaultDict):
raise TypeError("Type DefaultDict cannot be instantiated; "
@@ -1800,6 +1761,8 @@ class Type(Generic[CT_co], extra=type):
At this point the type checker knows that joe has type BasicUser.
"""
+ __slots__ = ()
+
def _make_nmtuple(name, types):
nm_tpl = collections.namedtuple(name, [n for n, t in types])