Skip to content

Commit bbf8b1e

Browse files
committed
Add pydantic v2
1 parent 298283e commit bbf8b1e

File tree

11 files changed

+111
-71
lines changed

11 files changed

+111
-71
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Most Notable Features are:
2424

2525
## Benchmarks
2626

27+
### v0.
2728
On an average PC ~16GB RAM, i7 Core
2829

2930
```
@@ -55,6 +56,37 @@ benchmark_bulk_insert[redis_store] 1,025.0436 (8.29)
5556
-------------------------------------------------------------------------------------------------------------------------
5657
```
5758

59+
# v1. (with pydantic v2)
60+
61+
```
62+
------------------------------------------------- benchmark: 22 tests -------------------------------------------------
63+
Name (time in us) Mean Min Max
64+
-----------------------------------------------------------------------------------------------------------------------
65+
benchmark_delete[redis_store-Wuthering Heights] 124.1668 (1.0) 108.9610 (1.0) 418.1310 (1.04)
66+
benchmark_bulk_delete[redis_store] 137.7564 (1.11) 121.6380 (1.12) 470.7510 (1.17)
67+
benchmark_select_columns_for_one_id[redis_store-book2] 166.7328 (1.34) 147.9490 (1.36) 430.3780 (1.07)
68+
benchmark_select_columns_for_one_id[redis_store-book1] 171.0826 (1.38) 148.6430 (1.36) 426.0820 (1.06)
69+
benchmark_select_columns_for_one_id[redis_store-book0] 171.7202 (1.38) 148.6460 (1.36) 431.3730 (1.07)
70+
benchmark_select_columns_for_one_id[redis_store-book3] 172.1800 (1.39) 148.9410 (1.37) 471.5910 (1.17)
71+
benchmark_select_all_for_one_id[redis_store-book1] 189.0068 (1.52) 163.5860 (1.50) 457.3090 (1.14)
72+
benchmark_select_all_for_one_id[redis_store-book2] 188.5258 (1.52) 163.6650 (1.50) 401.7030 (1.0)
73+
benchmark_select_all_for_one_id[redis_store-book3] 187.5434 (1.51) 165.3890 (1.52) 460.7100 (1.15)
74+
benchmark_select_all_for_one_id[redis_store-book0] 190.3049 (1.53) 165.7280 (1.52) 459.8080 (1.14)
75+
benchmark_select_columns_for_some_items[redis_store] 222.1405 (1.79) 198.9940 (1.83) 485.6230 (1.21)
76+
benchmark_select_columns_paginated[redis_store] 229.5429 (1.85) 200.4560 (1.84) 494.4250 (1.23)
77+
benchmark_select_default_paginated[redis_store] 262.3155 (2.11) 231.3960 (2.12) 568.8410 (1.42)
78+
benchmark_select_some_items[redis_store] 270.4251 (2.18) 232.3230 (2.13) 537.2130 (1.34)
79+
benchmark_update[redis_store-Wuthering Heights-data0] 280.6308 (2.26) 248.7310 (2.28) 676.0330 (1.68)
80+
benchmark_select_columns[redis_store] 316.7642 (2.55) 283.6720 (2.60) 560.9610 (1.40)
81+
benchmark_single_insert[redis_store-book2] 343.9583 (2.77) 284.1000 (2.61) 585.6200 (1.46)
82+
benchmark_single_insert[redis_store-book1] 328.5308 (2.65) 291.8760 (2.68) 600.8130 (1.50)
83+
benchmark_single_insert[redis_store-book3] 341.0249 (2.75) 292.2800 (2.68) 575.1020 (1.43)
84+
benchmark_single_insert[redis_store-book0] 349.9540 (2.82) 299.6660 (2.75) 606.0370 (1.51)
85+
benchmark_select_default[redis_store] 381.0231 (3.07) 346.2910 (3.18) 669.7460 (1.67)
86+
benchmark_bulk_insert[redis_store] 840.4876 (6.77) 790.2340 (7.25) 1,049.8260 (2.61)
87+
-----------------------------------------------------------------------------------------------------------------------
88+
```
89+
5890
## Contributions
5991

