mirror of https://github.com/python/cpython
gh-90633: Improve error and docs for typing.assert_never (#91720)
Closes #90633 Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
9ff2f12c87
commit
93d280141c
|
@ -2345,11 +2345,25 @@ Functions and decorators
|
|||
case _ as unreachable:
|
||||
assert_never(unreachable)
|
||||
|
||||
Here, the annotations allow the type checker to infer that the
|
||||
last case can never execute, because ``arg`` is either
|
||||
an :class:`int` or a :class:`str`, and both options are covered by
|
||||
earlier cases.
|
||||
If a type checker finds that a call to ``assert_never()`` is
|
||||
reachable, it will emit an error.
|
||||
reachable, it will emit an error. For example, if the type annotation
|
||||
for ``arg`` was instead ``int | str | float``, the type checker would
|
||||
emit an error pointing out that ``unreachable`` is of type :class:`float`.
|
||||
For a call to ``assert_never`` to succeed, the inferred type of
|
||||
the argument passed in must be the bottom type, :data:`Never`, and nothing
|
||||
else.
|
||||
|
||||
At runtime, this throws an exception when called.
|
||||
|
||||
.. seealso::
|
||||
`Unreachable Code and Exhaustiveness Checking
|
||||
<https://typing.readthedocs.io/en/latest/source/unreachable.html>_` has more
|
||||
information about exhaustiveness checking with static typing.
|
||||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
.. function:: reveal_type(obj)
|
||||
|
|
|
@ -223,6 +223,19 @@ class AssertNeverTests(BaseTestCase):
|
|||
with self.assertRaises(AssertionError):
|
||||
assert_never(None)
|
||||
|
||||
value = "some value"
|
||||
with self.assertRaisesRegex(AssertionError, value):
|
||||
assert_never(value)
|
||||
|
||||
# Make sure a huge value doesn't get printed in its entirety
|
||||
huge_value = "a" * 10000
|
||||
with self.assertRaises(AssertionError) as cm:
|
||||
assert_never(huge_value)
|
||||
self.assertLess(
|
||||
len(cm.exception.args[0]),
|
||||
typing._ASSERT_NEVER_REPR_MAX_LENGTH * 2,
|
||||
)
|
||||
|
||||
|
||||
class SelfTests(BaseTestCase):
|
||||
def test_equality(self):
|
||||
|
|
|
@ -2382,6 +2382,9 @@ def is_typeddict(tp):
|
|||
return isinstance(tp, _TypedDictMeta)
|
||||
|
||||
|
||||
_ASSERT_NEVER_REPR_MAX_LENGTH = 100
|
||||
|
||||
|
||||
def assert_never(arg: Never, /) -> Never:
|
||||
"""Statically assert that a line of code is unreachable.
|
||||
|
||||
|
@ -2402,7 +2405,10 @@ def assert_never(arg: Never, /) -> Never:
|
|||
At runtime, this throws an exception when called.
|
||||
|
||||
"""
|
||||
raise AssertionError("Expected code to be unreachable")
|
||||
value = repr(arg)
|
||||
if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH:
|
||||
value = value[:_ASSERT_NEVER_REPR_MAX_LENGTH] + '...'
|
||||
raise AssertionError(f"Expected code to be unreachable, but got: {value}")
|
||||
|
||||
|
||||
def no_type_check(arg):
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Include the passed value in the exception thrown by
|
||||
:func:`typing.assert_never`. Patch by Jelle Zijlstra.
|
Loading…
Reference in New Issue