Skip to content

Fix Regex(flags=re.I) crashing on CPython <= 3.10 and PyPy (#246) - #357

Open
vineethsaivs wants to merge 1 commit into
keleshev:masterfrom
vineethsaivs:fix/regex-enum-flags-crash
Open

Fix Regex(flags=re.I) crashing on CPython <= 3.10 and PyPy (#246)#357
vineethsaivs wants to merge 1 commit into
keleshev:masterfrom
vineethsaivs:fix/regex-enum-flags-crash

Conversation

@vineethsaivs

Copy link
Copy Markdown
Contributor

What

Constructing a Regex with an actual re flag crashes on CPython <= 3.10 and PyPy:

import re
from schema import Regex
Regex(r"foo", flags=re.IGNORECASE)
# ValueError: Unknown format code 'b' for object of type 'str'

re.IGNORECASE and the other re.* flags are re.RegexFlag (an IntFlag) members, not plain ints. Regex.__init__ builds the human-readable flag list with

Regex.NAMES[i] for i, f in enumerate(f"{flags:09b}") if f != "0"

On CPython <= 3.10 and PyPy, applying the b format code to an IntFlag routes through Enum.__format__, which formats the member via its string form ("re.IGNORECASE") and then rejects the b code, raising ValueError. This happens before re.compile(...), so Regex(pattern, flags=<any re flag>), the natural documented usage, is completely unusable on those versions; passing a plain int works, which is why it slipped past the tests.

Fix

Coerce to int before the binary formatting (f"{int(flags):09b}"). re.compile already accepts the enum unchanged, so only the repr computation needed the coercion. The rendered output is byte-identical for the existing int-flag usage.

Test

Added test_regex_flags: it constructs Regex with re.IGNORECASE and with re.IGNORECASE | re.MULTILINE, and asserts both validate correctly and the flag name appears in the repr. It fails before the change (ValueError) on affected versions and passes after; harmless on newer versions where the crash never fired.

Fixes #246.

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=<any re flag>), 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error when calling Regex

1 participant