diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index f9e54b2725f..ade8a3587de 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -15,6 +15,7 @@ from typing import Generic 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 NamedTuple from typing import IO, TextIO, BinaryIO from typing import Pattern, Match @@ -1373,6 +1374,33 @@ class OtherABCTests(BaseTestCase): 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() + + joe = 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() + + joe = new_user(BasicUser) + + class NamedTupleTests(BaseTestCase): def test_basics(self): diff --git a/Lib/typing.py b/Lib/typing.py index 841e778648a..4bd21354362 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -19,9 +19,10 @@ __all__ = [ 'Callable', 'Generic', 'Optional', + 'Tuple', + 'Type', 'TypeVar', 'Union', - 'Tuple', # ABCs (from collections.abc). 'AbstractSet', # collections.abc.Set. @@ -447,6 +448,7 @@ class TypeVar(TypingMeta, metaclass=TypingMeta, _root=True): # Some unconstrained type variables. These are used by the container types. +# (These are not for export.) T = TypeVar('T') # Any type. KT = TypeVar('KT') # Key type. VT = TypeVar('VT') # Value type. @@ -456,6 +458,7 @@ VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers. T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant. # A useful type variable with constraints. This represents string types. +# (This one *is* for export!) AnyStr = TypeVar('AnyStr', bytes, str) @@ -1572,6 +1575,35 @@ class Generator(Iterator[T_co], Generic[T_co, T_contra, V_co], return super().__new__(cls, *args, **kwds) +# Internal type variable used for Type[]. +CT = TypeVar('CT', covariant=True, bound=type) + + +class Type(type, Generic[CT], extra=type): + """A generic type usable to annotate class objects. + + For example, suppose we have the following classes:: + + class User: ... # Abstract base for User classes + class BasicUser(User): ... + class ProUser(User): ... + class TeamUser(User): ... + + And a function that takes a class argument that's a subclass of + User and returns an instance of the corresponding class:: + + U = TypeVar('U', bound=User) + def new_user(user_class: Type[U]) -> U: + user = user_class() + # (Here we could write the user object to a database) + return user + + joe = new_user(BasicUser) + + At this point the type checker knows that joe has type BasicUser. + """ + + def NamedTuple(typename, fields): """Typed version of namedtuple.