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 ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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__ = [ ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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.
......
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