feat: remove pydantic v1 output support#3031
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR removes Pydantic v1 support and migrates the codebase and docs to Pydantic v2: deletes v1 generator modules/tests, updates examples to RootModel/ConfigDict/TypeAliasType/model_rebuild, replaces parse_obj with model_validate, and removes Pydantic v1 compatibility shims. Changes
Sequence Diagram(s)(Skipped) Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
Merging this PR will not alter performance
|
b547ca6 to
e6902a6
Compare
68cfffd to
927fa33
Compare
a63d588 to
5ccfb23
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3031 +/- ##
==========================================
Coverage 100.00% 100.00%
==========================================
Files 95 86 -9
Lines 18095 17710 -385
Branches 2094 2069 -25
==========================================
- Hits 18095 17710 -385
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:
|
🤖 Generated by GitHub Actions
Generated by GitHub Actions
5ccfb23 to
29e75b7
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/datamodel_code_generator/util.py (1)
302-306:⚠️ Potential issue | 🟡 MinorRemove the unused
model_validate()utility function or document its purpose.This function is not used anywhere in the codebase. All
.model_validate()calls are on Pydantic model instances (e.g.,JsonSchemaObject.model_validate(...),Config.model_validate(...)), not calls to this utility wrapper. If this function is intended as a public API for external users or for future use, it should have explicit documentation, tests, and either be removed from# pragma: no coveror marked as intentionally uncovered with a comment explaining why.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/datamodel_code_generator/util.py` around lines 302 - 306, The helper function model_validate is unused and should be removed or explicitly documented/tested: either delete the model_validate function and any related unused imports/usages, or keep it but add a clear docstring explaining its public purpose, remove the "# pragma: no cover" (or add a comment why coverage is excluded), add unit tests exercising model_validate (covering both pydantic v1 and v2 paths), and, if it's part of the public API, include it in module exports (e.g., __all__) so callers can find it; locate the function by name model_validate in this module to apply the change.src/datamodel_code_generator/model/base.py (1)
189-197:⚠️ Potential issue | 🟡 MinorDon’t exempt
process_const()from coverage.This is active field-initialization logic, not a dead branch: it changes
default,required, andnullablefor const fields. Marking the whole methodno covermakes const regressions invisible to diff-cover instead of exercising them with a targeted test.Suggested change
- def process_const(self) -> None: # pragma: no cover + def process_const(self) -> None:🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/datamodel_code_generator/model/base.py` around lines 189 - 197, Remove the coverage exemption on process_const and add a targeted unit test: delete the "# pragma: no cover" on the process_const method in the class defined in src/datamodel_code_generator/model/base.py so the method is measured by coverage, and add a unit test that constructs the model with extras containing "const" and asserts that process_const sets self.default to extras["const"], self.const is True, self.required is False, and self.nullable is False (call the method via the same public initializer/path used in production to ensure behavior is exercised).
🧹 Nitpick comments (1)
src/datamodel_code_generator/__main__.py (1)
394-410: Remove redundant@classmethoddecorators for consistency.In Pydantic v2,
@field_validatorimplicitly handles classmethod behavior. The explicit@classmethoddecorator is redundant. Other validators in this file (e.g., lines 159, 174, 187) don't use@classmethod, so removing it here would improve consistency.♻️ Proposed fix
`@field_validator`("input_model", mode="before") -@classmethod -def coerce_input_model_to_list(cls, v: str | list[str] | None) -> list[str] | None: # ty: ignore +def coerce_input_model_to_list(cls, v: str | list[str] | None) -> list[str] | None: # noqa: N805 # ty: ignore """Convert string input_model to list for backwards compatibility.""" if isinstance(v, str): return [v] return v `@field_validator`("class_name_affix_scope", mode="before") -@classmethod -def validate_class_name_affix_scope(cls, v: str | ClassNameAffixScope | None) -> ClassNameAffixScope: # ty: ignore +def validate_class_name_affix_scope(cls, v: str | ClassNameAffixScope | None) -> ClassNameAffixScope: # noqa: N805 # ty: ignore """Convert string to ClassNameAffixScope enum.""" if v is None: # pragma: no cover return ClassNameAffixScope.All if isinstance(v, str): return ClassNameAffixScope(v) return v # pragma: no cover🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/datamodel_code_generator/__main__.py` around lines 394 - 410, Remove the redundant `@classmethod` decorators on the two Pydantic validators: coerce_input_model_to_list and validate_class_name_affix_scope; keep the `@field_validator`(...) decorators (mode="before") intact so Pydantic v2 treats them as class-level validators, and ensure the function signatures and return types remain unchanged to preserve behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/cli-reference/field-customization.md`:
- Around line 3705-3712: Replace the incorrect construction
ExtendedProcessingTask('COMPLETED') in the default_factory of
ProcessingStatusUnionTitle with the union-appropriate variant
ProcessingStatusUnionTitle('COMPLETED'); the literal 'COMPLETED' corresponds to
the ProcessingStatusTitle enum branch (not ExtendedProcessingTask which expects
ProcessingTasksTitle or NestedCommentTitle), so update the Field default_factory
to instantiate ProcessingStatusUnionTitle('COMPLETED') to match the union type
and the example at line 3681.
In `@docs/cli-reference/typing-customization.md`:
- Around line 3835-3842: The docs overstate pendulum support: update the
--use-pendulum option description to state it only maps OpenAPI date, time and
duration to pendulum.Date, pendulum.Time and pendulum.Duration, and that
date-time fields continue to use pydantic.AwareDatetime (not pendulum.DateTime);
also mention that users can change the generated datetime type via the
--output-datetime-class option if they need a different datetime class. Ensure
references to AwareDatetime, Date, Duration, --use-pendulum, and
--output-datetime-class are present so readers can find the related examples and
flags.
- Around line 3145-3147: The example showing class Pets(RootModel[list[Pet]]):
root: Annotated[list[Pet], Field(max_length=10, min_length=1)] hides the fact
that the original schema's uniqueItems: true is not preserved when using
--use-annotated; update the docs text near this example to explicitly state that
--use-annotated alone will not enforce uniqueItems and either add a short note
explaining this or add a cross-reference/link to the --use-unique-items-as-set
option so readers know to use that flag to preserve uniqueness constraints for
the Pets root type.
---
Outside diff comments:
In `@src/datamodel_code_generator/model/base.py`:
- Around line 189-197: Remove the coverage exemption on process_const and add a
targeted unit test: delete the "# pragma: no cover" on the process_const method
in the class defined in src/datamodel_code_generator/model/base.py so the method
is measured by coverage, and add a unit test that constructs the model with
extras containing "const" and asserts that process_const sets self.default to
extras["const"], self.const is True, self.required is False, and self.nullable
is False (call the method via the same public initializer/path used in
production to ensure behavior is exercised).
In `@src/datamodel_code_generator/util.py`:
- Around line 302-306: The helper function model_validate is unused and should
be removed or explicitly documented/tested: either delete the model_validate
function and any related unused imports/usages, or keep it but add a clear
docstring explaining its public purpose, remove the "# pragma: no cover" (or add
a comment why coverage is excluded), add unit tests exercising model_validate
(covering both pydantic v1 and v2 paths), and, if it's part of the public API,
include it in module exports (e.g., __all__) so callers can find it; locate the
function by name model_validate in this module to apply the change.
---
Nitpick comments:
In `@src/datamodel_code_generator/__main__.py`:
- Around line 394-410: Remove the redundant `@classmethod` decorators on the two
Pydantic validators: coerce_input_model_to_list and
validate_class_name_affix_scope; keep the `@field_validator`(...) decorators
(mode="before") intact so Pydantic v2 treats them as class-level validators, and
ensure the function signatures and return types remain unchanged to preserve
behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: fef37158-673f-4bc7-8650-27abd8ead56a
⛔ Files ignored due to path filters (4)
docs/llms-full.txtis excluded by none and included by nonesrc/datamodel_code_generator/model/template/pydantic/BaseModel.jinja2is excluded by none and included by nonesrc/datamodel_code_generator/model/template/pydantic/BaseModel_root.jinja2is excluded by none and included by nonesrc/datamodel_code_generator/model/template/pydantic/Config.jinja2is excluded by none and included by none
📒 Files selected for processing (43)
docs/cli-reference/base-options.mddocs/cli-reference/field-customization.mddocs/cli-reference/general-options.mddocs/cli-reference/graphql-only-options.mddocs/cli-reference/model-customization.mddocs/cli-reference/openapi-only-options.mddocs/cli-reference/quick-reference.mddocs/cli-reference/template-customization.mddocs/cli-reference/typing-customization.mdsrc/datamodel_code_generator/__main__.pysrc/datamodel_code_generator/arguments.pysrc/datamodel_code_generator/enums.pysrc/datamodel_code_generator/input_model.pysrc/datamodel_code_generator/model/__init__.pysrc/datamodel_code_generator/model/base.pysrc/datamodel_code_generator/model/pydantic/__init__.pysrc/datamodel_code_generator/model/pydantic/base_model.pysrc/datamodel_code_generator/model/pydantic/custom_root_type.pysrc/datamodel_code_generator/model/pydantic/imports.pysrc/datamodel_code_generator/model/pydantic/types.pysrc/datamodel_code_generator/model/pydantic_base.pysrc/datamodel_code_generator/prompt_data.pysrc/datamodel_code_generator/types.pysrc/datamodel_code_generator/util.pytests/conftest.pytests/data/expected/main/input_model/config_class.pytests/data/expected/main/input_model/dataclass_with_python_types.pytests/data/expected/main/input_model/model_with_python_types.pytests/data/expected/main/input_model/multiple_with_pydantic_output.pytests/data/expected/main/input_model/recursive_model_types.pytests/data/expected/main/jsonschema/additional_properties_false_pydantic_v1.pytests/data/expected/main/jsonschema/additional_properties_true_pydantic_v1.pytests/data/expected/main/jsonschema/unevaluated_properties_pydantic_v1.pytests/data/expected/main/jsonschema/unevaluated_properties_true_pydantic_v1.pytests/data/expected/main/jsonschema/use_frozen_field_v1.pytests/main/jsonschema/test_main_jsonschema.pytests/main/openapi/test_main_openapi.pytests/model/pydantic/__init__.pytests/model/pydantic/test_base_model.pytests/model/pydantic/test_constraint.pytests/model/pydantic/test_custom_root_type.pytests/model/pydantic/test_types.pytests/test_input_model.py
💤 Files with no reviewable changes (21)
- src/datamodel_code_generator/enums.py
- src/datamodel_code_generator/model/pydantic/types.py
- tests/data/expected/main/input_model/config_class.py
- tests/model/pydantic/init.py
- tests/data/expected/main/jsonschema/use_frozen_field_v1.py
- src/datamodel_code_generator/model/init.py
- tests/data/expected/main/jsonschema/additional_properties_false_pydantic_v1.py
- tests/model/pydantic/test_base_model.py
- tests/data/expected/main/jsonschema/unevaluated_properties_true_pydantic_v1.py
- src/datamodel_code_generator/model/pydantic/base_model.py
- src/datamodel_code_generator/input_model.py
- tests/model/pydantic/test_custom_root_type.py
- tests/model/pydantic/test_types.py
- tests/model/pydantic/test_constraint.py
- src/datamodel_code_generator/model/pydantic/custom_root_type.py
- tests/data/expected/main/jsonschema/unevaluated_properties_pydantic_v1.py
- tests/main/jsonschema/test_main_jsonschema.py
- tests/data/expected/main/jsonschema/additional_properties_true_pydantic_v1.py
- src/datamodel_code_generator/model/pydantic/init.py
- src/datamodel_code_generator/model/pydantic/imports.py
- tests/main/openapi/test_main_openapi.py
There was a problem hiding this comment.
♻️ Duplicate comments (1)
docs/cli-reference/field-customization.md (1)
3708-3712:⚠️ Potential issue | 🟠 MajorFix the default_factory to return the inner union member, not the RootModel wrapper.
In Pydantic v2,
RootModelvalidates therootfield against its inner type. Here,rootis typed asProcessingStatusDetail | ExtendedProcessingTask | ProcessingStatusTitle, but the factory returnsProcessingStatusUnionTitle(...)(the wrapper class). The factory must produce a value matching the inner union type instead.🛠️ Suggested doc fix
class ProcessingStatusUnionTitle( RootModel[ProcessingStatusDetail | ExtendedProcessingTask | ProcessingStatusTitle] ): root: ProcessingStatusDetail | ExtendedProcessingTask | ProcessingStatusTitle = ( Field( - default_factory=lambda: ProcessingStatusUnionTitle('COMPLETED'), + default_factory=lambda: ProcessingStatusTitle('COMPLETED'), title='Processing Status Union Title', ) )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/cli-reference/field-customization.md` around lines 3708 - 3712, The default_factory for the root field is returning a RootModel wrapper (ProcessingStatusUnionTitle(...)) instead of the inner union member; change the default_factory to return the inner type value (e.g., an instance of ProcessingStatusTitle) so the root field (typed as ProcessingStatusDetail | ExtendedProcessingTask | ProcessingStatusTitle) receives a matching inner union member; update the default_factory lambda to construct and return ProcessingStatusTitle('COMPLETED') (or the appropriate ProcessingStatusDetail/ExtendedProcessingTask instance) rather than ProcessingStatusUnionTitle.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@docs/cli-reference/field-customization.md`:
- Around line 3708-3712: The default_factory for the root field is returning a
RootModel wrapper (ProcessingStatusUnionTitle(...)) instead of the inner union
member; change the default_factory to return the inner type value (e.g., an
instance of ProcessingStatusTitle) so the root field (typed as
ProcessingStatusDetail | ExtendedProcessingTask | ProcessingStatusTitle)
receives a matching inner union member; update the default_factory lambda to
construct and return ProcessingStatusTitle('COMPLETED') (or the appropriate
ProcessingStatusDetail/ExtendedProcessingTask instance) rather than
ProcessingStatusUnionTitle.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 655d9b32-56d3-45d7-ba2e-114182ec2475
⛔ Files ignored due to path filters (1)
docs/llms-full.txtis excluded by none and included by none
📒 Files selected for processing (9)
docs/cli-reference/field-customization.mddocs/cli-reference/quick-reference.mddocs/cli-reference/typing-customization.mdsrc/datamodel_code_generator/prompt_data.pytests/data/expected/main/jsonschema/titles_use_title_as_name_cli_doc.pytests/main/graphql/test_annotated.pytests/main/jsonschema/test_main_jsonschema.pytests/main/openapi/test_main_openapi.pytests/test_main_kr.py
✅ Files skipped from review due to trivial changes (2)
- tests/main/graphql/test_annotated.py
- tests/data/expected/main/jsonschema/titles_use_title_as_name_cli_doc.py
🚧 Files skipped from review as they are similar to previous changes (2)
- docs/cli-reference/quick-reference.md
- src/datamodel_code_generator/prompt_data.py
Breaking Change AnalysisResult: Breaking changes detected Reasoning: PR #3031 removes all Pydantic v1 output support including: (1) the Content for Release NotesCode Generation Changes
Custom Template Update Required
API/CLI Changes
This analysis was performed by Claude Code Action |
|
🎉 Released in 0.55.0 This PR is now available in the latest release. See the release notes for details. |
Summary
Validation
Summary by CodeRabbit
Breaking Changes
Documentation
Improvements