Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-46480: add typing.assert_type #30843

Merged
merged 9 commits into from
Mar 17, 2022
25 changes: 25 additions & 0 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2114,6 +2114,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, /)
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved

Assert (to the type checker) that *value* has an inferred type of *type*.
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved

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)

JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved
.. versionadded:: 3.11

.. function:: assert_never(arg, /)

Assert to the type checker that a line of code is unreachable.
Expand Down
18 changes: 17 additions & 1 deletion Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
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
Expand Down Expand Up @@ -3302,6 +3302,22 @@ def test_errors(self):
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

Expand Down
18 changes: 18 additions & 0 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def _idfunc(_, x):

# One-off things.
'AnyStr',
'assert_type',
'assert_never',
'cast',
'final',
Expand Down Expand Up @@ -2093,6 +2094,23 @@ 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.

"""
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved
return val


_allowed_types = (types.FunctionType, types.BuiltinFunctionType,
types.MethodType, types.ModuleType,
WrapperDescriptorType, MethodWrapperType, MethodDescriptorType)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :func:`typing.assert_type`. Patch by Jelle Zijlstra.