Conversation
WalkthroughA new CLI option --allof-merge-mode (values: constraints, all, none) was added and propagated into the public generate() API, Config, and parser constructors. JSON Schema parsing gained helpers to merge parent/child property schemas and now applies merged items during allOf processing according to the selected mode. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant CLI as CLI (argparse)
participant Config as Config
participant Generate as generate()
participant ParserFactory as Parser (OpenAPI/GraphQL/JsonSchema)
participant JsonParser as JsonSchemaParser
participant Fields as parse_object_fields
CLI->>Config: parse args (includes --allof-merge-mode)
Config->>Generate: call generate(allof_merge_mode)
Generate->>ParserFactory: construct parser(allof_merge_mode)
ParserFactory->>JsonParser: instantiate with allof_merge_mode
JsonParser->>JsonParser: parse schemas
alt allOf item is non-$ref
JsonParser->>JsonParser: _merge_properties_with_parent_constraints(parent_refs)
JsonParser->>Fields: parse_object_fields(merged_item)
else $ref item
JsonParser->>Fields: parse_object_fields(all_of_item)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
🤖 Generated by GitHub Actions
CodSpeed Performance ReportMerging #2671 will not alter performanceComparing Summary
Footnotes
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/datamodel_code_generator/parser/jsonschema.py (1)
1389-1431: Consider narrowing exception handling or adding logging.Line 1400 uses a broad
except Exceptionwhich silently continues on any error. While this prevents crashes when loading parent refs fails, it could hide legitimate issues (e.g., malformed schemas, I/O errors).Consider either:
- Catching more specific exceptions (e.g.,
KeyError,ValueError)- Adding debug logging when an exception occurs
- except Exception: # noqa: BLE001, S112 + except (KeyError, ValueError, TypeError) as e: # noqa: S112 + # Parent schema could not be loaded, skip constraint merging continueAlternatively, if you want to keep the broad catch for robustness:
- except Exception: # noqa: BLE001, S112 + except Exception: # noqa: BLE001, S112 + # Log at debug level for troubleshooting + # import logging; logging.debug(f"Could not load parent ref {ref}: {e}") continue
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
README.md(1 hunks)docs/index.md(1 hunks)src/datamodel_code_generator/__init__.py(3 hunks)src/datamodel_code_generator/__main__.py(3 hunks)src/datamodel_code_generator/arguments.py(2 hunks)src/datamodel_code_generator/parser/base.py(3 hunks)src/datamodel_code_generator/parser/jsonschema.py(6 hunks)src/datamodel_code_generator/parser/openapi.py(3 hunks)tests/data/expected/main/openapi/allof_materialize_defaults.py(1 hunks)tests/data/expected/main/openapi/allof_partial_override_unique_items.py(1 hunks)tests/data/expected/main/openapi/allof_partial_override_unique_items_pydantic_v2.py(1 hunks)tests/data/openapi/allof_materialize_defaults.yaml(1 hunks)tests/data/openapi/allof_partial_override_unique_items.yaml(1 hunks)tests/main/openapi/test_main_openapi.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (10)
tests/main/openapi/test_main_openapi.py (2)
tests/main/conftest.py (2)
output_file(94-96)run_main_and_assert(196-352)tests/test_main_kr.py (1)
output_file(37-39)
src/datamodel_code_generator/parser/base.py (1)
src/datamodel_code_generator/__init__.py (1)
AllOfMergeMode(273-283)
src/datamodel_code_generator/__init__.py (3)
src/datamodel_code_generator/model/msgspec.py (1)
Constraints(158-163)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/openapi.py (1)
src/datamodel_code_generator/__init__.py (1)
AllOfMergeMode(273-283)
tests/data/expected/main/openapi/allof_materialize_defaults.py (2)
src/datamodel_code_generator/model/base.py (1)
name(583-585)src/datamodel_code_generator/parser/base.py (1)
Child(563-569)
src/datamodel_code_generator/__main__.py (1)
src/datamodel_code_generator/__init__.py (1)
AllOfMergeMode(273-283)
src/datamodel_code_generator/arguments.py (1)
src/datamodel_code_generator/__init__.py (1)
AllOfMergeMode(273-283)
src/datamodel_code_generator/parser/jsonschema.py (1)
src/datamodel_code_generator/__init__.py (1)
AllOfMergeMode(273-283)
tests/data/expected/main/openapi/allof_partial_override_unique_items.py (2)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
Field(6-7)tests/data/expected/main/openapi/allof_partial_override_unique_items_pydantic_v2.py (2)
Thing(12-13)Person(16-17)
tests/data/expected/main/openapi/allof_partial_override_unique_items_pydantic_v2.py (1)
tests/data/expected/main/openapi/allof_partial_override_unique_items.py (2)
Thing(12-13)Person(16-17)
🪛 Checkov (3.2.334)
tests/data/openapi/allof_partial_override_unique_items.yaml
[high] 1-26: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[medium] 11-16: Ensure that arrays have a maximum number of items
(CKV_OPENAPI_21)
tests/data/openapi/allof_materialize_defaults.yaml
[high] 1-28: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
🪛 GitHub Actions: Test
src/datamodel_code_generator/__init__.py
[error] 616-616: GraphQLParser.init() got an unexpected keyword argument 'allof_merge_mode'. This indicates a mismatch between parser API and its usage (likely due to version/API changes).
src/datamodel_code_generator/__main__.py
[error] 1-1: GraphQLParser.init() got an unexpected keyword argument 'allof_merge_mode' during code generation. This indicates a mismatch between the GraphQL parser implementation and the code that invokes it (likely an API incompatibility between dependencies).
⏰ 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). (1)
- GitHub Check: benchmarks
🔇 Additional comments (19)
README.md (1)
365-370: LGTM! Clear documentation for the new CLI option.The help text clearly describes the three merge modes (constraints, all, none) and their behavior for allOf schemas.
src/datamodel_code_generator/arguments.py (2)
21-21: LGTM! Correct import of AllOfMergeMode.
426-434: LGTM! Proper CLI argument definition.The argument correctly uses the AllOfMergeMode enum values as choices and provides clear help text.
docs/index.md (1)
357-362: LGTM! Documentation is consistent with README.tests/data/openapi/allof_partial_override_unique_items.yaml (1)
1-24: LGTM! Appropriate test fixture for allOf partial override behavior.The OpenAPI schema correctly defines a base Thing schema with uniqueItems constraint and a Person schema that uses allOf to override the tags field with a default value. This properly tests the constraint inheritance behavior.
Note: The static analysis warnings about missing security and maxItems are false positives for test data and can be safely ignored.
src/datamodel_code_generator/parser/openapi.py (3)
22-22: LGTM! Correct import of AllOfMergeMode.
239-239: LGTM! Proper parameter definition.The
allof_merge_modeparameter is correctly typed withAllOfMergeModeand has the appropriate default value ofAllOfMergeMode.Constraints.
333-333: LGTM! Correct parameter forwarding.The
allof_merge_modeparameter is properly forwarded to the parent class initializer.tests/data/openapi/allof_materialize_defaults.yaml (1)
1-26: LGTM! Appropriate test fixture for allOf default materialization.This OpenAPI schema properly tests how default values and constraints are inherited and merged in allOf compositions. The Parent schema defines defaults and minimum constraints, while the Child schema extends it with additional maximum constraints.
Note: The static analysis warning about missing global security is a false positive for test data and can be safely ignored.
tests/data/expected/main/openapi/allof_materialize_defaults.py (1)
1-19: AllOf defaults fixture matches intended merge semanticsParent/Child models correctly reflect merged constraints and inherited defaults for the
allmerge mode; structure and imports are consistent with other expected OpenAPI fixtures.tests/main/openapi/test_main_openapi.py (1)
1827-1845: New allOf tests are well-scoped and consistent with existing patterns
test_main_openapi_allof_partial_override_unique_itemsparametrization over output model types plus--use-unique-items-as-setmirrors the style of other OpenAPI tests and directly targets the uniqueItems inheritance bug.test_main_openapi_allof_merge_mode_allcleanly exercises the new--allof-merge-mode alloption against a dedicated YAML/expected pair.No issues spotted with arguments, paths, or expectations.
Also applies to: 1848-1857
src/datamodel_code_generator/parser/base.py (1)
26-34: Parser now exposes allOf merge mode cleanlyImporting
AllOfMergeMode, threading it throughParser.__init__with a default ofConstraints, and storing it asself.allof_merge_modeare straightforward and maintain backward compatibility while giving concrete parsers the configuration they need.Also applies to: 647-740, 761-875
src/datamodel_code_generator/__init__.py (1)
273-284: The review comment is incorrect—GraphQLParser already accepts and properly forwards theallof_merge_modeparameter.GraphQLParser.init at line 155 includes
allof_merge_mode: AllOfMergeMode = AllOfMergeMode.Constraints,and forwards it to the base Parser class at line 250 viasuper().__init__(). The unconditional passing ofallof_merge_modeat line 674 in generate() does not cause a failure because the parameter is already properly wired in the GraphQL parser. Neither of the suggested fixes is necessary—the parameter integration is complete and functional.Likely an incorrect or invalid review comment.
src/datamodel_code_generator/__main__.py (2)
23-38: LGTM: Import addition is correct.The
AllOfMergeModeimport is properly added alongside other enum imports from the package.
425-425: LGTM: Config field addition is correct.The
allof_merge_modefield with defaultAllOfMergeMode.Constraintsfollows the established pattern for other config options.src/datamodel_code_generator/parser/jsonschema.py (4)
24-36: LGTM: Import addition is correct.The
AllOfMergeModeimport is properly placed with other imports fromdatamodel_code_generator.
1371-1387: LGTM: Merge logic for property schemas is well-implemented.The three merge modes are correctly handled:
NoMerge: Returns child dict without parent fieldsConstraints: Excludes annotation fields (default,examples,example) from parentAll: Merges all fields from parentThe recursive merge on line 1384 correctly handles nested property schemas.
1730-1755: LGTM: Integration of parent constraint merging in allOf processing.The changes correctly:
- Compute
parent_refsupfront from all$refitems inallOf- For non-ref items, merge child properties with parent constraints before processing
- Use the merged item for
parse_object_fieldsThis ensures child schemas inherit constraints from parent schemas according to the selected merge mode.
566-566: LGTM: Constructor parameter addition follows established pattern.The
allof_merge_modeparameter is correctly added with the appropriate default value (AllOfMergeMode.Constraints) at line 566 and passed to the parent constructor at line 660. TheParserbase class inbase.pyhas been updated to accept the parameter (line 702) and store it as an instance attribute (line 801). The parameter is actively used in the implementation (lines 1373, 1377).
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2671 +/- ##
==========================================
- Coverage 99.61% 99.50% -0.11%
==========================================
Files 76 76
Lines 10666 10731 +65
Branches 1303 1316 +13
==========================================
+ Hits 10625 10678 +53
- Misses 21 32 +11
- Partials 20 21 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
… partial overrides
… partial overrides
…rents with same property
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/datamodel_code_generator/parser/jsonschema.py (1)
1398-1401: Consider narrowing the exception handling or adding a warning.The bare
except Exceptionwithcontinuesilently swallows any error when loading parent schemas. While this prevents failures for edge cases like circular references or invalid refs, it could also mask legitimate issues (e.g., malformed schemas, encoding errors).Consider either:
- Catching more specific exceptions (e.g.,
KeyError,ValueError)- Logging a warning when an exception occurs
try: parent_schema = self._load_ref_schema_object(ref) - except Exception: # pragma: no cover # noqa: BLE001, S112 + except (KeyError, NotImplementedError) as exc: # pragma: no cover + warn(f"Could not load parent schema {ref}: {exc}", stacklevel=2) continue
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
src/datamodel_code_generator/parser/jsonschema.py(6 hunks)tests/data/expected/main/openapi/allof_merge_mode_none.py(1 hunks)tests/data/expected/main/openapi/allof_multiple_parents_same_property.py(1 hunks)tests/data/expected/main/openapi/allof_parent_bool_property.py(1 hunks)tests/data/expected/main/openapi/allof_parent_no_properties.py(1 hunks)tests/data/expected/main/openapi/allof_property_bool_schema.py(1 hunks)tests/data/openapi/allof_merge_mode_none.yaml(1 hunks)tests/data/openapi/allof_multiple_parents_same_property.yaml(1 hunks)tests/data/openapi/allof_parent_bool_property.yaml(1 hunks)tests/data/openapi/allof_parent_no_properties.yaml(1 hunks)tests/data/openapi/allof_property_bool_schema.yaml(1 hunks)tests/main/openapi/test_main_openapi.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
tests/data/expected/main/openapi/allof_property_bool_schema.py (2)
tests/data/expected/main/openapi/allof_merge_mode_none.py (2)
Parent(12-13)Child(16-17)tests/data/expected/main/openapi/allof_parent_no_properties.py (1)
Child(16-17)
tests/data/openapi/allof_parent_no_properties.yaml (2)
tests/data/expected/parser/openapi/openapi_parser_parse_allof/output.py (5)
AllOfNested2(75-76)AllOfNested1(79-80)AllOfNested3(71-72)AllOfref(19-20)AllOfCombine(28-30)tests/data/expected/parser/openapi/openapi_parser_parse_alias/__init__.py (5)
AllOfRef(52-53)AnyOfCombine(61-62)AllOfCombine(56-58)AllOfObj(30-32)AnyOfCombineInRoot(81-83)
tests/data/openapi/allof_merge_mode_none.yaml (2)
tests/data/expected/parser/openapi/openapi_parser_parse_allof/output.py (7)
AllOfNested2(75-76)AllOfNested3(71-72)AllOfNested1(79-80)AllOfref(19-20)AllOfobj(23-25)AllOfCombine(28-30)AnyOfCombine(33-34)tests/data/expected/parser/openapi/openapi_parser_parse_alias/__init__.py (1)
AllOfCombine(56-58)
tests/main/openapi/test_main_openapi.py (1)
tests/main/conftest.py (2)
output_file(94-96)run_main_and_assert(196-352)
src/datamodel_code_generator/parser/jsonschema.py (1)
src/datamodel_code_generator/__init__.py (1)
AllOfMergeMode(273-283)
tests/data/expected/main/openapi/allof_parent_bool_property.py (1)
tests/data/expected/main/openapi/allof_multiple_parents_same_property.py (1)
Child(21-23)
tests/data/expected/main/openapi/allof_multiple_parents_same_property.py (1)
tests/data/expected/main/openapi/allof_parent_bool_property.py (1)
Child(17-18)
tests/data/expected/main/openapi/allof_parent_no_properties.py (2)
tests/data/expected/main/openapi/allof_merge_mode_none.py (1)
Child(16-17)tests/data/expected/main/openapi/allof_property_bool_schema.py (1)
Child(16-18)
🪛 Checkov (3.2.334)
tests/data/openapi/allof_parent_no_properties.yaml
[high] 1-19: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
tests/data/openapi/allof_merge_mode_none.yaml
[high] 1-22: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
tests/data/openapi/allof_parent_bool_property.yaml
[high] 1-22: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
tests/data/openapi/allof_multiple_parents_same_property.yaml
[high] 1-33: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
tests/data/openapi/allof_property_bool_schema.yaml
[high] 1-22: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
⏰ 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). (13)
- GitHub Check: 3.10 on Windows
- GitHub Check: 3.10 on macOS
- GitHub Check: 3.11 on Windows
- GitHub Check: 3.11 on macOS
- GitHub Check: 3.12 on macOS
- GitHub Check: 3.13 on macOS
- GitHub Check: 3.12 on Windows
- GitHub Check: 3.9 on Windows
- GitHub Check: 3.14 on Windows
- GitHub Check: 3.14 on macOS
- GitHub Check: 3.13 on Windows
- GitHub Check: Analyze (python)
- GitHub Check: benchmarks
🔇 Additional comments (20)
tests/data/openapi/allof_merge_mode_none.yaml (1)
1-20: LGTM!This test fixture correctly demonstrates the allOf partial override scenario where the child adds
maxLength: 100without redeclaring the full property schema. The missingtype: stringin the child'snameproperty is intentional to test constraint inheritance behavior.The Checkov warning about missing global security field is a false positive for test fixtures.
src/datamodel_code_generator/parser/jsonschema.py (3)
566-566: LGTM!The
allof_merge_modeparameter is correctly added with a sensible default ofAllOfMergeMode.Constraintsand properly threaded to the superclass.
1371-1387: LGTM!The merge logic correctly implements all three modes:
NoMerge: Returns child dict without parent fieldsConstraints: Merges all except annotation fields (default,examples,example)All(implicit when notNoMergeorConstraints): Merges everythingThe recursive merge for nested dicts properly maintains mode semantics.
1730-1755: LGTM!The integration correctly:
- Collects all
$refpaths upfront as potential parent schemas- Merges child properties with parent constraints before parsing
- Uses the merged item for field parsing while preserving original
requiredextractionThis ensures constraint inheritance works for partial property overrides in allOf schemas.
tests/data/openapi/allof_parent_no_properties.yaml (1)
1-17: LGTM!Good edge case test for the merge logic when the parent schema has no properties. This validates that
_merge_properties_with_parent_constraintscorrectly handles empty parents without errors.The Checkov warning about missing global security field is a false positive for test fixtures.
tests/data/openapi/allof_property_bool_schema.yaml (1)
1-20: LGTM!This test fixture validates an important edge case: boolean property schemas (
allowed: true). In JSON Schema,trueas a property schema means "any value is allowed." The implementation correctly handles this at line 1412 of jsonschema.py where non-JsonSchemaObjectproperties are passed through unchanged.The Checkov warning about missing global security field is a false positive for test fixtures.
tests/data/expected/main/openapi/allof_merge_mode_none.py (1)
16-17: Expected output for merge mode "none" shows incorrect constraint inheritance.With
--allof-merge-mode none, the Child.name field should not inherit the parent'smin_length=1constraint. The input YAML specifies onlymaxLength: 100for Child.name, so the generated field should reflect that (or be a plainOptional[str]), not includemin_length=1from the Parent class definition.The current expected output violates the "none" merge mode semantics, which explicitly means "do not merge any fields from parent properties." Either the expected output file is incorrect, or the implementation has a flaw where fields with incomplete constraint specifications fall back to inheriting the entire parent field type instead of respecting the merge mode.
tests/data/openapi/allof_parent_bool_property.yaml (1)
1-20: LGTM! Test data correctly exercises boolean schema in allOf.This test case properly validates handling of boolean property schemas (
allowed: true) within allOf compositions, which is an edge case worth testing.Note: The static analysis warning about missing global security is a false positive for test data files.
tests/data/openapi/allof_multiple_parents_same_property.yaml (1)
1-31: LGTM! Well-designed test for multiple parent constraint merging.This test case validates the important scenario where multiple parents define the same property with different constraints (minLength: 1 vs 5), ensuring the generator correctly merges to the most restrictive constraint.
tests/data/expected/main/openapi/allof_parent_no_properties.py (1)
1-17: LGTM! Expected output correctly represents empty parent scenario.The generated code properly handles the edge case of a parent schema with no properties, creating an empty base class and child with inherited structure.
tests/data/expected/main/openapi/allof_property_bool_schema.py (1)
1-18: LGTM! Constraint inheritance correctly implemented.The Child class properly inherits the
min_length=1constraint from Parent and combines it with the child'smax_length=100, demonstrating the fix for partial override constraint inheritance.tests/data/expected/main/openapi/allof_parent_bool_property.py (1)
1-18: LGTM! Parent field inheritance working correctly.The Child class properly inherits both the
allowedfield and themin_lengthconstraint onnamefrom Parent, while adding its ownmax_lengthconstraint.tests/data/expected/main/openapi/allof_multiple_parents_same_property.py (1)
21-23: LGTM! Constraint merging correctly selects most restrictive values.The Child class correctly merges constraints from multiple parents:
- Takes
min_length=5(more restrictive than Parent1'smin_length=1)- Combines age constraints from Parent2 (
ge=0) with child's own (le=150)Note: Child inherits from BaseModel directly rather than from Parent1/Parent2, which is the expected behavior for allOf composition with multiple parents.
tests/main/openapi/test_main_openapi.py (7)
1827-1846: LGTM! Well-structured parametrized test.The test properly validates uniqueItems inheritance across both Pydantic versions with appropriate flags (
--use-unique-items-as-set).
1848-1858: LGTM! Merge mode "all" test correctly configured.The test validates that
--allof-merge-mode allproperly merges parent defaults, which is the core functionality of this PR.
1860-1870: LGTM! Merge mode "none" test correctly configured.The test validates that
--allof-merge-mode noneskips parent constraint merging, providing the opposite behavior to "all" mode.
1872-1881: LGTM! Boolean schema property test is correctly structured.The test validates proper handling of boolean property schemas (e.g.,
allowed: true) in allOf compositions, an important edge case.
1883-1892: LGTM! Empty parent edge case properly tested.The test validates correct handling of allOf when the parent schema has no properties, an edge case that could cause issues if not handled properly.
1894-1903: LGTM! Parent boolean property test correctly structured.The test validates that boolean property schemas in parent classes are properly inherited by children in allOf compositions.
1905-1914: LGTM! Multiple parent constraint merging properly tested.The test validates the critical scenario where multiple parents define the same property with different constraints, ensuring the generator correctly merges to the most restrictive values.
Summary
--allof-merge-modeoption to control field merging behavior in allOf schemasSummary by CodeRabbit
New Features
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.