Skip to content

Commit aa212b0

Browse files
committed
Fix and deprecate min_items and max_items parameters to Field
1 parent 5611bda commit aa212b0

File tree

2 files changed

+85
-10
lines changed

2 files changed

+85
-10
lines changed

sqlmodel/main.py

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import builtins
44
import ipaddress
55
import uuid
6+
import warnings
67
import weakref
78
from collections.abc import Mapping, Sequence, Set
89
from datetime import date, datetime, time, timedelta
@@ -11,6 +12,7 @@
1112
from pathlib import Path
1213
from typing import (
1314
TYPE_CHECKING,
15+
Annotated,
1416
Any,
1517
Callable,
1618
ClassVar,
@@ -89,6 +91,13 @@
8991
]
9092
OnDeleteType = Literal["CASCADE", "SET NULL", "RESTRICT"]
9193

94+
MIN_ITEMS_DEPRECATION_MSG = (
95+
"`min_items` is deprecated and will be removed, use `min_length` instead"
96+
)
97+
MAX_ITEMS_DEPRECATION_MSG = (
98+
"`max_items` is deprecated and will be removed, use `max_length` instead"
99+
)
100+
92101

93102
def __dataclass_transform__(
94103
*,
@@ -221,8 +230,14 @@ def Field(
221230
multiple_of: Optional[float] = None,
222231
max_digits: Optional[int] = None,
223232
decimal_places: Optional[int] = None,
224-
min_items: Optional[int] = None,
225-
max_items: Optional[int] = None,
233+
min_items: Annotated[
234+
Optional[int],
235+
deprecated(MIN_ITEMS_DEPRECATION_MSG),
236+
] = None,
237+
max_items: Annotated[
238+
Optional[int],
239+
deprecated(MAX_ITEMS_DEPRECATION_MSG),
240+
] = None,
226241
unique_items: Optional[bool] = None,
227242
min_length: Optional[int] = None,
228243
max_length: Optional[int] = None,
@@ -264,8 +279,14 @@ def Field(
264279
multiple_of: Optional[float] = None,
265280
max_digits: Optional[int] = None,
266281
decimal_places: Optional[int] = None,
267-
min_items: Optional[int] = None,
268-
max_items: Optional[int] = None,
282+
min_items: Annotated[
283+
Optional[int],
284+
deprecated(MIN_ITEMS_DEPRECATION_MSG),
285+
] = None,
286+
max_items: Annotated[
287+
Optional[int],
288+
deprecated(MAX_ITEMS_DEPRECATION_MSG),
289+
] = None,
269290
unique_items: Optional[bool] = None,
270291
min_length: Optional[int] = None,
271292
max_length: Optional[int] = None,
@@ -316,8 +337,14 @@ def Field(
316337
multiple_of: Optional[float] = None,
317338
max_digits: Optional[int] = None,
318339
decimal_places: Optional[int] = None,
319-
min_items: Optional[int] = None,
320-
max_items: Optional[int] = None,
340+
min_items: Annotated[
341+
Optional[int],
342+
deprecated(MIN_ITEMS_DEPRECATION_MSG),
343+
] = None,
344+
max_items: Annotated[
345+
Optional[int],
346+
deprecated(MAX_ITEMS_DEPRECATION_MSG),
347+
] = None,
321348
unique_items: Optional[bool] = None,
322349
min_length: Optional[int] = None,
323350
max_length: Optional[int] = None,
@@ -349,8 +376,14 @@ def Field(
349376
multiple_of: Optional[float] = None,
350377
max_digits: Optional[int] = None,
351378
decimal_places: Optional[int] = None,
352-
min_items: Optional[int] = None,
353-
max_items: Optional[int] = None,
379+
min_items: Annotated[
380+
Optional[int],
381+
deprecated(MIN_ITEMS_DEPRECATION_MSG),
382+
] = None,
383+
max_items: Annotated[
384+
Optional[int],
385+
deprecated(MAX_ITEMS_DEPRECATION_MSG),
386+
] = None,
354387
unique_items: Optional[bool] = None,
355388
min_length: Optional[int] = None,
356389
max_length: Optional[int] = None,
@@ -371,6 +404,16 @@ def Field(
371404
schema_extra: Optional[dict[str, Any]] = None,
372405
) -> Any:
373406
current_schema_extra = schema_extra or {}
407+
408+
if min_items is not None:
409+
warnings.warn(MIN_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
410+
if min_length is None:
411+
min_length = min_items
412+
if max_items is not None:
413+
warnings.warn(MAX_ITEMS_DEPRECATION_MSG, DeprecationWarning, stacklevel=2)
414+
if max_length is None:
415+
max_length = max_items
416+
374417
# Extract possible alias settings from schema_extra so we can control precedence
375418
schema_validation_alias = current_schema_extra.pop("validation_alias", None)
376419
schema_serialization_alias = current_schema_extra.pop("serialization_alias", None)
@@ -388,8 +431,6 @@ def Field(
388431
"multiple_of": multiple_of,
389432
"max_digits": max_digits,
390433
"decimal_places": decimal_places,
391-
"min_items": min_items,
392-
"max_items": max_items,
393434
"unique_items": unique_items,
394435
"min_length": min_length,
395436
"max_length": max_length,

tests/test_pydantic/test_field.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,37 @@ class Model(SQLModel):
5454

5555
instance = Model(id=123, foo="bar")
5656
assert "foo=" not in repr(instance)
57+
58+
59+
def test_min_items():
60+
with pytest.warns(
61+
DeprecationWarning,
62+
match="`min_items` is deprecated and will be removed, use `min_length` instead",
63+
):
64+
65+
class Model(SQLModel):
66+
items: list[int] = Field(min_items=2)
67+
68+
Model(items=[1, 2])
69+
70+
with pytest.raises(ValidationError) as exc_info:
71+
Model(items=[1])
72+
assert len(exc_info.value.errors()) == 1
73+
assert exc_info.value.errors()[0]["type"] == "too_short"
74+
75+
76+
def test_max_items():
77+
with pytest.warns(
78+
DeprecationWarning,
79+
match="`max_items` is deprecated and will be removed, use `max_length` instead",
80+
):
81+
82+
class Model(SQLModel):
83+
items: list[int] = Field(max_items=2)
84+
85+
Model(items=[1, 2])
86+
87+
with pytest.raises(ValidationError) as exc_info:
88+
Model(items=[1, 2, 3])
89+
assert len(exc_info.value.errors()) == 1
90+
assert exc_info.value.errors()[0]["type"] == "too_long"

0 commit comments

Comments
 (0)