@@ -63,6 +63,20 @@ def _validate_schema_object(
6363 return super ()._validate_schema_object (raw , path )
6464
6565
66+ class RefBodyCountingJsonSchemaParser (CountingJsonSchemaParser ):
67+ """JsonSchemaParser that records reference body loads."""
68+
69+ def __init__ (self , * args : Any , ** kwargs : Any ) -> None :
70+ """Initialize the parser and reference body recorder."""
71+ super ().__init__ (* args , ** kwargs )
72+ self .ref_body_paths : list [str ] = []
73+ self .ref_bodies : dict [str , dict [str , Any ]] = {}
74+
75+ def _get_ref_body (self , resolved_ref : str ) -> dict [str , Any ]:
76+ self .ref_body_paths .append (resolved_ref )
77+ return self .ref_bodies [resolved_ref ]
78+
79+
6680@pytest .fixture (autouse = True )
6781def block_dns_by_default (mocker : MockerFixture ) -> None :
6882 """Keep tests that mock httpx.get independent from external DNS."""
@@ -108,24 +122,88 @@ def test_load_ref_schema_object_caches_refs() -> None:
108122 ]
109123
110124
125+ def test_load_ref_schema_object_reuses_current_raw_obj_for_current_root_ref () -> None :
126+ """Test same-document refs use the current raw object instead of loading a ref body."""
127+ parser = RefBodyCountingJsonSchemaParser ("" )
128+ parser .raw_obj = {
129+ "definitions" : {
130+ "User" : {
131+ "type" : "object" ,
132+ "properties" : {"name" : {"type" : "string" }},
133+ },
134+ },
135+ }
136+
137+ with parser .model_resolver .current_root_context (["current.json" ]):
138+ schema = parser ._load_ref_schema_object ("#/definitions/User" )
139+
140+ assert schema .type == "object"
141+ assert parser .ref_body_paths == []
142+ assert parser .validation_paths == [
143+ ("current.json#/definitions/User" ,),
144+ ]
145+
146+
147+ def test_load_ref_schema_object_loads_non_current_root_ref_body () -> None :
148+ """Test refs outside the current root still load their referenced body."""
149+ parser = RefBodyCountingJsonSchemaParser ("" )
150+ parser .raw_obj = {}
151+ parser .ref_bodies ["other.json" ] = {
152+ "definitions" : {
153+ "User" : {
154+ "type" : "object" ,
155+ "properties" : {"name" : {"type" : "string" }},
156+ },
157+ },
158+ }
159+
160+ with parser .model_resolver .current_root_context (["current.json" ]):
161+ schema = parser ._load_ref_schema_object ("other.json#/definitions/User" )
162+
163+ assert schema .type == "object"
164+ assert parser .ref_body_paths == ["other.json" ]
165+ assert parser .validation_paths == [
166+ ("other.json#/definitions/User" ,),
167+ ]
168+
169+
111170def test_parse_file_reuses_validated_definition_objects () -> None :
112- """Test definitions validated for metadata are reused when parsed."""
171+ """Test definitions validated for metadata are reused when parsed and referenced ."""
113172 parser = CountingJsonSchemaParser ("" )
114173 raw = {
174+ "type" : "object" ,
175+ "properties" : {
176+ "user" : {"$ref" : "#/definitions/User" },
177+ "member" : {"$ref" : "#/definitions/Namespaces/$defs/Member" },
178+ },
115179 "definitions" : {
116180 "User" : {
117181 "type" : "object" ,
118182 "properties" : {"name" : {"type" : "string" }},
119183 },
184+ "Namespaces" : {
185+ "$defs" : {
186+ "Member" : {
187+ "type" : "object" ,
188+ "properties" : {"id" : {"type" : "integer" }},
189+ },
190+ },
191+ },
120192 },
121193 }
122194
123195 parser ._parse_file (raw , "Root" , [])
124196
125197 assert parser .validation_paths .count (("#/definitions" , "User" )) == 1
198+ assert parser .validation_paths .count (("#/definitions" , "Namespaces" , "$defs" , "Member" )) == 1
199+ assert ("#/definitions/User" ,) not in parser .validation_paths
200+ assert ("#/definitions/Namespaces/$defs/Member" ,) not in parser .validation_paths
126201 reference = parser .model_resolver .get (["#/definitions" , "User" ])
127202 assert reference is not None
128203 assert reference .loaded
204+ nested_reference = parser .model_resolver .get (["#/definitions" , "Namespaces" , "$defs" , "Member" ])
205+ assert nested_reference is not None
206+ assert nested_reference .loaded
129207
130208
131209@pytest .mark .parametrize (
0 commit comments