diff options
author | Guido van Rossum <guido@python.org> | 2016-06-08 18:19:11 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2016-06-08 18:19:11 (GMT) |
commit | 91185fe0284a04162e0b3425b53be49bdbfad67d (patch) | |
tree | d7ce0fa5970b79c29850d61a0e7b79479c39e874 /Lib | |
parent | 07a9fcdc86b740ac5c5108d10418e7668a06e3df (diff) | |
download | cpython-91185fe0284a04162e0b3425b53be49bdbfad67d.zip cpython-91185fe0284a04162e0b3425b53be49bdbfad67d.tar.gz cpython-91185fe0284a04162e0b3425b53be49bdbfad67d.tar.bz2 |
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).
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_typing.py | 38 | ||||
-rw-r--r-- | 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 index ade8a35..a7f8dd5 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -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): diff --git a/Lib/typing.py b/Lib/typing.py index b7f3ffa..4cac66c 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -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. |