Commit 91185fe0 authored by Guido van Rossum's avatar Guido van Rossum

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).
parent 07a9fcdc
......@@ -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):
......
......@@ -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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment