Skip to content

Fix allOf with $ref to root model losing constraints#2676

Merged
koxudaxi merged 10 commits intomainfrom
fix/allof-root-model-constraints
Dec 18, 2025
Merged

Fix allOf with $ref to root model losing constraints#2676
koxudaxi merged 10 commits intomainfrom
fix/allof-root-model-constraints

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Dec 17, 2025

Summary

  • Fix issue where allOf combining a $ref to a root model (primitive type with constraints) and additional constraints would generate an empty class body instead of properly merging the constraints.

Closes #1901

Summary by CodeRabbit

  • New Features

    • Improved JSON Schema allOf handling for root-level primitive models with constraints and selectable merge behavior, yielding more accurate generated types for composed constraints.
  • New Files

    • Added an example JSON Schema and corresponding generated model modules showcasing many constrained root types and allOf composition cases.
  • Tests

    • Added end-to-end and parser tests covering root-model constraint combinations, primitive-allOf merging, and multiple merge-mode behaviors.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 17, 2025

Walkthrough

Adds root-model-aware allOf handling to the JSON Schema parser: new helpers detect root primitive schemas, merge primitive constraints per AllOfMergeMode, and short-circuit parse_all_of to produce constrained root models when an allOf mixes a $ref with extra constraints. Tests and expected outputs for both merge modes were added.

Changes

Cohort / File(s) Summary
Parser Logic Changes
src/datamodel_code_generator/parser/jsonschema.py
Imports SPECIAL_PATH_MARKER, ModelType, Reference, is_url; adds _is_root_model_schema(), _merge_primitive_schemas_for_allof(), _handle_allof_root_model_with_constraints(); updates parse_all_of() to attempt root-model-with-constraints handling and to use primitive-schema merging when applicable.
Test Schema Data
tests/data/jsonschema/allof_root_model_constraints.json
New JSON Schema exercising refs combined with primitive constraints, formats, patternProperties, items, and allOf compositions to validate root-model allOf behavior.
Generated Expected Outputs
tests/data/expected/main/jsonschema/allof_root_model_constraints.py, tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py
New expected Python modules (Pydantic models) for merge modes "none" and "constraints", reflecting constrained root types, merged primitive wrappers, and composed models.
Test Coverage (integration)
tests/main/jsonschema/test_main_jsonschema.py
Adds test_main_allof_root_model_constraints() and test_main_allof_root_model_constraints_merge() to run generation/assertion for both allOf merge modes.
Parser Unit Tests
tests/parser/test_jsonschema.py
Adds unit tests covering root-model detection, primitive-schema merging across allOf, SPECIAL_PATH_MARKER handling, AllOfMergeMode behaviors, and edge cases involving refs plus constraints.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review focus: correctness of _merge_primitive_schemas_for_allof() merging rules (formats, constraint intersections) and early-return logic in parse_all_of().
  • Check _is_root_model_schema() heuristics and _handle_allof_root_model_with_constraints() integration with parse_root_type().
  • Confirm imports (SPECIAL_PATH_MARKER, ModelType, Reference, is_url) are used and tested.

Possibly related PRs

Poem

🐇
I hop through schemas, nibbling at each rule,
I stitch refs to constraints like a careful little tool,
When allOf brings roots with extra demands,
I bind them in models with my whiskered hands,
Hooray — tests pass, and I munch on carrot-coded strands! 🥕

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 PR title 'Fix allOf with $ref to root model losing constraints' directly describes the main bug fix, clearly summarizing the specific issue being addressed.
Linked Issues check ✅ Passed The PR addresses issue #1901 by implementing root model constraint merging for allOf schemas. The changes include new methods to detect root model schemas, merge primitive allOf items, handle allOf with root model refs and constraints, and comprehensive test coverage validating the fix.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing allOf constraint merging: parser enhancements (three new private methods), test data files for validation, and test functions. No unrelated modifications detected.
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-root-model-constraints

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.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Dec 17, 2025

CodSpeed Performance Report

Merging #2676 will not alter performance

Comparing fix/allof-root-model-constraints (adf9b9b) with main (599ae84)

Summary

✅ 50 untouched
🆕 2 new
⏩ 3 skipped1

Benchmarks breakdown

