diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f169513c..b131ab28 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,8 @@ +v4.27.0 +======= + +* Report a string as an invalid ``regex`` format rather than crashing when it contains a syntactically valid but oversized repetition count (which makes ``re.compile`` raise ``OverflowError`` instead of ``re.error``). + v4.26.0 ======= diff --git a/jsonschema/_format.py b/jsonschema/_format.py index 62c0e4ee..ca7b5451 100644 --- a/jsonschema/_format.py +++ b/jsonschema/_format.py @@ -413,7 +413,7 @@ def is_time(instance: object) -> bool: return is_datetime("1970-01-01T" + instance) -@_checks_drafts(name="regex", raises=re.error) +@_checks_drafts(name="regex", raises=(re.error, OverflowError)) def is_regex(instance: object) -> bool: if not isinstance(instance, str): return True diff --git a/jsonschema/tests/test_format.py b/jsonschema/tests/test_format.py index d829f984..536fadfc 100644 --- a/jsonschema/tests/test_format.py +++ b/jsonschema/tests/test_format.py @@ -80,6 +80,15 @@ def test_format_checkers_come_with_defaults(self): with self.assertRaises(FormatError): checker.check(instance="not-an-ipv4", format="ipv4") + def test_regex_format_rejects_overflowing_repeat_count(self): + # A syntactically valid but oversized repetition count makes + # re.compile raise OverflowError, which is not an re.error, so it + # must be declared alongside it or it escapes uncaught instead of + # being reported as an invalid regex. + checker = FormatChecker() + with self.assertRaises(FormatError): + checker.check(instance="a{99999999999999}", format="regex") + def test_repr(self): checker = FormatChecker(formats=()) checker.checks("foo")(lambda thing: True) # pragma: no cover