@@ -449,26 +449,33 @@ def canonicalish(schema: JSONType) -> Dict[str, Any]:
449
449
# Canonicalise "not" subschemas
450
450
if "not" in schema :
451
451
not_ = schema .pop ("not" )
452
- if not_ == TRUTHY or not_ == schema :
453
- # If everything is rejected, discard all other (irrelevant) keys
454
- # TODO: more sensitive detection of cases where the not-clause
455
- # excludes everything in the schema.
456
- return FALSEY
457
- type_keys = {k : set (v .split ()) for k , v in TYPE_SPECIFIC_KEYS }
458
- type_constraints = {"type" }
459
- for v in type_keys .values ():
460
- type_constraints |= v
461
- if set (not_ ).issubset (type_constraints ):
462
- not_ ["type" ] = get_type (not_ )
463
- for t in set (type_ ).intersection (not_ ["type" ]):
464
- if not type_keys .get (t , set ()).intersection (not_ ):
465
- type_ .remove (t )
466
- if t not in ("integer" , "number" ):
467
- not_ ["type" ].remove (t )
468
- not_ = canonicalish (not_ )
469
- if not_ != FALSEY :
470
- # If the "not" key rejects nothing, discard it
471
- schema ["not" ] = not_
452
+
453
+ negated = []
454
+ to_negate = not_ ["anyOf" ] if set (not_ ) == {"anyOf" } else [not_ ]
455
+ for not_ in to_negate :
456
+ type_keys = {k : set (v .split ()) for k , v in TYPE_SPECIFIC_KEYS }
457
+ type_constraints = {"type" }
458
+ for v in type_keys .values ():
459
+ type_constraints |= v
460
+ if set (not_ ).issubset (type_constraints ):
461
+ not_ ["type" ] = get_type (not_ )
462
+ for t in set (type_ ).intersection (not_ ["type" ]):
463
+ if not type_keys .get (t , set ()).intersection (not_ ):
464
+ type_ .remove (t )
465
+ if t not in ("integer" , "number" ):
466
+ not_ ["type" ].remove (t )
467
+ not_ = canonicalish (not_ )
468
+
469
+ m = merged ([not_ , {** schema , "type" : type_ }])
470
+ if m is not None :
471
+ not_ = m
472
+ if not_ != FALSEY :
473
+ negated .append (not_ )
474
+ if len (negated ) > 1 :
475
+ schema ["not" ] = {"anyOf" : negated }
476
+ elif negated :
477
+ schema ["not" ] = negated [0 ]
478
+
472
479
assert isinstance (type_ , list ), type_
473
480
if not type_ :
474
481
assert type_ == []
@@ -490,6 +497,9 @@ def canonicalish(schema: JSONType) -> Dict[str, Any]:
490
497
if TRUTHY in schema .get ("anyOf" , ()):
491
498
schema .pop ("anyOf" , None )
492
499
if "anyOf" in schema :
500
+ for i , s in enumerate (list (schema ["anyOf" ])):
501
+ if set (s ) == {"anyOf" }:
502
+ schema ["anyOf" ][i : i + 1 ] = s ["anyOf" ]
493
503
schema ["anyOf" ] = sorted (schema ["anyOf" ], key = encode_canonical_json )
494
504
schema ["anyOf" ] = [s for s in schema ["anyOf" ] if s != FALSEY ]
495
505
if not schema ["anyOf" ]:
0 commit comments