diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 14f49b01aa9f01..d6e4ed02e9c45f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -270,6 +270,12 @@ class UnionTests(BaseTestCase): def test_basics(self): u = Union[int, float] self.assertNotEqual(u, Union) + with self.assertRaises(TypeError): + Union[int, 42] + with self.assertRaises(TypeError): + Union[int, chr] + with self.assertRaises(TypeError): + Union[int, ...] def test_subclass_error(self): with self.assertRaises(TypeError): @@ -395,10 +401,6 @@ def test_no_eval_union(self): def f(x: u): ... self.assertIs(get_type_hints(f)['x'], u) - def test_function_repr_union(self): - def fun() -> int: ... - self.assertEqual(repr(Union[fun, int]), 'typing.Union[fun, int]') - def test_union_str_pattern(self): # Shouldn't crash; see http://bugs.python.org/issue25390 A = Union[str, Pattern] @@ -411,11 +413,6 @@ def test_etree(self): Union[Element, str] # Shouldn't crash - def Elem(*args): - return Element(*args) - - Union[Elem, str] # Nor should this - class TupleTests(BaseTestCase): @@ -2511,6 +2508,8 @@ class ClassVarTests(BaseTestCase): def test_basics(self): with self.assertRaises(TypeError): ClassVar[1] + with self.assertRaises(TypeError): + ClassVar[chr] with self.assertRaises(TypeError): ClassVar[int, str] with self.assertRaises(TypeError): @@ -2551,6 +2550,8 @@ def test_basics(self): Final[int] # OK with self.assertRaises(TypeError): Final[1] + with self.assertRaises(TypeError): + Final[chr] with self.assertRaises(TypeError): Final[int, str] with self.assertRaises(TypeError): diff --git a/Lib/typing.py b/Lib/typing.py index e4e32b5b320d04..1a65f854fb22b6 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -178,11 +178,10 @@ def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms= return arg if isinstance(arg, _SpecialForm) or arg in (Generic, Protocol): raise TypeError(f"Plain {arg} is not valid as type argument") - if isinstance(arg, (type, TypeVar, ForwardRef, types.UnionType, ParamSpec)): + if isinstance(arg, (type, TypeVar, ForwardRef, types.UnionType, ParamSpec, + _GenericAlias, _SpecialGenericAlias, NewType)): return arg - if not callable(arg): - raise TypeError(f"{msg} Got {arg!r:.100}.") - return arg + raise TypeError(f"{msg} Got {arg!r:.100}.") def _is_param_expr(arg): @@ -2065,6 +2064,50 @@ class Other(Leaf): # Error reported by type checker return f +class NewType: + """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 callable 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 + """ + + __call__ = _idfunc + + def __init__(self, name, tp): + self.__qualname__ = name + if '.' in name: + name = name.rpartition('.')[-1] + self.__name__ = name + self.__supertype__ = tp + def_mod = _caller() + if def_mod != 'typing': + self.__module__ = def_mod + + def __repr__(self): + return f'{self.__module__}.{self.__qualname__}' + + def __reduce__(self): + return self.__qualname__ + + def __or__(self, other): + return Union[self, other] + + def __ror__(self, other): + return Union[other, self] + + # Some unconstrained type variables. These are used by the container types. # (These are not for export.) T = TypeVar('T') # Any type. @@ -2438,50 +2481,6 @@ class body be required. TypedDict.__mro_entries__ = lambda bases: (_TypedDict,) -class NewType: - """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 callable 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 - """ - - __call__ = _idfunc - - def __init__(self, name, tp): - self.__qualname__ = name - if '.' in name: - name = name.rpartition('.')[-1] - self.__name__ = name - self.__supertype__ = tp - def_mod = _caller() - if def_mod != 'typing': - self.__module__ = def_mod - - def __repr__(self): - return f'{self.__module__}.{self.__qualname__}' - - def __reduce__(self): - return self.__qualname__ - - def __or__(self, other): - return Union[self, other] - - def __ror__(self, other): - return Union[other, self] - - # Python-version-specific alias (Python 2: unicode; Python 3: str) Text = str diff --git a/Misc/NEWS.d/next/Library/2022-02-06-13-56-58.bpo-46644.rWSd0I.rst b/Misc/NEWS.d/next/Library/2022-02-06-13-56-58.bpo-46644.rWSd0I.rst new file mode 100644 index 00000000000000..4943e0c94a0a6b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-02-06-13-56-58.bpo-46644.rWSd0I.rst @@ -0,0 +1,2 @@ +No longer accept arbitrary callables as type arguments in generics. E.g. +``List[chr]`` is now an error. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy