@@ -1443,14 +1443,17 @@ def test_new_without_init_is_usable() -> None:
14431443[case testLibrtStringsCodepointClassifiers_librt]
14441444from typing import Any
14451445from mypy_extensions import i32
1446- from librt.strings import isspace, isdigit
1446+ from librt.strings import isspace, isdigit, isalnum
1447+
1448+ from testutil import assertRaises
14471449
14481450
14491451def test_codepoint_classifiers() -> None:
14501452 # Negative values are not codepoints.
14511453 for bad in (i32(-1), i32(-113)):
14521454 assert not isspace(bad)
14531455 assert not isdigit(bad)
1456+ assert not isalnum(bad)
14541457 # Verify each codepoint primitive agrees with the matching str method
14551458 # across all Unicode codepoints, including the ord(chr(i)) round-trip.
14561459 # Any forces generic dispatch on the str side.
@@ -1460,3 +1463,24 @@ def test_codepoint_classifiers() -> None:
14601463 o = ord(c)
14611464 assert isspace(o) == isspace(i) == a.isspace()
14621465 assert isdigit(o) == isdigit(i) == a.isdigit()
1466+ assert isalnum(o) == isalnum(i) == a.isalnum()
1467+
1468+
1469+ def test_codepoint_classifiers_via_any() -> None:
1470+ # Iterate so the callee is opaque to mypyc and dispatch falls back to
1471+ # the PyMethodDef wrapper, exercising the i32 range check.
1472+ for fn, true_input, false_input in (
1473+ (isspace, " ", "a"),
1474+ (isdigit, "5", "a"),
1475+ (isalnum, "A", " "),
1476+ ):
1477+ f: Any = fn
1478+ assert f(ord(true_input)) is True
1479+ assert f(ord(false_input)) is False
1480+ # Negative values are valid i32, just not codepoints.
1481+ assert f(-1) is False
1482+ # Inputs outside i32 range raise OverflowError through the wrapper.
1483+ with assertRaises(OverflowError, "codepoint out of i32 range"):
1484+ f(1 << 40)
1485+ with assertRaises(OverflowError, "codepoint out of i32 range"):
1486+ f(-(1 << 40))
0 commit comments