summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2016-06-08 11:19:11 -0700
committerGuido van Rossum <guido@python.org>2016-06-08 11:19:11 -0700
commitc76772812334961fca16856b8b184554514a23f1 (patch)
tree37f3557e99b257fcfb97eb6126a0a5793887fe5e
parent2777073b19fbf61a78cc57bec0017db0f371e43b (diff)
downloadcpython-c76772812334961fca16856b8b184554514a23f1.tar.gz
Sync typing.py with upstream.
(Upstream is https://github.com/python/typing) - Add TYPE_CHECKING (false at runtime, true in type checkers) (upstream #230). - Avoid error on Union[xml.etree.cElementTree.Element, str] (upstream #229). - Repr of Tuple[()] should be 'Tuple[()]' (upstream #231). - Add NewType() (upstream #189).
-rw-r--r--Lib/test/test_typing.py38
-rw-r--r--Lib/typing.py42
2 files changed, 76 insertions, 4 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index ade8a3587d..a7f8dd5006 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -3,7 +3,7 @@ import collections
import pickle
import re
import sys
-from unittest import TestCase, main, skipUnless
+from unittest import TestCase, main, skipUnless, SkipTest
from typing import Any
from typing import TypeVar, AnyStr
@@ -16,6 +16,7 @@ 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
@@ -339,6 +340,20 @@ class UnionTests(BaseTestCase):
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 TypeVarUnionTests(BaseTestCase):
@@ -410,7 +425,7 @@ class TupleTests(BaseTestCase):
def test_repr(self):
self.assertEqual(repr(Tuple), 'typing.Tuple')
- 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, ...]')
@@ -1401,6 +1416,25 @@ class TypeTests(BaseTestCase):
joe = new_user(BasicUser)
+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):
diff --git a/Lib/typing.py b/Lib/typing.py
index b7f3ffa0aa..4cac66cd13 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -64,10 +64,12 @@ __all__ = [
'AnyStr',
'cast',
'get_type_hints',
+ 'NewType',
'no_type_check',
'no_type_check_decorator',
'overload',
'Text',
+ 'TYPE_CHECKING',
]
# The pseudo-submodules 're' and 'io' are part of the public
@@ -306,7 +308,7 @@ def _type_check(arg, msg):
return type(None)
if isinstance(arg, str):
arg = _ForwardRef(arg)
- if not isinstance(arg, (type, _TypeAlias)):
+ if not isinstance(arg, (type, _TypeAlias)) and not callable(arg):
raise TypeError(msg + " Got %.100r." % (arg,))
return arg
@@ -503,7 +505,10 @@ class UnionMeta(TypingMeta):
if isinstance(t1, _TypeAlias):
# _TypeAlias is not a real class.
continue
- if any(issubclass(t1, t2)
+ 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)):
all_params.remove(t1)
# It's not a union if there's only one type left.
@@ -684,6 +689,8 @@ class TupleMeta(TypingMeta):
params = [_type_repr(p) for p in self.__tuple_params__]
if self.__tuple_use_ellipsis__:
params.append('...')
+ if not params:
+ params.append('()')
r += '[%s]' % (
', '.join(params))
return r
@@ -1632,10 +1639,41 @@ def NamedTuple(typename, fields):
return cls
+def NewType(name, tp):
+ """NewType creates simple unique types with almost zero
+ runtime overhead. NewType(name, tp) is considered a subtype of tp
+ by static type checkers. At runtime, NewType(name, tp) returns
+ a dummy function that simply returns its argument. Usage::
+
+ UserId = NewType('UserId', int)
+
+ def name_by_id(user_id: UserId) -> str:
+ ...
+
+ UserId('user') # Fails type check
+
+ name_by_id(42) # Fails type check
+ name_by_id(UserId(42)) # OK
+
+ num = UserId(5) + 1 # type: int
+ """
+
+ def new_type(x):
+ return x
+
+ new_type.__name__ = name
+ new_type.__supertype__ = tp
+ return new_type
+
+
# Python-version-specific alias (Python 2: unicode; Python 3: str)
Text = str
+# Constant that's True when type checking, but False here.
+TYPE_CHECKING = False
+
+
class IO(Generic[AnyStr]):
"""Generic base class for TextIO and BinaryIO.