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).
This commit is contained in:
parent
07a9fcdc86
commit
91185fe028
|
@ -3,7 +3,7 @@ import collections
|
||||||
import pickle
|
import pickle
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from unittest import TestCase, main, skipUnless
|
from unittest import TestCase, main, skipUnless, SkipTest
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import TypeVar, AnyStr
|
from typing import TypeVar, AnyStr
|
||||||
|
@ -16,6 +16,7 @@ from typing import cast
|
||||||
from typing import get_type_hints
|
from typing import get_type_hints
|
||||||
from typing import no_type_check, no_type_check_decorator
|
from typing import no_type_check, no_type_check_decorator
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
from typing import NewType
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
from typing import IO, TextIO, BinaryIO
|
from typing import IO, TextIO, BinaryIO
|
||||||
from typing import Pattern, Match
|
from typing import Pattern, Match
|
||||||
|
@ -339,6 +340,20 @@ class UnionTests(BaseTestCase):
|
||||||
A = Union[str, Pattern]
|
A = Union[str, Pattern]
|
||||||
A
|
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):
|
class TypeVarUnionTests(BaseTestCase):
|
||||||
|
|
||||||
|
@ -410,7 +425,7 @@ class TupleTests(BaseTestCase):
|
||||||
|
|
||||||
def test_repr(self):
|
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[()]), 'typing.Tuple[()]')
|
||||||
self.assertEqual(repr(Tuple[int, float]), 'typing.Tuple[int, float]')
|
self.assertEqual(repr(Tuple[int, float]), 'typing.Tuple[int, float]')
|
||||||
self.assertEqual(repr(Tuple[int, ...]), 'typing.Tuple[int, ...]')
|
self.assertEqual(repr(Tuple[int, ...]), 'typing.Tuple[int, ...]')
|
||||||
|
|
||||||
|
@ -1401,6 +1416,25 @@ class TypeTests(BaseTestCase):
|
||||||
joe = new_user(BasicUser)
|
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):
|
class NamedTupleTests(BaseTestCase):
|
||||||
|
|
||||||
def test_basics(self):
|
def test_basics(self):
|
||||||
|
|
|
@ -64,10 +64,12 @@ __all__ = [
|
||||||
'AnyStr',
|
'AnyStr',
|
||||||
'cast',
|
'cast',
|
||||||
'get_type_hints',
|
'get_type_hints',
|
||||||
|
'NewType',
|
||||||
'no_type_check',
|
'no_type_check',
|
||||||
'no_type_check_decorator',
|
'no_type_check_decorator',
|
||||||
'overload',
|
'overload',
|
||||||
'Text',
|
'Text',
|
||||||
|
'TYPE_CHECKING',
|
||||||
]
|
]
|
||||||
|
|
||||||
# The pseudo-submodules 're' and 'io' are part of the public
|
# The pseudo-submodules 're' and 'io' are part of the public
|
||||||
|
@ -306,7 +308,7 @@ def _type_check(arg, msg):
|
||||||
return type(None)
|
return type(None)
|
||||||
if isinstance(arg, str):
|
if isinstance(arg, str):
|
||||||
arg = _ForwardRef(arg)
|
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,))
|
raise TypeError(msg + " Got %.100r." % (arg,))
|
||||||
return arg
|
return arg
|
||||||
|
|
||||||
|
@ -503,7 +505,10 @@ class UnionMeta(TypingMeta):
|
||||||
if isinstance(t1, _TypeAlias):
|
if isinstance(t1, _TypeAlias):
|
||||||
# _TypeAlias is not a real class.
|
# _TypeAlias is not a real class.
|
||||||
continue
|
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)):
|
for t2 in all_params - {t1} if not isinstance(t2, TypeVar)):
|
||||||
all_params.remove(t1)
|
all_params.remove(t1)
|
||||||
# It's not a union if there's only one type left.
|
# 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__]
|
params = [_type_repr(p) for p in self.__tuple_params__]
|
||||||
if self.__tuple_use_ellipsis__:
|
if self.__tuple_use_ellipsis__:
|
||||||
params.append('...')
|
params.append('...')
|
||||||
|
if not params:
|
||||||
|
params.append('()')
|
||||||
r += '[%s]' % (
|
r += '[%s]' % (
|
||||||
', '.join(params))
|
', '.join(params))
|
||||||
return r
|
return r
|
||||||
|
@ -1632,10 +1639,41 @@ def NamedTuple(typename, fields):
|
||||||
return cls
|
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)
|
# Python-version-specific alias (Python 2: unicode; Python 3: str)
|
||||||
Text = str
|
Text = str
|
||||||
|
|
||||||
|
|
||||||
|
# Constant that's True when type checking, but False here.
|
||||||
|
TYPE_CHECKING = False
|
||||||
|
|
||||||
|
|
||||||
class IO(Generic[AnyStr]):
|
class IO(Generic[AnyStr]):
|
||||||
"""Generic base class for TextIO and BinaryIO.
|
"""Generic base class for TextIO and BinaryIO.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue