Skip to content

Extract shared pydantic base module for v2/dataclass/msgspec#3022

Merged
koxudaxi merged 2 commits intomainfrom
pr1-extract-pydantic-base
Mar 5, 2026
Merged

Extract shared pydantic base module for v2/dataclass/msgspec#3022
koxudaxi merged 2 commits intomainfrom
pr1-extract-pydantic-base

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Mar 5, 2026

Summary by CodeRabbit

  • New Features
    • Expanded and standardized Pydantic v2 support, adding broader constrained/strict type coverage and improved Field handling.
  • Refactor
    • Reorganized internal Pydantic scaffolding and type management for clearer separation between v1 and v2 implementations and simplified public surface.
    • Consolidated imports and simplified field/constraint handling for more consistent generated models.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d3f4aa86-a48e-4537-9b9b-24509dde7b3f

📥 Commits

Reviewing files that changed from the base of the PR and between cb935b2 and bfdac92.

📒 Files selected for processing (2)
  • src/datamodel_code_generator/model/pydantic/base_model.py
  • src/datamodel_code_generator/model/pydantic/types.py

📝 Walkthrough

Walkthrough

Centralizes Pydantic v1/v2 base logic into a new pydantic_base module, re-exports/simplifies existing pydantic modules to use that shared surface, adds Pydantic v2-specific type & import definitions, and updates parser logic and cross-module import paths to reference the new base.

Changes

Cohort / File(s) Summary
New shared pydantic base
src/datamodel_code_generator/model/pydantic_base.py
Adds Constraints, DataModelField, BaseModelBase, plus IMPORT_ANYURL and IMPORT_FIELD; implements Pydantic v2-aware field/default/constraint handling and template resolution surface.
Pydantic v1 surface simplified
src/datamodel_code_generator/model/pydantic/base_model.py, src/datamodel_code_generator/model/pydantic/types.py
Replaces heavy in-module implementations with re-exports from pydantic_base; types.py now inherits v2-style manager and exposes HOSTNAME_REGEX.
Pydantic v2 implementation & imports
src/datamodel_code_generator/model/pydantic_v2/base_model.py, src/datamodel_code_generator/model/pydantic_v2/types.py, src/datamodel_code_generator/model/pydantic_v2/imports.py
Redirects imports to pydantic_base, introduces _PydanticDataTypeManager and Pydantic v2 type/constraint logic; adds many IMPORT_* constants for v2 types (constr, conint, UUID*, Field, Strict*, AnyUrl, IP types, etc.).
Cross-module import updates
src/datamodel_code_generator/model/dataclass.py, src/datamodel_code_generator/model/msgspec.py
Updated imports to use datamodel_code_generator.model.pydantic_base.Constraints instead of previous path.
Parser discriminator handling
src/datamodel_code_generator/parser/base.py
Extends __collapse_root_models to accept pydantic_v2.DataModelField alongside v1 DataModelField when detecting discriminators for collapsing root models.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

breaking-change-analyzed, breaking-change

Suggested reviewers

  • ilovelinux

Poem

🐰 I hopped through modules, tidy and spry,
Gathering Constraints beneath Pydantic sky;
Fields and bases now sit in one tree,
Types and imports aligned merrily,
A tidy burrow for code to fly ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.42% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: extracting shared Pydantic base module components used across v2, dataclass, and msgspec implementations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pr1-extract-pydantic-base

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 5, 2026

Comment thread src/datamodel_code_generator/model/pydantic_base.py Dismissed
Comment thread src/datamodel_code_generator/model/pydantic_base.py Dismissed
Comment thread src/datamodel_code_generator/model/pydantic_base.py Dismissed
@koxudaxi koxudaxi force-pushed the pr1-extract-pydantic-base branch from cb935b2 to bfdac92 Compare March 5, 2026 03:08
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 5, 2026

Merging this PR will degrade performance by 16.43%

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

❌ 11 regressed benchmarks
⏩ 98 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
WallTime test_perf_stripe_style_pydantic_v2 1.7 s 2 s -14.74%
WallTime test_perf_duplicate_names 856.3 ms 1,013.9 ms -15.55%
WallTime test_perf_aws_style_openapi_pydantic_v2 1.7 s 2 s -14.54%
WallTime test_perf_large_models_pydantic_v2 3.1 s 3.7 s -15.91%
WallTime test_perf_deep_nested 5.1 s 5.8 s -12.93%
WallTime test_perf_multiple_files_input 3.2 s 3.8 s -15.7%
WallTime test_perf_kubernetes_style_pydantic_v2 2.2 s 2.7 s -16.16%
WallTime test_perf_graphql_style_pydantic_v2 712.5 ms 834.4 ms -14.62%
WallTime test_perf_complex_refs 1.7 s 2.1 s -16.43%
WallTime test_perf_openapi_large 2.5 s 2.9 s -13.69%
WallTime test_perf_all_options_enabled 5.9 s 6.8 s -13.39%

Comparing pr1-extract-pydantic-base (bfdac92) with main (66bc811)

Open in CodSpeed

Footnotes

  1. 98 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/datamodel_code_generator/model/pydantic_v2/types.py (1)

457-484: Rebuild type_map after replacing self.data_type with PydanticV2ContextDataType.

super().__init__() initializes type_map/strict_type_map before Line 475 swaps self.data_type, so maps may stay bound to the pre-swap type class.

♻️ Proposed adjustment
         super().__init__(
             python_version=python_version,
             use_standard_collections=use_standard_collections,
             use_generic_container_types=use_generic_container_types,
             strict_types=strict_types,
             use_non_positive_negative_number_constrained_types=use_non_positive_negative_number_constrained_types,
             use_decimal_for_multiple_of=use_decimal_for_multiple_of,
             use_union_operator=use_union_operator,
             use_pendulum=use_pendulum,
             target_datetime_class=target_datetime_class,
             target_date_class=target_date_class,
             treat_dot_as_module=treat_dot_as_module,
             use_serialize_as_any=use_serialize_as_any,
         )

         # Override the data_type with our pydantic v2 version
         from pydantic import create_model  # noqa: PLC0415

         self.data_type: type[DataType] = create_model(
             "PydanticV2ContextDataType",
             python_version=(PythonVersion, python_version),
             use_standard_collections=(bool, use_standard_collections),
             use_generic_container=(bool, use_generic_container_types),
             use_union_operator=(bool, use_union_operator),
             treat_dot_as_module=(bool, treat_dot_as_module),
             use_serialize_as_any=(bool, use_serialize_as_any),
             __base__=PydanticV2DataType,
         )
+        self.type_map = self.type_map_factory(
+            self.data_type,
+            strict_types=self.strict_types,
+            pattern_key=self.PATTERN_KEY,
+            target_datetime_class=target_datetime_class,
+            target_date_class=target_date_class,
+        )
+        self.strict_type_map = strict_type_map_factory(self.data_type)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/datamodel_code_generator/model/pydantic_v2/types.py` around lines 457 -
484, super().__init__() builds type_map/strict_type_map using the original
data_type, but the code then replaces self.data_type with the
PydanticV2ContextDataType model; to fix, after assigning self.data_type =
create_model(..., __base__=PydanticV2DataType) ensure you rebuild/recompute the
instance's type_map and strict_type_map so they bind to the new
PydanticV2ContextDataType (e.g., call whatever internal helper or re-run the
logic used by super().__init__ that populates type_map/strict_type_map,
immediately after the self.data_type replacement).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/datamodel_code_generator/model/pydantic_v2/types.py`:
- Around line 457-484: super().__init__() builds type_map/strict_type_map using
the original data_type, but the code then replaces self.data_type with the
PydanticV2ContextDataType model; to fix, after assigning self.data_type =
create_model(..., __base__=PydanticV2DataType) ensure you rebuild/recompute the
instance's type_map and strict_type_map so they bind to the new
PydanticV2ContextDataType (e.g., call whatever internal helper or re-run the
logic used by super().__init__ that populates type_map/strict_type_map,
immediately after the self.data_type replacement).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4db51102-a0ca-4dec-be3e-95bf88fa78bc

📥 Commits

Reviewing files that changed from the base of the PR and between 66bc811 and cb935b2.

📒 Files selected for processing (9)
  • src/datamodel_code_generator/model/dataclass.py
  • src/datamodel_code_generator/model/msgspec.py
  • src/datamodel_code_generator/model/pydantic/base_model.py
  • src/datamodel_code_generator/model/pydantic/types.py
  • src/datamodel_code_generator/model/pydantic_base.py
  • src/datamodel_code_generator/model/pydantic_v2/base_model.py
  • src/datamodel_code_generator/model/pydantic_v2/imports.py
  • src/datamodel_code_generator/model/pydantic_v2/types.py
  • src/datamodel_code_generator/parser/base.py

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (66bc811) to head (bfdac92).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #3022   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           94        95    +1     
  Lines        18348     18389   +41     
  Branches      2129      2129           
=========================================
+ Hits         18348     18389   +41     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@koxudaxi koxudaxi merged commit 06edfad into main Mar 5, 2026
37 of 38 checks passed
@koxudaxi koxudaxi deleted the pr1-extract-pydantic-base branch March 5, 2026 16:05
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 5, 2026

Breaking Change Analysis

Result: No breaking changes detected

Reasoning: This PR is a pure internal refactoring that consolidates duplicated code into a shared pydantic_base.py module. All public API entry points remain unchanged: (1) Public classes like BaseModel, DataModelField, DataTypeManager, and Constraints are still importable from their documented locations (datamodel_code_generator.model.pydantic and datamodel_code_generator.model.pydantic_v2), (2) The __init__.py files still export the same symbols, (3) No CLI or configuration options changed, (4) No Jinja2 templates were modified, (5) Generated code output is unchanged. The only relocated items (type_map_factory, strict_type_map_factory) were internal helper functions never exposed in any __all__ exports, so they are not part of the documented public API.


This analysis was performed by Claude Code Action

@github-actions
Copy link
Copy Markdown
Contributor

🎉 Released in 0.55.0

This PR is now available in the latest release. See the release notes for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants