Skip to content

Commit f3300d7

Browse files
committed
Add exclude_if param to Field, add tests
1 parent 159838f commit f3300d7

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

sqlmodel/main.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ def Field(
216216
examples: Optional[list[Any]] = None,
217217
deprecated: Union[Deprecated, str, bool, None] = None,
218218
exclude: Union[Set[Union[int, str]], Mapping[Union[int, str], Any], Any] = None,
219+
exclude_if: Optional[Callable[[Any], bool]] = None,
219220
include: Union[Set[Union[int, str]], Mapping[Union[int, str], Any], Any] = None,
220221
const: Optional[bool] = None,
221222
gt: Optional[float] = None,
@@ -262,6 +263,7 @@ def Field(
262263
examples: Optional[list[Any]] = None,
263264
deprecated: Union[Deprecated, str, bool, None] = None,
264265
exclude: Union[Set[Union[int, str]], Mapping[Union[int, str], Any], Any] = None,
266+
exclude_if: Optional[Callable[[Any], bool]] = None,
265267
include: Union[Set[Union[int, str]], Mapping[Union[int, str], Any], Any] = None,
266268
const: Optional[bool] = None,
267269
gt: Optional[float] = None,
@@ -317,6 +319,7 @@ def Field(
317319
examples: Optional[list[Any]] = None,
318320
deprecated: Union[Deprecated, str, bool, None] = None,
319321
exclude: Union[Set[Union[int, str]], Mapping[Union[int, str], Any], Any] = None,
322+
exclude_if: Optional[Callable[[Any], bool]] = None,
320323
include: Union[Set[Union[int, str]], Mapping[Union[int, str], Any], Any] = None,
321324
const: Optional[bool] = None,
322325
gt: Optional[float] = None,
@@ -353,6 +356,7 @@ def Field(
353356
examples: Optional[list[Any]] = None,
354357
deprecated: Union[Deprecated, str, bool, None] = None,
355358
exclude: Union[Set[Union[int, str]], Mapping[Union[int, str], Any], Any] = None,
359+
exclude_if: Optional[Callable[[Any], bool]] = None,
356360
include: Union[Set[Union[int, str]], Mapping[Union[int, str], Any], Any] = None,
357361
const: Optional[bool] = None,
358362
gt: Optional[float] = None,
@@ -386,7 +390,7 @@ def Field(
386390
) -> Any:
387391
current_schema_extra = schema_extra or {}
388392

389-
for param_name in ("strict", "examples", "deprecated"):
393+
for param_name in ("strict", "examples", "deprecated", "exclude_if"):
390394
if param_name in current_schema_extra:
391395
msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
392396
warnings.warn(msg, DeprecationWarning, stacklevel=2)
@@ -397,13 +401,15 @@ def Field(
397401
current_strict = strict or current_schema_extra.pop("strict", None)
398402
current_examples = examples or current_schema_extra.pop("examples", None)
399403
current_deprecated = deprecated or current_schema_extra.pop("deprecated", None)
404+
current_exclude_if = exclude_if or current_schema_extra.pop("exclude_if", None)
400405
field_info_kwargs = {
401406
"alias": alias,
402407
"title": title,
403408
"description": description,
404409
"examples": current_examples,
405410
"deprecated": current_deprecated,
406411
"exclude": exclude,
412+
"exclude_if": current_exclude_if,
407413
"include": include,
408414
"const": const,
409415
"gt": gt,

tests/test_pydantic/test_field.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from decimal import Decimal
2-
from typing import Literal, Optional, Union
2+
from typing import Any, Literal, Optional, Union
33

44
import pytest
55
from pydantic import ValidationError
@@ -175,3 +175,48 @@ class Model(SQLModel):
175175
model_schema = Model.model_json_schema()
176176
assert model_schema["properties"]["old_field"]["deprecated"] is True
177177
assert model_schema["properties"]["another_old_field"]["deprecated"] is True
178+
179+
180+
def test_exclude_if():
181+
def is_empty_string(value: Any) -> bool:
182+
return value == ""
183+
184+
class Model(SQLModel):
185+
name: str = Field(exclude_if=is_empty_string)
186+
age: int
187+
188+
model1 = Model(name="Alice", age=30)
189+
model2 = Model(name="", age=25)
190+
191+
dict1 = model1.model_dump()
192+
dict2 = model2.model_dump()
193+
194+
assert "name" in dict1
195+
assert dict1["name"] == "Alice"
196+
197+
assert "name" not in dict2
198+
199+
200+
def test_exclude_if_via_schema_extra():
201+
def is_empty_string(value: Any) -> bool:
202+
return value == ""
203+
204+
with pytest.warns(
205+
DeprecationWarning,
206+
match="Pass `exclude_if` parameter directly to Field instead of passing it via `schema_extra`",
207+
):
208+
209+
class Model(SQLModel):
210+
name: str = Field(schema_extra={"exclude_if": is_empty_string})
211+
age: int
212+
213+
model1 = Model(name="Alice", age=30)
214+
model2 = Model(name="", age=25)
215+
216+
dict1 = model1.model_dump()
217+
dict2 = model2.model_dump()
218+
219+
assert "name" in dict1
220+
assert dict1["name"] == "Alice"
221+
222+
assert "name" not in dict2

0 commit comments

Comments
 (0)