Add --collapse-root-models-name-strategy option#2791
Conversation
📝 WalkthroughWalkthroughAdds three CLI options (--collapse-root-models-name-strategy, --http-timeout, --use-field-description-example), threads them through CLI, config, and parser layers, implements collapse-root-models naming strategies (Child/Parent) and schema-extension/propertyNames support, adds HTTP timeout handling, updates generate() return behavior, and expands tests and docs accordingly. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant CLI as CLI
participant Main as datamodel_code_generator.__main__
participant Gen as generate()
participant Parser as Parser (JsonSchema/OpenAPI/GraphQL)
participant HTTP as http.get
note right of CLI `#a3be8c`: user supplies flags (--http-timeout,\n--collapse-root-models-name-strategy,\n--use-field-description-example)
CLI->>Main: parse args -> Config
Main->>Gen: run_generate_from_config(config, extra_template_data)
Gen->>Parser: init(parser_settings including collapse_root_models_name_strategy,\nuse_field_description_example, http_timeout)
Parser->>HTTP: fetch external refs (timeout param)
HTTP-->>Parser: schema content
Parser->>Parser: parse schemas, apply collapse-root-models logic (Parent/Child), set schema extensions/propertyNames
Parser-->>Gen: module bodies
Gen->>Gen: _build_module_content(header, body, custom_file_header)
Gen-->>CLI: return string | GeneratedModules | write files
note left of Gen `#efe1b3`: warnings emitted for conflicts (multiple wrappers, direct refs)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (4 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 #2791 will not alter performanceComparing Summary
Footnotes
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2791 +/- ##
==========================================
- Coverage 99.46% 99.46% -0.01%
==========================================
Files 88 88
Lines 13504 13564 +60
Branches 1594 1600 +6
==========================================
+ Hits 13432 13491 +59
Misses 36 36
- Partials 36 37 +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:
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/datamodel_code_generator/arguments.py (1)
17-33: Clarify or enforce the--collapse-root-modelsdependencyThe new argument is wired correctly (Enum-backed
choices, defaultNone, good help text), but the help currently states:“Requires --collapse-root-models to be set.”
There’s no enforcement in
arguments.pyitself; if a user passes only--collapse-root-models-name-strategy, it will effectively be a no-op rather than an error.Consider either:
- Enforcing this constraint in config/generation code (raise if name-strategy is set while
collapse_root_modelsis falsey), or- Softening the wording to “Only has effect when --collapse-root-models is set.”
Also applies to: 180-187
docs/cli-reference/model-customization.md (1)
14-15: Docs clearly describe the option; consider highlighting theparentuse caseThe table entry and dedicated section for
--collapse-root-models-name-strategyare accurate and link correctly, and the JSON Schema example for thechildstrategy matches the expected output.Since the primary new capability is the
parentbehavior, you might optionally:
- Add a short contrasting example (or diff) for
--collapse-root-models-name-strategy parent, or- Explicitly note that omitting the option behaves like
child, whileparentswitches to preserving the wrapper name.This would make the motivation from issue #1418 more obvious to readers skimming the docs.
Also applies to: 1510-1577
src/datamodel_code_generator/parser/base.py (1)
1683-1683: Remove unused noqa directive.The complexity-related noqa codes (
PLR0912,PLR0914,PLR0915) are not enabled in your Ruff configuration, making this directive unnecessary.🔎 Proposed fix
- def __collapse_root_models( # noqa: PLR0912, PLR0914, PLR0915 + def __collapse_root_models( self, models: list[DataModel], unused_models: list[DataModel],
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
tests/data/jsonschema/collapse_root_models_name_strategy_child.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/collapse_root_models_name_strategy_direct_refs.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/collapse_root_models_name_strategy_multiple_wrappers.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/collapse_root_models_name_strategy_parent.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/collapse_root_models_name_strategy_with_inheritance.jsonis excluded by!tests/data/**/*.jsonand included by none
📒 Files selected for processing (18)
docs/cli-reference/index.mddocs/cli-reference/model-customization.mddocs/cli-reference/quick-reference.mdsrc/datamodel_code_generator/__init__.pysrc/datamodel_code_generator/__main__.pysrc/datamodel_code_generator/arguments.pysrc/datamodel_code_generator/cli_options.pysrc/datamodel_code_generator/parser/base.pysrc/datamodel_code_generator/parser/graphql.pysrc/datamodel_code_generator/parser/jsonschema.pysrc/datamodel_code_generator/parser/openapi.pysrc/datamodel_code_generator/prompt_data.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_child.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_direct_refs.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_multiple_wrappers.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_parent.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_with_inheritance.pytests/main/jsonschema/test_main_jsonschema.py
🧰 Additional context used
🧬 Code graph analysis (10)
src/datamodel_code_generator/parser/openapi.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(302-310)
src/datamodel_code_generator/parser/jsonschema.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(302-310)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_parent.py (3)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_child.py (1)
Model(14-15)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_direct_refs.py (1)
Model(22-24)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_multiple_wrappers.py (1)
Model(22-24)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_multiple_wrappers.py (3)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_child.py (1)
Model(14-15)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_direct_refs.py (1)
Model(22-24)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_parent.py (1)
Model(14-15)
src/datamodel_code_generator/parser/graphql.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(302-310)
src/datamodel_code_generator/arguments.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(302-310)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_child.py (3)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_direct_refs.py (1)
Model(22-24)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_multiple_wrappers.py (1)
Model(22-24)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_parent.py (1)
Model(14-15)
src/datamodel_code_generator/parser/base.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(302-310)
tests/main/jsonschema/test_main_jsonschema.py (2)
tests/main/conftest.py (2)
output_file(98-100)run_main_and_assert(244-408)src/datamodel_code_generator/__main__.py (1)
Exit(95-101)
src/datamodel_code_generator/__main__.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(302-310)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/base.py
1683-1683: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/__main__.py
491-491: Unused noqa directive (non-enabled: UP045)
Remove unused noqa directive
(RUF100)
960-960: Unused noqa directive (non-enabled: T201)
Remove unused noqa directive
(RUF100)
🔇 Additional comments (20)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_multiple_wrappers.py (1)
10-24: The expected output correctly preserves all three classes (SharedInner, Wrapper1, Wrapper2) without collapsing. The test function at line 4999 confirms this is intentional: when the parent strategy is applied to a schema with multiple wrappers referencing the same inner model, the code issues a UserWarning ("Cannot apply 'parent' strategy when inner model has multiple root models") and skips the collapse operation to avoid ambiguity. This design correctly prevents semantic loss—collapsing would either lose the Wrapper1/Wrapper2 distinction (child strategy) or create ambiguity about which wrapper name to preserve (parent strategy). The expected output is correct.tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_with_inheritance.py (1)
1-20: Expected inheritance fixture looks consistent with feature intentThe generated Wrapper/Derived/Model layout is clean, uses the modern
from __future__ import annotations+| Nonestyle, and matches the intended “parent strategy with inheritance” scenario for the new option.tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_parent.py (1)
1-15: Parent-strategy expected output matches requested behaviorPreserving
ISectionBlockMetadataas the inner model name and wiringModel.metadatato it aligns with the “keep wrapper name” requirement from the linked issue, and the style matches other expected fixtures.src/datamodel_code_generator/parser/graphql.py (1)
16-31: New name-strategy parameter is correctly plumbed through GraphQLParserImporting
CollapseRootModelsNameStrategy, adding an optionalcollapse_root_models_name_strategyargument, and forwarding it intosuper().__init__keeps the API backward compatible while enabling the new behavior for GraphQL inputs as well. The parameter is grouped next tocollapse_root_models, which keeps the signature coherent.Also applies to: 175-176, 285-287
docs/cli-reference/quick-reference.md (1)
80-90: Quick-reference entries for--collapse-root-models-name-strategyare accurate and consistentThe new option is correctly listed under Model Customization and in the alphabetical index, with a concise description that matches the test docstring and points to the
model-customization.md#collapse-root-models-name-strategyanchor.Also applies to: 186-202
tests/main/jsonschema/test_main_jsonschema.py (1)
4951-5031: New tests give solid coverage for--collapse-root-models-name-strategybehaviorThe added tests exercise:
- Happy-path behavior for both
childandparentstrategies (including CLI-doc coverage forchild),- The argument validation error when the strategy is used without
--collapse-root-models, and- Warning paths where
parentcannot be safely applied (multiple wrappers, direct refs), plus an inheritance case.The use of
run_main_and_assert,pytest.warns, and function-name–derived expected filenames is consistent with the rest of the suite and should keep the new option well guarded against regressions.docs/cli-reference/index.md (1)
14-18: Category count and index entry stay consistent with new optionThe Model Customization count bump to 34 and the new
--collapse-root-models-name-strategyentry under C are consistent and correctly linked to the detailed docs section.Also applies to: 48-50
src/datamodel_code_generator/prompt_data.py (1)
23-31: New prompt description matches option semanticsThe
OPTION_DESCRIPTIONSentry for--collapse-root-models-name-strategyis concise and aligned with the intended behavior of choosing the kept name when collapsing root models.tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_child.py (1)
1-15: Expected output correctly reflectschildnaming strategyThe generated models keep the inner
FieldType2name and reference it fromModel.metadata, which matches the documentedchildbehavior for--collapse-root-models-name-strategy.src/datamodel_code_generator/cli_options.py (1)
83-88: CLI metadata wiring for new option is correct
CLI_OPTION_METAnow includes--collapse-root-models-name-strategyin the Model category, matching the argparse option and keeping docs sync infrastructure intact.src/datamodel_code_generator/parser/openapi.py (1)
20-36: OpenAPI parser correctly threads the new naming strategy to the base parserThe added import, constructor parameter, and
super().__init__forwarding forcollapse_root_models_name_strategyare consistent with existing configuration plumbing and ensure OpenAPI benefits from the same collapse-root-models naming behavior as JSON Schema.Also applies to: 259-262, 299-372
src/datamodel_code_generator/parser/jsonschema.py (1)
27-27: LGTM! Parameter threading is clean and consistent.The new
collapse_root_models_name_strategyparameter is properly imported, typed, and forwarded to the parentParserclass, following the same pattern as the existingcollapse_root_modelsparameter.Also applies to: 601-601, 711-711
src/datamodel_code_generator/__init__.py (2)
302-310: Excellent enum documentation.The
CollapseRootModelsNameStrategyenum is well-documented with clear explanations of both theChildandParentstrategies, making it easy for users to understand the behavior.
529-529: Parameter correctly integrated into generate() API.The new parameter is properly added to the function signature and forwarded to the parser initialization.
Also applies to: 803-803
src/datamodel_code_generator/__main__.py (3)
28-28: Configuration field properly integrated.The new
collapse_root_models_name_strategyfield is correctly added to theConfigmodel with appropriate typing.Note: The static analysis hint about line 491's
noqa: UP045directive is a false positive—the directive is necessary to maintain consistency with otherOptionaltype annotations in the Config class.Also applies to: 491-491
959-964: Validation logic is correct.The validation appropriately enforces that
--collapse-root-models-name-strategycan only be used when--collapse-root-modelsis enabled, with a clear error message.
808-808: Parameter correctly forwarded to generate function.The
collapse_root_models_name_strategyis properly passed through from the config to thegenerate()call.tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_direct_refs.py (1)
1-24: Test data file for direct-refs scenario.This is an expected output file used for test validation. No review needed as it represents generated output that will be compared against actual generation results during testing.
src/datamodel_code_generator/parser/base.py (2)
30-30: LGTM! Proper parameter threading for the new strategy.The new
collapse_root_models_name_strategyparameter is correctly imported, added to__init__, and stored as an instance variable. TheNonedefault ensures backward compatibility.Also applies to: 754-754, 944-944
1714-1784: Excellent implementation with thorough conflict detection.The strategy implementation is well-designed:
- Backward compatibility: The
Nonecheck (lines 1716-1718) preserves existing behavior when no strategy is specified.- Defensive checks: Proper validation prevents edge cases:
- Multiple wrappers referencing the same inner model (lines 1735-1742)
- Direct non-wrapper references to the inner model (lines 1754-1760)
- Clear warnings: Users are informed when the strategy cannot be applied, helping them understand why their configuration isn't taking effect.
- Correct reference management: The code properly rewires references (lines 1770-1778) and cleans up unused wrappers (lines 1781-1783).
The
Parentstrategy implementation (line 1763) correctly renames the inner model to adopt the wrapper's name, addressing the issue described in #1418.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/datamodel_code_generator/parser/base.py
🧰 Additional context used
🧬 Code graph analysis (1)
src/datamodel_code_generator/parser/base.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(302-310)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/base.py
1683-1683: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)
Remove unused noqa directive
(RUF100)
🔇 Additional comments (4)
src/datamodel_code_generator/parser/base.py (4)
30-30: LGTM!Import addition is correct and properly placed.
754-754: LGTM!Parameter addition maintains backward compatibility with
Nonedefault.
944-944: LGTM!Instance variable assignment follows existing patterns.
1683-1683: Remove unusednoqadirective.The complexity checks (
PLR0912,PLR0914,PLR0915) are not triggered for this method, so thenoqadirective is unnecessary.🔎 Proposed fix
- def __collapse_root_models( # noqa: PLR0912, PLR0914, PLR0915 + def __collapse_root_models(⛔ Skipped due to learnings
Learnt from: koxudaxi Repo: koxudaxi/datamodel-code-generator PR: 2681 File: tests/cli_doc/test_cli_doc_coverage.py:82-82 Timestamp: 2025-12-18T13:43:16.235Z Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/datamodel_code_generator/parser/base.py (1)
1683-1683: Optional: Remove unusednoqadirective.The static analysis tool reports that the
noqadirective forPLR0912,PLR0914,PLR0915is unnecessary because these rules are not enabled in your configuration.🔎 Proposed fix
- def __collapse_root_models( # noqa: PLR0912, PLR0914, PLR0915 + def __collapse_root_models(
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
tests/data/jsonschema/collapse_root_models_name_strategy_complex.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/collapse_root_models_name_strategy_nested_wrappers.jsonis excluded by!tests/data/**/*.jsonand included by none
📒 Files selected for processing (9)
src/datamodel_code_generator/parser/base.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_child.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_child_v2.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent_v2.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_child.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent_v2.pytests/main/jsonschema/test_main_jsonschema.py
🧰 Additional context used
🧬 Code graph analysis (9)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent.py (4)
src/datamodel_code_generator/model/base.py (1)
name(741-743)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_child.py (1)
Model(24-27)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_child.py (1)
Model(14-15)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent.py (1)
Model(18-19)
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/__main__.py (1)
Exit(95-101)
src/datamodel_code_generator/parser/base.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(302-310)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_child_v2.py (3)
src/datamodel_code_generator/model/base.py (1)
name(741-743)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent_v2.py (1)
Model(24-27)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent_v2.py (1)
Model(18-19)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_child.py (3)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_child.py (1)
Model(24-27)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent.py (1)
Model(24-27)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent.py (1)
Model(18-19)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent_v2.py (2)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_child_v2.py (1)
Model(24-27)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent_v2.py (1)
Model(24-27)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_child.py (1)
src/datamodel_code_generator/model/base.py (1)
name(741-743)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent.py (3)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_child.py (1)
Model(24-27)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent.py (1)
Model(24-27)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_child.py (1)
Model(14-15)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent_v2.py (3)
src/datamodel_code_generator/model/base.py (1)
name(741-743)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_child_v2.py (1)
Model(24-27)tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent_v2.py (1)
Model(18-19)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/base.py
1683-1683: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)
Remove unused noqa directive
(RUF100)
🔇 Additional comments (9)
tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_child.py (1)
1-15: LGTM! Test fixture correctly demonstrates the "child" naming strategy.The generated output appropriately shows the inner model name (
Inner) being preserved when using the "child" collapse strategy, which aligns with the PR objectives.tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent.py (1)
1-19: LGTM! Test fixture correctly demonstrates the "parent" naming strategy for Pydantic v1.The generated output appropriately shows wrapper names (
MiddleWrapper,OuterWrapper) being preserved when using the "parent" collapse strategy with Pydantic v1's__root__pattern.tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent_v2.py (1)
1-19: LGTM! Test fixture correctly demonstrates the "parent" naming strategy for Pydantic v2.The generated output appropriately shows wrapper names being preserved when using the "parent" collapse strategy with Pydantic v2's
RootModelpattern.tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent.py (1)
1-27: LGTM! Test fixture correctly demonstrates the "parent" naming strategy with inheritance.The generated output appropriately shows wrapper names (
UserWrapper,AdminWrapper,SettingsWrapper) being preserved, including proper inheritance (AdminWrapper(UserWrapper)), when using the "parent" collapse strategy in complex scenarios.src/datamodel_code_generator/parser/base.py (3)
30-30: LGTM! Import addition is correct.The
CollapseRootModelsNameStrategyenum import is properly placed alongside other strategy/enum imports.
754-754: LGTM! Parameter properly threaded through Parser initialization.The
collapse_root_models_name_strategyparameter is correctly typed withCollapseRootModelsNameStrategy | None, has an appropriate default ofNone, and is properly stored as an instance variable.Also applies to: 944-944
1714-1774: LGTM! Parent strategy implementation is well-designed and addresses previous feedback.The collapse logic for the new
CollapseRootModelsNameStrategy.Parentstrategy is robust:
Validation checks prevent incorrect collapsing:
- Lines 1722-1737: Warns and skips when multiple wrappers reference the same inner model
- Lines 1739-1754: Warns and skips when the inner model is directly referenced by non-wrapper models
Proper metadata synchronization (lines 1756-1758):
- Updates
inner_model.class_name- Updates
inner_model.reference.name- Calls
inner_model.set_reference_path()This addresses the past review comment about keeping reference metadata consistent after renaming.
Clean reference management (lines 1762-1774):
- Correctly updates reference children
- Removes unused imports
- Marks wrapper for removal when no longer referenced
tests/main/jsonschema/test_main_jsonschema.py (1)
4951-5076: Comprehensive test coverage for the new feature.The test suite thoroughly covers the new
--collapse-root-models-name-strategyoption with tests for:
- Both child and parent strategies
- Error validation when
--collapse-root-modelsis missing- Warning scenarios (multiple wrappers, direct references)
- Edge cases (inheritance, nested wrappers, complex schemas)
The tests follow existing patterns and properly use
pytest.warnsfor warning validation.tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_complex_parent_v2.py (1)
1-27: Expected output correctly demonstrates parent naming strategy.The file shows wrapper names (
UserWrapper,AdminWrapper,SettingsWrapper) are preserved in the parent strategy, as opposed to the child strategy which uses inner names (Person,Admin,Config). This correctly validates the intended behavior of the--collapse-root-models-name-strategy parentoption.
e3fb365 to
ffd73c9
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
tests/main/jsonschema/test_main_jsonschema.py
🧰 Additional context used
🧬 Code graph analysis (1)
tests/main/jsonschema/test_main_jsonschema.py (3)
tests/test_main_kr.py (1)
output_file(44-46)tests/main/conftest.py (1)
output_file(98-100)src/datamodel_code_generator/__main__.py (1)
Exit(95-101)
* Add --http-timeout CLI option for configurable HTTP request timeout * docs: update CLI reference documentation and prompt data 🤖 Generated by GitHub Actions --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* Pass schema extensions to templates * Move model_base import to top of file * Add schema extensions documentation Document how x-* schema extensions are passed to custom templates via the extensions variable, with examples for database model configuration and other use cases. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
* Add propertyNames and x-propertyNames support * Fix Pydantic v1 compatibility for x-propertyNames Use the model_validate utility function from util module instead of calling JsonSchemaObject.model_validate() directly, which only exists in Pydantic v2. 🤖 Generated with [Claude Code](https://claude.com/claude-code) * Add test for x-propertyNames non-dict branch coverage Test that x-propertyNames with non-dict value (e.g., boolean) is correctly ignored, achieving 100% diff coverage. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
* Add --use-field-description-example option * docs: update CLI reference documentation and prompt data 🤖 Generated by GitHub Actions * Add tests for complete branch coverage of docstring property --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2489c00 to
f4283e2
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
tests/main/jsonschema/test_main_jsonschema.py (1)
5075-5244: Collapse-root-models name-strategy tests cover the key behaviors; just verify the fixtures and v1/v2 outputs.The new
--collapse-root-models-name-strategytests look well thought out:
- Happy paths for both
childandparentstrategies, including inheritance and nested/complex wrapper scenarios.- Negative path enforcing
--collapse-root-modelsas a prerequisite.- Guardrails for ambiguous cases (
multiple_wrappers,direct_refs) viapytest.warns(UserWarning, match=...).- Parametrization over
pydantic.BaseModel/pydantic_v2.BaseModelwhere relevant.Two small things to verify:
JSON/expected fixtures exist and are wired correctly for all of these inputs/outputs, since they live outside this diff (
collapse_root_models_name_strategy_*.jsonand the correspondingjsonschema_collapse_root_models_name_strategy_*.pyfiles).For
test_main_jsonschema_collapse_root_models_name_strategy_complex_parent, a singleexpected_fileis used for both pydantic v1 and v2. If the generator truly produces identical code there, that’s fine; otherwise, you may want to mirror the split used innested_wrappers_parentand add a separate v2 golden file.#!/bin/bash # Verify that all collapse_root_models_name_strategy fixtures exist and inspect any v1/v2 diffs. echo "== Checking JSON schema fixtures ==" names=( child parent multiple_wrappers direct_refs with_inheritance nested_wrappers complex ) for n in "${names[@]}"; do echo "- collapse_root_models_name_strategy_${n}.json" find tests -type f -name "collapse_root_models_name_strategy_${n}.json" || echo " MISSING" done echo "" echo "== Checking expected Python outputs for complex/nested wrappers ==" find tests -type f -name "jsonschema_collapse_root_models_name_strategy_nested_wrappers_*.py" -o \ -name "jsonschema_collapse_root_models_name_strategy_complex_*.py" echo "" echo "If both pydantic v1/v2 complex-parent runs are intended to share one golden file, you should see only:" echo " jsonschema_collapse_root_models_name_strategy_complex_parent.py" echo "Otherwise, consider adding a separate *_v2.py and updating the test accordingly."
🧹 Nitpick comments (13)
tests/main/graphql/test_main_graphql.py (1)
368-424: Consider parametrizing these similar tests.All three tests share nearly identical structure (same input, output, skip condition) and differ only in the extra arguments and JSON files used. Consider parametrizing them to reduce duplication:
🔎 Example parametrization approach
+@pytest.mark.parametrize( + ("scenario", "extra_args", "expected_file"), + [ + ( + "extra_template_data_string", + ["--extra-template-data", str(GRAPHQL_DATA_PATH / "additional-imports-in-extra-template-data.json")], + "additional_imports.py", + ), + ( + "extra_template_data_list", + ["--extra-template-data", str(GRAPHQL_DATA_PATH / "additional-imports-list-format.json")], + "additional_imports.py", + ), + ( + "merged", + [ + "--extra-template-data", str(GRAPHQL_DATA_PATH / "additional-imports-partial.json"), + "--additional-imports", "datetime.date,mymodule.myclass.MyCustomPythonClass", + ], + "additional_imports.py", + ), + ], +) @pytest.mark.skipif( black.__version__.split(".")[0] == "19", reason="Installed black doesn't support the old style", ) -def test_main_graphql_additional_imports_in_extra_template_data(output_file: Path) -> None: - """Test additional_imports specified in extra-template-data JSON file (string format).""" +def test_main_graphql_additional_imports_scenarios(scenario: str, extra_args: list, expected_file: str, output_file: Path) -> None: + """Test additional_imports with various input scenarios.""" run_main_and_assert( input_path=GRAPHQL_DATA_PATH / "additional-imports.graphql", output_path=output_file, input_file_type="graphql", assert_func=assert_file_content, - expected_file="additional_imports.py", - extra_args=[ - "--extra-template-data", - str(GRAPHQL_DATA_PATH / "additional-imports-in-extra-template-data.json"), - ], + expected_file=expected_file, + extra_args=extra_args, ) - - -@pytest.mark.skipif( - black.__version__.split(".")[0] == "19", - reason="Installed black doesn't support the old style", -) -def test_main_graphql_additional_imports_in_extra_template_data_list_format(output_file: Path) -> None: - """Test additional_imports specified in extra-template-data JSON file (list format).""" - run_main_and_assert( - input_path=GRAPHQL_DATA_PATH / "additional-imports.graphql", - output_path=output_file, - input_file_type="graphql", - assert_func=assert_file_content, - expected_file="additional_imports.py", - extra_args=[ - "--extra-template-data", - str(GRAPHQL_DATA_PATH / "additional-imports-list-format.json"), - ], - ) - - -@pytest.mark.skipif( - black.__version__.split(".")[0] == "19", - reason="Installed black doesn't support the old style", -) -def test_main_graphql_additional_imports_merged(output_file: Path) -> None: - """Test merging additional_imports from CLI and extra-template-data JSON.""" - run_main_and_assert( - input_path=GRAPHQL_DATA_PATH / "additional-imports.graphql", - output_path=output_file, - input_file_type="graphql", - assert_func=assert_file_content, - expected_file="additional_imports.py", - extra_args=[ - "--extra-template-data", - str(GRAPHQL_DATA_PATH / "additional-imports-partial.json"), - "--additional-imports", - "datetime.date,mymodule.myclass.MyCustomPythonClass", - ], - )src/datamodel_code_generator/http.py (1)
32-32: Remove unusednoqadirective.Static analysis indicates that
FBT001andFBT002rules are not enabled, making thisnoqadirective unnecessary.🔎 Proposed fix
- ignore_tls: bool = False, # noqa: FBT001, FBT002 + ignore_tls: bool = False,tests/main/openapi/test_main_openapi.py (1)
32-32: Cache clearing for schema extension tests is appropriate but couples to private helpersImporting
datamodel_code_generator.model.baseand calling_get_environment.cache_clear()/_get_template_with_custom_dir.cache_clear()beforetest_main_openapi_schema_extensionsis a reasonable way to avoid cross-test interference from the new Jinja2 environment/template caching. The test itself cleanly exercises schema extensions via a custom template dir. The only minor downside is coupling to underscored helpers; if their implementation stops usinglru_cache, this test will need updating, but that’s acceptable for a targeted regression test.Also applies to: 613-634
src/datamodel_code_generator/__init__.py (1)
1001-1043: Consider extracting shared logic to reduce duplication.The future import extraction logic in lines 1008-1035 duplicates the logic in
_build_module_content(lines 493-519). While the file-writing case handlesfuture_importsslightly differently (using pre-extractedresult.future_imports), the core extraction and header manipulation logic is identical.This is a minor maintainability concern - if the header/future-import handling logic needs to change, it must be updated in both places.
src/datamodel_code_generator/parser/base.py (3)
682-793: Parser.init wiring for new options looks correct; watch default behavior for name strategy
use_field_description_example,http_timeout, andcollapse_root_models_name_strategyare added to the constructor and stored onself, and they’re consistently threaded to where they’re used.- One thing to double‑check: with
collapse_root_models=Trueandcollapse_root_models_name_strategy=None(the default in this signature), the behavior in__collapse_root_modelschanges for root models that wrap another model via reference (they’re now skipped entirely in that branch). If historical behavior was to always keep the child name, you may want to ensure that the CLI (and any programmatic entry points) explicitly passCollapseRootModelsNameStrategy.Childwhencollapse_root_modelsis enabled, or defaultNonetoChildinside the parser to avoid silent behavior changes for library users.Also applies to: 835-836, 938-939, 947-949
1059-1068: HTTP timeout integration into _get_text_from_url is sound; trim unused noqa
- Using
self.http_timeoutwith fallback toDEFAULT_HTTP_TIMEOUTand passing it through toget_bodycleanly introduces per‑parser HTTP timeouts without changing existing call sites.- Ruff reports
# noqa: PLC0415as unused under current settings; you can safely drop this directive to avoid RUF100 noise.Suggested cleanup
- def _get_text_from_url(self, url: str) -> str: - from datamodel_code_generator.http import DEFAULT_HTTP_TIMEOUT, get_body # noqa: PLC0415 + def _get_text_from_url(self, url: str) -> str: + from datamodel_code_generator.http import DEFAULT_HTTP_TIMEOUT, get_body
1688-1780: Collapse-root-models naming strategy logic is mostly solid; confirm defaults and consider minor robustness tweaks
- The new
CollapseRootModelsNameStrategyhandling looks careful:
- For
Parent, you guard against:
- Multiple distinct root wrappers for the same inner model (
root_model_wrapperslength check).- Direct references to the inner model from non‑wrapper models (
direct_refs).- On success, you correctly:
- Rename
inner_model.class_name.- Update
inner_model.reference.name.- Call
inner_model.set_reference_path(root_type_model.reference.path)sopathand related metadata stay consistent (matches the pattern used in__rename_and_relocate_scc_models).- Rebind
data_type.referenceand clean uproot_type_model.reference.children, imports, and unused wrappers.- Two points to consider:
- Default strategy behavior: when
root_type_field.data_type.referenceis set andcollapse_root_models_name_strategy is None, the code now skips collapsing entirely (continue). If “child” naming was the previous default, this changes behavior for callers who enablecollapse_root_modelsbut don’t pass a strategy (especially programmatic uses ofParser/JsonSchemaParser). It might be safer to:
- Treat
NoneasCollapseRootModelsNameStrategy.Childinside this method, or- Normalize
NonetoChildin__init__whencollapse_root_modelsisTrue.
Please verify this against existing behavior and tests.- Duplicate wrapper detection:
root_model_wrappersis a list and can contain the same wrapper multiple times if the inner model is referenced multiple times within a single root wrapper (unlikely but possible with complex schemas). Converting this to a set before thelen(...) > 1check would make the “multiple root models” warning more precise.Also, Ruff flags the
# noqa: PLR0912, PLR0914, PLR0915on the function definition as unused under current rules; you can drop it if you’re not enabling those checks.Optional robustness tweak for wrapper collection
- root_model_wrappers = [ - parent_model - for child in inner_reference.children - if isinstance(child, DataType) - and (parent_model := get_most_of_parent(child, DataModel)) - and isinstance(parent_model, self.data_model_root_type) - ] + root_model_wrappers = { + parent_model + for child in inner_reference.children + if isinstance(child, DataType) + and (parent_model := get_most_of_parent(child, DataModel)) + and isinstance(parent_model, self.data_model_root_type) + } ... - if len(root_model_wrappers) > 1: + if len(root_model_wrappers) > 1: warn( - f"Cannot apply 'parent' strategy for '{inner_model.class_name}' - " - f"it is referenced by multiple root models: " - f"{[m.class_name for m in root_model_wrappers]}. Skipping collapse.", + f"Cannot apply 'parent' strategy for '{inner_model.class_name}' - " + f"it is referenced by multiple root models: " + f"{[m.class_name for m in root_model_wrappers]}. Skipping collapse.",src/datamodel_code_generator/parser/jsonschema.py (5)
329-347: JsonSchemaObject: propertyNames support and x-propertyNames shim look correct; clean up unused noqa
- Adding
propertyNames: Optional[JsonSchemaObject]aligns with JSON Schema and your laterparse_property_namesimplementation.- The
__init__logic to support the OpenAPI 3.0x-propertyNamesextension (parsing it into aJsonSchemaObjectviamodel_validateand storing inpropertyNames) is sensible, and popping it fromextrasavoids duplication.- Ruff notes the
# noqa: N815, UP045on thepropertyNamesfield as unused under current configuration; you can safely remove that directive.Suggested minor cleanup
- propertyNames: Optional[JsonSchemaObject] = None # noqa: N815, UP045 + propertyNames: Optional[JsonSchemaObject] = NoneAlso applies to: 383-399
1605-1623: _is_root_model_schema correctly treats propertyNames as non-root; unused noqa hint
- Adding
obj.propertyNamesto the list of disqualifiers for “root model schema” is correct: if propertyNames is present, the schema is better treated via the object/property‑names path instead of primitive root‑type handling.- Ruff reports the
# noqa: PLR0911here as unused under current rules; removing it would avoid RUF100 noise.Suggested cleanup
- def _is_root_model_schema(self, obj: JsonSchemaObject) -> bool: # noqa: PLR0911 + def _is_root_model_schema(self, obj: JsonSchemaObject) -> bool:
1730-1784: propertyNames support is a solid first pass; note interaction with patternProperties
parse_property_namesbuilds a dict type where:
- The value type is taken from
additionalProperties(falling back toAny), which matches JSON Schema’s semantics for map values.- The key type is:
- A Literal over string enums if
propertyNames.enumcontains strings.- A constrained string type when
pattern,minLength, ormaxLengthare present.- A plain string otherwise.
- Routing is added in:
parse_item:if item.is_object or item.patternProperties or item.propertyNames: ...then falls through topatternPropertiesorpropertyNameshandling when there are no explicitproperties.parse_root_type: choosespatternPropertiesfirst, thenpropertyNames, then other branches.parse_obj:elif obj.patternProperties or obj.propertyNames:now sends such schemas throughparse_root_type.- This is a clear improvement over the previous lack of
propertyNamessupport. One nuance: when bothpatternPropertiesandpropertyNamesare present,patternProperties“wins” andpropertyNamesis ignored. That diverges slightly from the JSON Schema spec (where both constraints can apply), but it still represents strictly better behavior than before. If you want full fidelity later, you might consider combining both constraints into a single dict type instead of usingelif.Also applies to: 2443-2531, 2688-2744, 3283-3284
2222-2237: _validate_schema_object improves error reporting; consider extending to ref loading
_validate_schema_objectwrapsmodel_validatein aSchemaParseErrorthat includes the schema path, which is very helpful for debugging malformed schemas.- It’s correctly used at key entry points:
parse_raw_obj(generic raw handling),- File‑level parsing in
_parse_file(root object, definitions, targeted object paths, and reserved refs).- As a result, most top‑level and definition‑level validation errors will report a clear path.
- Note that
_load_ref_schema_objectstill callsmodel_validatedirectly, so validation errors resolved via$refcan still surface as raw Pydantic exceptions. If you want completely uniform error handling, you could optionally move_validate_schema_objectinto_load_ref_schema_objecttoo by threading through an appropriate path, but that’s an enhancement rather than a blocker.Also applies to: 3246-3247, 3392-3412, 3431-3432
2816-2837: _parse_multiple_types_with_properties: extensions are now propagated to the root wrapper
- For schemas with multiple primitive types plus object properties, the root wrapper created here now also receives schema extensions via
set_schema_extensions, and the newuse_field_description_exampleflag is passed to its root field.- This keeps behavior consistent with
parse_root_typeandparse_object.Also note: Ruff reports
# noqa: FBT001on theadditional_propertiesparameter inparse_property_names(line ~2382) and# noqa: PLR0912, PLR0915onparse_root_type(line ~2688) as unused under current rules, so you can remove them if you want a clean static‑analysis run.tests/main/jsonschema/test_main_jsonschema.py (1)
684-693: HTTP timeout expectations are consistent; consider adding a non-default timeout case.The added
timeout=30.0assertions on allhttpx.getcalls keep the tests aligned with the new default HTTP timeout and look correct across the various URL/headers/TLS scenarios. If you want slightly stronger coverage of--http-timeout, a follow-up test that passes a non-default value (e.g.,--http-timeout 5) and asserts that value is forwarded tohttpx.getwould close the loop, but this is not strictly required for this PR.Also applies to: 730-739, 759-768, 1629-1697, 1781-1850, 5518-5525
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (19)
tests/data/graphql/additional-imports-in-extra-template-data.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/graphql/additional-imports-list-format.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/graphql/additional-imports-partial.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/extras.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/multiline_description_with_example.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/multiple_examples.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/property_names_allof_ref.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/property_names_enum.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/property_names_enum_integers.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/property_names_min_max_length.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/property_names_nested.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/property_names_no_additional.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/property_names_pattern.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/single_line_description_with_example.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/openapi/schema_extensions.yamlis excluded by!tests/data/**/*.yamland included by nonetests/data/openapi/x_property_names.yamlis excluded by!tests/data/**/*.yamland included by nonetests/data/openapi/x_property_names_non_dict.yamlis excluded by!tests/data/**/*.yamland included by nonetests/data/templates_extensions/pydantic_v2/BaseModel.jinja2is excluded by none and included by noneuv.lockis excluded by!**/*.lock,!**/*.lockand included by none
📒 Files selected for processing (48)
docs/cli-reference/field-customization.mddocs/cli-reference/general-options.mddocs/cli-reference/index.mddocs/cli-reference/quick-reference.mddocs/custom_template.mddocs/using_as_module.mdpyproject.tomlsrc/datamodel_code_generator/__init__.pysrc/datamodel_code_generator/__main__.pysrc/datamodel_code_generator/arguments.pysrc/datamodel_code_generator/cli_options.pysrc/datamodel_code_generator/http.pysrc/datamodel_code_generator/model/base.pysrc/datamodel_code_generator/parser/base.pysrc/datamodel_code_generator/parser/graphql.pysrc/datamodel_code_generator/parser/jsonschema.pysrc/datamodel_code_generator/parser/openapi.pysrc/datamodel_code_generator/prompt_data.pytests/data/expected/main/jsonschema/field_extras.pytests/data/expected/main/jsonschema/field_extras_field_extra_keys.pytests/data/expected/main/jsonschema/field_extras_field_extra_keys_v2.pytests/data/expected/main/jsonschema/field_extras_field_include_all_keys.pytests/data/expected/main/jsonschema/field_extras_field_include_all_keys_v2.pytests/data/expected/main/jsonschema/field_extras_v2.pytests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent_v2.pytests/data/expected/main/jsonschema/property_names_allof_ref.pytests/data/expected/main/jsonschema/property_names_enum.pytests/data/expected/main/jsonschema/property_names_enum_integers.pytests/data/expected/main/jsonschema/property_names_min_max_length.pytests/data/expected/main/jsonschema/property_names_nested.pytests/data/expected/main/jsonschema/property_names_no_additional.pytests/data/expected/main/jsonschema/property_names_pattern.pytests/data/expected/main/jsonschema/string_dict.pytests/data/expected/main/openapi/schema_extensions.pytests/data/expected/main/openapi/x_property_names.pytests/data/expected/main/openapi/x_property_names_non_dict.pytests/data/expected/main_kr/main_use_field_description_example/output.pytests/data/expected/main_kr/main_use_field_description_example_multiple/output.pytests/data/expected/main_kr/main_use_field_description_with_example/output.pytests/data/expected/main_kr/main_use_inline_field_description_example_only/output.pytests/data/expected/main_kr/main_use_inline_field_description_with_example/output.pytests/main/graphql/test_main_graphql.pytests/main/jsonschema/test_main_jsonschema.pytests/main/openapi/test_main_openapi.pytests/main/test_main_general.pytests/main/test_main_json.pytests/parser/test_jsonschema.pytests/test_main_kr.py
✅ Files skipped from review due to trivial changes (1)
- tests/data/expected/main_kr/main_use_field_description_example/output.py
🚧 Files skipped from review as they are similar to previous changes (4)
- src/datamodel_code_generator/arguments.py
- src/datamodel_code_generator/prompt_data.py
- docs/cli-reference/index.md
- src/datamodel_code_generator/parser/graphql.py
🧰 Additional context used
🧬 Code graph analysis (18)
tests/data/expected/main/jsonschema/field_extras_field_include_all_keys.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
Field(6-7)
tests/data/expected/main/jsonschema/property_names_pattern.py (1)
tests/data/expected/main/openapi/x_property_names.py (1)
PatternKeys(10-11)
tests/data/expected/main/openapi/x_property_names.py (1)
tests/data/expected/main/jsonschema/property_names_pattern.py (1)
PatternKeys(10-11)
tests/data/expected/main/jsonschema/property_names_enum_integers.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
Field(6-7)
tests/data/expected/main/jsonschema/field_extras_field_extra_keys.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
Field(6-7)
tests/main/test_main_general.py (1)
src/datamodel_code_generator/__init__.py (4)
Error(370-379)InputFileType(204-214)SchemaParseError(411-431)generate(523-1059)
src/datamodel_code_generator/__main__.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(309-317)
tests/test_main_kr.py (3)
tests/main/conftest.py (3)
run_main_with_args(215-241)output_file(98-100)run_main_and_assert(244-408)src/datamodel_code_generator/__main__.py (3)
Exit(95-101)main(878-1141)get(118-120)tests/conftest.py (1)
freeze_time(285-288)
tests/data/expected/main/jsonschema/property_names_enum.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
Field(6-7)
src/datamodel_code_generator/parser/base.py (2)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(309-317)src/datamodel_code_generator/http.py (1)
get_body(29-45)
src/datamodel_code_generator/parser/jsonschema.py (2)
src/datamodel_code_generator/__init__.py (2)
CollapseRootModelsNameStrategy(309-317)SchemaParseError(411-431)src/datamodel_code_generator/util.py (1)
model_validate(201-205)
src/datamodel_code_generator/parser/openapi.py (1)
src/datamodel_code_generator/__init__.py (1)
CollapseRootModelsNameStrategy(309-317)
tests/data/expected/main/jsonschema/string_dict.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
Field(6-7)
tests/data/expected/main_kr/main_use_field_description_example_multiple/output.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
Field(6-7)
tests/main/jsonschema/test_main_jsonschema.py (1)
tests/main/conftest.py (2)
output_file(98-100)run_main_and_assert(244-408)
tests/data/expected/main/openapi/schema_extensions.py (1)
src/datamodel_code_generator/model/base.py (1)
name(764-766)
tests/main/openapi/test_main_openapi.py (1)
src/datamodel_code_generator/model/base.py (2)
_get_environment(428-443)_get_template_with_custom_dir(447-459)
src/datamodel_code_generator/__init__.py (1)
src/datamodel_code_generator/http.py (1)
get_body(29-45)
🪛 markdownlint-cli2 (0.18.1)
docs/custom_template.md
86-86: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
111-111: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
122-122: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
129-129: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/__main__.py
485-485: Unused noqa directive (non-enabled: UP045)
Remove unused noqa directive
(RUF100)
490-490: Unused noqa directive (non-enabled: UP045)
Remove unused noqa directive
(RUF100)
493-493: Unused noqa directive (non-enabled: UP045)
Remove unused noqa directive
(RUF100)
985-985: Unused noqa directive (non-enabled: T201)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/parser/base.py
1060-1060: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
1688-1688: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/http.py
32-32: Unused noqa directive (non-enabled: FBT001, FBT002)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/parser/jsonschema.py
346-346: Unused noqa directive (non-enabled: N815, UP045)
Remove unused noqa directive
(RUF100)
1605-1605: Unused noqa directive (non-enabled: PLR0911)
Remove unused noqa directive
(RUF100)
2382-2382: Unused noqa directive (non-enabled: FBT001)
Remove unused noqa directive
(RUF100)
2688-2688: Unused noqa directive (non-enabled: PLR0912, PLR0915)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/__init__.py
660-660: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
🔇 Additional comments (85)
tests/data/expected/main/jsonschema/field_extras_field_extra_keys_v2.py (1)
19-19: Code is technically correct; verify relevance to PR scope.The addition of the
statusfield is syntactically correct and follows standard Pydantic patterns. However, this test file appears to validate field extras functionality, while the PR objectives focus on adding--collapse-root-models-name-strategy.Please confirm this change is intentional and related to the PR scope, or if it's a side effect of test fixture regeneration.
tests/data/expected/main/jsonschema/string_dict.py (2)
7-7: LGTM!The
Fieldimport is correctly added to support the title parameter on the__root__field below.
11-11: LGTM! Consider verifying alignment with the new naming strategy.The addition of
Field(..., title='MyStringDict')correctly preserves the model name as a title on the root field. This aligns with the PR's objective to add a naming strategy for collapsed root models.Since this is a test expectation file, please verify that this output correctly demonstrates the intended behavior of the new
--collapse-root-models-name-strategyoption when preserving parent/root model names.tests/data/expected/main_kr/main_use_inline_field_description_with_example/output.py (1)
1-21: LGTM - Valid test fixture for inline field description with example.This test fixture correctly demonstrates the expected output when using the
--use-field-description-exampleoption with multiline descriptions. The attribute docstring pattern following the field definition is a recognized convention for documentation tools.tests/data/expected/main_kr/main_use_inline_field_description_example_only/output.py (1)
1-14: LGTM - Valid test fixture for example-only inline documentation.The fixture correctly shows the expected output when a field has a single-line description with an example, where the attribute docstring displays only the example value.
tests/data/expected/main_kr/main_use_field_description_example_multiple/output.py (1)
1-18: LGTM - Valid test fixture for multiple examples.The fixture correctly demonstrates the expected output when a field has multiple examples, using the
examples(plural) parameter inField()and formatting them as a bullet list in the attribute docstring.tests/data/expected/main_kr/main_use_field_description_with_example/output.py (1)
1-26: LGTM - Valid test fixture demonstrating various example patterns.The fixture correctly demonstrates multiple field example scenarios:
- Single example with description
- Both
exampleandexamplesparameters (line 17 shows the expected behavior when both are present)examplesonly with array valueThe attribute docstrings are consistently formatted for each pattern.
pyproject.toml (1)
107-107: Version 0.0.15 is the latest available version and is safe to use.The zensical version is current and valid. There are no newer releases available, and the bump from 0.0.13 to 0.0.15 aligns with recent development activity in the library.
tests/main/graphql/test_main_graphql.py (4)
368-384: LGTM! Test follows established patterns.The test correctly verifies that
additional_importscan be specified via the--extra-template-dataJSON file in string format. The structure, skip condition, and assertion approach are consistent with existing tests in this file.
387-403: LGTM! List format test is well-structured.This test properly verifies that
additional_importscan be specified in list format within the extra-template-data JSON, complementing the string format test above.
406-424: LGTM! Merge test covers an important scenario.This test correctly verifies that
additional_importsfrom both CLI (--additional-imports) and extra-template-data are properly merged, which is essential functionality.
368-424: Clarify relationship to PR objectives.The PR title is "Add --collapse-root-models-name-strategy" and references issue #1418 about preserving root model names during collapse operations. However, these tests are for
additional_importsfunctionality in GraphQL code generation, which appears unrelated to the stated PR objectives.Please clarify:
- Are these tests part of a separate feature that was bundled into this PR?
- Is the AI summary incomplete and missing context about additional_imports changes?
- Should these tests be in a different PR?
tests/data/expected/main/jsonschema/property_names_min_max_length.py (1)
7-13: No changes needed. This is a test fixture showing the expected generator output when--field-constraintsis not specified. The generator deliberately producesconstrby default and supports modernAnnotated[str, StringConstraints(...)]patterns via the--field-constraintsflag. The test explicitly validates thatconstris generated for this scenario.Likely an incorrect or invalid review comment.
tests/main/test_main_json.py (1)
182-182: LGTM! HTTP timeout assertion updated correctly.The test now correctly asserts that
timeout=30.0is passed tohttpx.get, aligning with the new HTTP timeout functionality introduced in this PR.tests/parser/test_jsonschema.py (1)
90-90: LGTM! HTTP timeout assertions updated consistently.All test assertions now correctly verify that
timeout=30.0is passed tohttpx.getcalls, ensuring the new HTTP timeout functionality is properly tested across JSON Schema parser scenarios.Also applies to: 120-120, 158-158, 193-193
tests/data/expected/main/jsonschema/field_extras_field_include_all_keys_v2.py (1)
32-32: LGTM! Expected test output updated correctly.The addition of the
statusfield with an example demonstrates correct handling of field examples in the generated code.tests/data/expected/main/openapi/x_property_names_non_dict.py (1)
1-11: LGTM! Expected output for x-propertyNames test case.The generated code correctly uses
RootModel[dict[str, str]]to represent a non-dict property names scenario for OpenAPI schema extensions.tests/data/expected/main/jsonschema/property_names_no_additional.py (1)
1-13: LGTM! Expected output for propertyNames constraint.The generated code correctly applies the pattern constraint
^[a-z]+$to dictionary keys usingconstr, demonstrating proper handling of JSON SchemapropertyNamesvalidation.tests/data/expected/main/jsonschema/property_names_enum.py (1)
1-13: LGTM! Expected output for propertyNames enum constraint.The generated code correctly uses
Literal['name', 'age', 'email']to constrain dictionary keys to specific values, demonstrating proper handling of JSON SchemapropertyNameswith enum validation.tests/data/expected/main/jsonschema/property_names_enum_integers.py (1)
1-11: LGTM! Expected output for integer enum propertyNames.The generated code correctly falls back to
dict[str, str]for integer enum constraints on property names, which is appropriate since JSON object keys must be strings.tests/data/expected/main/openapi/x_property_names.py (1)
1-11: LGTM! Expected output for OpenAPI x-propertyNames extension.The generated code correctly handles the
x-propertyNamesextension by applying pattern constraints to dictionary keys usingconstr(pattern=r'^[a-z]+$'), consistent with JSON SchemapropertyNameshandling.tests/data/expected/main/jsonschema/property_names_pattern.py (1)
1-11: LGTM!The generated test file correctly demonstrates the new
propertyNamespattern constraint support. TheRootModelwithdict[constr(pattern=...), str]is the appropriate pattern for constraining dictionary keys, and the structure aligns with the similar file intests/data/expected/main/openapi/x_property_names.py.src/datamodel_code_generator/model/base.py (3)
322-332: Edge case: emptyexampleslist may cause unexpected behavior.The condition on line 326
if examples and isinstance(examples, list) and len(examples) > 1correctly guards against empty lists for the multi-example case. However, line 331elif examples and isinstance(examples, list) and len(examples) == 1handles single-item lists.If
examplesis an empty list[], both conditions are false, so no example is added—which is correct. The logic handles this edge case properly.
317-320: Verify the interaction betweenuse_inline_field_descriptionanduse_field_description_example.This block only adds the description to
partswhen using inline field description with examples AND the description contains a newline. This seems intentional to prevent duplicating single-line descriptions (which would appear both inline and in docstring).However, the condition
elif self.use_inline_field_description and self.use_field_description_examplemeans this block is only reached whenuse_field_descriptionis False (due to the precedingif). Ensure this interaction is the intended behavior for the combined flags.
152-152: LGTM!The new
use_field_description_examplefield follows the established pattern for boolean configuration flags inDataModelFieldBase.tests/data/expected/main/openapi/schema_extensions.py (1)
1-19: LGTM!The generated test file correctly demonstrates the new schema extensions (
x-*) support, with the__collection__class attribute being populated from OpenAPI schema extensions. This validates that extensions are properly passed through to custom templates.tests/data/expected/main/jsonschema/property_names_nested.py (1)
1-11: LGTM!The generated test file correctly demonstrates
propertyNamesconstraints on nested dictionary properties. TheParentmodel with an optionalchildfield of typedict[constr(pattern=...), str]properly shows how key constraints propagate to nested object properties.tests/data/expected/main/jsonschema/jsonschema_collapse_root_models_name_strategy_nested_wrappers_parent_v2.py (1)
1-19: LGTM!The generated test file correctly demonstrates the "Parent" naming strategy for
--collapse-root-models-name-strategy. With the parent strategy,OuterWrapperretains its name (the outer/root model's name) rather than being replaced by the inner model's name. This aligns with the PR objective from issue #1418.src/datamodel_code_generator/http.py (2)
26-27: LGTM!The
DEFAULT_HTTP_TIMEOUT = 30.0constant is a sensible default and is properly used as the parameter default value.
34-45: LGTM!The
timeoutparameter is correctly added and properly passed through tohttpx.get(). The implementation follows the existing pattern for other HTTP configuration parameters.tests/test_main_kr.py (5)
334-356: LGTM!Good test coverage for the new
--use-field-description-exampleflag. The test is properly decorated with@pytest.mark.cli_docfor documentation generation and uses the establishedrun_main_and_assertpattern.
359-404: Good coverage of combined flag scenarios.These tests cover important combinations:
--use-field-description+--use-field-description-example--use-inline-field-description+--use-field-description-exampleThis ensures the interaction between description-related flags works correctly.
407-437: Good edge case coverage.Tests for:
- Single-line description with inline + example flags (only example in docstring)
- Multiple examples formatting as bulleted list
These align with the logic implemented in
DataModelFieldBase.docstring.
1538-1570: LGTM!The HTTP timeout test properly:
- Mocks
httpx.getto avoid actual network calls- Passes
--http-timeout 60via CLI- Asserts the timeout value is correctly passed to
httpx.getas60.0
104-109: Behavior is correct and intentional.When no
--outputfile is specified, the tool correctly outputs generated code to stdout. The test properly verifies that running with modular input and no output file produces the expected classes in stdout.tests/data/expected/main/jsonschema/field_extras_field_include_all_keys.py (1)
27-28: LGTM!The new
statusfield follows the established pattern for field extras, usingField(None, examples=['active'])which aligns with the existingagefield's use of theexamplesparameter.tests/data/expected/main/jsonschema/field_extras_field_extra_keys.py (1)
20-20: LGTM!The new
statusfield follows the same pattern as existing fields and correctly uses theexamplesparameter.tests/data/expected/main/jsonschema/field_extras.py (1)
13-13: LGTM!The
statusfield addition is consistent with the test expectations for field examples support.tests/data/expected/main/jsonschema/field_extras_v2.py (1)
13-13: LGTM!Consistent addition of the
statusfield with examples support.docs/custom_template.md (1)
78-159: LGTM! Well-documented feature addition.The Schema Extensions documentation is clear and includes helpful examples showing how to use x- prefixed fields in custom templates. The static analysis warnings about "emphasis as heading" (MD036) are false positives—the bold text labels are appropriate for code example annotations, not misused headings.
docs/cli-reference/quick-reference.md (1)
74-74: LGTM! Clean documentation additions.The three new CLI options are properly documented in both the categorized tables and alphabetical index with correct links and descriptions.
Also applies to: 90-90, 164-164, 203-203, 239-239, 291-291
src/datamodel_code_generator/cli_options.py (1)
84-86: LGTM! Properly categorized CLI option metadata.The three new CLI options are correctly registered with appropriate categories (MODEL, FIELD, GENERAL) and follow the established pattern.
Also applies to: 137-139, 239-239
docs/cli-reference/general-options.md (1)
1605-1662: The--http-timeoutdocumentation is well-structured with no duplication issues.The search confirms only one
--http-timeoutsection exists in the file (line 1605). No duplication was found. The documentation includes clear descriptions, usage examples, and concrete JSON/Python code samples.tests/data/expected/main/jsonschema/property_names_allof_ref.py (1)
14-15: Input schema file not found; unable to verify expected output.The expected output file references
property_names_allof_ref.jsonas input, but this file could not be located in the repository despite thorough searching. Without access to the input schema, the correctness of the emptyModelclass cannot be verified.docs/cli-reference/field-customization.md (1)
25-26: New field-description example option and examples look coherentThe added
--use-field-description-examplerow, updated extras/status examples, and the new sections for both--use-field-description-exampleand--use-inline-field-descriptionare internally consistent: inputs and outputs line up, anchors match option names, and behavior is described clearly (single vs multiple examples, interaction with descriptions). I don’t see any issues here.Also applies to: 1556-1566, 1575-1596, 1600-1620, 1670-1720, 2879-2970, 2974-3306
tests/main/openapi/test_main_openapi.py (2)
1681-1697: HTTP timeout assertions correctly cover new default behaviorThe updated
httpx_get_mock.assert_has_callsexpectations now includetimeout=30.0for both the primary OpenAPI fetch and nested refs, and similarly for the body/parameters remote ref test. This accurately pins the new default timeout wiring without over-specifying other parameters. Looks good.Also applies to: 1758-1765
4466-4487: x-propertyNames tests nicely cover both happy path and invalid-input behaviorThe new tests for
x-propertyNamesverify both correct translation topropertyNamesand the non-dict case being ignored, following the existing OpenAPI test patterns (input path, expected file, pydantic_v2 output). This gives solid coverage for the extension handling with clear, focused assertions.docs/using_as_module.md (1)
7-8: Updated generate() usage and return-value docs are clear and consistentThe new sections for getting generated code as a string, handling multi-module output via
GeneratedModules, and the return-value summary table accurately describe the different behaviors based onoutput. The examples are coherent and the note about raisingdatamodel_code_generator.Errorwhen multiple modules target a single file path sets expectations well.Also applies to: 15-62, 190-199
src/datamodel_code_generator/parser/openapi.py (4)
20-38: LGTM!The
CollapseRootModelsNameStrategyimport is correctly added alongside related imports fromdatamodel_code_generator.
184-298: LGTM!The three new parameters (
use_field_description_example,http_timeout,collapse_root_models_name_strategy) are properly added to the__init__signature with correct type annotations and default values that match their usage patterns.
301-410: LGTM!All three new parameters are correctly propagated to the
super().__init__()call, maintaining consistency with the parameter order in the parentJsonSchemaParserclass.
748-779: LGTM!The
use_field_description_exampleparameter is correctly propagated to thedata_model_field_typeconstructor call withinparse_all_parameters, enabling field description examples to be included when parsing operation parameters.tests/main/test_main_general.py (6)
10-22: LGTM!New imports for
inline_snapshot,GeneratedModules, andSchemaParseErrorare correctly added to support the new test cases.
479-554: LGTM!Comprehensive test coverage for
SchemaParseError:
test_schema_parse_error_includes_path: Validates error message contains schema path contexttest_schema_parse_error_includes_nested_path: Validates nested path references (e.g.,$defs/MyModel)test_schema_parse_error_original_error: Verifiesoriginal_errorandpathattributes are preservedtest_schema_parse_error_without_path: Tests error formatting when no path is provided
1517-1591: LGTM!Good test coverage for the
generate()return value behavior:
- Returns
strwhenoutput=Nonefor single file- Returns
strfor Pydantic v2 and dataclass model types- Returns
Nonewhen an output path is provided
1593-1630: LGTM!
test_generate_file_content_matches_return_valueproperly validates that the string returned bygenerate()withoutput=Nonematches the content written to a file whenoutputis provided. This is important for API consistency.
1632-1723: Consider adding cleanup for temporary files.The test creates two schema files in
tmp_pathbut relies solely on pytest'stmp_pathfixture for cleanup. While this works, the test could be more robust by verifying the returned dict structure more explicitly.Also, the snapshot at line 1673-1676 shows
test_generate_returns_dict_for0which appears truncated - this is expected behavior from the temp directory name, but the assertion validates the structure correctly.
1725-1792: LGTM!Good coverage of
custom_file_headerbehavior withgenerate():
- Basic custom header
- Header containing code after docstring (validates future import extraction)
- Header with
disable_future_imports=Truesrc/datamodel_code_generator/__main__.py (7)
23-43: LGTM!The
CollapseRootModelsNameStrategyimport is correctly added to the imports fromdatamodel_code_generator.
449-449: LGTM!New
use_field_description_exampleconfig field correctly added withbooltype andFalsedefault.
485-493: LGTM!New config fields
http_timeoutandcollapse_root_models_name_strategyare correctly added with appropriate types and defaults.
551-563: LGTM!The
_extract_additional_importshelper function cleanly extractsadditional_importsfromextra_template_dataentries, handling both string and list formats. The use ofpop()ensures imports aren't duplicated in the template data.
741-876: LGTM!
run_generate_from_configproperly:
- Passes through the three new parameters (
use_field_description_example,http_timeout,collapse_root_models_name_strategy)- Captures the return value from
generate()- Handles both
stranddictreturn types whenoutput is None, writing to stdout appropriately
984-990: LGTM!Proper validation that
--collapse-root-models-name-strategyrequires--collapse-root-modelsto be set. This prevents user confusion from setting a naming strategy without enabling the collapse feature.
1016-1024: LGTM!The logic to extract and merge
additional_importsfromextra_template_dataintoconfig.additional_importsis correct. Theasserton line 1017 is safe since we're inside theelsebranch whereextra_template_datais assigned fromjson.load().src/datamodel_code_generator/__init__.py (9)
85-91: LGTM!The
GeneratedModulestype alias is well-defined and documented. Usingtuple[str, ...]as the key type allows for flexible module path representation (e.g.,("models", "user.py")).
309-318: LGTM!The
CollapseRootModelsNameStrategyenum is correctly defined with clear documentation explaining theChildandParentstrategies for naming when collapsing root models.
411-432: LGTM!The
SchemaParseErrorexception class properly:
- Extends the base
Errorclass- Stores path and original_error for debugging
- Formats the message with path context when available
- Falls back to plain message when no path is provided
482-521: LGTM!The
_build_module_contenthelper function correctly handles:
- Future import extraction and repositioning after custom headers
- Header insertion point calculation via
_find_future_import_insertion_point- Edge cases when body is empty or no custom header is provided
523-654: LGTM!The
generate()function signature is properly updated with:
- New parameters:
use_field_description_example,http_timeout,collapse_root_models_name_strategy- Updated return type annotation:
str | GeneratedModules | None- Updated docstring documenting the three return scenarios
656-668: LGTM!The HTTP timeout handling correctly:
- Imports
DEFAULT_HTTP_TIMEOUTfrom the http module- Uses user-provided
http_timeoutif not None, otherwise falls back to default- Passes the timeout to
get_body()call
841-888: LGTM!All three new parameters are correctly passed to the parser constructor:
use_field_description_example(line 841)http_timeout(line 878)collapse_root_models_name_strategy(line 887)
948-979: LGTM!The new return value handling for
output=Nonecase properly:
- Returns
strfor single-module output (using_build_module_content)- Returns
GeneratedModulesdict for multi-module output- Correctly sanitizes filenames and applies custom headers
1086-1107: LGTM!The
__all__list is correctly updated to exportGeneratedModulesandSchemaParseError.src/datamodel_code_generator/parser/base.py (2)
25-38: New CollapseRootModelsNameStrategy import is consistent with downstream usageThe enum import is correctly added and matches the new
collapse_root_models_name_strategytype annotations below. No issues here.
2911-2923: Updated __collapse_root_models call signature is consistentPassing
importsandscoped_model_resolverinto__collapse_root_modelsmatches the updated method signature and enables it to manage imports when collapsing/root‑model rewrites are performed. No functional concerns here.src/datamodel_code_generator/parser/jsonschema.py (8)
24-41: New imports (CollapseRootModelsNameStrategy, SchemaParseError) are appropriateBoth
CollapseRootModelsNameStrategyandSchemaParseErrorare used meaningfully later (JsonSchemaParser.__init__and_validate_schema_objectrespectively). The import block remains tidy and consistent with existing style.
534-757: JsonSchemaParser.init: new options are correctly threaded to the base Parser
- The new parameters
use_field_description_example,http_timeout, andcollapse_root_models_name_strategyare added toJsonSchemaParser.__init__and passed straight through tosuper().__init__, matching the baseParsersignature.- This keeps the JSON Schema parser aligned with the core configuration surface. Just ensure the CLI/options layer is updated to map the new flags correctly (especially defaulting the collapse name strategy as intended).
1105-1107: use_field_description_example is consistently passed to DataModelField constructionThe new
use_field_description_exampleflag is threaded through all relevantdata_model_field_typecall sites (object fields, bool properties, arrays, root types, enums, etc.), matching the parser’sself.use_field_description_exampleattribute. This wiring looks internally consistent; behavior will be driven by the DataModelField implementation.Also applies to: 2197-2212, 2629-2633, 2667-2669, 2770-2772, 2833-2837, 2923-2926, 2955-2958, 3017-3018, 3040-3041
1165-1171: Schema extensions (x-*) are now exposed to templates in a uniform way
set_schema_extensionscorrectly filtersobj.extrasfor keys starting with"x-"and attaches them underextra_template_data[path]["extensions"].- Call sites cover object models, root models (arrays, primitives, combined allOf), and enum root wrappers, so templates can consistently access schema extensions regardless of construct.
- No functional issues spotted; this is a straightforward, useful addition.
Also applies to: 1172-1177, 1920-1921, 2072-2073, 2126-2127, 2297-2299, 2647-2649, 2751-2753, 2817-2819, 2943-2944, 3017-3018
2330-2377: Traversal and patternProperties integration remain consistent after adding propertyNames
parse_pattern_propertiesis unchanged and still aggregates patterns by value type, which is fine._traverse_schema_objectsand_add_id_callbackare extended to descend intopropertyNames, ensuring$idand$refresolution covers constraints defined there as well.- No functional regressions apparent; recursion remains well‑bounded (no new cycles introduced).
Also applies to: 3153-3158
2589-2637: Array parsing + extensions/description-example integration look consistent
parse_array_fieldsandparse_arraynow:
- Preserve the previous constraints/nullable/required logic,
- Attach schema extensions via
set_schema_extensions,- And pass
use_field_description_examplethrough to the constructed field(s).- The self‑reference handling in
parse_arrayis unchanged aside from threading the new flag.- Overall, array behavior should stay backward compatible while enabling the new features.
Also applies to: 2647-2669
2923-3041: Enum parsing: extensions and description-example flag are wired consistently
- For both nullable and non‑nullable enum schemas, the code now:
- Attaches schema extensions to the appropriate reference path before building root wrappers.
- Passes
use_field_description_exampleinto the enum field(s), ensuring this feature applies uniformly.- Control flow and nullability handling are otherwise unchanged, so existing behavior should be preserved.
3132-3213: Traversal and id-resolution updates for propertyNames are correct
_traverse_schema_objectsand_add_id_callbacknow also walkpropertyNames, ensuring both$refresolution and$idregistration work for property‑name constraint schemas.- This mirrors existing handling for
patternPropertiesandadditionalProperties, keeping traversal semantics coherent.tests/main/jsonschema/test_main_jsonschema.py (1)
3117-3220: PropertyNames test matrix looks solid and idiomatic.The new
property_names_*tests cleanly exercise the keypropertyNamesbehaviors (pattern, enum, length, no additionalProperties, nesting, allOf+$ref) againstpydantic_v2.BaseModeland integrate correctly withrun_main_and_assert/golden files. No issues from the test harness side.
Breaking Change AnalysisResult: No breaking changes detected Reasoning: This PR adds a new optional CLI option (--collapse-root-models-name-strategy) and corresponding Python API parameter (collapse_root_models_name_strategy) with default value None. When not specified (the default), the existing behavior of --collapse-root-models is preserved exactly - it continues to skip collapsing root models that reference other models. The new functionality is purely opt-in and requires explicitly passing either 'child' or 'parent' as a value. All existing workflows and generated code remain unchanged unless users explicitly adopt the new option. This is a backwards-compatible additive feature. This analysis was performed by Claude Code Action |
Fixes: #1418
Summary by CodeRabbit
New Features
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.