-
-
Notifications
You must be signed in to change notification settings - Fork 298
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] extendable_fastapi: New class StrictExtendableBaseModel
- Loading branch information
1 parent
b834273
commit 6d64994
Showing
7 changed files
with
113 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
from . import fastapi_dispatcher | ||
from .schemas import StrictExtendableBaseModel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from extendable_pydantic import ExtendableBaseModel | ||
|
||
|
||
class StrictExtendableBaseModel( | ||
ExtendableBaseModel, | ||
revalidate_instances="always", | ||
validate_assignment=True, | ||
extra="forbid", | ||
strict=True, | ||
): | ||
""" | ||
An ExtendableBaseModel with strict validation. | ||
By default, Pydantic does not revalidate instances during validation, nor | ||
when the data is changed. Validation only occurs when the model is created. | ||
This is not suitable for a REST API, where the data is changed after the | ||
model is created or the model is created from a partial set of data and | ||
then updated with more data. This class enforce strict validation by | ||
forcing the revalidation of instances when the method `model_validate` is | ||
called and by ensuring that the values assignment is validated. | ||
The following parameters are added: | ||
* revalidate_instances="always": model instances are revalidated during validation | ||
(default is "never") | ||
* validate_assignment=True: revalidate the model when the data is changed (default is False) | ||
* extra="forbid": Forbid any extra attributes (default is "ignore") | ||
* strict=True: raise an error if a value's type does not match the field's type | ||
annotation (default is False; Pydantic attempts to coerce values to the correct type) | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import test_strict_extendable_base_model |
68 changes: 68 additions & 0 deletions
68
extendable_fastapi/tests/test_strict_extendable_base_model.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import warnings | ||
from datetime import date | ||
|
||
from extendable_pydantic import ExtendableBaseModel | ||
|
||
from pydantic import ValidationError | ||
|
||
from ..schemas import StrictExtendableBaseModel | ||
from .common import FastAPITransactionCase | ||
|
||
|
||
class TestStrictExtendableBaseModel(FastAPITransactionCase): | ||
class Model(ExtendableBaseModel): | ||
x: int | ||
d: date | None | ||
|
||
class StrictModel(StrictExtendableBaseModel): | ||
x: int | ||
d: date | None | ||
|
||
def test_Model_revalidate_instance_never(self): | ||
# Missing required fields but no re-validation | ||
m = self.Model.model_construct() | ||
self.assertEqual(m.model_validate(m).model_dump(), {}) | ||
|
||
def test_StrictModel_revalidate_instance_always(self): | ||
# Missing required fields and always revalidate | ||
m = self.StrictModel.model_construct() | ||
with self.assertRaises(ValidationError): | ||
m.model_validate(m) | ||
|
||
def test_Model_validate_assignment_false(self): | ||
# Wrong assignment but no re-validation at assignment | ||
m = self.Model(x=1, d=None) | ||
m.x = "TEST" | ||
with warnings.catch_warnings(): | ||
# Disable 'Expected `int` but got `str`' warning | ||
warnings.simplefilter("ignore") | ||
self.assertEqual(m.model_dump(), {"x": "TEST", "d": None}) | ||
|
||
def test_StrictModel_validate_assignment_true(self): | ||
# Wrong assignment and validation at assignment | ||
m = self.StrictModel.model_construct() | ||
m.x = 1 # Validate only this field -> OK even if m.d is not set | ||
with self.assertRaises(ValidationError): | ||
m.x = "TEST" | ||
|
||
def test_Model_extra_ignored(self): | ||
# Ignore extra fields | ||
m = self.Model(x=1, z=3, d=None) | ||
self.assertEqual(m.model_dump(), {"x": 1, "d": None}) | ||
|
||
def test_StrictModel_extra_forbidden(self): | ||
# Forbid extra fields | ||
with self.assertRaises(ValidationError): | ||
self.StrictModel(x=1, z=3, d=None) | ||
|
||
def test_Model_strict_false(self): | ||
# Coerce str->date is allowed | ||
m = self.Model(x=1, d=None) | ||
m.d = "2023-01-01" | ||
self.assertTrue(m.model_validate(m)) | ||
|
||
def test_StrictModel_strict_true(self): | ||
# Coerce str->date is forbidden | ||
m = self.StrictModel(x=1, d=None) | ||
with self.assertRaises(ValidationError): | ||
m.d = "2023-01-01" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters