]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46480: add typing.assert_type (GH-30843)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Thu, 17 Mar 2022 03:02:26 +0000 (20:02 -0700)
committerGitHub <noreply@github.com>
Thu, 17 Mar 2022 03:02:26 +0000 (20:02 -0700)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: David Foster <david@dafoster.net>
Doc/library/typing.rst
Lib/test/test_typing.py
Lib/typing.py
Misc/NEWS.d/next/Library/2022-01-23-16-33-07.bpo-46480.E4jHlh.rst [new file with mode: 0644]

index c7c2cd6866b708b09c5a77000beed04d32b04b6c..57979cbb08e69a87052ab4c94552cd72370eec10 100644 (file)
@@ -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.
index b212b52304880953726742b7a71741323d5b2505..e88f7322b2fa8570943ed672054fbb1ea1c50aa8 100644 (file)
@@ -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
 
index dd68e71db1558c7c223b832a3520803d3f1e220e..6930f5ddac42acc1ca27fea4d28c04cdfdf34e89 100644 (file)
@@ -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)
diff --git a/Misc/NEWS.d/next/Library/2022-01-23-16-33-07.bpo-46480.E4jHlh.rst b/Misc/NEWS.d/next/Library/2022-01-23-16-33-07.bpo-46480.E4jHlh.rst
new file mode 100644 (file)
index 0000000..fd18a81
--- /dev/null
@@ -0,0 +1 @@
+Add :func:`typing.assert_type`. Patch by Jelle Zijlstra.