Skip to content

Commit 272181e

Browse files
committed
fix: make generics work with SQLModel as base class
1 parent 7d00768 commit 272181e

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

sqlmodel/main.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,12 @@ def __new__(
538538
config_kwargs = {
539539
key: kwargs[key] for key in kwargs.keys() & allowed_config_kwargs
540540
}
541+
# Also include pydantic's internal kwargs
542+
config_kwargs.update(
543+
(key, value)
544+
for key, value in kwargs.items()
545+
if key.startswith("__pydantic_")
546+
)
541547
new_cls = super().__new__(cls, name, bases, dict_used, **config_kwargs)
542548
new_cls.__annotations__ = {
543549
**relationship_annotations,
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from typing import Generic, List, Optional, TypeVar
2+
3+
import pydantic
4+
import pytest
5+
from sqlmodel import SQLModel
6+
7+
from tests.conftest import needs_pydanticv2
8+
9+
# Example adapted from
10+
# https://docs.pydantic.dev/2.10/concepts/models/#generic-models
11+
DataT = TypeVar("DataT")
12+
13+
14+
class DataModel(SQLModel):
15+
numbers: List[int]
16+
people: List[str]
17+
18+
19+
class Response(SQLModel, Generic[DataT]):
20+
data: Optional[DataT] = None
21+
22+
23+
@needs_pydanticv2
24+
@pytest.mark.parametrize(
25+
["data_type", "data_value"],
26+
[
27+
(int, 1),
28+
(str, "value"),
29+
(DataModel, DataModel(numbers=[1, 2, 3], people=[])),
30+
(DataModel, {"numbers": [1, 2, 3], "people": []}),
31+
],
32+
)
33+
def test_valid_generics(data_type, data_value):
34+
# Should be able to create a model without an error.
35+
response = Response[data_type](data=data_value)
36+
assert Response[data_type](**response.model_dump()) == response
37+
38+
39+
@needs_pydanticv2
40+
@pytest.mark.parametrize(
41+
["data_type", "data_value", "error_loc", "error_type"],
42+
[
43+
(
44+
str,
45+
1,
46+
("data",),
47+
"string_type",
48+
),
49+
(
50+
int,
51+
"some-string",
52+
("data",),
53+
"int_parsing",
54+
),
55+
(
56+
DataModel,
57+
"some-string",
58+
("data",),
59+
"model_attributes_type",
60+
),
61+
(
62+
DataModel,
63+
{"numbers": [1, 2, "unexpected string"], "people": []},
64+
("data", "numbers", 2),
65+
"int_parsing",
66+
),
67+
],
68+
)
69+
def test_invalid_generics(data_type, data_value, error_loc, error_type):
70+
with pytest.raises(pydantic.ValidationError) as raised:
71+
Response[data_type](data=data_value)
72+
[error_dict] = raised.value.errors()
73+
assert error_dict["loc"] == error_loc
74+
assert error_dict["type"] == error_type

0 commit comments

Comments
 (0)