From 75d305f4830b19d760436bafc3be4d2840a82bda Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Mon, 22 Jun 2026 03:06:25 +0900 Subject: [PATCH] Revert schema object reuse --- .../parser/jsonschema.py | 20 +-- .../jsonschema/same_file_ref_fast_path.py | 15 -- .../jsonschema/same_file_ref_fast_path.json | 25 ---- tests/main/jsonschema/test_main_jsonschema.py | 10 -- tests/parser/test_jsonschema.py | 137 ------------------ 5 files changed, 2 insertions(+), 205 deletions(-) delete mode 100644 tests/data/expected/main/jsonschema/same_file_ref_fast_path.py delete mode 100644 tests/data/jsonschema/same_file_ref_fast_path.json diff --git a/src/datamodel_code_generator/parser/jsonschema.py b/src/datamodel_code_generator/parser/jsonschema.py index 4cb8c6833..cf1850f79 100644 --- a/src/datamodel_code_generator/parser/jsonschema.py +++ b/src/datamodel_code_generator/parser/jsonschema.py @@ -901,7 +901,6 @@ def __init__( self._dynamic_anchor_index: dict[tuple[str, ...], dict[str, str]] = {} self._recursive_anchor_index: dict[tuple[str, ...], list[str]] = {} self._ref_data_type_facts: dict[str, tuple[Any, bool]] = {} - self._ref_schema_object_cache: dict[str, JsonSchemaObject] = {} self._force_base_model_refs: set[str] = set() self._force_base_model_generation = False self.field_keys: set[str] = { @@ -2463,29 +2462,15 @@ def _deep_merge(self, dict1: dict[Any, Any], dict2: dict[Any, Any]) -> dict[Any, def _load_ref_schema_object(self, ref: str) -> JsonSchemaObject: """Load a JsonSchemaObject from a $ref using standard resolve/load pipeline.""" resolved_ref = self.model_resolver.resolve_ref(ref) - if (cached := self._ref_schema_object_cache.get(resolved_ref)) is not None: - return cached - file_part, fragment = ([*resolved_ref.split("#", 1), ""])[:2] - raw_doc = self._get_ref_raw_doc(file_part) + raw_doc = self._get_ref_body(file_part) if file_part else self.raw_obj target_schema: dict[str, YamlValue] | YamlValue = raw_doc if fragment: pointer = split_json_pointer(raw_doc, fragment) target_schema = get_model_by_path(raw_doc, pointer) - ref_schema = self._validate_schema_object(target_schema, [resolved_ref]) - self._ref_schema_object_cache[resolved_ref] = ref_schema - return ref_schema - - def _get_ref_raw_doc(self, file_part: str) -> dict[str, YamlValue]: - """Return the raw schema document for a resolved reference file part.""" - match file_part: - case "": - return self.raw_obj - case current_root_ref if current_root_ref == "/".join(self.model_resolver.current_root): - return self.raw_obj - return self._get_ref_body(file_part) + return self._validate_schema_object(target_schema, [resolved_ref]) def _anchor_ref_path(self, root_key: tuple[str, ...], path: list[str]) -> str: # noqa: PLR6301 """Return the local ref path for an anchor under the current root.""" @@ -5996,7 +5981,6 @@ def _parse_file( # noqa: PLR0912, PLR0913, PLR0914, PLR0915 seen_definition_metadata_paths.add(definition_path_key) obj = self._validate_schema_object(model, definition_path) validated_definition_objects[definition_path_key] = obj - self._ref_schema_object_cache.setdefault(self.model_resolver.resolve_ref(definition_path), obj) self.parse_id(obj, definition_path) if obj.recursiveAnchor: ref_path = self._anchor_ref_path(root_key, definition_path) diff --git a/tests/data/expected/main/jsonschema/same_file_ref_fast_path.py b/tests/data/expected/main/jsonschema/same_file_ref_fast_path.py deleted file mode 100644 index e5825571f..000000000 --- a/tests/data/expected/main/jsonschema/same_file_ref_fast_path.py +++ /dev/null @@ -1,15 +0,0 @@ -# generated by datamodel-codegen: -# filename: same_file_ref_fast_path.json -# timestamp: 2019-07-26T00:00:00+00:00 - -from __future__ import annotations - -from pydantic import BaseModel - - -class User(BaseModel): - name: str - - -class SameFileRefFastPath(BaseModel): - user: User diff --git a/tests/data/jsonschema/same_file_ref_fast_path.json b/tests/data/jsonschema/same_file_ref_fast_path.json deleted file mode 100644 index a615346ce..000000000 --- a/tests/data/jsonschema/same_file_ref_fast_path.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "title": "SameFileRefFastPath", - "type": "object", - "properties": { - "user": { - "$ref": "#/definitions/User" - } - }, - "required": [ - "user" - ], - "definitions": { - "User": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - }, - "required": [ - "name" - ] - } - } -} diff --git a/tests/main/jsonschema/test_main_jsonschema.py b/tests/main/jsonschema/test_main_jsonschema.py index 1b717a20f..e7d1eb412 100644 --- a/tests/main/jsonschema/test_main_jsonschema.py +++ b/tests/main/jsonschema/test_main_jsonschema.py @@ -2246,16 +2246,6 @@ def test_main_serialize_as_any_import_fast_path(output_file: Path) -> None: ) -def test_main_same_file_ref_fast_path(output_file: Path) -> None: - """Test same-file refs keep generated output unchanged.""" - run_main_and_assert( - input_path=JSON_SCHEMA_DATA_PATH / "same_file_ref_fast_path.json", - output_path=output_file, - input_file_type="jsonschema", - assert_func=assert_file_content, - ) - - def test_main_root_model_with_additional_properties_literal(min_version: str, output_file: Path) -> None: """Test root model additional properties with literal types.""" run_main_and_assert( diff --git a/tests/parser/test_jsonschema.py b/tests/parser/test_jsonschema.py index dbdb7a171..c1086a399 100644 --- a/tests/parser/test_jsonschema.py +++ b/tests/parser/test_jsonschema.py @@ -46,37 +46,6 @@ def _json_schema_object(data: dict[str, Any]) -> JsonSchemaObject: return JsonSchemaObject.model_validate(data) -class CountingJsonSchemaParser(JsonSchemaParser): - """JsonSchemaParser that records schema validation paths for cache tests.""" - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """Initialize the parser and validation path recorder.""" - super().__init__(*args, **kwargs) - self.validation_paths: list[tuple[str, ...]] = [] - - def _validate_schema_object( - self, - raw: dict[str, Any] | Any, - path: list[str], - ) -> JsonSchemaObject: - self.validation_paths.append(tuple(path)) - return super()._validate_schema_object(raw, path) - - -class RefBodyCountingJsonSchemaParser(CountingJsonSchemaParser): - """JsonSchemaParser that records reference body loads.""" - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """Initialize the parser and reference body recorder.""" - super().__init__(*args, **kwargs) - self.ref_body_paths: list[str] = [] - self.ref_bodies: dict[str, dict[str, Any]] = {} - - def _get_ref_body(self, resolved_ref: str) -> dict[str, Any]: - self.ref_body_paths.append(resolved_ref) - return self.ref_bodies[resolved_ref] - - @pytest.fixture(autouse=True) def block_dns_by_default(mocker: MockerFixture) -> None: """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: assert get_model_by_path(schema, path.split("/") if path else []) == model -def test_load_ref_schema_object_caches_refs() -> None: - """Test repeated ref schema loads reuse the cached validated object.""" - parser = CountingJsonSchemaParser("") - parser.raw_obj = { - "definitions": { - "User": { - "type": "object", - "properties": {"name": {"type": "string"}}, - }, - }, - } - - first = parser._load_ref_schema_object("#/definitions/User") - second = parser._load_ref_schema_object("#/definitions/User") - third = parser._load_ref_schema_object("#/definitions/User") - - assert first is second is third - assert parser.validation_paths == [ - ("#/definitions/User",), - ] - - -def test_load_ref_schema_object_reuses_current_raw_obj_for_current_root_ref() -> None: - """Test same-document refs use the current raw object instead of loading a ref body.""" - parser = RefBodyCountingJsonSchemaParser("") - parser.raw_obj = { - "definitions": { - "User": { - "type": "object", - "properties": {"name": {"type": "string"}}, - }, - }, - } - - with parser.model_resolver.current_root_context(["current.json"]): - schema = parser._load_ref_schema_object("#/definitions/User") - - assert schema.type == "object" - assert parser.ref_body_paths == [] - assert parser.validation_paths == [ - ("current.json#/definitions/User",), - ] - - -def test_load_ref_schema_object_loads_non_current_root_ref_body() -> None: - """Test refs outside the current root still load their referenced body.""" - parser = RefBodyCountingJsonSchemaParser("") - parser.raw_obj = {} - parser.ref_bodies["other.json"] = { - "definitions": { - "User": { - "type": "object", - "properties": {"name": {"type": "string"}}, - }, - }, - } - - with parser.model_resolver.current_root_context(["current.json"]): - schema = parser._load_ref_schema_object("other.json#/definitions/User") - - assert schema.type == "object" - assert parser.ref_body_paths == ["other.json"] - assert parser.validation_paths == [ - ("other.json#/definitions/User",), - ] - - -def test_parse_file_reuses_validated_definition_objects() -> None: - """Test definitions validated for metadata are reused when parsed and referenced.""" - parser = CountingJsonSchemaParser("") - raw = { - "type": "object", - "properties": { - "user": {"$ref": "#/definitions/User"}, - "member": {"$ref": "#/definitions/Namespaces/$defs/Member"}, - }, - "definitions": { - "User": { - "type": "object", - "properties": {"name": {"type": "string"}}, - }, - "Namespaces": { - "$defs": { - "Member": { - "type": "object", - "properties": {"id": {"type": "integer"}}, - }, - }, - }, - }, - } - - parser._parse_file(raw, "Root", []) - - assert parser.validation_paths.count(("#/definitions", "User")) == 1 - assert parser.validation_paths.count(("#/definitions", "Namespaces", "$defs", "Member")) == 1 - assert ("#/definitions/User",) not in parser.validation_paths - assert ("#/definitions/Namespaces/$defs/Member",) not in parser.validation_paths - reference = parser.model_resolver.get(["#/definitions", "User"]) - assert reference is not None - assert reference.loaded - nested_reference = parser.model_resolver.get(["#/definitions", "Namespaces", "$defs", "Member"]) - assert nested_reference is not None - assert nested_reference.loaded - - @pytest.mark.parametrize( ("path", "match"), [