mirror of
https://github.com/fastapi/sqlmodel.git
synced 2026-03-13 09:29:54 +08:00
Fix and deprecate min_items and max_items parameters to Field
This commit is contained in:
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import builtins
|
||||
import ipaddress
|
||||
import uuid
|
||||
import warnings
|
||||
import weakref
|
||||
from collections.abc import Mapping, Sequence, Set
|
||||
from datetime import date, datetime, time, timedelta
|
||||
@@ -11,6 +12,7 @@ from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Annotated,
|
||||
Any,
|
||||
Callable,
|
||||
ClassVar,
|
||||
@@ -89,6 +91,13 @@ IncEx: TypeAlias = Union[
|
||||
]
|
||||
OnDeleteType = Literal["CASCADE", "SET NULL", "RESTRICT"]
|
||||
|
||||
MIN_ITEMS_DEPRECATION_MSG = (
|
||||
"`min_items` is deprecated and will be removed, use `min_length` instead"
|
||||
)
|
||||
MAX_ITEMS_DEPRECATION_MSG = (
|
||||
"`max_items` is deprecated and will be removed, use `max_length` instead"
|
||||
)
|
||||
|
||||
|
||||
def __dataclass_transform__(
|
||||
*,
|
||||
@@ -221,8 +230,14 @@ def Field(
|
||||
multiple_of: Optional[float] = None,
|
||||
max_digits: Optional[int] = None,
|
||||
decimal_places: Optional[int] = None,
|
||||
min_items: Optional[int] = None,
|
||||
max_items: Optional[int] = None,
|
||||
min_items: Annotated[
|
||||
Optional[int],
|
||||
deprecated(MIN_ITEMS_DEPRECATION_MSG),
|
||||
] = None,
|
||||
max_items: Annotated[
|
||||
Optional[int],
|
||||
deprecated(MAX_ITEMS_DEPRECATION_MSG),
|
||||
] = None,
|
||||
unique_items: Optional[bool] = None,
|
||||
min_length: Optional[int] = None,
|
||||
max_length: Optional[int] = None,
|
||||
@@ -264,8 +279,14 @@ def Field(
|
||||
multiple_of: Optional[float] = None,
|
||||
max_digits: Optional[int] = None,
|
||||
decimal_places: Optional[int] = None,
|
||||
min_items: Optional[int] = None,
|
||||
max_items: Optional[int] = None,
|
||||
min_items: Annotated[
|
||||
Optional[int],
|
||||
deprecated(MIN_ITEMS_DEPRECATION_MSG),
|
||||
] = None,
|
||||
max_items: Annotated[
|
||||
Optional[int],
|
||||
deprecated(MAX_ITEMS_DEPRECATION_MSG),
|
||||
] = None,
|
||||
unique_items: Optional[bool] = None,
|
||||
min_length: Optional[int] = None,
|
||||
max_length: Optional[int] = None,
|
||||
@@ -316,8 +337,14 @@ def Field(
|
||||
multiple_of: Optional[float] = None,
|
||||
max_digits: Optional[int] = None,
|
||||
decimal_places: Optional[int] = None,
|
||||
min_items: Optional[int] = None,
|
||||
max_items: Optional[int] = None,
|
||||
min_items: Annotated[
|
||||
Optional[int],
|
||||
deprecated(MIN_ITEMS_DEPRECATION_MSG),
|
||||
] = None,
|
||||
max_items: Annotated[
|
||||
Optional[int],
|
||||
deprecated(MAX_ITEMS_DEPRECATION_MSG),
|
||||
] = None,
|
||||
unique_items: Optional[bool] = None,
|
||||
min_length: Optional[int] = None,
|
||||
max_length: Optional[int] = None,
|
||||
@@ -349,8 +376,14 @@ def Field(
|
||||
multiple_of: Optional[float] = None,
|
||||
max_digits: Optional[int] = None,
|
||||
decimal_places: Optional[int] = None,
|
||||
min_items: Optional[int] = None,
|
||||
max_items: Optional[int] = None,
|
||||
min_items: Annotated[
|
||||
Optional[int],
|
||||
deprecated(MIN_ITEMS_DEPRECATION_MSG),
|
||||
] = None,
|
||||
max_items: Annotated[
|
||||
Optional[int],
|
||||
deprecated(MAX_ITEMS_DEPRECATION_MSG),
|
||||
] = None,
|
||||
unique_items: Optional[bool] = None,
|
||||
min_length: Optional[int] = None,
|
||||
max_length: Optional[int] = None,
|
||||
@@ -371,6 +404,16 @@ def Field(
|
||||
schema_extra: Optional[dict[str, Any]] = None,
|
||||
) -> Any:
|
||||
current_schema_extra = schema_extra or {}
|
||||
|
||||
if min_items is not None:
|
||||
warnings.warn(MIN_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
|
||||
if min_length is None:
|
||||
min_length = min_items
|
||||
if max_items is not None:
|
||||
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
|
||||
if max_length is None:
|
||||
max_length = max_items
|
||||
|
||||
# Extract possible alias settings from schema_extra so we can control precedence
|
||||
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
|
||||
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
|
||||
@@ -388,8 +431,6 @@ def Field(
|
||||
"multiple_of": multiple_of,
|
||||
"max_digits": max_digits,
|
||||
"decimal_places": decimal_places,
|
||||
"min_items": min_items,
|
||||
"max_items": max_items,
|
||||
"unique_items": unique_items,
|
||||
"min_length": min_length,
|
||||
"max_length": max_length,
|
||||
|
||||
@@ -54,3 +54,37 @@ def test_repr():
|
||||
|
||||
instance = Model(id=123, foo="bar")
|
||||
assert "foo=" not in repr(instance)
|
||||
|
||||
|
||||
def test_min_items():
|
||||
with pytest.warns(
|
||||
DeprecationWarning,
|
||||
match="`min_items` is deprecated and will be removed, use `min_length` instead",
|
||||
):
|
||||
|
||||
class Model(SQLModel):
|
||||
items: list[int] = Field(min_items=2)
|
||||
|
||||
Model(items=[1, 2])
|
||||
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
Model(items=[1])
|
||||
assert len(exc_info.value.errors()) == 1
|
||||
assert exc_info.value.errors()[0]["type"] == "too_short"
|
||||
|
||||
|
||||
def test_max_items():
|
||||
with pytest.warns(
|
||||
DeprecationWarning,
|
||||
match="`max_items` is deprecated and will be removed, use `max_length` instead",
|
||||
):
|
||||
|
||||
class Model(SQLModel):
|
||||
items: list[int] = Field(max_items=2)
|
||||
|
||||
Model(items=[1, 2])
|
||||
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
Model(items=[1, 2, 3])
|
||||
assert len(exc_info.value.errors()) == 1
|
||||
assert exc_info.value.errors()[0]["type"] == "too_long"
|
||||
|
||||
Reference in New Issue
Block a user