Add --type-overrides option to replace schema types with custom Python types#2758
Add --type-overrides option to replace schema types with custom Python types#2758
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2758 +/- ##
==========================================
+ Coverage 99.37% 99.47% +0.10%
==========================================
Files 83 83
Lines 12233 12537 +304
Branches 1467 1498 +31
==========================================
+ Hits 12156 12471 +315
+ Misses 45 35 -10
+ Partials 32 31 -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:
|
|
Warning Rate limit exceeded@koxudaxi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 24 minutes and 14 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (15)
WalkthroughA new Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant CLI as CLI/Arguments
participant Config as Config
participant Parser as Parser.\_\_init\_\_
participant ProcessModule as Parser.\_process_single_module
participant Override as Override Logic
User->>CLI: --type-overrides '{"ModelA": "pkg.Type"}'
CLI->>CLI: _type_overrides() validates JSON
CLI->>Config: type_overrides stored in Config
Config->>Parser: type_overrides passed to Parser.__init__
Parser->>Parser: _type_override_imports = Import.from_full_path()
Parser->>ProcessModule: Process models normally
ProcessModule->>Override: Call __remove_overridden_models()
Override->>Override: Filter models by override keys
ProcessModule->>Override: Call __apply_type_overrides()
Override->>Override: Apply scoped (ClassName.field) overrides to fields
Override->>Override: Apply model-level overrides to DataType
Override->>Override: Set Import references and clear nested types
ProcessModule->>Parser: Return processed models with custom types
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the 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 |
CodSpeed Performance ReportMerging #2758 will not alter performanceComparing Summary
Footnotes
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/datamodel_code_generator/arguments.py (1)
67-86: _type_overrides validation looks solid; consider clarifying CLI semantics and input formThe JSON parsing and validation for
_type_overridesare correct and consistent with_dataclass_arguments(good error messages and strictstr -> strmapping). The--type-overridesoption wiring also looks fine.Two points to double‑check:
- The option currently expects an inline JSON string (e.g.
--type-overrides '{"Foo": "pkg.Type"}'), whereas the original issue text suggested a JSON file similar to--aliases. If file-based usage is still desired, you may want to add aPath-based variant or explicit docs that this is inline JSON only.- The help text mentions scoped keys like
"User.field", but the implementation later usesmodel.class_nameandfield.name. If users are expected to key by the Python field name (after snake-casing / renaming) rather than the original schema property name, it’s worth calling that out explicitly in the help to avoid confusion.Also applies to: 533-541
src/datamodel_code_generator/__main__.py (1)
473-474: Config plumbing for type_overrides is correct; consider adding TOML support for dict-valued optionsThe new
Config.type_overrides: Optional[dict[str, str]]field and its propagation viarun_generate_from_config(..., type_overrides=config.type_overrides, ...)intogenerate()look correct and align with the argparse_type_overridesparser and pyproject key normalization (type-overrides→type_overrides).One follow‑up improvement:
generate_pyproject_config()currently formats values via_format_toml_value, which only handlesbool,str, and list/tuple types. Fortype_overrides(and similarlydataclass_arguments), this will serialize the mapping as a TOML array of keys rather than a proper inline table, leading to unusable config if the user runs:datamodel-codegen --type-overrides '{"Foo": "pkg.Type"}' --generate-pyproject-configIt would be worth extending
_format_toml_valueto supportdict[str, TomlValue](emitting{ key = value, ... }) and updatingTomlValueaccordingly, so thattype_overridesround-trips cleanly into pyproject.toml.Also applies to: 784-785
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
tests/data/jsonschema/type_overrides_test.jsonis excluded by!tests/data/**/*.jsonand included by none
📒 Files selected for processing (9)
src/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.pytests/main/test_main_general.py
🔇 Additional comments (10)
src/datamodel_code_generator/parser/jsonschema.py (1)
616-616: LGTM! Clean parameter propagation for type overrides feature.The
type_overridesparameter is correctly added to the signature and passed through to the base parser. The implementation follows the established pattern used by other configuration parameters liketype_mappings.Also applies to: 718-718
src/datamodel_code_generator/parser/graphql.py (1)
195-195: LGTM! Consistent implementation across parsers.The
type_overridesparameter addition mirrors the implementation inJsonSchemaParser, maintaining consistency across parser subclasses. Both parsers correctly delegate the actual override logic to the baseParserclass.Also applies to: 296-296
tests/main/test_main_general.py (4)
21-21: LGTM! Consistent import addition for test validation.The
_type_overridesimport follows the same pattern as_dataclass_arguments, enabling validation function testing for the new feature.
439-471: Excellent validation test coverage.The test cases thoroughly validate the
_type_overridesargument parser, covering:
- Model-level overrides:
{"CustomType": "my_app.types.MyType"}- Scoped overrides:
{"User.field": "my_app.Type"}- Multiple mappings and edge cases (empty dict)
- Comprehensive error scenarios with specific error messages
The test structure mirrors the existing
_dataclass_argumentstests, maintaining consistency.
473-546: Well-documented tests highlighting important behavioral distinctions.The integration tests effectively demonstrate and validate two key scenarios:
Model-level overrides (lines 473-512): Correctly verify that the overridden type model is NOT generated (
assert "class CustomType" not in result) while the import IS added. The@pytest.mark.cli_docwithprimary=Truemakes this the canonical documentation example.Scoped overrides (lines 515-546): The comment at line 542 documents critical behavior: "Address model SHOULD still be generated (scoped override doesn't remove models)". This distinction—that
User.addressoverrides only the field reference, not the model definition—is essential for users to understand.These tests serve as both validation and documentation of the feature's nuanced behavior.
548-583: Comprehensive coverage of nested type scenarios.This test validates that type overrides work correctly with container types (
List[Tag]), ensuring:
- Overridden types aren't generated as models (
assert "class Tag" not in result)- Imports are correctly added (
assert "from my_app import Tag" in result)- The overridden type is properly referenced in nested contexts (array items)
This completes the test coverage for common override scenarios (model-level, scoped, and nested).
src/datamodel_code_generator/parser/openapi.py (1)
279-285: OpenAPIParser correctly forwards type_overrides to the base parserThe new
type_overridesparameter is threaded through the OpenAPI parser’s constructor and passed tosuper().__init__in the correct position alongsidetype_mappings, preserving existing behavior when it’sNone.Also applies to: 382-387
src/datamodel_code_generator/__init__.py (1)
497-504: Public generate() API extension for type_overrides is consistent and non-breakingAdding
type_overridestogenerate()and forwarding it into the parser constructor is done cleanly and maintains backward compatibility (optional arg, defaultNone). This aligns with the CLI/config plumbing and the base parser’s new parameter.Also applies to: 749-751
src/datamodel_code_generator/cli_options.py (1)
171-172: CLI metadata for --type-overrides is correctly categorized
--type-overridesis registered under the Typing customization category, matching the argparse group and keeping the docs metadata in sync.src/datamodel_code_generator/parser/base.py (1)
776-937: The current implementation correctly registers override imports through the property chain; the proposed fix is unnecessary.The review's concern appears to be based on incomplete analysis of the import collection flow. When
__apply_type_overridessetsdata_type.import_ = override_import, these imports are automatically collected through the existing property chain:
data_type.importsproperty yieldsself.import_if setdata_type.all_importsrecursively yields fromself.importsfield.importscollects fromself.data_type.all_importsmodel.importsproperty collects from all field imports_finalize_modulesappendsmodel.importsto the module's importsCrucially,
model.importsis a non-cached property evaluated after__apply_type_overrideshas modified the DataTypes in_process_single_module, so the override imports are properly included. Existing tests (test_type_overrides_model_level,test_type_overrides_scoped,test_type_overrides_nested_types) confirm this behavior by expecting the override imports to be present in the generated output.No changes to the import registration logic are needed. The review's proposed diff, while well-intentioned, introduces unnecessary complexity that the current design already handles correctly through its property-based import collection system.
6916fd7 to
faaa923
Compare
faaa923 to
f9885ea
Compare
Breaking Change AnalysisResult: No breaking changes detected Reasoning: This PR adds a new This analysis was performed by Claude Code Action |
Fixes: #2243
Summary by CodeRabbit
--type-overridesCLI option to customize type mappings during code generation, supporting both model-level and scoped field-level overrides. Users can now map types to custom implementations via JSON-formatted configuration.✏️ Tip: You can customize this high-level summary in your review settings.