Benchmark BASE HEAD Change
🆕 test_main_allof_root_model_constraints_merge N/A 288.6 ms N/A
🆕 test_main_allof_root_model_constraints N/A 287.1 ms N/A

Footnotes

  1. 3 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 17, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.52%. Comparing base (599ae84) to head (adf9b9b).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main    #2676    +/-   ##
========================================
  Coverage   99.51%   99.52%            
========================================
  Files          79       79            
  Lines       11001    11162   +161     
  Branches     1318     1347    +29     
========================================
+ Hits        10948    11109   +161     
  Misses         32       32            
  Partials       21       21            
Flag Coverage Δ
unittests 99.52% <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 marked this pull request as ready for review December 17, 2025 11:41
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/datamodel_code_generator/parser/jsonschema.py (2)

1494-1510: Remove unused noqa directive.

The logic correctly identifies root model schemas by excluding arrays, compositions (allOf/oneOf/anyOf), objects with properties, pattern properties, and enums. This aligns with the parse_raw_obj method's routing logic.

Apply this diff to remove the unused noqa directive:

-    def _is_root_model_schema(self, obj: JsonSchemaObject) -> bool:  # noqa: PLR6301
+    def _is_root_model_schema(self, obj: JsonSchemaObject) -> bool:

Based on static analysis, PLR6301 is not enabled in your Ruff configuration.


1512-1573: Remove unused noqa directive.

The method correctly handles the core fix for issue #1901:

  1. Filters out inline properties (only applies to named schema definitions)
  2. Identifies allOf with exactly one $ref to a root model
  3. Collects additional constraint items from other allOf members
  4. Validates type compatibility (allowing integer/number cross-compatibility)
  5. Merges constraints using _merge_primitive_schemas_for_allof
  6. Generates a root model with the merged constraints

The logic correctly excludes schemas with properties or items from constraint items (line 1550), ensuring this handler only applies to primitive types with constraints.

Apply this diff to remove the unused noqa directive:

