[Python-checkins] cpython (3.5): Sync typing.py with upstream.

guido.van.rossum python-checkins at python.org
Wed Jun 8 14:22:07 EDT 2016


https://hg.python.org/cpython/rev/d11082567e76
changeset:   101806:d11082567e76
branch:      3.5
parent:      101804:e0cd9effcb85
user:        Guido van Rossum <guido at python.org>
date:        Wed Jun 08 11:19:11 2016 -0700
summary:
  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).

files:
  Lib/test/test_typing.py |  38 ++++++++++++++++++++++++-
  Lib/typing.py           |  42 +++++++++++++++++++++++++++-
  2 files changed, 76 insertions(+), 4 deletions(-)


diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -3,7 +3,7 @@
 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 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 @@
         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 @@
 
     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 @@
         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
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -64,10 +64,12 @@
     '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 @@
         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 @@
             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 @@
             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 @@
     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.
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list