Skip to content

Commit 91185fe

Browse files
committed
Sync typing.py with upstream.
(Upstream is https://github.com/python/typing) - Add TYPE_CHECKING (false at runtime, true in type checkers) (upstream python#230). - Avoid error on Union[xml.etree.cElementTree.Element, str] (upstream python#229). - Repr of Tuple[()] should be 'Tuple[()]' (upstream python#231). - Add NewType() (upstream python#189).
1 parent 07a9fcd commit 91185fe

2 files changed

Lines changed: 76 additions & 4 deletions

File tree

‎Lib/test/test_typing.py‎

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pickle
44
import re
55
import sys
6-
from unittest import TestCase, main, skipUnless
6+
from unittest import TestCase, main, skipUnless, SkipTest
77

88
from typing import Any
99
from typing import TypeVar, AnyStr
@@ -16,6 +16,7 @@
1616
from typing import get_type_hints
1717
from typing import no_type_check, no_type_check_decorator
1818
from typing import Type
19+
from typing import NewType
1920
from typing import NamedTuple
2021
from typing import IO, TextIO, BinaryIO
2122
from typing import Pattern, Match
@@ -339,6 +340,20 @@ def test_union_str_pattern(self):
339340
A = Union[str, Pattern]
340341
A
341342

343+
def test_etree(self):
344+
# See https://github.com/python/typing/issues/229
345+
# (Only relevant for Python 2.)
346+
try:
347+
from xml.etree.cElementTree import Element
348+
except ImportError:
349+
raise SkipTest("cElementTree not found")
350+
Union[Element, str] # Shouldn't crash
351+
352+
def Elem(*args):
353+
return Element(*args)
354+
355+
Union[Elem, str] # Nor should this
356+
342357

343358
class TypeVarUnionTests(BaseTestCase):
344359

@@ -410,7 +425,7 @@ class C(B):
410425

411426
def test_repr(self):
412427
self.assertEqual(repr(Tuple), 'typing.Tuple')
413-
self.assertEqual(repr(Tuple[()]), 'typing.Tuple[]')
428+
self.assertEqual(repr(Tuple[()]), 'typing.Tuple[()]')
414429
self.assertEqual(repr(Tuple[int, float]), 'typing.Tuple[int, float]')
415430
self.assertEqual(repr(Tuple[int, ...]), 'typing.Tuple[int, ...]')
416431

@@ -1401,6 +1416,25 @@ def new_user(user_class: Type[U]) -> U:
14011416
joe = new_user(BasicUser)
14021417

14031418

1419+
class NewTypeTests(BaseTestCase):
1420+
1421+
def test_basic(self):
1422+
UserId = NewType('UserId', int)
1423+
UserName = NewType('UserName', str)
1424+
self.assertIsInstance(UserId(5), int)
1425+
self.assertIsInstance(UserName('Joe'), str)
1426+
self.assertEqual(UserId(5) + 1, 6)
1427+
1428+
def test_errors(self):
1429+
UserId = NewType('UserId', int)
1430+
UserName = NewType('UserName', str)
1431+
with self.assertRaises(TypeError):
1432+
issubclass(UserId, int)
1433+
with self.assertRaises(TypeError):
1434+
class D(UserName):
1435+
pass
1436+
1437+
14041438
class NamedTupleTests(BaseTestCase):
14051439

14061440
def test_basics(self):

‎Lib/typing.py‎

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,12 @@
6464
'AnyStr',
6565
'cast',
6666
'get_type_hints',
67+
'NewType',
6768
'no_type_check',
6869
'no_type_check_decorator',
6970
'overload',
7071
'Text',
72+
'TYPE_CHECKING',
7173
]
7274

7375
# The pseudo-submodules 're' and 'io' are part of the public
@@ -306,7 +308,7 @@ def _type_check(arg, msg):
306308
return type(None)
307309
if isinstance(arg, str):
308310
arg = _ForwardRef(arg)
309-
if not isinstance(arg, (type, _TypeAlias)):
311+
if not isinstance(arg, (type, _TypeAlias)) and not callable(arg):
310312
raise TypeError(msg + " Got %.100r." % (arg,))
311313
return arg
312314

@@ -503,7 +505,10 @@ def __new__(cls, name, bases, namespace, parameters=None, _root=False):
503505
if isinstance(t1, _TypeAlias):
504506
# _TypeAlias is not a real class.
505507
continue
506-
if any(issubclass(t1, t2)
508+
if not isinstance(t1, type):
509+
assert callable(t1) # A callable might sneak through.
510+
continue
511+
if any(isinstance(t2, type) and issubclass(t1, t2)
507512
for t2 in all_params - {t1} if not isinstance(t2, TypeVar)):
508513
all_params.remove(t1)
509514
# It's not a union if there's only one type left.
@@ -684,6 +689,8 @@ def __repr__(self):
684689
params = [_type_repr(p) for p in self.__tuple_params__]
685690
if self.__tuple_use_ellipsis__:
686691
params.append('...')
692+
if not params:
693+
params.append('()')
687694
r += '[%s]' % (
688695
', '.join(params))
689696
return r
@@ -1632,10 +1639,41 @@ def NamedTuple(typename, fields):
16321639
return cls
16331640

16341641

1642+
def NewType(name, tp):
1643+
"""NewType creates simple unique types with almost zero
1644+
runtime overhead. NewType(name, tp) is considered a subtype of tp
1645+
by static type checkers. At runtime, NewType(name, tp) returns
1646+
a dummy function that simply returns its argument. Usage::
1647+
1648+
UserId = NewType('UserId', int)
1649+
1650+
def name_by_id(user_id: UserId) -> str:
1651+
...
1652+
1653+
UserId('user') # Fails type check
1654+
1655+
name_by_id(42) # Fails type check
1656+
name_by_id(UserId(42)) # OK
1657+
1658+
num = UserId(5) + 1 # type: int
1659+
"""
1660+
1661+
def new_type(x):
1662+
return x
1663+
1664+
new_type.__name__ = name
1665+
new_type.__supertype__ = tp
1666+
return new_type
1667+
1668+
16351669
# Python-version-specific alias (Python 2: unicode; Python 3: str)
16361670
Text = str
16371671

16381672

1673+
# Constant that's True when type checking, but False here.
1674+
TYPE_CHECKING = False
1675+
1676+
16391677
class IO(Generic[AnyStr]):
16401678
"""Generic base class for TextIO and BinaryIO.
16411679

0 commit comments

Comments
 (0)