Skip to content

Fix allOf multi-ref to preserve inheritance with property overrides#2838

Merged
koxudaxi merged 1 commit intomainfrom
fix/allof-multi-ref-inheritance
Dec 28, 2025
Merged

Fix allOf multi-ref to preserve inheritance with property overrides#2838
koxudaxi merged 1 commit intomainfrom
fix/allof-multi-ref-inheritance

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Dec 28, 2025

Fixes: #2645

Summary by CodeRabbit

  • Bug Fixes

    • Improved JSON schema parser handling of multiple references in schema definitions to properly manage property overrides and prevent inheritance conflicts.
  • Tests

    • Added test coverage for multiple inheritance scenarios with property overrides to validate correct parsing behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 28, 2025

📝 Walkthrough

Walkthrough

This change fixes a regression in allOf handling where multiple $ref entries with property overrides lose their class hierarchy. The parser's merge logic is adjusted to properly preserve multi-inheritance when merging conflicting properties from referenced definitions.

Changes

Cohort / File(s) Summary
Core Parser Logic
src/datamodel_code_generator/parser/jsonschema.py
Modified _merge_all_of_object method to change conflict detection strategy: now only considers conflicts among referenced properties (from multiple $ref entries), excluding child obj.properties from conflict aggregation. Updated docstring clarifies that multiple refs with conflicting property definitions should be merged to avoid MRO issues.
Test Fixtures
tests/data/expected/main/jsonschema/all_of_multi_ref_with_property_override.py
New Pydantic model definitions demonstrating multi-inheritance: Person inherits from both Thing and Location, with property overrides/extensions (type, name with optional union types and defaults, age).
Test Coverage
tests/main/jsonschema/test_main_jsonschema.py
Added test_main_all_of_multi_ref_with_property_override() test function verifying multi-ref inheritance with property overrides generates correct class hierarchy.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

breaking-change-analyzed

Poem

🐰 A ref that split in two did mend,
Inheritance restored, conflict's end,
Where Person Now inherits true,
From Thing and Location too,
Hierarchy fixed, the schema's friend!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: fixing allOf multi-ref inheritance preservation with property overrides.
Linked Issues check ✅ Passed The PR addresses issue #2645 by modifying _merge_all_of_object logic to preserve class hierarchy for allOf with multiple $refs while allowing property overrides.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing allOf multi-ref inheritance: parser logic modification, test data generation, and test case addition.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/allof-multi-ref-inheritance

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cc9cee and dd92ba7.

⛔ Files ignored due to path filters (1)
  • tests/data/jsonschema/all_of_multi_ref_with_property_override.json is excluded by !tests/data/**/*.json and included by none
📒 Files selected for processing (3)
  • src/datamodel_code_generator/parser/jsonschema.py
  • tests/data/expected/main/jsonschema/all_of_multi_ref_with_property_override.py
  • tests/main/jsonschema/test_main_jsonschema.py
🧰 Additional context used
🧬 Code graph analysis (2)
tests/data/expected/main/jsonschema/all_of_multi_ref_with_property_override.py (1)
src/datamodel_code_generator/model/base.py (1)
  • name (826-828)
tests/main/jsonschema/test_main_jsonschema.py (3)
tests/test_main_kr.py (1)
  • output_file (44-46)
tests/main/conftest.py (2)
  • output_file (98-100)
  • run_main_and_assert (244-408)
src/datamodel_code_generator/__init__.py (1)
  • chdir (245-255)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.10 on macOS
  • GitHub Check: benchmarks
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.12 on macOS
  • GitHub Check: 3.11 on macOS
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: Analyze (python)
🔇 Additional comments (3)
tests/data/expected/main/jsonschema/all_of_multi_ref_with_property_override.py (1)

10-22: Expected multi-inheritance model matches regression scenario

The generated Thing, Location, and Person(Thing, Location) models (with local overrides for type/name and added age) align with the described allOf multi‑ref + property override behavior and follow the existing style of other JSON Schema golden files. No changes needed.

tests/main/jsonschema/test_main_jsonschema.py (1)

1267-1276: New allOf multi‑ref regression test is consistent and well‑wired

This test mirrors the existing single‑ref override test, correctly using chdir(JSON_SCHEMA_DATA_PATH) and pointing to the new JSON schema and expected output file. It should reliably guard the restored multi‑inheritance + override behavior.

src/datamodel_code_generator/parser/jsonschema.py (1)

1738-1771: LGTM! Documentation accurately describes the inheritance preservation fix.

