Skip to content

Commit 96568e9

Browse files
JelleZijlstraAlexWaygooddavidfstr
authored
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>
1 parent 7c353b7 commit 96568e9

File tree

4 files changed

+60
-1
lines changed

4 files changed

+60
-1
lines changed

Doc/library/typing.rst

+25
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,31 @@ Functions and decorators
21482148
runtime we intentionally don't check anything (we want this
21492149
to be as fast as possible).
21502150

2151+
.. function:: assert_type(val, typ, /)
2152+
2153+
Assert (to the type checker) that *val* has an inferred type of *typ*.
2154+
2155+
When the type checker encounters a call to ``assert_type()``, it
2156+
emits an error if the value is not of the specified type::
2157+
2158+
def greet(name: str) -> None:
2159+
assert_type(name, str) # OK, inferred type of `name` is `str`
2160+
assert_type(name, int) # type checker error
2161+
2162+
At runtime this returns the first argument unchanged with no side effects.
2163+
2164+
This function is useful for ensuring the type checker's understanding of a
2165+
script is in line with the developer's intentions::
2166+
2167+
def complex_function(arg: object):
2168+
# Do some complex type-narrowing logic,
2169+
# after which we hope the inferred type will be `int`
2170+
...
2171+
# Test whether the type checker correctly understands our function
2172+
assert_type(arg, int)
2173+
2174+
.. versionadded:: 3.11
2175+
21512176
.. function:: assert_never(arg, /)
21522177

21532178
Assert to the type checker that a line of code is unreachable.

Lib/test/test_typing.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from typing import Tuple, List, Dict, MutableMapping
1717
from typing import Callable
1818
from typing import Generic, ClassVar, Final, final, Protocol
19-
from typing import cast, runtime_checkable
19+
from typing import assert_type, cast, runtime_checkable
2020
from typing import get_type_hints
2121
from typing import get_origin, get_args
2222
from typing import is_typeddict
@@ -3302,6 +3302,22 @@ def test_errors(self):
33023302
cast('hello', 42)
33033303

33043304

3305+
class AssertTypeTests(BaseTestCase):
3306+
3307+
def test_basics(self):
3308+
arg = 42
3309+
self.assertIs(assert_type(arg, int), arg)
3310+
self.assertIs(assert_type(arg, str | float), arg)
3311+
self.assertIs(assert_type(arg, AnyStr), arg)
3312+
self.assertIs(assert_type(arg, None), arg)
3313+
3314+
def test_errors(self):
3315+
# Bogus calls are not expected to fail.
3316+
arg = 42
3317+
self.assertIs(assert_type(arg, 42), arg)
3318+
self.assertIs(assert_type(arg, 'hello'), arg)
3319+
3320+
33053321
# We need this to make sure that `@no_type_check` respects `__module__` attr:
33063322
from test import ann_module8
33073323

Lib/typing.py

+17
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def _idfunc(_, x):
118118

119119
# One-off things.
120120
'AnyStr',
121+
'assert_type',
121122
'assert_never',
122123
'cast',
123124
'final',
@@ -2093,6 +2094,22 @@ def cast(typ, val):
20932094
return val
20942095

20952096

2097+
def assert_type(val, typ, /):
2098+
"""Assert (to the type checker) that the value is of the given type.
2099+
2100+
When the type checker encounters a call to assert_type(), it
2101+
emits an error if the value is not of the specified type::
2102+
2103+
def greet(name: str) -> None:
2104+
assert_type(name, str) # ok
2105+
assert_type(name, int) # type checker error
2106+
2107+
At runtime this returns the first argument unchanged and otherwise
2108+
does nothing.
2109+
"""
2110+
return val
2111+
2112+
20962113
_allowed_types = (types.FunctionType, types.BuiltinFunctionType,
20972114
types.MethodType, types.ModuleType,
20982115
WrapperDescriptorType, MethodWrapperType, MethodDescriptorType)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add :func:`typing.assert_type`. Patch by Jelle Zijlstra.

0 commit comments

Comments
 (0)