diff options
author | Jelle Zijlstra <jelle.zijlstra@gmail.com> | 2022-03-17 03:02:26 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-17 03:02:26 (GMT) |
commit | 96568e995d840c66edb25b6b9d85e4dcccf5a936 (patch) | |
tree | 907a903c2807fb7437b4e5a5779d034609320a9f | |
parent | 7c353b7594545fb9403b3123a17ad06cadc2f73d (diff) | |
download | cpython-96568e995d840c66edb25b6b9d85e4dcccf5a936.zip cpython-96568e995d840c66edb25b6b9d85e4dcccf5a936.tar.gz cpython-96568e995d840c66edb25b6b9d85e4dcccf5a936.tar.bz2 |
bpo-46480: add typing.assert_type (GH-30843)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: David Foster <david@dafoster.net>
-rw-r--r-- | Doc/library/typing.rst | 25 | ||||
-rw-r--r-- | Lib/test/test_typing.py | 18 | ||||
-rw-r--r-- | Lib/typing.py | 17 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2022-01-23-16-33-07.bpo-46480.E4jHlh.rst | 1 |
4 files changed, 60 insertions, 1 deletions
diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index c7c2cd6..57979cb 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2148,6 +2148,31 @@ Functions and decorators runtime we intentionally don't check anything (we want this to be as fast as possible). +.. function:: assert_type(val, typ, /) + + Assert (to the type checker) that *val* has an inferred type of *typ*. + + 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, inferred type of `name` is `str` + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged with no side effects. + + This function is useful for ensuring the type checker's understanding of a + script is in line with the developer's intentions:: + + def complex_function(arg: object): + # Do some complex type-narrowing logic, + # after which we hope the inferred type will be `int` + ... + # Test whether the type checker correctly understands our function + assert_type(arg, int) + + .. versionadded:: 3.11 + .. function:: assert_never(arg, /) Assert to the type checker that a line of code is unreachable. diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index b212b52..e88f732 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -16,7 +16,7 @@ from typing import Union, Optional, Literal from typing import Tuple, List, Dict, MutableMapping from typing import Callable from typing import Generic, ClassVar, Final, final, Protocol -from typing import cast, runtime_checkable +from typing import assert_type, cast, runtime_checkable from typing import get_type_hints from typing import get_origin, get_args from typing import is_typeddict @@ -3302,6 +3302,22 @@ class CastTests(BaseTestCase): cast('hello', 42) +class AssertTypeTests(BaseTestCase): + + def test_basics(self): + arg = 42 + self.assertIs(assert_type(arg, int), arg) + self.assertIs(assert_type(arg, 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) + + # We need this to make sure that `@no_type_check` respects `__module__` attr: from test import ann_module8 diff --git a/Lib/typing.py b/Lib/typing.py index dd68e71..6930f5d 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -118,6 +118,7 @@ __all__ = [ # One-off things. 'AnyStr', + 'assert_type', 'assert_never', 'cast', 'final', @@ -2093,6 +2094,22 @@ def cast(typ, val): return val +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 + + _allowed_types = (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.ModuleType, WrapperDescriptorType, MethodWrapperType, MethodDescriptorType) diff --git a/Misc/NEWS.d/next/Library/2022-01-23-16-33-07.bpo-46480.E4jHlh.rst b/Misc/NEWS.d/next/Library/2022-01-23-16-33-07.bpo-46480.E4jHlh.rst new file mode 100644 index 0000000..fd18a81 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-23-16-33-07.bpo-46480.E4jHlh.rst @@ -0,0 +1 @@ +Add :func:`typing.assert_type`. Patch by Jelle Zijlstra. |