]> git.ipfire.org Git - thirdparty/fastapi/sqlmodel.git/commitdiff
Add `fail_fast` param to Field, add tests add-missing-parameters-to-field-2 1726/head
authorYurii Motov <yurii.motov.monte@gmail.com>
Wed, 28 Jan 2026 16:20:53 +0000 (17:20 +0100)
committerYurii Motov <yurii.motov.monte@gmail.com>
Wed, 28 Jan 2026 16:20:53 +0000 (17:20 +0100)
sqlmodel/main.py
tests/test_pydantic/test_field.py

index fe9eb4e6f715ad0b3fee9187f03ba447bc437813..07c836fb323b9f23c85fd740a247579e664cf64f 100644 (file)
@@ -229,6 +229,7 @@ def Field(
     min_length: Optional[int] = None,
     max_length: Optional[int] = None,
     union_mode: Optional[Literal["smart", "left_to_right"]] = None,
+    fail_fast: Optional[bool] = None,
     allow_mutation: bool = True,
     regex: Optional[str] = None,
     discriminator: Optional[str] = None,
@@ -275,6 +276,7 @@ def Field(
     min_length: Optional[int] = None,
     max_length: Optional[int] = None,
     union_mode: Optional[Literal["smart", "left_to_right"]] = None,
+    fail_fast: Optional[bool] = None,
     allow_mutation: bool = True,
     regex: Optional[str] = None,
     discriminator: Optional[str] = None,
@@ -330,6 +332,7 @@ def Field(
     min_length: Optional[int] = None,
     max_length: Optional[int] = None,
     union_mode: Optional[Literal["smart", "left_to_right"]] = None,
+    fail_fast: Optional[bool] = None,
     allow_mutation: bool = True,
     regex: Optional[str] = None,
     discriminator: Optional[str] = None,
@@ -366,6 +369,7 @@ def Field(
     min_length: Optional[int] = None,
     max_length: Optional[int] = None,
     union_mode: Optional[Literal["smart", "left_to_right"]] = None,
+    fail_fast: Optional[bool] = None,
     allow_mutation: bool = True,
     regex: Optional[str] = None,
     discriminator: Optional[str] = None,
@@ -389,6 +393,7 @@ def Field(
         "coerce_numbers_to_str",
         "validate_default",
         "union_mode",
+        "fail_fast",
     ):
         if param_name in current_schema_extra:
             msg = f"Pass `{param_name}` parameter directly to Field instead of passing it via `schema_extra`"
@@ -403,6 +408,7 @@ def Field(
     current_validate_default = validate_default or current_schema_extra.pop(
         "validate_default", None
     )
+    current_fail_fast = fail_fast or current_schema_extra.pop("fail_fast", None)
     field_info_kwargs = {
         "alias": alias,
         "title": title,
@@ -424,6 +430,7 @@ def Field(
         "unique_items": unique_items,
         "min_length": min_length,
         "max_length": max_length,
+        "fail_fast": current_fail_fast,
         "allow_mutation": allow_mutation,
         "regex": regex,
         "discriminator": discriminator,
index 0635ce73dbe5d43969a70bf5157c6583744f1a8c..284cb81eb4e0e7d911b098ffe0a80fd4c4c3361e 100644 (file)
@@ -195,3 +195,51 @@ def test_union_mode_via_schema_extra():  # Current workaround. Remove after some
 
     c = Model.model_validate({"val": 123.1})
     assert isinstance(c.val, float)
+
+
+def test_fail_fast_true():
+    class Model(SQLModel):
+        val: list[int] = Field(fail_fast=True)
+
+    with pytest.raises(ValidationError) as exc_info:
+        Model.model_validate({"val": [1.1, "not an int"]})
+
+    errors = exc_info.value.errors()
+    assert len(errors) == 1
+    assert errors[0]["type"] == "int_from_float"
+
+
+@pytest.mark.parametrize("fail_fast", [None, False])
+def test_fail_fast_false(fail_fast: Optional[bool]):
+    class Model(SQLModel):
+        val: list[int] = Field(fail_fast=fail_fast)
+
+    with pytest.raises(ValidationError) as exc_info:
+        Model.model_validate({"val": [1.1, "not an int"]})
+
+    errors = exc_info.value.errors()
+    assert len(errors) == 2
+    error_types = {error["type"] for error in errors}
+
+    assert "int_from_float" in error_types
+    assert "int_parsing" in error_types
+
+
+def test_fail_fast_via_schema_extra():  # Current workaround. Remove after some time
+    with pytest.warns(
+        UserWarning,
+        match=(
+            "Pass `fail_fast` parameter directly to Field instead of passing "
+            "it via `schema_extra`"
+        ),
+    ):
+
+        class Model(SQLModel):
+            val: list[int] = Field(schema_extra={"fail_fast": True})
+
+    with pytest.raises(ValidationError) as exc_info:
+        Model.model_validate({"val": [1.1, "not an int"]})
+
+    errors = exc_info.value.errors()
+    assert len(errors) == 1
+    assert errors[0]["type"] == "int_from_float"