Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mypy/typeshed/stubs/librt/librt/strings.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ def read_f64_be(b: bytes, index: i64, /) -> float: ...
# obtained via ord(s[i])). Negative inputs return False.
def isspace(c: i32, /) -> bool: ...
def isdigit(c: i32, /) -> bool: ...
def isalnum(c: i32, /) -> bool: ...
4 changes: 4 additions & 0 deletions mypyc/lib-rt/codepoint_extra_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ static inline bool LibRTStrings_IsDigit(int32_t c) {
return c >= 0 && Py_UNICODE_ISDIGIT((Py_UCS4)c);
}

static inline bool LibRTStrings_IsAlnum(int32_t c) {
return c >= 0 && Py_UNICODE_ISALNUM((Py_UCS4)c);
}

#endif // MYPYC_CODEPOINT_EXTRA_OPS_H
4 changes: 4 additions & 0 deletions mypyc/lib-rt/strings/librt_strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,7 @@ cp_parse_i32(PyObject *arg, int32_t *out) {

DEFINE_CP_BOOL_WRAPPER(isspace, LibRTStrings_IsSpace)
DEFINE_CP_BOOL_WRAPPER(isdigit, LibRTStrings_IsDigit)
DEFINE_CP_BOOL_WRAPPER(isalnum, LibRTStrings_IsAlnum)

static PyMethodDef librt_strings_module_methods[] = {
{"write_i16_le", (PyCFunction) write_i16_le, METH_FASTCALL,
Expand Down Expand Up @@ -1260,6 +1261,9 @@ static PyMethodDef librt_strings_module_methods[] = {
{"isdigit", cp_isdigit, METH_O,
PyDoc_STR("Test whether a codepoint (i32) is a Unicode digit.")
},
{"isalnum", cp_isalnum, METH_O,
PyDoc_STR("Test whether a codepoint (i32) is alphanumeric.")
},
{NULL, NULL, 0, NULL}
};

Expand Down
9 changes: 9 additions & 0 deletions mypyc/primitives/librt_strings_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,12 @@
error_kind=ERR_NEVER,
dependencies=[LIBRT_STRINGS, CODEPOINT_EXTRA_OPS],
)

function_op(
name="librt.strings.isalnum",
arg_types=[int32_rprimitive],
return_type=bool_rprimitive,
c_function_name="LibRTStrings_IsAlnum",
error_kind=ERR_NEVER,
dependencies=[LIBRT_STRINGS, CODEPOINT_EXTRA_OPS],
)
14 changes: 14 additions & 0 deletions mypyc/test-data/irbuild-librt-strings.test
Original file line number Diff line number Diff line change
Expand Up @@ -359,3 +359,17 @@ def is_d(c):
L0:
r0 = LibRTStrings_IsDigit(c)
return r0

[case testLibrtStringsIsAlnumIR]
from librt.strings import isalnum
from mypy_extensions import i32

def is_an(c: i32) -> bool:
return isalnum(c)
[out]
def is_an(c):
c :: i32
r0 :: bool
L0:
r0 = LibRTStrings_IsAlnum(c)
return r0
4 changes: 3 additions & 1 deletion mypyc/test-data/run-librt-strings.test
Original file line number Diff line number Diff line change
Expand Up @@ -1443,14 +1443,15 @@ def test_new_without_init_is_usable() -> None:
[case testLibrtStringsCodepointClassifiers_librt]
from typing import Any
from mypy_extensions import i32
from librt.strings import isspace, isdigit
from librt.strings import isspace, isdigit, isalnum


def test_codepoint_classifiers() -> None:
# Negative values are not codepoints.
for bad in (i32(-1), i32(-113)):
assert not isspace(bad)
assert not isdigit(bad)
assert not isalnum(bad)
# Verify each codepoint primitive agrees with the matching str method
# across all Unicode codepoints, including the ord(chr(i)) round-trip.
# Any forces generic dispatch on the str side.
Expand All @@ -1460,3 +1461,4 @@ def test_codepoint_classifiers() -> None:
o = ord(c)
assert isspace(o) == isspace(i) == a.isspace()
assert isdigit(o) == isdigit(i) == a.isdigit()
assert isalnum(o) == isalnum(i) == a.isalnum()
Copy link
Copy Markdown
Collaborator

@p-sawicki p-sawicki May 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we're missing coverage for calling these functions through the python wrappers because here they are transformed into direct C function calls.

could you add a driver.py in this test and call them with a couple of values? doesn't have to be the entire space like in the compiled file. would be good to also test the exception raised when the codepoint is outside of int32 range.

edit: or instead of driver.py wrap the librt functions with Any variables and call through the wrapper. we have a couple of examples in other tests like this.

Loading