Skip to content

Commit 194bc41

Browse files
committed
Add exclude_if param to Field, add tests
1 parent 5b64d05 commit 194bc41

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
@@ -148,3 +148,48 @@ class Model(SQLModel):
148148
model_schema = Model.model_json_schema()
149149
assert model_schema["properties"]["old_field"]["deprecated"] is True
150150
assert model_schema["properties"]["another_old_field"]["deprecated"] is True
151+
152+
153+
def test_exclude_if():
154+
def is_empty_string(value: Any) -> bool:
155+
return value == ""
156+
157+
class Model(SQLModel):
158+
name: str = Field(exclude_if=is_empty_string)
159+
age: int
160+
161+
model1 = Model(name="Alice", age=30)
162+
model2 = Model(name="", age=25)
163+
164+
dict1 = model1.model_dump()
165+
dict2 = model2.model_dump()
166+
167+
assert "name" in dict1
168+
assert dict1["name"] == "Alice"
169+
170+
assert "name" not in dict2
171+
172+
173+
def test_exclude_if_via_schema_extra():
174+
def is_empty_string(value: Any) -> bool:
175+
return value == ""
176+
177+
with pytest.warns(
178+
DeprecationWarning,
179+
match="Pass `exclude_if` parameter directly to Field instead of passing it via `schema_extra`",
180+
):
181+
182+
class Model(SQLModel):
183+
name: str = Field(schema_extra={"exclude_if": is_empty_string})
184+
age: int
185+
186+
model1 = Model(name="Alice", age=30)
187+
model2 = Model(name="", age=25)
188+
189+
dict1 = model1.model_dump()
190+
dict2 = model2.model_dump()
191+
192+
assert "name" in dict1
193+
assert dict1["name"] == "Alice"
194+
195+
assert "name" not in dict2

0 commit comments

Comments
 (0)