Fix reuse-foreign to compare with output type instead of input type#2854
Fix reuse-foreign to compare with output type instead of input type#2854
Conversation
📝 WalkthroughWalkthroughThis PR extends the datamodel-code-generator's type reuse logic to support mixed type families (Pydantic, dataclass, TypedDict, Enum, msgspec) when using the reuse-foreign strategy. It adds type family classification for msgspec, new reuse decision logic based on output model type, and comprehensive test coverage for nested mixed-type scenarios. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant TypeDiscovery as Type Discovery
participant FamilyClass as Family Classification
participant ReuseLogic as Reuse Decision
participant SchemaFilter as Schema Filtering
User->>TypeDiscovery: Load input model with annotations
TypeDiscovery->>TypeDiscovery: Scan for BaseModel, Enum, dataclass,<br/>TypedDict, msgspec structures
TypeDiscovery->>FamilyClass: Provide discovered types
FamilyClass->>FamilyClass: Map each type to family<br/>(PYDANTIC, DATACLASS,<br/>TYPEDDICT, MSGSPEC, ENUM)
FamilyClass->>ReuseLogic: Provide source family & output type
rect rgba(100, 200, 150, 0.3)
Note over ReuseLogic: Reuse Decision Logic
ReuseLogic->>ReuseLogic: Get output family from<br/>output_model_type
ReuseLogic->>ReuseLogic: If Enum: always reuse
ReuseLogic->>ReuseLogic: Else: compare source family<br/>vs output family
end
ReuseLogic->>SchemaFilter: Decision: reuse or regenerate?
SchemaFilter->>SchemaFilter: Filter definitions by<br/>ReuseForeign strategy
SchemaFilter->>User: Output schema with<br/>correct imports/regenerations
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
📚 Docs Preview: https://pr-2854.datamodel-code-generator.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/datamodel_code_generator/__main__.py (1)
1008-1039: Remove unusednoqadirective on line 1016.The static analysis indicates that
# noqa: PLR0911is no longer needed since the rule isn't enabled or the function no longer triggers it.🔎 Proposed fix
-def _get_type_family(tp: type) -> str: # noqa: PLR0911 +def _get_type_family(tp: type) -> str:
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/datamodel_code_generator/__main__.pytests/data/python/input_model/mixed_nested.pytests/test_input_model.py
🧰 Additional context used
🧬 Code graph analysis (1)
src/datamodel_code_generator/__main__.py (1)
src/datamodel_code_generator/enums.py (2)
DataModelType(48-56)InputModelRefStrategy(199-210)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/__main__.py
1016-1016: Unused noqa directive (non-enabled: PLR0911)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: 3.10 on Windows
- GitHub Check: 3.10 on macOS
- GitHub Check: 3.12 on macOS
- GitHub Check: 3.11 on Windows
- GitHub Check: 3.12 on Windows
- GitHub Check: 3.14 on Windows
- GitHub Check: 3.13 on Windows
- GitHub Check: Analyze (python)
- GitHub Check: benchmarks
🔇 Additional comments (15)
tests/test_input_model.py (8)
780-797: LGTM! Test correctly validates reuse-foreign imports enum and same-family types.The test verifies that when using
reuse-foreignstrategy with TypedDict output:
Statusenum is imported (enums always reused)Metadataclass is present (TypedDict reused as same-family)AddressandUserclasses are regenerated
800-821: LGTM! Properly validates that Status TypeAlias is not regenerated when imported.The test correctly asserts that
Status: TypeAliasis not in the output when usingreuse-foreign, confirming the enum is imported rather than regenerated.
967-988: LGTM! Test validates same-family TypedDict reuse.This test correctly verifies that when output is TypedDict and input contains a nested TypedDict (
NestedTypedDict), it's imported rather than regenerated (verified byassert "class NestedTypedDict" not in content).
990-1007: LGTM! Test validates cross-family regeneration.Correctly tests that a Pydantic model (
NestedPydantic) is regenerated when output type is TypedDict, since they belong to different families.
1010-1031: LGTM! Test validates same-family dataclass reuse.Test correctly verifies that when output is dataclass and input contains a nested dataclass (
NestedDataclass), it's imported rather than regenerated.
1033-1056: LGTM! Comprehensive test for mixed nested types.This test validates the complete behavior with mixed types: TypedDict is reused (imported), while Pydantic and dataclass are regenerated when output is TypedDict.
1058-1079: LGTM! Validates Pydantic-to-Pydantic same-family reuse.Test correctly verifies that Pydantic models are imported when output is also Pydantic BaseModel.
1081-1099: LGTM! Test validates msgspec output behavior.This test correctly verifies that non-msgspec types (like Pydantic) are regenerated when output type is msgspec.Struct, confirming the new msgspec family handling works.
src/datamodel_code_generator/__main__.py (6)
924-943: LGTM! Extended type discovery to include TypedDict and msgspec.The updated
_find_models_in_typefunction now correctly identifies:
BaseModelsubclassesEnumsubclasses- Dataclasses
- TypedDict (via
__required_keys__)- msgspec Structs (via
__struct_fields__)This enables proper classification for the reuse-foreign strategy.
1042-1057: LGTM! Proper mapping of DataModelType to type families.The
_get_output_familyfunction correctly maps:
- Pydantic variants (BaseModel, V2BaseModel, V2Dataclass) →
pydantic- DataclassesDataclass →
dataclass- TypingTypedDict →
typeddict- MsgspecStruct →
msgspecThis aligns with the
DataModelTypeenum values shown in the relevant code snippets.
1060-1068: LGTM! Clean reuse decision logic.The
_should_reuse_typefunction correctly implements the reuse-foreign strategy:
- Enums are always reusable (return
True)- Other types are reusable only when source family matches output family
This is the core fix for comparing with output type instead of input type.
1071-1109: LGTM! Updated strategy filtering to use output model type.The
_filter_defs_by_strategyfunction now correctly:
- Derives
output_familyfromoutput_model_type- Uses
_should_reuse_type(type_family, output_family)for the reuse decisionThis is the key change that makes reuse-foreign compare against output type rather than input type.
1112-1116: LGTM! Function signature updated with new parameter.The
output_model_typeparameter with a sensible default allows backward compatibility while enabling the new behavior.
1827-1832: LGTM! Correctly propagates output_model_type to schema loading.The
config.output_model_typeis now passed through to_load_model_schema, ensuring the reuse-foreign strategy uses the correct output type for comparison.tests/data/python/input_model/mixed_nested.py (1)
1-68: LGTM! Well-structured test fixtures for mixed-type reuse scenarios.This test data file provides comprehensive coverage for the reuse-foreign strategy:
Categoryenum (always reused)NestedTypedDict(reused when output is TypedDict)NestedPydantic(reused when output is Pydantic)NestedDataclass(reused when output is dataclass)- Composite models that combine these for testing mixed scenarios
The docstrings clearly document the expected behavior, making tests self-documenting.
CodSpeed Performance ReportMerging #2854 will not alter performanceComparing
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2854 +/- ##
=======================================
Coverage 99.50% 99.50%
=======================================
Files 90 90
Lines 14824 14869 +45
Branches 1777 1781 +4
=======================================
+ Hits 14750 14795 +45
Misses 38 38
Partials 36 36
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:
|
Breaking Change AnalysisResult: Breaking changes detected Reasoning: This PR changes the behavior of the Content for Release NotesDefault Behavior Changes
This analysis was performed by Claude Code Action |
|
🎉 Released in 0.51.0 This PR is now available in the latest release. See the release notes for details. |
Summary by CodeRabbit
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.