6092
Contributions are welcome. The docs have to maintained, the code has to be made cleaner, more idiomatic and faster,

pydantic_redis/_shared/model/base.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import typing
55
from typing import Dict, Tuple, Any, Type, Union, List, Optional
66

7-
from pydantic import BaseModel
7+
from pydantic import ConfigDict, BaseModel
8+
from pydantic.fields import ModelPrivateAttr
89

910
from pydantic_redis._shared.utils import (
1011
typing_get_origin,
@@ -45,9 +46,7 @@ class AbstractModel(BaseModel):
4546
_nested_model_tuple_fields: Dict[str, Tuple[Any, ...]] = {}
4647
_nested_model_list_fields: Dict[str, Type["AbstractModel"]] = {}
4748
_nested_model_fields: Dict[str, Type["AbstractModel"]] = {}
48-
49-
class Config:
50-
arbitrary_types_allowed = True
49+
model_config = ConfigDict(arbitrary_types_allowed=True)
5150

5251
@classmethod
5352
def get_store(cls) -> AbstractStore:
@@ -93,7 +92,10 @@ def get_primary_key_field(cls):
9392
Returns:
9493
the field that can be used to uniquely identify each record of current Model
9594
"""
96-
return cls._primary_key_field
95+
try:
96+
return cls._primary_key_field.get_default()
97+
except AttributeError:
98+
return cls._primary_key_field
9799

98100
@classmethod
99101
def get_field_types(cls) -> Dict[str, Any]:

pydantic_redis/_shared/store.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
"""
44
from typing import Optional, Union, Type, Dict, Any
55

6+
from pydantic.fields import ModelPrivateAttr
67
from redis import Redis
78
from redis.asyncio import Redis as AioRedis
8-
from pydantic import BaseModel
9+
from pydantic import ConfigDict, BaseModel
910
from redis.commands.core import Script, AsyncScript
1011

1112
from ..config import RedisConfig
@@ -45,10 +46,7 @@ class AbstractStore(BaseModel):
4546
] = None
4647
select_some_fields_for_some_ids_script: Optional[Union[AsyncScript, Script]] = None
4748
models: Dict[str, Type["AbstractModel"]] = {}
48-
49-
class Config:
50-
arbitrary_types_allowed = True
51-
orm_mode = True
49+
model_config = ConfigDict(arbitrary_types_allowed=True, from_attributes=True)
5250

