Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 93d2801

Browse filesBrowse files
gh-90633: Improve error and docs for typing.assert_never (#91720)
Closes #90633 Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
1 parent 9ff2f12 commit 93d2801
Copy full SHA for 93d2801

File tree

4 files changed

+37
-2
lines changed
Filter options

4 files changed

+37
-2
lines changed

‎Doc/library/typing.rst

Copy file name to clipboardExpand all lines: Doc/library/typing.rst
+15-1Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2345,11 +2345,25 @@ Functions and decorators
23452345
case _ as unreachable:
23462346
assert_never(unreachable)
23472347

2348+
Here, the annotations allow the type checker to infer that the
2349+
last case can never execute, because ``arg`` is either
2350+
an :class:`int` or a :class:`str`, and both options are covered by
2351+
earlier cases.
23482352
If a type checker finds that a call to ``assert_never()`` is
2349-
reachable, it will emit an error.
2353+
reachable, it will emit an error. For example, if the type annotation
2354+
for ``arg`` was instead ``int | str | float``, the type checker would
2355+
emit an error pointing out that ``unreachable`` is of type :class:`float`.
2356+
For a call to ``assert_never`` to succeed, the inferred type of
2357+
the argument passed in must be the bottom type, :data:`Never`, and nothing
2358+
else.
23502359

23512360
At runtime, this throws an exception when called.
23522361

2362+
.. seealso::
2363+
`Unreachable Code and Exhaustiveness Checking
2364+
<https://typing.readthedocs.io/en/latest/source/unreachable.html>_` has more
2365+
information about exhaustiveness checking with static typing.
2366+
23532367
.. versionadded:: 3.11
23542368

23552369
.. function:: reveal_type(obj)

‎Lib/test/test_typing.py

Copy file name to clipboardExpand all lines: Lib/test/test_typing.py
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,19 @@ def test_exception(self):
223223
with self.assertRaises(AssertionError):
224224
assert_never(None)
225225

226+
value = "some value"
227+
with self.assertRaisesRegex(AssertionError, value):
228+
assert_never(value)
229+
230+
# Make sure a huge value doesn't get printed in its entirety
231+
huge_value = "a" * 10000
232+
with self.assertRaises(AssertionError) as cm:
233+
assert_never(huge_value)
234+
self.assertLess(
235+
len(cm.exception.args[0]),
236+
typing._ASSERT_NEVER_REPR_MAX_LENGTH * 2,
237+
)
238+
226239

227240
class SelfTests(BaseTestCase):
228241
def test_equality(self):

‎Lib/typing.py

Copy file name to clipboardExpand all lines: Lib/typing.py
+7-1Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2382,6 +2382,9 @@ class Film(TypedDict):
23822382
return isinstance(tp, _TypedDictMeta)
23832383

23842384

2385+
_ASSERT_NEVER_REPR_MAX_LENGTH = 100
2386+
2387+
23852388
def assert_never(arg: Never, /) -> Never:
23862389
"""Statically assert that a line of code is unreachable.
23872390
@@ -2402,7 +2405,10 @@ def int_or_str(arg: int | str) -> None:
24022405
At runtime, this throws an exception when called.
24032406
24042407
"""
2405-
raise AssertionError("Expected code to be unreachable")
2408+
value = repr(arg)
2409+
if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH:
2410+
value = value[:_ASSERT_NEVER_REPR_MAX_LENGTH] + '...'
2411+
raise AssertionError(f"Expected code to be unreachable, but got: {value}")
24062412

24072413

24082414
def no_type_check(arg):
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Include the passed value in the exception thrown by
2+
:func:`typing.assert_never`. Patch by Jelle Zijlstra.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.