Skip to content

Commit 19039d0

Browse files
authored
Revert schema object reuse (#3469)
1 parent d71d633 commit 19039d0

5 files changed

Lines changed: 2 additions & 205 deletions

File tree

src/datamodel_code_generator/parser/jsonschema.py

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,6 @@ def __init__(
901901
self._dynamic_anchor_index: dict[tuple[str, ...], dict[str, str]] = {}
902902
self._recursive_anchor_index: dict[tuple[str, ...], list[str]] = {}
903903
self._ref_data_type_facts: dict[str, tuple[Any, bool]] = {}
904-
self._ref_schema_object_cache: dict[str, JsonSchemaObject] = {}
905904
self._force_base_model_refs: set[str] = set()
906905
self._force_base_model_generation = False
907906
self.field_keys: set[str] = {
@@ -2463,29 +2462,15 @@ def _deep_merge(self, dict1: dict[Any, Any], dict2: dict[Any, Any]) -> dict[Any,
24632462
def _load_ref_schema_object(self, ref: str) -> JsonSchemaObject:
24642463
"""Load a JsonSchemaObject from a $ref using standard resolve/load pipeline."""
24652464
resolved_ref = self.model_resolver.resolve_ref(ref)
2466-
if (cached := self._ref_schema_object_cache.get(resolved_ref)) is not None:
2467-
return cached
2468-
24692465
file_part, fragment = ([*resolved_ref.split("#", 1), ""])[:2]
2470-
raw_doc = self._get_ref_raw_doc(file_part)
2466+
raw_doc = self._get_ref_body(file_part) if file_part else self.raw_obj
24712467

24722468
target_schema: dict[str, YamlValue] | YamlValue = raw_doc
24732469
if fragment:
24742470
pointer = split_json_pointer(raw_doc, fragment)
24752471
target_schema = get_model_by_path(raw_doc, pointer)
24762472

2477-
ref_schema = self._validate_schema_object(target_schema, [resolved_ref])
2478-
self._ref_schema_object_cache[resolved_ref] = ref_schema
2479-
return ref_schema
2480-
2481-
def _get_ref_raw_doc(self, file_part: str) -> dict[str, YamlValue]:
2482-
"""Return the raw schema document for a resolved reference file part."""
2483-
match file_part:
2484-
case "":
2485-
return self.raw_obj
2486-
case current_root_ref if current_root_ref == "/".join(self.model_resolver.current_root):
2487-
return self.raw_obj
2488-
return self._get_ref_body(file_part)
2473+
return self._validate_schema_object(target_schema, [resolved_ref])
24892474

24902475
def _anchor_ref_path(self, root_key: tuple[str, ...], path: list[str]) -> str: # noqa: PLR6301
24912476
"""Return the local ref path for an anchor under the current root."""
@@ -5996,7 +5981,6 @@ def _parse_file( # noqa: PLR0912, PLR0913, PLR0914, PLR0915
59965981
seen_definition_metadata_paths.add(definition_path_key)
59975982
obj = self._validate_schema_object(model, definition_path)
59985983
validated_definition_objects[definition_path_key] = obj
5999-
self._ref_schema_object_cache.setdefault(self.model_resolver.resolve_ref(definition_path), obj)
60005984
self.parse_id(obj, definition_path)
60015985
if obj.recursiveAnchor:
60025986
ref_path = self._anchor_ref_path(root_key, definition_path)

tests/data/expected/main/jsonschema/same_file_ref_fast_path.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

tests/data/jsonschema/same_file_ref_fast_path.json

Lines changed: 0 additions & 25 deletions
This file was deleted.

tests/main/jsonschema/test_main_jsonschema.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2246,16 +2246,6 @@ def test_main_serialize_as_any_import_fast_path(output_file: Path) -> None:
22462246
)
22472247

22482248

2249-
def test_main_same_file_ref_fast_path(output_file: Path) -> None:
2250-
"""Test same-file refs keep generated output unchanged."""
2251-
run_main_and_assert(
2252-
input_path=JSON_SCHEMA_DATA_PATH / "same_file_ref_fast_path.json",
2253-
output_path=output_file,
2254-
input_file_type="jsonschema",
2255-
assert_func=assert_file_content,
2256-
)
2257-
2258-
22592249
def test_main_root_model_with_additional_properties_literal(min_version: str, output_file: Path) -> None:
22602250
"""Test root model additional properties with literal types."""
22612251
run_main_and_assert(

tests/parser/test_jsonschema.py

Lines changed: 0 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -46,37 +46,6 @@ def _json_schema_object(data: dict[str, Any]) -> JsonSchemaObject:
4646
return JsonSchemaObject.model_validate(data)
4747

4848

49-
class CountingJsonSchemaParser(JsonSchemaParser):
50-
"""JsonSchemaParser that records schema validation paths for cache tests."""
51-
52-
def __init__(self, *args: Any, **kwargs: Any) -> None:
53-
"""Initialize the parser and validation path recorder."""
54-
super().__init__(*args, **kwargs)
55-
self.validation_paths: list[tuple[str, ...]] = []
56-
57-
def _validate_schema_object(
58-
self,
59-
raw: dict[str, Any] | Any,
60-
path: list[str],
61-
) -> JsonSchemaObject:
62-
self.validation_paths.append(tuple(path))
63-
return super()._validate_schema_object(raw, path)
64-
65-
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-
8049
@pytest.fixture(autouse=True)
8150
def block_dns_by_default(mocker: MockerFixture) -> None:
8251
"""Keep tests that mock httpx.get independent from external DNS."""
@@ -100,112 +69,6 @@ def test_get_model_by_path(schema: dict, path: str, model: dict) -> None:
10069
assert get_model_by_path(schema, path.split("/") if path else []) == model
10170

10271

103-
def test_load_ref_schema_object_caches_refs() -> None:
104-
"""Test repeated ref schema loads reuse the cached validated object."""
105-
parser = CountingJsonSchemaParser("")
106-
parser.raw_obj = {
107-
"definitions": {
108-
"User": {
109-
"type": "object",
110-
"properties": {"name": {"type": "string"}},
111-
},
112-
},
113-
}
114-
115-
first = parser._load_ref_schema_object("#/definitions/User")
116-
second = parser._load_ref_schema_object("#/definitions/User")
117-
third = parser._load_ref_schema_object("#/definitions/User")
118-
119-
assert first is second is third
120-
assert parser.validation_paths == [
121-
("#/definitions/User",),
122-
]
123-
124-
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-
170-
def test_parse_file_reuses_validated_definition_objects() -> None:
171-
"""Test definitions validated for metadata are reused when parsed and referenced."""
172-
parser = CountingJsonSchemaParser("")
173-
raw = {
174-
"type": "object",
175-
"properties": {
176-
"user": {"$ref": "#/definitions/User"},
177-
"member": {"$ref": "#/definitions/Namespaces/$defs/Member"},
178-
},
179-
"definitions": {
180-
"User": {
181-
"type": "object",
182-
"properties": {"name": {"type": "string"}},
183-
},
184-
"Namespaces": {
185-
"$defs": {
186-
"Member": {
187-
"type": "object",
188-
"properties": {"id": {"type": "integer"}},
189-
},
190-
},
191-
},
192-
},
193-
}
194-
195-
parser._parse_file(raw, "Root", [])
196-
197-
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
201-
reference = parser.model_resolver.get(["#/definitions", "User"])
202-
assert reference is not None
203-
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
207-
208-
20972
@pytest.mark.parametrize(
21073
("path", "match"),
21174
[

0 commit comments

Comments
 (0)