Skip to content

Commit 99f8ce3

Browse files
✨ Add support for all Field parameters from Pydantic 1.9.0 and above, make Pydantic 1.9.0 the minimum required version (#440)
Co-authored-by: Sebastián Ramírez <[email protected]>
1 parent d05c3ee commit 99f8ce3

File tree

4 files changed

+73
-2
lines changed

4 files changed

+73
-2
lines changed

Diff for: pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ classifiers = [
3232
[tool.poetry.dependencies]
3333
python = "^3.7"
3434
SQLAlchemy = ">=1.4.36,<2.0.0"
35-
pydantic = "^1.8.2"
35+
pydantic = "^1.9.0"
3636
sqlalchemy2-stubs = {version = "*", allow-prereleases = true}
3737

3838
[tool.poetry.group.dev.dependencies]

Diff for: sqlmodel/main.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,17 @@ def Field(
145145
lt: Optional[float] = None,
146146
le: Optional[float] = None,
147147
multiple_of: Optional[float] = None,
148+
max_digits: Optional[int] = None,
149+
decimal_places: Optional[int] = None,
148150
min_items: Optional[int] = None,
149151
max_items: Optional[int] = None,
152+
unique_items: Optional[bool] = None,
150153
min_length: Optional[int] = None,
151154
max_length: Optional[int] = None,
152155
allow_mutation: bool = True,
153156
regex: Optional[str] = None,
157+
discriminator: Optional[str] = None,
158+
repr: bool = True,
154159
primary_key: bool = False,
155160
foreign_key: Optional[Any] = None,
156161
unique: bool = False,
@@ -176,12 +181,17 @@ def Field(
176181
lt=lt,
177182
le=le,
178183
multiple_of=multiple_of,
184+
max_digits=max_digits,
185+
decimal_places=decimal_places,
179186
min_items=min_items,
180187
max_items=max_items,
188+
unique_items=unique_items,
181189
min_length=min_length,
182190
max_length=max_length,
183191
allow_mutation=allow_mutation,
184192
regex=regex,
193+
discriminator=discriminator,
194+
repr=repr,
185195
primary_key=primary_key,
186196
foreign_key=foreign_key,
187197
unique=unique,
@@ -587,7 +597,11 @@ def parse_obj(
587597

588598
def __repr_args__(self) -> Sequence[Tuple[Optional[str], Any]]:
589599
# Don't show SQLAlchemy private attributes
590-
return [(k, v) for k, v in self.__dict__.items() if not k.startswith("_sa_")]
600+
return [
601+
(k, v)
602+
for k, v in super().__repr_args__()
603+
if not (isinstance(k, str) and k.startswith("_sa_"))
604+
]
591605

592606
# From Pydantic, override to enforce validation with dict
593607
@classmethod

Diff for: tests/test_pydantic/__init__.py

Whitespace-only changes.

Diff for: tests/test_pydantic/test_field.py

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from decimal import Decimal
2+
from typing import Optional, Union
3+
4+
import pytest
5+
from pydantic import ValidationError
6+
from sqlmodel import Field, SQLModel
7+
from typing_extensions import Literal
8+
9+
10+
def test_decimal():
11+
class Model(SQLModel):
12+
dec: Decimal = Field(max_digits=4, decimal_places=2)
13+
14+
Model(dec=Decimal("3.14"))
15+
Model(dec=Decimal("69.42"))
16+
17+
with pytest.raises(ValidationError):
18+
Model(dec=Decimal("3.142"))
19+
with pytest.raises(ValidationError):
20+
Model(dec=Decimal("0.069"))
21+
with pytest.raises(ValidationError):
22+
Model(dec=Decimal("420"))
23+
24+
25+
def test_discriminator():
26+
# Example adapted from
27+
# [Pydantic docs](https://pydantic-docs.helpmanual.io/usage/types/#discriminated-unions-aka-tagged-unions):
28+
29+
class Cat(SQLModel):
30+
pet_type: Literal["cat"]
31+
meows: int
32+
33+
class Dog(SQLModel):
34+
pet_type: Literal["dog"]
35+
barks: float
36+
37+
class Lizard(SQLModel):
38+
pet_type: Literal["reptile", "lizard"]
39+
scales: bool
40+
41+
class Model(SQLModel):
42+
pet: Union[Cat, Dog, Lizard] = Field(..., discriminator="pet_type")
43+
n: int
44+
45+
Model(pet={"pet_type": "dog", "barks": 3.14}, n=1) # type: ignore[arg-type]
46+
47+
with pytest.raises(ValidationError):
48+
Model(pet={"pet_type": "dog"}, n=1) # type: ignore[arg-type]
49+
50+
51+
def test_repr():
52+
class Model(SQLModel):
53+
id: Optional[int] = Field(primary_key=True)
54+
foo: str = Field(repr=False)
55+
56+
instance = Model(id=123, foo="bar")
57+
assert "foo=" not in repr(instance)

0 commit comments

Comments
 (0)