Skip to content

Commit 1cbfbc5

Browse files
authored
Remove pydantic v1 runtime compat shims and update dependencies (#3027)
* Remove pydantic v1 runtime compat shims and update dependencies * build: constrain pydantic for Python 3.14
1 parent bef3fe5 commit 1cbfbc5

4 files changed

Lines changed: 48 additions & 175 deletions

File tree

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ dependencies = [
3535
"inflect>=4.1,<8",
3636
"isort>=4.3.21,<9",
3737
"jinja2>=2.10.1,<4",
38-
"packaging",
39-
"pydantic>=1.5",
38+
"pydantic>=2,<3; python_version<'3.14'",
39+
"pydantic>=2.12,<3; python_version>='3.14'",
4040
"pyyaml>=6.0.1",
4141
"tomli>=2.2.1,<3; python_version<='3.11'",
4242
]

src/datamodel_code_generator/pydantic_patch.py

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/datamodel_code_generator/util.py

Lines changed: 7 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
1-
"""Utility functions and Pydantic version compatibility helpers.
2-
3-
Provides Pydantic version detection (PYDANTIC_V2), YAML/TOML loading,
4-
and version-compatible decorators (model_validator, field_validator).
5-
"""
1+
"""Utility functions for YAML/TOML loading and lazy BaseModel access."""
62

73
from __future__ import annotations
84

95
import re
106
import warnings
117
from functools import lru_cache
12-
from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload
8+
from typing import TYPE_CHECKING, Any
139

1410
if TYPE_CHECKING:
1511
from collections.abc import Callable
1612
from pathlib import Path
1713

18-
from pydantic import BaseModel as _BaseModel
19-
2014
try:
2115
from tomllib import load as load_tomllib # type: ignore[ignoreMissingImports]
2216
except ImportError: # pragma: no cover
@@ -29,28 +23,6 @@ def load_toml(path: Path) -> dict[str, Any]:
2923
return load_tomllib(f)
3024

3125

32-
@lru_cache(maxsize=1)
33-
def get_pydantic_version() -> tuple[Any, bool, bool]:
34-
"""Get pydantic version info lazily. Returns (version, is_v2, is_v2_11)."""
35-
# Apply pydantic patch before importing pydantic
36-
from datamodel_code_generator.pydantic_patch import apply_patch # noqa: PLC0415
37-
38-
apply_patch()
39-
40-
import pydantic # noqa: PLC0415
41-
from packaging import version # noqa: PLC0415
42-
43-
pydantic_version = version.parse(pydantic.VERSION if isinstance(pydantic.VERSION, str) else str(pydantic.VERSION))
44-
is_v2 = version.parse("2.0b3") <= pydantic_version
45-
is_v2_11 = version.parse("2.11") <= pydantic_version
46-
return pydantic_version, is_v2, is_v2_11
47-
48-
49-
def is_pydantic_v2() -> bool:
50-
"""Check if pydantic v2 is installed."""
51-
return get_pydantic_version()[1]
52-
53-
5426
_YAML_1_2_BOOL_PATTERN = re.compile(r"^(?:true|false|True|False|TRUE|FALSE)$")
5527
_YAML_DEPRECATED_BOOL_VALUES = {"True", "False", "TRUE", "FALSE"}
5628
# Pattern for scientific notation without decimal point (e.g., 1e-5, 1E+10)
@@ -111,121 +83,16 @@ class CustomSafeLoader(_SafeLoader): # type: ignore[valid-type,misc]
11183
return CustomSafeLoader
11284

11385

114-
Model = TypeVar("Model", bound="_BaseModel") # ty: ignore
115-
T = TypeVar("T")
116-
117-
118-
@overload
119-
def model_validator(
120-
mode: Literal["before"],
121-
) -> (
122-
Callable[[Callable[[type[Model], T], T]], Callable[[type[Model], T], T]]
123-
| Callable[[Callable[[Model, T], T]], Callable[[Model, T], T]]
124-
): ...
125-
126-
127-
@overload
128-
def model_validator(
129-
mode: Literal["after"],
130-
) -> (
131-
Callable[[Callable[[type[Model], T], T]], Callable[[type[Model], T], T]]
132-
| Callable[[Callable[[Model, T], T]], Callable[[Model, T], T]]
133-
| Callable[[Callable[[Model], Model]], Callable[[Model], Model]]
134-
): ...
135-
136-
137-
@overload
138-
def model_validator() -> (
139-
Callable[[Callable[[type[Model], T], T]], Callable[[type[Model], T], T]]
140-
| Callable[[Callable[[Model, T], T]], Callable[[Model, T], T]]
141-
| Callable[[Callable[[Model], Model]], Callable[[Model], Model]]
142-
): ...
143-
144-
145-
def model_validator( # ty: ignore
146-
mode: Literal["before", "after"] = "after",
147-
) -> (
148-
Callable[[Callable[[type[Model], T], T]], Callable[[type[Model], T], T]]
149-
| Callable[[Callable[[Model, T], T]], Callable[[Model, T], T]]
150-
| Callable[[Callable[[Model], Model]], Callable[[Model], Model]]
151-
):
152-
"""Decorate model validators for both Pydantic v1 and v2."""
153-
154-
@overload
155-
def inner(method: Callable[[type[Model], T], T]) -> Callable[[type[Model], T], T]: ...
156-
157-
@overload
158-
def inner(method: Callable[[Model, T], T]) -> Callable[[Model, T], T]: ...
159-
160-
@overload
161-
def inner(method: Callable[[Model], Model]) -> Callable[[Model], Model]: ...
162-
163-
def inner( # pragma: no cover
164-
method: Callable[[type[Model], T], T] | Callable[[Model, T], T] | Callable[[Model], Model],
165-
) -> Callable[[type[Model], T], T] | Callable[[Model, T], T] | Callable[[Model], Model]:
166-
if is_pydantic_v2():
167-
from pydantic import model_validator as model_validator_v2 # noqa: PLC0415
168-
169-
if mode == "before":
170-
return model_validator_v2(mode=mode)(classmethod(method)) # type: ignore[reportReturnType]
171-
return model_validator_v2(mode=mode)(method) # type: ignore[reportReturnType]
172-
from pydantic import root_validator # noqa: PLC0415 # pragma: no cover
173-
174-
return root_validator(method, pre=mode == "before") # ty: ignore # pragma: no cover
175-
176-
return inner # pragma: no cover
177-
178-
179-
def field_validator(
180-
field_name: str,
181-
*fields: str,
182-
mode: Literal["before", "after"] = "after",
183-
) -> Callable[[Any], Callable[[Any, Any], Any]]:
184-
"""Decorate field validators for both Pydantic v1 and v2."""
185-
186-
def inner(method: Callable[[Model, Any], Any]) -> Callable[[Model, Any], Any]: # pragma: no cover
187-
if is_pydantic_v2():
188-
from pydantic import field_validator as field_validator_v2 # noqa: PLC0415
189-
190-
return field_validator_v2(field_name, *fields, mode=mode)(method) # ty: ignore
191-
from pydantic import validator # noqa: PLC0415 # pragma: no cover
192-
193-
return validator(field_name, *fields, pre=mode == "before")(method) # ty: ignore # pragma: no cover
194-
195-
return inner # pragma: no cover
196-
197-
198-
@lru_cache(maxsize=1)
199-
def _get_config_dict() -> type: # pragma: no cover
200-
"""Get ConfigDict type lazily. Only used with pydantic v2."""
201-
from pydantic import ConfigDict # noqa: PLC0415
202-
203-
return ConfigDict
204-
205-
206-
class _ConfigDictProxy:
207-
"""Proxy for lazy ConfigDict access."""
208-
209-
def __call__(self, **kwargs: Any) -> Any: # pragma: no cover
210-
return _get_config_dict()(**kwargs)
211-
212-
213-
ConfigDict: type = _ConfigDictProxy() # type: ignore[assignment]
214-
215-
21686
@lru_cache(maxsize=1)
21787
def _get_base_model_class() -> type:
218-
"""Get version-compatible BaseModel class lazily."""
88+
"""Get BaseModel class with strict=False config lazily."""
21989
from pydantic import BaseModel as _PydanticBaseModel # noqa: PLC0415
90+
from pydantic import ConfigDict as _ConfigDict # noqa: PLC0415
22091

221-
if is_pydantic_v2():
222-
from pydantic import ConfigDict as _ConfigDict # noqa: PLC0415
223-
224-
class _BaseModelV2(_PydanticBaseModel):
225-
model_config = _ConfigDict(strict=False)
92+
class _BaseModelV2(_PydanticBaseModel):
93+
model_config = _ConfigDict(strict=False)
22694

227-
return _BaseModelV2
228-
return _PydanticBaseModel # pragma: no cover
95+
return _BaseModelV2
22996

23097

23198
_BaseModel: type | None = None

0 commit comments

Comments
 (0)