-    def _handle_allof_root_model_with_constraints(  # noqa: PLR0911, PLR0912
+    def _handle_allof_root_model_with_constraints(

Based on static analysis, PLR0911 and PLR0912 are not enabled in your Ruff configuration.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 599ae84 and fec0dc7.

📒 Files selected for processing (6)
  • src/datamodel_code_generator/parser/jsonschema.py (4 hunks)
  • tests/data/expected/main/jsonschema/allof_root_model_constraints.py (1 hunks)
  • tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py (1 hunks)
  • tests/data/jsonschema/allof_root_model_constraints.json (1 hunks)
  • tests/main/jsonschema/test_main_jsonschema.py (1 hunks)
  • tests/parser/test_jsonschema.py (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
tests/main/jsonschema/test_main_jsonschema.py (1)
tests/main/conftest.py (2)
  • output_file (94-96)
  • run_main_and_assert (196-352)
tests/parser/test_jsonschema.py (4)
src/datamodel_code_generator/__init__.py (1)
  • AllOfMergeMode (273-283)
src/datamodel_code_generator/parser/jsonschema.py (6)
  • JsonSchemaObject (186-450)
  • parse_obj (2955-2996)
  • _is_root_model_schema (1494-1510)
  • _merge_primitive_schemas_for_allof (1165-1194)
  • _handle_allof_root_model_with_constraints (1512-1573)
  • _load_ref_schema_object (1109-1120)
src/datamodel_code_generator/model/pydantic/base_model.py (1)
  • Constraints (35-47)
src/datamodel_code_generator/model/pydantic_v2/base_model.py (1)
  • Constraints (43-61)
src/datamodel_code_generator/parser/jsonschema.py (1)
src/datamodel_code_generator/__init__.py (1)
  • AllOfMergeMode (273-283)
tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py (1)
tests/data/expected/main/jsonschema/allof_root_model_constraints.py (3)
  • StringDatatype (12-15)
  • ConstrainedStringDatatype (18-21)
  • Model (76-87)
🪛 Ruff (0.14.8)
src/datamodel_code_generator/parser/jsonschema.py

1494-1494: Unused noqa directive (non-enabled: PLR6301)

Remove unused noqa directive

(RUF100)


1512-1512: Unused noqa directive (non-enabled: PLR0911, PLR0912)

Remove unused noqa directive

(RUF100)

🔇 Additional comments (13)
tests/data/jsonschema/allof_root_model_constraints.json (1)

1-110: Comprehensive test schema for allOf root model constraints.

The schema provides excellent coverage of edge cases including:

  • Basic string/integer constraints (lines 4-33)
  • Format constraints like email (lines 34-40)
  • Object inheritance vs root model (lines 41-53)
  • Multiple refs, no constraints, incompatible types (lines 54-73)
  • Constraints with properties/items that should fall back (lines 74-87)
  • Number/integer type compatibility (lines 88-94)

This test data aligns well with the PR objective to fix issue #1901.

tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py (2)

18-21: Merged pattern uses lookaheads correctly.

The regex r'(?=^\S(.*\S)?$)(?=^[A-Z].*)' correctly combines the base pattern (^\S(.*\S)?$) and child pattern (^[A-Z].*) using positive lookaheads. This ensures both constraints must be satisfied, which is the semantically correct behavior for allOf merging.


50-67: Empty class bodies for fallback cases are expected.

MultiRefAllOf, NoConstraintAllOf, IncompatibleTypeAllOf, and ConstraintWithItems correctly fall back to empty pass bodies when the allOf root model handler cannot process them (multiple refs, no constraints, incompatible types, or items constraint). This matches the handler's documented behavior of returning None to let existing logic handle these cases.

tests/data/expected/main/jsonschema/allof_root_model_constraints.py (2)

18-21: NoMerge mode correctly uses only child pattern.

In non-merge mode, ConstrainedStringDatatype uses only r'^[A-Z].*' (the child constraint) rather than merging with the base pattern. This correctly demonstrates the AllOfMergeMode.NoMerge behavior where constraints overwrite rather than combine.


1-87: Expected output structure is correct.

The file correctly represents the expected generated code for the allOf root model constraints test case with --allof-merge-mode none. All type mappings (EmailStr, conint, constr) and model structures match the schema definitions.

tests/parser/test_jsonschema.py (4)

14-14: New imports added for testing allOf root model handling.

The imports of AllOfMergeMode and SPECIAL_PATH_MARKER are necessary for the new test cases validating the allOf merge behavior and special path handling.

Also applies to: 26-26


935-954: Comprehensive parametrized test for _is_root_model_schema.

The test covers all conditions in the helper method: arrays, allOf/oneOf/anyOf, properties, patternProperties, object type, enum, and valid root model cases (plain string, string with constraints). This provides good coverage of the detection logic.


957-999: Tests for _merge_primitive_schemas_for_allof cover key scenarios.

The tests verify:

  • Single item passthrough (lines 957-962)
  • NoMerge mode constraint handling (lines 965-975)
  • Format preservation in both NoMerge and Constraints modes (lines 978-999)

This validates the merge behavior respects allof_merge_mode settings correctly.


1002-1111: Edge case tests for _handle_allof_root_model_with_constraints.

The tests comprehensively cover the early-return conditions:

  • SPECIAL_PATH_MARKER in path (lines 1002-1013)
  • Multiple refs (lines 1016-1026)
  • No refs (lines 1029-1039)
  • No constraint items (lines 1042-1052)
  • Constraint with properties (lines 1055-1066)
  • Constraint with items (lines 1069-1080)
  • Incompatible types (lines 1083-1094)
  • Ref to non-root model (lines 1097-1111)

Using lambda to mock _load_ref_schema_object is appropriate for isolating the unit under test.

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

4297-4320: Well-structured integration tests for allOf root model constraints.

Both tests follow the established patterns in this file:

  • @pytest.mark.benchmark decorator for performance tracking
  • Clear docstrings referencing issue #1901
  • run_main_and_assert with appropriate parameters
  • Testing both merge modes (none and constraints) for complete coverage

The tests will validate the end-to-end behavior of the fix for the issue where allOf combining a $ref to a root model with additional constraints would generate an empty class body.

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

63-63: LGTM!

The import of SPECIAL_PATH_MARKER is necessary for the new root model constraint handling logic.


1984-1987: LGTM!

The integration correctly adds an early return path for root model with constraints. The placement is optimal:

  1. After attempting to merge allOf objects (line 1973)
  2. Before the general allOf parsing logic (line 1989+)

This ensures the specific root-model-with-constraints case is handled before falling back to general object inheritance logic.


1165-1194: Implementation correctly respects allof_merge_mode setting with appropriate test coverage.

The method properly handles both merge modes:

  • Non-NoMerge modes (lines 1170-1176): Uses intersection logic via _merge_primitive_schemas, then preserves format from any item that defines it
  • NoMerge mode (lines 1178-1193): Takes base type and overlays constraint fields without intersection (last value wins), with format preservation

This correctly addresses the allOf use case where constraints should be added/overridden rather than intersected. Comprehensive test cases validate the behavior: test_merge_primitive_schemas_for_allof_nomerge_mode, test_merge_primitive_schemas_for_allof_nomerge_mode_with_format, and test_merge_primitive_schemas_for_allof_constraints_mode_with_format confirm expected constraint merging and format handling.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/datamodel_code_generator/parser/jsonschema.py (3)

1494-1494: Remove unused noqa directive.

The static analysis tool correctly identified that the noqa directive for PLR6301 is unused. Remove it to keep the code clean.

Apply this diff:

-    def _is_root_model_schema(self, obj: JsonSchemaObject) -> bool:  # noqa: PLR6301
+    def _is_root_model_schema(self, obj: JsonSchemaObject) -> bool:

1512-1512: Remove unused noqa directives.

The static analysis tool correctly identified unused noqa directives for PLR0911 and PLR0912. Remove them to keep the code clean.

Apply this diff:

-    def _handle_allof_root_model_with_constraints(  # noqa: PLR0911, PLR0912
+    def _handle_allof_root_model_with_constraints(

1554-1559: Consider expanding type compatibility beyond integer/number.

The type compatibility check currently only handles integer/number pairs:

compatible_type_pairs = {
    ("integer", "number"),
    ("number", "integer"),
}

While this is correct for the current use case, consider whether other type compatibility scenarios should be supported (e.g., number subtypes, string format variations). This could be left as a future enhancement if not needed now.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fec0dc7 and 0f6d4dd.

📒 Files selected for processing (4)
  • src/datamodel_code_generator/parser/jsonschema.py (4 hunks)
  • tests/data/expected/main/jsonschema/allof_root_model_constraints.py (1 hunks)
  • tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py (1 hunks)
  • tests/data/jsonschema/allof_root_model_constraints.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/datamodel_code_generator/parser/jsonschema.py (2)
src/datamodel_code_generator/reference.py (2)
  • reference (77-79)
  • is_url (988-990)
src/datamodel_code_generator/__init__.py (1)
  • AllOfMergeMode (273-283)
🪛 Ruff (0.14.8)
src/datamodel_code_generator/parser/jsonschema.py

1494-1494: Unused noqa directive (non-enabled: PLR6301)

Remove unused noqa directive

(RUF100)


1512-1512: Unused noqa directive (non-enabled: PLR0911, PLR0912)

Remove unused noqa directive

(RUF100)

⏰ 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). (11)
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.9 on Windows
  • GitHub Check: 3.12 on macOS
  • GitHub Check: 3.14 on macOS
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.9 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (6)
tests/data/jsonschema/allof_root_model_constraints.json (1)

1-197: LGTM! Comprehensive test schema.

The JSON Schema test file provides excellent coverage of allOf scenarios with root models and constraints, including edge cases like incompatible types, empty constraints, nested allOf, and various primitive type combinations.

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

63-63: LGTM! Import addition is necessary.

The SPECIAL_PATH_MARKER import is correctly added and used in the new _handle_allof_root_model_with_constraints method to filter out inline properties.


1985-1987: LGTM! Integration point is well-placed.

The call to _handle_allof_root_model_with_constraints is correctly positioned after object merging but before the inheritance-based processing, allowing the new root model path to take precedence when applicable while preserving existing behavior for object inheritance.

tests/data/expected/main/jsonschema/allof_root_model_constraints.py (2)

50-67: Expected empty classes for edge cases.

The empty classes like MultiRefAllOf, NoConstraintAllOf, and IncompatibleTypeAllOf are expected outputs for edge cases where:

  • Multiple refs (not handled by new code)
  • No constraints added beyond the ref
  • Incompatible types in allOf

This correctly reflects that these schemas don't benefit from the new root model constraint handling.


134-153: LGTM! Model class correctly aggregates all types.

The Model class properly references all the defined constraint types with appropriate optional field declarations.

tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py (1)

18-21: Merged regex pattern uses positive lookahead for intersection.

The generated regex r'(?=^\S(.*\S)?$)(?=^[A-Z].*)' correctly merges two patterns using positive lookahead assertions to enforce both constraints. This aligns with allOf semantics where both patterns must be satisfied.

Note: The generated pattern is more complex than hand-written alternatives (e.g., r'^[A-Z]\S*(\S| \S+)*$'), but ensures correctness when merging arbitrary patterns.

Comment thread src/datamodel_code_generator/parser/jsonschema.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/datamodel_code_generator/parser/jsonschema.py (1)

1165-1200: Consider documenting format handling behavior.

The format handling is improved from the previous concern (multiple different formats now cause the method to return None at line 1172, preventing conflicts), but the behavior could be more explicit:

  • When all items share the same format or only one has a format: applied ✓
  • When multiple different formats exist: returns None (parent falls back to other handling) ✓
  • The distinction between merge modes (intersection vs last-wins for constraints) is clear

Consider adding a docstring note explaining the format handling strategy, especially the conflict resolution approach. This addresses the previous review feedback.

Based on learnings from past review comments about format handling.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f6d4dd and adf9b9b.

📒 Files selected for processing (4)
  • src/datamodel_code_generator/parser/jsonschema.py (4 hunks)
  • tests/data/expected/main/jsonschema/allof_root_model_constraints.py (1 hunks)
  • tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py (1 hunks)
  • tests/data/jsonschema/allof_root_model_constraints.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/data/jsonschema/allof_root_model_constraints.json
🧰 Additional context used
🧬 Code graph analysis (2)
tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py (1)
tests/data/expected/main/jsonschema/allof_root_model_constraints.py (30)
  • StringDatatype (12-15)
  • ConstrainedStringDatatype (18-21)
  • IntegerDatatype (24-25)
  • NonNegativeIntegerDatatype (28-29)
  • BoundedIntegerDatatype (32-35)
  • EmailDatatype (38-39)
  • FormattedStringDatatype (42-43)
  • ObjectBase (46-47)
  • ObjectWithAllOf (50-51)
  • MultiRefAllOf (54-55)
  • NoConstraintAllOf (58-59)
  • IncompatibleTypeAllOf (62-63)
  • ConstraintWithProperties (66-67)
  • ConstraintWithItems (70-71)
  • NumberIntegerCompatible (74-77)
  • RefWithSchemaKeywords (80-83)
  • ArrayDatatype (86-87)
  • RefToArrayAllOf (90-91)
  • ObjectNoPropsDatatype (94-95)
  • RefToObjectNoPropsAllOf (98-99)
  • PatternPropsDatatype (102-103)
  • RefToPatternPropsAllOf (106-107)
  • NestedAllOfDatatype (110-111)
  • RefToNestedAllOfAllOf (114-115)
  • ConstraintsOnlyDatatype (118-119)
  • RefToConstraintsOnlyAllOf (122-123)
  • NoDescriptionAllOf (126-129)
  • EmptyConstraintItemAllOf (132-135)
  • ConflictingFormatAllOf (138-139)
  • Model (142-162)
tests/data/expected/main/jsonschema/allof_root_model_constraints.py (1)
tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py (3)
  • StringDatatype (12-15)
  • ConstrainedStringDatatype (18-21)
  • Model (142-162)
🪛 Ruff (0.14.8)
src/datamodel_code_generator/parser/jsonschema.py

1500-1500: Unused noqa directive (non-enabled: PLR6301)

Remove unused noqa directive

(RUF100)


1518-1518: Unused noqa directive (non-enabled: PLR0911, PLR0912)

Remove unused noqa directive

(RUF100)

⏰ 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). (12)
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.12 on macOS
  • GitHub Check: 3.9 on macOS
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.11 on macOS
  • GitHub Check: 3.13 on macOS
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: benchmarks
  • GitHub Check: Analyze (python)
🔇 Additional comments (13)
src/datamodel_code_generator/parser/jsonschema.py (4)

63-63: LGTM! Imports support new allOf root model handling.

The added imports are necessary for the new functionality that handles allOf with root model constraints.


1500-1516: LGTM! Root model detection logic is correct.

The method correctly identifies root primitive schemas by excluding arrays, combined schemas (allOf/oneOf/anyOf), objects with properties/patternProperties, and enums. This aligns with the conditions in parse_raw_obj.

Note: The static analysis warning about the unused noqa directive at line 1500 is a false positive—the method intentionally remains an instance method for consistency with other parser methods.


1518-1581: Excellent fix for the core issue!

This method correctly handles the case where allOf combines a $ref to a root primitive model with additional constraints. Key strengths:

  • Validates single $ref: Lines 1534-1537 ensure exactly one reference
  • Type compatibility: Lines 1559-1565 properly allow integer/number coercion
  • Constraint collection: Lines 1552-1566 gather additional constraints while filtering out schemas with properties/items
  • Proper merging: Lines 1571-1574 delegate to _merge_primitive_schemas_for_allof respecting merge mode
  • Description preservation: Lines 1576-1579 ensure parent description is retained
  • Graceful fallback: Multiple None returns allow other allOf handling to take over when this pattern doesn't apply

This directly addresses the issue #1901 where such schemas generated empty class bodies.

Note: The static analysis warning at line 1518 about unused noqa directives is a false positive—the method's complexity justifies keeping it readable without splitting.


1992-1995: Clean integration of the fix.

The placement after _merge_all_of_object and before the general allOf handling is correct. The early return pattern ensures the new handler takes precedence only when applicable, preserving all existing behavior.

tests/data/expected/main/jsonschema/allof_root_model_constraints.py (6)

1-40: LGTM! Basic root models are correctly generated.

The generated root models properly demonstrate non-merge mode behavior, where allOf constraints are not merged with the referenced base model's constraints. For example, ConstrainedStringDatatype shows only the new regex pattern without merging the base StringDatatype pattern.


46-72: LGTM! Object allOf and edge cases correctly handled.

Object-based allOf correctly uses inheritance (ObjectWithAllOf extends ObjectBase), while empty classes represent legitimate edge cases where allOf merging cannot produce meaningful results (e.g., incompatible types, multiple refs).


80-84: LGTM! Key test case demonstrating the fix for issue #1901.

RefWithSchemaKeywords correctly demonstrates the core fix: an allOf combining a $ref to a root model (StringDatatype) with additional schema keywords (minLength, maxLength) now generates a proper root model with merged constraints instead of an empty class body.


110-140: LGTM! Edge cases comprehensively covered.

The remaining edge cases properly demonstrate:

  • Inheritance for nested allOf structures
  • Any type for constraint-only schemas without explicit types
  • Partial constraint merging where applicable
  • Empty classes for irreconcilable conflicts (e.g., format conflicts)

142-162: LGTM! Comprehensive test model aggregator.

The Model class effectively aggregates all test datatypes as optional fields, ensuring comprehensive test coverage of the allOf root model constraint scenarios.


86-88: No action needed—ArrayDatatype is correctly generated.

ArrayDatatype lacks a Field wrapper not because of inconsistency, but because its JSON schema source has no description field. Other root models like StringDatatype and IntegerDatatype have descriptions in the schema and thus receive Field(..., description=...) wrapping in the generated code. The generator correctly reflects the source schema: models with descriptions get Field wrappers; models without descriptions don't. The code is working as intended.

tests/data/expected/main/jsonschema/allof_root_model_constraints_merge.py (3)

18-21: LGTM! Merge mode correctly combines regex patterns.

ConstrainedStringDatatype demonstrates proper constraint merging: the regex patterns from both the base StringDatatype (^\S(.*\S)?$) and the allOf item (^[A-Z].*) are combined using positive lookahead assertions: (?=^\S(.*\S)?$)(?=^[A-Z].*). This is the correct behavior for merge mode.


1-84: LGTM! Merge and non-merge modes produce identical output where appropriate.

Models without multiple regex patterns (e.g., StringDatatype, RefWithSchemaKeywords, integer models) correctly produce identical output in both merge and non-merge modes. Only models combining multiple regex patterns show differences, which is the expected behavior.


86-162: LGTM! Remaining models and edge cases correctly identical to non-merge mode.

The remaining models, edge cases, and the Model aggregator are correctly identical to the non-merge file, as these cases don't involve multiple regex patterns requiring merging.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

datamodel-codegen produces class with missing body parts

1 participant