Skip to content

bpo-46480: add typing.assert_type #30843

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

Merged
merged 9 commits into from
Mar 17, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2029,6 +2029,22 @@ 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 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.

.. 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 @@ -3259,6 +3259,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 @@ -2079,6 +2080,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.

"""
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.