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
15 changes: 15 additions & 0 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1932,6 +1932,21 @@ 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 the value is of the given 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
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved
assert_type(name, int) # type checker error

At runtime this returns the first argument unchanged.
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved

.. versionadded:: 3.11

.. function:: reveal_type(obj)

Reveal the inferred static type of an expression.
Expand Down
17 changes: 16 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 @@ -2670,6 +2670,21 @@ 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.
assert_type(42, 42)
assert_type(42, 'hello')
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved


class ForwardRefTests(BaseTestCase):

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

# One-off things.
'AnyStr',
'assert_type',
'cast',
'final',
'get_args',
Expand Down Expand Up @@ -1731,6 +1732,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.
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved

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


def _get_defaults(func):
"""Internal helper to extract the default arguments, by name."""
try:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :func:`typing.assert_type`. Patch by Jelle Zijlstra.