From 755d07d83c6e8aeb4f8763cb88cbd14e0187c804 Mon Sep 17 00:00:00 2001 From: Vineeth Sai Date: Sun, 12 Jul 2026 13:53:28 -0700 Subject: [PATCH] Fix Regex(flags=re.I) crashing on CPython <= 3.10 and PyPy re.IGNORECASE and friends are re.RegexFlag (IntFlag) members, not plain ints. Building the human-readable flag list formatted flags with the "b" format code (f"{flags:09b}"); on CPython <= 3.10 and PyPy, IntFlag routes that through Enum.__format__, which formats the member as its string form and rejects the "b" code, raising ValueError before re.compile ran. So Regex(pattern, flags=), the documented usage, was unusable on those versions; only a plain int worked. Coerce to int before the binary formatting. re.compile already accepts the enum, so only the repr computation needed the coercion; output is identical for the existing int-flag usage. --- schema/__init__.py | 2 +- test_schema.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/schema/__init__.py b/schema/__init__.py index 10d6e8a..6533090 100644 --- a/schema/__init__.py +++ b/schema/__init__.py @@ -246,7 +246,7 @@ def __init__( ) -> None: self._pattern_str: str = pattern_str flags_list = [ - Regex.NAMES[i] for i, f in enumerate(f"{flags:09b}") if f != "0" + Regex.NAMES[i] for i, f in enumerate(f"{int(flags):09b}") if f != "0" ] # Name for each bit self._flags_names: str = ", flags=" + "|".join(flags_list) if flags_list else "" diff --git a/test_schema.py b/test_schema.py index 4d78456..adaf216 100644 --- a/test_schema.py +++ b/test_schema.py @@ -215,6 +215,19 @@ def test_regex(): Regex(None).validate("bar") +def test_regex_flags(): + # Passing an actual re flag (a re.RegexFlag enum member, not a plain int) + # must not crash while building the human-readable repr, and the flag must + # still be applied. On CPython <= 3.10 and PyPy, formatting a RegexFlag with + # the "b" format code raised ValueError before the flag was compiled. + single = Regex(r"foo", flags=re.IGNORECASE) + assert single.validate("FOObar") == "FOObar" + assert "re.IGNORECASE" in repr(single) + + multi = Regex(r"^foo", flags=re.IGNORECASE | re.MULTILINE) + assert multi.validate("bar\nFOO") == "bar\nFOO" + + def test_validate_list(): assert Schema([1, 0]).validate([1, 0, 1, 1]) == [1, 0, 1, 1] assert Schema([1, 0]).validate([]) == []