From 43eb24017f7b5e5df88c0c2b9bd759dac70be55f Mon Sep 17 00:00:00 2001 From: ahmetveburak Date: Wed, 24 Dec 2025 08:29:49 +0300 Subject: [PATCH] Exclude OpenAPI/JSON Schema extension fields (x-*) --- .../parser/jsonschema.py | 9 ++++++-- tests/parser/test_jsonschema.py | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/datamodel_code_generator/parser/jsonschema.py b/src/datamodel_code_generator/parser/jsonschema.py index ad0b52716..e9bb5a6ee 100644 --- a/src/datamodel_code_generator/parser/jsonschema.py +++ b/src/datamodel_code_generator/parser/jsonschema.py @@ -454,14 +454,19 @@ def has_ref_with_schema_keywords(self) -> bool: """Check if schema has $ref combined with schema-affecting keywords. Metadata-only keywords (title, description, etc.) are excluded - as they don't affect the schema structure. + as they don't affect the schema structure. OpenAPI/JSON Schema + extension fields (x-*) are also excluded as they are vendor + extensions and don't affect the core schema structure. """ if not self.ref: return False other_fields = get_fields_set(self) - {"ref"} schema_affecting_fields = other_fields - self.__metadata_only_fields__ - {"extras"} if self.extras: - schema_affecting_extras = {k for k in self.extras if k not in self.__metadata_only_fields__} + # Filter out metadata-only fields AND extension fields (x-* prefix) + schema_affecting_extras = { + k for k in self.extras if k not in self.__metadata_only_fields__ and not k.startswith("x-") + } if schema_affecting_extras: schema_affecting_fields |= {"extras"} return bool(schema_affecting_fields) diff --git a/tests/parser/test_jsonschema.py b/tests/parser/test_jsonschema.py index 7d50eb747..cffa068fb 100644 --- a/tests/parser/test_jsonschema.py +++ b/tests/parser/test_jsonschema.py @@ -910,6 +910,28 @@ def test_has_ref_with_schema_keywords_extras_with_metadata_only_keys() -> None: assert obj.has_ref_with_schema_keywords is False +def test_has_ref_with_schema_keywords_extras_with_extension_keys() -> None: + """Test has_ref_with_schema_keywords when extras contains only x-* extension keys. + + OpenAPI/JSON Schema extension fields (x-*) should be treated as metadata + and not trigger schema merging, which prevents infinite recursion with + self-referencing schemas. + """ + # x-* extensions are vendor extensions, should not trigger merge + obj = JsonSchemaObject.parse_obj({ + "$ref": "#/$defs/Base", + "deprecated": False, # metadata-only field + "x-internalAPI": False, # extension field + "x-custom-field": "value", # another extension field + }) + # Verify extras contains extension keys + assert obj.extras + assert "x-internalAPI" in obj.extras + assert "x-custom-field" in obj.extras + # Extension fields should NOT trigger schema merge + assert obj.has_ref_with_schema_keywords is False + + def test_has_ref_with_schema_keywords_no_extras() -> None: """Test has_ref_with_schema_keywords when extras is empty.""" # Only $ref and a schema-affecting field, no extras