@@ -42,6 +42,7 @@ def validate(value: Any, schema: dict[str, Any], path: str = "") -> list[str]:
4242 errors : list [str ] = []
4343
4444 expected_type = schema .get ("type" )
45+ types = None
4546 if expected_type is not None :
4647 types = expected_type if isinstance (expected_type , list ) else [expected_type ]
4748 if not any (_TYPE_CHECKS .get (t , lambda _v : True )(value ) for t in types ):
@@ -50,25 +51,28 @@ def validate(value: Any, schema: dict[str, Any], path: str = "") -> list[str]:
5051 errors .append (f"{ path or '<root>' } : expected { joined } , got { actual } " )
5152 return errors # short-circuit; downstream checks assume the type matches
5253
53- if expected_type == "object" or (expected_type is None and isinstance (value , dict )):
54- if isinstance (value , dict ):
55- required = schema .get ("required" ) or []
56- for field in required :
57- if field not in value :
58- errors .append (f"{ path or '<root>' } : missing required field '{ field } '" )
59- properties = schema .get ("properties" ) or {}
60- for k , sub_schema in properties .items ():
61- if k in value :
62- sub_path = f"{ path } .{ k } " if path else k
63- errors .extend (validate (value [k ], sub_schema , sub_path ))
64-
65- if expected_type == "array" or (expected_type is None and isinstance (value , list )):
66- if isinstance (value , list ):
67- item_schema = schema .get ("items" )
68- if isinstance (item_schema , dict ):
69- for i , item in enumerate (value ):
70- sub_path = f"{ path } [{ i } ]" if path else f"[{ i } ]"
71- errors .extend (validate (item , item_schema , sub_path ))
54+ # Structural checks run whenever the value is actually a dict/list and the
55+ # schema permits that type. `types is None` covers untyped schemas; the
56+ # `"object"/"array" in types` membership covers both a bare "object" string
57+ # and a union like ["object", "null"] — the list form was silently skipping
58+ # required/properties/items before.
59+ if isinstance (value , dict ) and (types is None or "object" in types ):
60+ required = schema .get ("required" ) or []
61+ for field in required :
62+ if field not in value :
63+ errors .append (f"{ path or '<root>' } : missing required field '{ field } '" )
64+ properties = schema .get ("properties" ) or {}
65+ for k , sub_schema in properties .items ():
66+ if k in value :
67+ sub_path = f"{ path } .{ k } " if path else k
68+ errors .extend (validate (value [k ], sub_schema , sub_path ))
69+
70+ if isinstance (value , list ) and (types is None or "array" in types ):
71+ item_schema = schema .get ("items" )
72+ if isinstance (item_schema , dict ):
73+ for i , item in enumerate (value ):
74+ sub_path = f"{ path } [{ i } ]" if path else f"[{ i } ]"
75+ errors .extend (validate (item , item_schema , sub_path ))
7276
7377 return errors
7478
0 commit comments