mirror of
https://github.com/python/cpython.git
synced 2025-12-15 21:44:50 +00:00
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>
This commit is contained in:
parent
7c353b7594
commit
96568e995d
4 changed files with 60 additions and 1 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Add :func:`typing.assert_type`. Patch by Jelle Zijlstra.
|
||||
Loading…
Add table
Add a link
Reference in a new issue