From 62fe1bb983084c74fd8e7028412d0130a14568f3 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 29 Oct 2016 16:05:26 -0700 Subject: [PATCH] Issue #28556: updates to typing.py (add Coroutine, prohibit Generic[T]()) --- Lib/test/test_typing.py | 23 ++++++++++++++++++++++- Lib/typing.py | 31 +++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index b50f36679d3..7a5b415baef 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -517,6 +517,9 @@ class GenericTests(BaseTestCase): 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): @@ -1255,7 +1258,7 @@ ASYNCIO = sys.version_info[:2] >= (3, 5) ASYNCIO_TESTS = """ import asyncio -T_a = TypeVar('T') +T_a = TypeVar('T_a') class AwaitableWrapper(typing.Awaitable[T_a]): @@ -1403,6 +1406,24 @@ class CollectionsAbcTests(BaseTestCase): 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] diff --git a/Lib/typing.py b/Lib/typing.py index 572708b5ed6..2a1ea081f2d 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -29,9 +29,6 @@ __all__ = [ # ABCs (from collections.abc). 'AbstractSet', # collections.abc.Set. - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', 'ByteString', 'Container', 'Hashable', @@ -47,6 +44,14 @@ __all__ = [ 'Sequence', 'Sized', 'ValuesView', + # The following are added depending on presence + # of their non-generic counterparts in stdlib: + # Awaitable, + # AsyncIterator, + # AsyncIterable, + # Coroutine, + # Collection, + # ContextManager # Structural checks, a.k.a. protocols. 'Reversible', @@ -1104,6 +1109,9 @@ class Generic(metaclass=GenericMeta): __slots__ = () def __new__(cls, *args, **kwds): + if _geqv(cls, Generic): + raise TypeError("Type Generic cannot be instantiated; " + "it can be used only as a base class") return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) @@ -1639,8 +1647,16 @@ Hashable = collections_abc.Hashable # Not generic. if hasattr(collections_abc, 'Awaitable'): class Awaitable(Generic[T_co], extra=collections_abc.Awaitable): __slots__ = () -else: - Awaitable = None + + __all__.append('Awaitable') + + +if hasattr(collections_abc, 'Coroutine'): + class Coroutine(Awaitable[V_co], Generic[T_co, T_contra, V_co], + extra=collections_abc.Coroutine): + __slots__ = () + + __all__.append('Coroutine') if hasattr(collections_abc, 'AsyncIterable'): @@ -1652,9 +1668,8 @@ if hasattr(collections_abc, 'AsyncIterable'): extra=collections_abc.AsyncIterator): __slots__ = () -else: - AsyncIterable = None - AsyncIterator = None + __all__.append('AsyncIterable') + __all__.append('AsyncIterator') class Iterable(Generic[T_co], extra=collections_abc.Iterable):