File tree Expand file tree Collapse file tree 4 files changed +37
-2
lines changed
Expand file tree Collapse file tree 4 files changed +37
-2
lines changed Original file line number Diff line number Diff 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)
Original file line number Diff line number Diff 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
227240class SelfTests (BaseTestCase ):
228241 def test_equality (self ):
Original file line number Diff line number Diff 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+
23852388def 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
24082414def no_type_check (arg ):
Original file line number Diff line number Diff line change 1+ Include the passed value in the exception thrown by
2+ :func: `typing.assert_never `. Patch by Jelle Zijlstra.
You can’t perform that action at this time.
0 commit comments