4
4
import math
5
5
import operator
6
6
import re
7
+ import warnings
7
8
from fractions import Fraction
8
9
from functools import partial
9
10
from typing import Any , Callable , Dict , List , NoReturn , Optional , Set , Union
@@ -388,6 +389,14 @@ def relative_json_pointers() -> st.SearchStrategy[str]:
388
389
}
389
390
390
391
392
+ def _warn_invalid_regex (pattern : str , err : re .error , kw : str = "pattern" ) -> None :
393
+ warnings .warn (
394
+ f"Got { kw } ={ pattern !r} , but this is not valid syntax for a Python regular "
395
+ f"expression ({ err } ) so it will not be handled by the strategy. See https://"
396
+ "json-schema.org/understanding-json-schema/reference/regular_expressions.html"
397
+ )
398
+
399
+
391
400
def string_schema (
392
401
custom_formats : Dict [str , st .SearchStrategy [str ]], schema : dict
393
402
) -> st .SearchStrategy [str ]:
@@ -402,14 +411,19 @@ def string_schema(
402
411
# See https://json-schema.org/latest/json-schema-validation.html#format
403
412
strategy = known_formats [schema ["format" ]]
404
413
if "pattern" in schema :
405
- # This isn't really supported, but we'll do our best.
406
- strategy = strategy .filter (re .compile (schema ["pattern" ]).search )
414
+ try :
415
+ # This isn't really supported, but we'll do our best with a filter.
416
+ strategy = strategy .filter (re .compile (schema ["pattern" ]).search )
417
+ except re .error as err :
418
+ _warn_invalid_regex (schema ["pattern" ], err )
419
+ return st .nothing ()
407
420
elif "pattern" in schema :
408
421
try :
409
422
re .compile (schema ["pattern" ])
410
423
strategy = st .from_regex (schema ["pattern" ])
411
- except re .error :
424
+ except re .error as err :
412
425
# Patterns that are invalid in Python, or just malformed
426
+ _warn_invalid_regex (schema ["pattern" ], err )
413
427
return st .nothing ()
414
428
# If we have size bounds but we're generating strings from a regex or pattern,
415
429
# apply a filter to ensure our size bounds are respected.
@@ -524,6 +538,15 @@ def object_schema(
524
538
additional = schema .get ("additionalProperties" , {})
525
539
additional_allowed = additional != FALSEY
526
540
541
+ for key in list (patterns ):
542
+ try :
543
+ re .compile (key )
544
+ except re .error as err :
545
+ _warn_invalid_regex (key , err , "patternProperties entry" )
546
+ if min_size == 0 and not required :
547
+ return st .builds (dict )
548
+ return st .nothing ()
549
+
527
550
dependencies = schema .get ("dependencies" , {})
528
551
dep_names = {k : v for k , v in dependencies .items () if isinstance (v , list )}
529
552
dep_schemas = {k : v for k , v in dependencies .items () if k not in dep_names }
0 commit comments