Add pydantic_v2.dataclass output type and remove pydantic v1 dataclass#2746
Add pydantic_v2.dataclass output type and remove pydantic v1 dataclass#2746
Conversation
|
Warning Rate limit exceeded@koxudaxi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 36 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 (4)
📒 Files selected for processing (8)
WalkthroughThis PR introduces support for Pydantic v2 dataclasses as an output format. It adds a new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–25 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
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 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2746 +/- ##
========================================
Coverage 99.36% 99.37%
========================================
Files 83 83
Lines 12221 12399 +178
Branches 1466 1479 +13
========================================
+ Hits 12144 12322 +178
Misses 45 45
Partials 32 32
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: 1
🧹 Nitpick comments (3)
src/datamodel_code_generator/model/__init__.py (1)
97-108: Remove unused noqa directive.The implementation correctly adds support for Pydantic v2 dataclasses with proper configuration:
dump_resolve_reference_action=Noneis correct (dataclasses don't needmodel_rebuild())root_model=type_alias_classis correct (dataclasses can't be root models)- Field ordering and DataTypeManager are properly configured
However, the
# noqa: PLC0415directive on line 98 is flagged as unused by static analysis.Based on static analysis, remove the unused noqa directive:
Proposed fix
if data_model_type == DataModelType.PydanticV2Dataclass: - from .pydantic_v2 import dataclass as pydantic_v2_dataclass # noqa: PLC0415 + from .pydantic_v2 import dataclass as pydantic_v2_dataclasssrc/datamodel_code_generator/model/pydantic_v2/dataclass.py (2)
38-38: Remove unused noqa directive.The
noqa: PLR0913directive is unused because PLR0913 (too many arguments) is not enabled in your linter configuration.🔎 Proposed fix
- def __init__( # noqa: PLR0913 + def __init__( self,
77-85: Clarify dataclass_arguments precedence behavior.When
dataclass_argumentsis provided, thefrozenandkeyword_onlyconstructor parameters are ignored. This precedence is reasonable (explicit arguments dictionary takes precedence), but it might surprise users who pass both.Consider documenting this behavior in the docstring or raising a warning if both are provided.
🔎 Example validation
# Handle dataclass decorator arguments if dataclass_arguments is not None: self.dataclass_arguments = dataclass_arguments # Optional: warn if frozen/keyword_only are also provided if (frozen or keyword_only): import warnings warnings.warn( "frozen and keyword_only parameters are ignored when dataclass_arguments is provided", UserWarning, stacklevel=2 ) else: self.dataclass_arguments = {} if frozen: self.dataclass_arguments["frozen"] = True if keyword_only: self.dataclass_arguments["kw_only"] = True
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
src/datamodel_code_generator/model/template/pydantic/dataclass.jinja2is excluded by none and included by nonesrc/datamodel_code_generator/model/template/pydantic_v2/dataclass.jinja2is excluded by none and included by nonetests/data/jsonschema/pydantic_v2_dataclass_additional_props_true.jsonis excluded by!tests/data/**/*.jsonand included by nonetests/data/jsonschema/pydantic_v2_dataclass_config.jsonis excluded by!tests/data/**/*.jsonand included by none
📒 Files selected for processing (19)
src/datamodel_code_generator/__init__.pysrc/datamodel_code_generator/model/__init__.pysrc/datamodel_code_generator/model/pydantic/__init__.pysrc/datamodel_code_generator/model/pydantic/dataclass.pysrc/datamodel_code_generator/model/pydantic/imports.pysrc/datamodel_code_generator/model/pydantic_v2/dataclass.pysrc/datamodel_code_generator/model/pydantic_v2/imports.pysrc/datamodel_code_generator/parser/graphql.pysrc/datamodel_code_generator/parser/jsonschema.pytests/data/expected/main/jsonschema/generate_pydantic_v2_dataclass.pytests/data/expected/main/jsonschema/pydantic_v2_dataclass_additional_props_true.pytests/data/expected/main/jsonschema/pydantic_v2_dataclass_config.pytests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_allow.pytests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_forbid.pytests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_ignore.pytests/data/expected/main/jsonschema/pydantic_v2_dataclass_use_attribute_docstrings.pytests/main/jsonschema/test_main_jsonschema.pytests/model/pydantic/test_data_class.pytests/model/pydantic_v2/test_dataclass.py
💤 Files with no reviewable changes (4)
- src/datamodel_code_generator/model/pydantic/imports.py
- src/datamodel_code_generator/model/pydantic/init.py
- tests/model/pydantic/test_data_class.py
- src/datamodel_code_generator/model/pydantic/dataclass.py
🧰 Additional context used
🧬 Code graph analysis (12)
tests/data/expected/main/jsonschema/pydantic_v2_dataclass_use_attribute_docstrings.py (1)
src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)
ConfigDict(26-41)
tests/model/pydantic_v2/test_dataclass.py (4)
src/datamodel_code_generator/model/base.py (3)
DataModelFieldBase(120-398)name(727-729)path(808-810)src/datamodel_code_generator/model/pydantic_v2/dataclass.py (3)
DataClass(30-143)DataModelField(146-156)create_reuse_model(127-143)src/datamodel_code_generator/reference.py (2)
reference(76-78)Reference(141-200)src/datamodel_code_generator/types.py (2)
DataType(286-758)Types(768-806)
src/datamodel_code_generator/parser/graphql.py (2)
src/datamodel_code_generator/model/pydantic_v2/dataclass.py (1)
DataClass(30-143)src/datamodel_code_generator/model/dataclass.py (1)
DataClass(46-117)
tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_forbid.py (1)
src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)
ConfigDict(26-41)
src/datamodel_code_generator/model/pydantic_v2/dataclass.py (5)
src/datamodel_code_generator/__init__.py (1)
DataclassArguments(61-73)src/datamodel_code_generator/imports.py (2)
Import(20-38)append(74-89)src/datamodel_code_generator/model/base.py (4)
DataModel(531-829)DataModelFieldBase(120-398)path(808-810)name(727-729)src/datamodel_code_generator/model/dataclass.py (1)
has_field_assignment(39-43)src/datamodel_code_generator/reference.py (2)
reference(76-78)Reference(141-200)
tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_allow.py (7)
src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)
ConfigDict(26-41)tests/data/expected/main/jsonschema/generate_pydantic_v2_dataclass.py (1)
Model(11-12)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_additional_props_true.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_config.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_forbid.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_ignore.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_use_attribute_docstrings.py (1)
Model(12-13)
tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_ignore.py (7)
src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)
ConfigDict(26-41)tests/data/expected/main/jsonschema/generate_pydantic_v2_dataclass.py (1)
Model(11-12)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_additional_props_true.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_config.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_allow.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_forbid.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_use_attribute_docstrings.py (1)
Model(12-13)
src/datamodel_code_generator/model/__init__.py (3)
src/datamodel_code_generator/__init__.py (1)
DataModelType(218-226)src/datamodel_code_generator/model/pydantic_v2/dataclass.py (2)
DataClass(30-143)DataModelField(146-156)src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)
dump_resolve_reference_action(21-23)
src/datamodel_code_generator/parser/jsonschema.py (2)
src/datamodel_code_generator/model/pydantic_v2/dataclass.py (1)
DataClass(30-143)src/datamodel_code_generator/model/dataclass.py (1)
DataClass(46-117)
tests/data/expected/main/jsonschema/generate_pydantic_v2_dataclass.py (6)
tests/data/expected/main/jsonschema/pydantic_v2_dataclass_additional_props_true.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_config.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_allow.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_forbid.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_ignore.py (1)
Model(12-13)tests/data/expected/main/jsonschema/pydantic_v2_dataclass_use_attribute_docstrings.py (1)
Model(12-13)
src/datamodel_code_generator/model/pydantic_v2/imports.py (1)
src/datamodel_code_generator/imports.py (2)
Import(20-38)from_full_path(35-38)
tests/data/expected/main/jsonschema/pydantic_v2_dataclass_additional_props_true.py (1)
src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)
ConfigDict(26-41)
🪛 GitHub Actions: Lint
tests/model/pydantic_v2/test_dataclass.py
[error] 1-1: ruff: 3 errors (3 fixed, 0 remaining) during pre-commit hook.
src/datamodel_code_generator/model/pydantic_v2/dataclass.py
[error] 1-1: ruff-format reformatted 1 file during pre-commit hook.
🪛 Ruff (0.14.10)
src/datamodel_code_generator/model/pydantic_v2/dataclass.py
38-38: Unused noqa directive (non-enabled: PLR0913)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/model/__init__.py
98-98: Unused noqa directive (non-enabled: PLC0415)
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.12 on Ubuntu
- GitHub Check: 3.10 on Ubuntu
- GitHub Check: py312-pydantic1 on Ubuntu
- GitHub Check: py312-black24 on Ubuntu
- GitHub Check: 3.11 on Windows
- GitHub Check: 3.10 on Windows
- GitHub Check: 3.12 on Windows
- GitHub Check: Analyze (python)
- GitHub Check: benchmarks
🔇 Additional comments (21)
src/datamodel_code_generator/__init__.py (1)
223-223: LGTM!The new
PydanticV2Dataclassenum member follows the established naming convention and value pattern used by other members inDataModelType. This addition cleanly enables pydantic v2 dataclass output support.src/datamodel_code_generator/parser/jsonschema.py (2)
56-56: LGTM!The import correctly brings in the
PydanticV2DataClassalias needed for the dataclass type check below.
1740-1761: LGTM!The broadened
issubclasscheck correctly handles both standardDataClassand the newPydanticV2DataClass. Both classes share the same constructor signature withdataclass_argumentssupport, making this unification appropriate.tests/data/expected/main/jsonschema/pydantic_v2_dataclass_additional_props_true.py (1)
1-13: LGTM!The test fixture correctly demonstrates the expected output for pydantic v2 dataclass generation with
additionalProperties: true. TheConfigDict(extra='allow')configuration properly maps to the JSON Schema behavior, and the imports follow correct pydantic v2 patterns.src/datamodel_code_generator/model/pydantic_v2/imports.py (1)
20-20: LGTM!The new
IMPORT_PYDANTIC_DATACLASSconstant correctly generatesfrom pydantic.dataclasses import dataclass, which is the proper import path for pydantic v2 dataclasses. The naming follows the established convention in this module.tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_ignore.py (1)
1-13: LGTM!The test fixture correctly demonstrates the expected output for pydantic v2 dataclass generation with
extra='ignore'configuration. The structure is consistent with other pydantic v2 dataclass fixtures in the test suite.tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_allow.py (1)
1-13: LGTM! Well-formed Pydantic v2 dataclass fixture.The expected output correctly demonstrates Pydantic v2 dataclass generation with
extra='allow'configuration, proper imports, and field definition.tests/data/expected/main/jsonschema/pydantic_v2_dataclass_use_attribute_docstrings.py (1)
1-13: LGTM! Correct fixture for use_attribute_docstrings config.The expected output properly demonstrates the
use_attribute_docstrings=Trueconfiguration in Pydantic v2 dataclass generation.tests/data/expected/main/jsonschema/pydantic_v2_dataclass_extra_forbid.py (1)
1-13: LGTM! Proper extra='forbid' configuration fixture.The expected output correctly shows Pydantic v2 dataclass generation with
extra='forbid'configuration.tests/data/expected/main/jsonschema/pydantic_v2_dataclass_config.py (1)
1-13: LGTM! Config fixture is correct.The expected output properly demonstrates Pydantic v2 dataclass generation with configuration options.
src/datamodel_code_generator/model/__init__.py (1)
59-59: LGTM! Correct inclusion of PydanticV2Dataclass in type alias logic.The condition properly groups
PydanticV2DataclasswithPydanticV2BaseModelfor TypeStatement/TypeAliasTypeBackport selection, as both require the same type alias handling.src/datamodel_code_generator/parser/graphql.py (2)
34-34: LGTM! Correct import for Pydantic v2 dataclass support.The import properly aliases the Pydantic v2 DataClass to distinguish it from the standard dataclasses.DataClass.
354-375: LGTM! Proper extension of dataclass argument handling.The
issubclasscheck correctly includesPydanticV2DataClassalongsideDataClass, ensuring both dataclass implementations receive properdataclass_argumentshandling (frozen, kw_only, etc.) while maintaining backward compatibility.tests/model/pydantic_v2/test_dataclass.py (1)
1-167: LGTM! Comprehensive test coverage for Pydantic v2 dataclass functionality.The test suite thoroughly validates:
- Basic dataclass generation and rendering
- Base class inheritance
- Optional fields and default values
- Type manager integration
- Field ordering (required before optional)
- Dataclass options (frozen, kw_only)
- Docstring generation
- Reuse model creation
All tests follow proper patterns and provide good coverage of the new functionality.
tests/data/expected/main/jsonschema/generate_pydantic_v2_dataclass.py (1)
1-12: LGTM! Clean baseline fixture for Pydantic v2 dataclass.The expected output correctly demonstrates basic Pydantic v2 dataclass generation with minimal configuration, proper imports, and the
@dataclassdecorator.tests/main/jsonschema/test_main_jsonschema.py (1)
1304-1411: LGTM! Comprehensive test coverage for Pydantic v2 dataclass generation.The seven new test functions provide thorough coverage of the pydantic_v2.dataclass output format across different configuration scenarios:
- Basic dataclass generation
- ConfigDict from schema
- additionalProperties handling
- use_attribute_docstrings option
- extra field policies (allow/forbid/ignore)
The tests follow the established patterns in this file and are well-structured.
src/datamodel_code_generator/model/pydantic_v2/dataclass.py (5)
61-61: LGTM! Field sorting is essential for dataclasses.Sorting fields by
has_field_assignmentensures that fields with default values appear after fields without defaults, which is a requirement for Python dataclasses. This prevents the "non-default argument follows default argument" error.
88-107: ConfigDict handling looks correct.The logic properly aggregates configuration from multiple sources:
- Extra field policy from
_get_config_extra()- Attribute docstrings from template data
- Arbitrary types detection from field data types
Line 101: The
# pragma: no covercomment indicates the custom types path isn't tested. Consider adding a test case that exercises this code path to ensurearbitrary_types_allowedis correctly set when custom types are present.
109-125: LGTM! Extra field precedence is well-designed.The
_get_config_extramethod implements a sensible precedence:
- Explicit
allow_extra_fieldsorextra_fieldssettings take highest precedence- Schema-inferred
additionalPropertiesis used as fallback- Returns None if no configuration is found
This ensures user intent is respected over schema inference.
127-143: LGTM! Reuse model correctly preserves dataclass configuration.The
create_reuse_modelmethod properly creates an inherited model while preserving all the dataclass-specific settings includingdataclass_arguments,keyword_only, andfrozen. This ensures that inherited models maintain the same configuration as their parent.
146-156: Verify the necessity of the type ignore comment.Line 152 uses
# pyright: ignore[reportIncompatibleVariableOverride]when overriding theconstraintsattribute. Please verify that this type ignore is actually necessary by checking if the parent classDataModelFieldV2has a different type annotation forconstraints.If the parent's type is compatible, the ignore comment should be removed. If it's incompatible, consider documenting why the override is needed.
Run the following to check the parent class's constraints attribute:
#!/bin/bash # Check the constraints attribute definition in DataModelFieldV2 ast-grep --pattern $'class DataModelFieldV2 { $$$ constraints: $TYPE $$$ }'
CodSpeed Performance ReportMerging #2746 will not alter performanceComparing Summary
Footnotes
|
Fixes: #1906
Summary by CodeRabbit
Release Notes
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.