From 9ffa1e131b0e7e08de4f1bebbf53e28105a5a87c Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 16 Mar 2022 20:12:36 -0700 Subject: [PATCH 1/3] Add assert_type See python/cpython#30843 --- typing_extensions/CHANGELOG | 4 ++++ typing_extensions/README.rst | 1 + .../src/test_typing_extensions.py | 18 +++++++++++++++- typing_extensions/src/typing_extensions.py | 21 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/typing_extensions/CHANGELOG b/typing_extensions/CHANGELOG index d27af2913..aa3f09c83 100644 --- a/typing_extensions/CHANGELOG +++ b/typing_extensions/CHANGELOG @@ -1,3 +1,7 @@ +# Unreleased + +- Add `typing.assert_type`. Backport from bpo-46480. + # Release 4.1.1 (February 13, 2022) - Fix importing `typing_extensions` on Python 3.7.0 and 3.7.1. Original diff --git a/typing_extensions/README.rst b/typing_extensions/README.rst index 5db69d150..c1362aa5e 100644 --- a/typing_extensions/README.rst +++ b/typing_extensions/README.rst @@ -45,6 +45,7 @@ This module currently contains the following: - In ``typing`` since Python 3.11 - ``assert_never`` + - ``assert_type`` - ``Never`` - ``reveal_type`` - ``Self`` (see PEP 673) diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py index a66a2f291..c517987a9 100644 --- a/typing_extensions/src/test_typing_extensions.py +++ b/typing_extensions/src/test_typing_extensions.py @@ -12,7 +12,7 @@ from unittest import TestCase, main, skipUnless, skipIf from test import ann_module, ann_module2, ann_module3 import typing -from typing import TypeVar, Optional, Union, Any +from typing import TypeVar, Optional, Union, Any, AnyStr from typing import T, KT, VT # Not in __all__. from typing import Tuple, List, Dict, Iterable, Iterator, Callable from typing import Generic, NamedTuple @@ -23,6 +23,7 @@ from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, overload, final, is_typeddict from typing_extensions import TypeVarTuple, Unpack, dataclass_transform, reveal_type, Never, assert_never, LiteralString +from typing_extensions import assert_type try: from typing_extensions import get_type_hints except ImportError: @@ -445,6 +446,21 @@ def blah(): blah() +class AssertTypeTests(BaseTestCase): + + def test_basics(self): + arg = 42 + self.assertIs(assert_type(arg, int), arg) + self.assertIs(assert_type(arg, Union[str, float]), arg) + self.assertIs(assert_type(arg, AnyStr), arg) + self.assertIs(assert_type(arg, None), arg) + + def test_errors(self): + # Bogus calls are not expected to fail. + arg = 42 + self.assertIs(assert_type(arg, 42), arg) + self.assertIs(assert_type(arg, 'hello'), arg) + T_a = TypeVar('T_a') diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py index 194731cd3..20ce3d453 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -1231,6 +1231,27 @@ class Film(TypedDict): """ return isinstance(tp, tuple(_TYPEDDICT_TYPES)) + +if hasattr(typing, "assert_type"): + assert_type = typing.assert_type + +else: + def assert_type(val, typ, /): + """Assert (to the type checker) that the value is of the given type. + + When the type checker encounters a call to assert_type(), it + emits an error if the value is not of the specified type:: + + def greet(name: str) -> None: + assert_type(name, str) # ok + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged and otherwise + does nothing. + """ + return val + + if hasattr(typing, "Required"): get_type_hints = typing.get_type_hints elif PEP_560: From e6084a002de87bab0d2c0d41bee5f7a26dd74a07 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 16 Mar 2022 20:14:52 -0700 Subject: [PATCH 2/3] living in the past --- typing_extensions/src/typing_extensions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/typing_extensions/src/typing_extensions.py b/typing_extensions/src/typing_extensions.py index 20ce3d453..f89df3e29 100644 --- a/typing_extensions/src/typing_extensions.py +++ b/typing_extensions/src/typing_extensions.py @@ -1236,7 +1236,7 @@ class Film(TypedDict): assert_type = typing.assert_type else: - def assert_type(val, typ, /): + def assert_type(__val, __typ): """Assert (to the type checker) that the value is of the given type. When the type checker encounters a call to assert_type(), it @@ -1249,7 +1249,7 @@ def greet(name: str) -> None: At runtime this returns the first argument unchanged and otherwise does nothing. """ - return val + return __val if hasattr(typing, "Required"): From c0ac1b86bce523836e26f6650097913ab249e1b5 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 22 Mar 2022 15:23:32 -0700 Subject: [PATCH 3/3] Update typing_extensions/src/test_typing_extensions.py --- typing_extensions/src/test_typing_extensions.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/typing_extensions/src/test_typing_extensions.py b/typing_extensions/src/test_typing_extensions.py index a197d3b2b..b8fe5e352 100644 --- a/typing_extensions/src/test_typing_extensions.py +++ b/typing_extensions/src/test_typing_extensions.py @@ -23,8 +23,7 @@ from typing_extensions import Awaitable, AsyncIterator, AsyncContextManager, Required, NotRequired from typing_extensions import Protocol, runtime, runtime_checkable, Annotated, overload, final, is_typeddict from typing_extensions import TypeVarTuple, Unpack, dataclass_transform, reveal_type, Never, assert_never, LiteralString -from typing_extensions import assert_type -from typing_extensions import get_type_hints, get_origin, get_args +from typing_extensions import assert_type, get_type_hints, get_origin, get_args # Flags used to mark tests that only apply after a specific # version of the typing module.