5351
def __init__(
5452
self,
@@ -122,7 +120,7 @@ def register_model(self, model_class: Type["AbstractModel"]):
122120
a certain type of records to be saved in redis.
123121
"""
124122
if not isinstance(model_class.get_primary_key_field(), str):
125-
raise NotImplementedError(
123+
raise AttributeError(
126124
f"{model_class.__name__} should have a _primary_key_field"
127125
)
128126

pydantic_redis/_shared/utils.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
"""
44
import typing
5-
from typing import Any, Tuple, Optional, Union, Dict, Callable, Type, List
5+
from typing import Any, Tuple, Optional, Union, Dict, Type, List
66

77
import orjson
88

@@ -63,15 +63,16 @@ def from_bytes_to_str(value: Union[str, bytes]) -> str:
6363
Returns:
6464
the string value of the argument passed
6565
"""
66-
if isinstance(value, bytes):
66+
try:
6767
return str(value, "utf-8")
68-
return value
68+
except TypeError:
69+
return value
6970

7071

7172
def from_str_or_bytes_to_any(value: Any, field_type: Type) -> Any:
7273
"""Converts str or bytes to arbitrary data.
7374
74-
Converts the the `value` from a string or bytes to the `field_type`.
75+
Converts the `value` from a string or bytes to the `field_type`.
7576
7677
Args:
7778
value: the string or bytes to be transformed to the `field_type`
@@ -116,9 +117,10 @@ def default_json_dump(obj: Any):
116117
Returns:
117118
the bytes or string value of the object
118119
"""
119-
if hasattr(obj, "json") and isinstance(obj.json, Callable):
120-
return obj.json()
121-
return obj
120+
try:
121+
return obj.model_dump_json()
122+
except AttributeError:
123+
return obj
122124

123125

124126
def from_dict_to_key_value_list(data: Dict[str, Any]) -> List[Any]:

pydantic_redis/asyncio/model.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,6 @@ async def select(
184184
return parse_select_response(
185185
model=cls, response=response, as_models=(columns is None)
186186
)
187+
188+
189+
Store.model_rebuild()

pydantic_redis/config.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""
33
from typing import Optional
44

5-
from pydantic import BaseModel
5+
from pydantic import ConfigDict, BaseModel
66

77

88
class RedisConfig(BaseModel):
@@ -24,6 +24,8 @@ class RedisConfig(BaseModel):
2424
(default: utf-8)
2525
"""
2626

27+
model_config = ConfigDict(from_attributes=True)
28+
2729
host: str = "localhost"
2830
port: int = 6379
2931
db: int = 0
@@ -38,6 +40,3 @@ def redis_url(self) -> str:
3840
if self.password is None:
3941
return f"{proto}://{self.host}:{self.port}/{self.db}"
4042
return f"{proto}://:{self.password}@{self.host}:{self.port}/{self.db}"
41-
42-
class Config:
43-
orm_mode = True

pydantic_redis/syncio/model.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,6 @@ def select(
180180
return parse_select_response(
181181
model=cls, response=response, as_models=(columns is None)
182182
)
183+
184+
185+
Store.model_rebuild()

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
orjson==3.6.1
22
hiredis==2.0.0
3-
pydantic==1.9.2
3+
pydantic==2.6.1
44
pytest==7.0.1
55
pytest-benchmark==3.4.1
66
pytest-lazy-fixture==0.6.3

test/conftest.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,21 +50,21 @@ class Library(syn.Model):
5050
_primary_key_field: str = "name"
5151
name: str
5252
address: str
53-
books: List[Book] = None
53+
books: List[Book] = []
5454
lost: Optional[List[Book]] = None
5555
popular: Optional[Tuple[Book, Book]] = None
56-
new: Tuple[Book, Author, Book, int] = None
56+
new: Optional[Tuple[Book, Author, Book, int]] = None
5757

5858

5959
class AsyncLibrary(asy.Model):
6060
# the _primary_key_field is mandatory
6161
_primary_key_field: str = "name"
6262
name: str
6363
address: str
64-
books: List[AsyncBook] = None
64+
books: List[AsyncBook] = []
6565
lost: Optional[List[AsyncBook]] = None
6666
popular: Optional[Tuple[AsyncBook, AsyncBook]] = None
67-
new: Tuple[AsyncBook, AsyncAuthor, AsyncBook, int] = None
67+
new: Optional[Tuple[AsyncBook, AsyncAuthor, AsyncBook, int]] = None
6868

6969

7070
authors = {
@@ -113,30 +113,30 @@ class AsyncLibrary(asy.Model):
113113
async_books = [
114114
AsyncBook(
115115
title="Oliver Twist",
116-
author=authors["charles"],
116+
author=async_authors["charles"],
117117
published_on=date(year=1215, month=4, day=4),
118118
in_stock=False,
119119
rating=2,
120120
tags=["Classic"],
121121
),
122122
AsyncBook(
123123
title="Great Expectations",
124-
author=authors["charles"],
124+
author=async_authors["charles"],
125125
published_on=date(year=1220, month=4, day=4),
126126
rating=5,
127127
tags=["Classic"],
128128
),
129129
AsyncBook(
130130
title="Jane Eyre",
131-
author=authors["charles"],
131+
author=async_authors["charles"],
132132
published_on=date(year=1225, month=6, day=4),
133133
in_stock=False,
134134
rating=3.4,
135135
tags=["Classic", "Romance"],
136136
),
137137
AsyncBook(
138138
title="Wuthering Heights",
139-
author=authors["jane"],
139+
author=async_authors["jane"],
140140
published_on=date(year=1600, month=4, day=4),
141141
rating=4.0,
142142
tags=["Classic", "Romance"],

0 commit comments

Comments
 (0)