The updated docstring clearly documents the critical behavior that fixes the regression:

  • Line 1746-1747's early return for single $ref cases preserves inheritance with property overrides
  • Multi-ref conflict detection (lines 1749-1759) correctly handles MRO scenarios
  • The clarification that obj.properties are excluded from conflict detection is accurate

The fix correctly allows schemas like:

{
  "allOf": [
    {"$ref": "#/$defs/Thing"},
    {"properties": {"name": {"default": "override"}}}
  ]
}

to generate Person(Thing) with property overrides, restoring pre-v0.38.0 behavior.

Minor note: The phrase "Child property overrides (obj.properties)" on line 1743 is accurate but might be clearer as "Direct properties (obj.properties)" to distinguish them from inline allOf property definitions.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Dec 28, 2025

CodSpeed Performance Report

Merging #2838 will degrade performance by 17.2%

Comparing fix/allof-multi-ref-inheritance (dd92ba7) with main (2cc9cee)

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

Summary

❌ 11 regressions
⏩ 98 skipped1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Mode Benchmark BASE HEAD Efficiency
WallTime test_perf_aws_style_openapi_pydantic_v2 1.7 s 2 s -15.12%
WallTime test_perf_duplicate_names 865.8 ms 1,020.5 ms -15.15%
WallTime test_perf_kubernetes_style_pydantic_v2 2.3 s 2.7 s -16.25%
WallTime test_perf_complex_refs 1.8 s 2.1 s -16.22%
WallTime test_perf_all_options_enabled 5.8 s 6.7 s -13.31%
WallTime test_perf_large_models_pydantic_v2 3.1 s 3.8 s -17.2%
WallTime test_perf_deep_nested 5.3 s 6.3 s -14.67%
WallTime test_perf_graphql_style_pydantic_v2 720 ms 842.5 ms -14.53%
WallTime test_perf_openapi_large 2.5 s 3 s -15.95%
WallTime test_perf_stripe_style_pydantic_v2 1.8 s 2.1 s -14.63%
WallTime test_perf_multiple_files_input 3.2 s 3.8 s -15.37%

Footnotes

  1. 98 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 28, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.51%. Comparing base (e4394af) to head (dd92ba7).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2838      +/-   ##
==========================================
- Coverage   99.52%   99.51%   -0.01%     
==========================================
  Files          90       90              
  Lines       14092    14245     +153     
  Branches     1674     1695      +21     
==========================================
+ Hits        14025    14176     +151     
- Misses         36       37       +1     
- Partials       31       32       +1     
Flag Coverage Δ
unittests 99.51% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@koxudaxi koxudaxi merged commit bb0eb62 into main Dec 28, 2025
36 of 38 checks passed
@koxudaxi koxudaxi deleted the fix/allof-multi-ref-inheritance branch December 28, 2025 15:49
@github-actions
Copy link
Copy Markdown
Contributor

Breaking Change Analysis

Result: Breaking changes detected

Reasoning: This PR modifies the _merge_all_of_object method to no longer include the child schema's properties (obj.properties) when detecting property conflicts between allOf refs. Previously, when a schema had multiple $ref items in allOf AND defined its own properties that overrode parent properties, the code would detect these as "conflicts" and merge all schemas into a single flat class. After this fix, only actual conflicts between the referenced parent schemas trigger merging. This means schemas that were previously flattened will now generate proper multiple inheritance hierarchies. This is a code generation change - users with such schemas will see different generated output.

Content for Release Notes

Code Generation Changes

  • allOf multi-ref with property overrides now preserves inheritance - Schemas using allOf with multiple $ref items where the child schema also defines properties that override parent properties will now generate classes with multiple inheritance (e.g., class Person(Thing, Location)) instead of a flattened single class with all properties merged inline. Previously, child property overrides were incorrectly treated as conflicts, triggering schema merging. Users relying on the flattened output may need to adjust their code. (Fix allOf multi-ref to preserve inheritance with property overrides #2838)

    Before:

    class Person(BaseModel):
        type: str | None = 'playground:Person'
        name: constr(min_length=1) | None = None
        address: constr(min_length=5)
        age: int | None = None

    After:

    class Thing(BaseModel):
        type: str
        name: constr(min_length=1)
    
    class Location(BaseModel):
        address: constr(min_length=5)
    
    class Person(Thing, Location):
        type: str | None = 'playground:Person'
        name: constr(min_length=1) | None = None
        age: int | None = None

This analysis was performed by Claude Code Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 1, 2026

🎉 Released in 0.51.0

This PR is now available in the latest release. See the release notes for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Version >= 0.38 breaks allof class hierarchy

1 participant