@@ -449,26 +449,33 @@ def canonicalish(schema: JSONType) -> Dict[str, Any]:
449449 # Canonicalise "not" subschemas
450450 if "not" in schema :
451451 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+
472479 assert isinstance (type_ , list ), type_
473480 if not type_ :
474481 assert type_ == []
@@ -490,6 +497,9 @@ def canonicalish(schema: JSONType) -> Dict[str, Any]:
490497 if TRUTHY in schema .get ("anyOf" , ()):
491498 schema .pop ("anyOf" , None )
492499 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" ]
493503 schema ["anyOf" ] = sorted (schema ["anyOf" ], key = encode_canonical_json )
494504 schema ["anyOf" ] = [s for s in schema ["anyOf" ] if s != FALSEY ]
495505 if not schema ["anyOf" ]:
0 commit comments