redis-dict 2.6.0__py3-none-any.whl → 2.7.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {redis_dict-2.6.0.dist-info → redis_dict-2.7.0.dist-info}/METADATA +48 -4
- redis_dict-2.7.0.dist-info/RECORD +6 -0
- {redis_dict-2.6.0.dist-info → redis_dict-2.7.0.dist-info}/WHEEL +1 -1
- redis_dict.py +43 -13
- redis_dict-2.6.0.dist-info/RECORD +0 -6
- {redis_dict-2.6.0.dist-info → redis_dict-2.7.0.dist-info}/LICENSE +0 -0
- {redis_dict-2.6.0.dist-info → redis_dict-2.7.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: redis-dict
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.7.0
|
4
4
|
Summary: Dictionary with Redis as storage backend
|
5
5
|
Home-page: https://github.com/Attumm/redisdict
|
6
6
|
Author: Melvin Bijman
|
@@ -44,7 +44,7 @@ The library includes utility functions for more complex use cases such as cachin
|
|
44
44
|
## Features
|
45
45
|
|
46
46
|
* Dictionary-like interface: Use familiar Python dictionary syntax to interact with Redis.
|
47
|
-
* Data Type Support: Comprehensive support for various data types
|
47
|
+
* Data Type Support: Comprehensive support for various data types.
|
48
48
|
* Pipelining support: Use pipelines for batch operations to improve performance.
|
49
49
|
* Expiration Support: Enables the setting of expiration times either globally or individually per key, through the use of context managers.
|
50
50
|
* Efficiency and Scalability: RedisDict is designed for use with large datasets and is optimized for efficiency. It retrieves only the data needed for a particular operation, ensuring efficient memory usage and fast performance.
|
@@ -253,9 +253,53 @@ print(dic["d"]) # Output: 4
|
|
253
253
|
For more advanced examples of RedisDict, please refer to the unit-test files in the repository. All features and functionalities are thoroughly tested in [unit tests (here)](https://github.com/Attumm/redis-dict/blob/main/tests.py#L1) Or take a look at load test for batching [load test](https://github.com/Attumm/redis-dict/blob/main/load_test.py#L1).
|
254
254
|
The unit-tests can be as used as a starting point.
|
255
255
|
|
256
|
-
|
256
|
+
## Types
|
257
257
|
|
258
|
-
|
258
|
+
### standard types
|
259
|
+
RedisDict supports a range of Python data types, from basic types to nested structures.
|
260
|
+
Basic types are handled natively, while complex data types like lists and dictionaries, RedisDict uses JSON serialization, specifically avoiding `pickle` due to its [security vulnerabilities](https://docs.python.org/3/library/pickle.html) in distributed computing contexts.
|
261
|
+
Although the library supports nested structures, the recommended best practice is to use RedisDict as a shallow dictionary.
|
262
|
+
This approach optimizes Redis database performance and efficiency by ensuring that each set and get operation efficiently maps to Redis's key-value storage capabilities, while still preserving the library's Pythonic interface.
|
263
|
+
Following types are supported:
|
264
|
+
`str, int, float, bool, NoneType, list, dict, tuple, set, datetime, date, time, timedelta, Decimal, complex, bytes, UUID, OrderedDict, defaultdict, frozenset`
|
265
|
+
```python
|
266
|
+
from redis_dict import RedisDict
|
267
|
+
|
268
|
+
from uuid import UUID
|
269
|
+
from decimal import Decimal
|
270
|
+
from collections import OrderedDict, defaultdict
|
271
|
+
from datetime import datetime, date, time, timedelta
|
272
|
+
|
273
|
+
|
274
|
+
dic = RedisDict()
|
275
|
+
|
276
|
+
dic["string"] = "Hello World"
|
277
|
+
dic["number"] = 42
|
278
|
+
dic["float"] = 3.14
|
279
|
+
dic["bool"] = True
|
280
|
+
dic["None"] = None
|
281
|
+
|
282
|
+
dic["list"] = [1, 2, 3]
|
283
|
+
dic["dict"] = {"a": 1, "b": 2}
|
284
|
+
dic["tuple"] = (1, 2, 3)
|
285
|
+
dic["set"] = {1, 2, 3}
|
286
|
+
|
287
|
+
dic["datetime"] = datetime.date(2024, 1, 1, 12, 30, 45)
|
288
|
+
dic["date"] = date(2024, 1, 1)
|
289
|
+
dic["time"] = time(12, 30, 45)
|
290
|
+
dic["delta"] = timedelta(days=1, hours=2)
|
291
|
+
|
292
|
+
dic["decimal"] = Decimal("3.14159")
|
293
|
+
dic["complex"] = complex(1, 2)
|
294
|
+
dic["bytes"] = bytes([72, 101, 108, 108, 111])
|
295
|
+
dic["uuid"] = UUID('12345678-1234-5678-1234-567812345678')
|
296
|
+
|
297
|
+
dic["ordered"] = OrderedDict([('a', 1), ('b', 2)])
|
298
|
+
dic["default"] = defaultdict(int, {'a': 1, 'b': 2})
|
299
|
+
dic["frozen"] = frozenset([1, 2, 3])
|
300
|
+
```
|
301
|
+
|
302
|
+
### Extending RedisDict with Custom Types
|
259
303
|
|
260
304
|
RedisDict supports custom type serialization. Here's how to add a new type:
|
261
305
|
|
@@ -0,0 +1,6 @@
|
|
1
|
+
redis_dict.py,sha256=LmP5C1lIf3KCG_3pfcnw3CZE5KuUUym2U_UqlbFoiVg,38214
|
2
|
+
redis_dict-2.7.0.dist-info/LICENSE,sha256=-QiLwYznh_vNUSz337k0faP9Jl0dgtCIHVZ39Uyl6cA,1070
|
3
|
+
redis_dict-2.7.0.dist-info/METADATA,sha256=8SDlje1sUiquUlKvk27LHRhLTsdwr9b5KTsKBa5XhGk,14300
|
4
|
+
redis_dict-2.7.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
5
|
+
redis_dict-2.7.0.dist-info/top_level.txt,sha256=Wyp5Xvq_imoxvu-c-Le1rbTZ3pYM5BF440H9YAcgBZ8,11
|
6
|
+
redis_dict-2.7.0.dist-info/RECORD,,
|
redis_dict.py
CHANGED
@@ -66,9 +66,14 @@ otherwise, they will be dropped.
|
|
66
66
|
>>> cache.get("1234") is None
|
67
67
|
>>> True
|
68
68
|
"""
|
69
|
+
# Types imports
|
69
70
|
import json
|
71
|
+
from datetime import datetime, time, timedelta, date
|
72
|
+
from decimal import Decimal
|
73
|
+
from uuid import UUID
|
74
|
+
from collections import OrderedDict, defaultdict
|
75
|
+
import base64
|
70
76
|
|
71
|
-
from datetime import timedelta
|
72
77
|
from typing import Any, Callable, Dict, Iterator, Set, List, Tuple, Union, Optional
|
73
78
|
from contextlib import contextmanager
|
74
79
|
|
@@ -189,7 +194,6 @@ class RedisDict:
|
|
189
194
|
expire (Union[int, None]): An optional expiration time for keys, in seconds.
|
190
195
|
|
191
196
|
"""
|
192
|
-
|
193
197
|
decoding_registry: DecodeType = {
|
194
198
|
type('').__name__: str,
|
195
199
|
type(1).__name__: int,
|
@@ -201,6 +205,20 @@ class RedisDict:
|
|
201
205
|
"dict": json.loads,
|
202
206
|
"tuple": _decode_tuple,
|
203
207
|
type(set()).__name__: _decode_set,
|
208
|
+
|
209
|
+
datetime.__name__: datetime.fromisoformat,
|
210
|
+
date.__name__: date.fromisoformat,
|
211
|
+
time.__name__: time.fromisoformat,
|
212
|
+
timedelta.__name__: lambda x: timedelta(seconds=float(x)),
|
213
|
+
|
214
|
+
Decimal.__name__: Decimal,
|
215
|
+
complex.__name__: lambda x: complex(*map(float, x.split(','))),
|
216
|
+
bytes.__name__: base64.b64decode,
|
217
|
+
|
218
|
+
UUID.__name__: UUID,
|
219
|
+
OrderedDict.__name__: lambda x: OrderedDict(json.loads(x)),
|
220
|
+
defaultdict.__name__: lambda x: defaultdict(type(None), json.loads(x)),
|
221
|
+
frozenset.__name__: lambda x: frozenset(json.loads(x)),
|
204
222
|
}
|
205
223
|
|
206
224
|
encoding_registry: EncodeType = {
|
@@ -208,6 +226,17 @@ class RedisDict:
|
|
208
226
|
"dict": json.dumps,
|
209
227
|
"tuple": _encode_tuple,
|
210
228
|
type(set()).__name__: _encode_set,
|
229
|
+
|
230
|
+
datetime.__name__: datetime.isoformat,
|
231
|
+
date.__name__: date.isoformat,
|
232
|
+
time.__name__: time.isoformat,
|
233
|
+
timedelta.__name__: lambda x: str(x.total_seconds()),
|
234
|
+
|
235
|
+
complex.__name__: lambda x: f"{x.real},{x.imag}",
|
236
|
+
bytes.__name__: lambda x: base64.b64encode(x).decode('ascii'),
|
237
|
+
OrderedDict.__name__: lambda x: json.dumps(list(x.items())),
|
238
|
+
defaultdict.__name__: lambda x: json.dumps(dict(x)),
|
239
|
+
frozenset.__name__: lambda x: json.dumps(list(x)),
|
211
240
|
}
|
212
241
|
|
213
242
|
def __init__(self,
|
@@ -269,6 +298,14 @@ class RedisDict:
|
|
269
298
|
return len(val) < self._max_string_size
|
270
299
|
return True
|
271
300
|
|
301
|
+
def _format_value(self, key: str, value: Any) -> str:
|
302
|
+
store_type, key = type(value).__name__, str(key)
|
303
|
+
if not self._valid_input(value, store_type) or not self._valid_input(key, "str"):
|
304
|
+
raise ValueError("Invalid input value or key size exceeded the maximum limit.")
|
305
|
+
encoded_value = self.encoding_registry.get(store_type, lambda x: x)(value) # type: ignore
|
306
|
+
|
307
|
+
return f'{store_type}:{encoded_value}'
|
308
|
+
|
272
309
|
def _store(self, key: str, value: Any) -> None:
|
273
310
|
"""
|
274
311
|
Store a value in Redis with the given key.
|
@@ -285,18 +322,12 @@ class RedisDict:
|
|
285
322
|
Allowing for simple dict set operation, but only cache data that makes sense.
|
286
323
|
|
287
324
|
"""
|
288
|
-
store_type, key = type(value).__name__, str(key)
|
289
|
-
if not self._valid_input(value, store_type) or not self._valid_input(key, "str"):
|
290
|
-
raise ValueError("Invalid input value or key size exceeded the maximum limit.")
|
291
|
-
value = self.encoding_registry.get(store_type, lambda x: x)(value) # type: ignore
|
292
|
-
|
293
|
-
store_value = f'{store_type}:{value}'
|
294
325
|
formatted_key = self._format_key(key)
|
295
|
-
|
326
|
+
formatted_value = self._format_value(key, value)
|
296
327
|
if self.preserve_expiration and self.redis.exists(formatted_key):
|
297
|
-
self.redis.set(formatted_key,
|
328
|
+
self.redis.set(formatted_key, formatted_value, keepttl=True)
|
298
329
|
else:
|
299
|
-
self.redis.set(formatted_key,
|
330
|
+
self.redis.set(formatted_key, formatted_value, ex=self.expire)
|
300
331
|
|
301
332
|
def _load(self, key: str) -> Tuple[bool, Any]:
|
302
333
|
"""
|
@@ -311,8 +342,7 @@ class RedisDict:
|
|
311
342
|
result = self.get_redis.get(self._format_key(key))
|
312
343
|
if result is None:
|
313
344
|
return False, None
|
314
|
-
|
315
|
-
return True, self.decoding_registry.get(type_, lambda x: x)(value)
|
345
|
+
return True, self._transform(result)
|
316
346
|
|
317
347
|
def _transform(self, result: str) -> Any:
|
318
348
|
"""
|
@@ -1,6 +0,0 @@
|
|
1
|
-
redis_dict.py,sha256=50CSZ5dMBBbr-UU9BSvoGgBItD7uce8F5ty1lphaiUw,36901
|
2
|
-
redis_dict-2.6.0.dist-info/LICENSE,sha256=-QiLwYznh_vNUSz337k0faP9Jl0dgtCIHVZ39Uyl6cA,1070
|
3
|
-
redis_dict-2.6.0.dist-info/METADATA,sha256=6QJ93NO1RrVKSYbmbgtFKOazqtKrauPstB-H0hI1vDs,12564
|
4
|
-
redis_dict-2.6.0.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
5
|
-
redis_dict-2.6.0.dist-info/top_level.txt,sha256=Wyp5Xvq_imoxvu-c-Le1rbTZ3pYM5BF440H9YAcgBZ8,11
|
6
|
-
redis_dict-2.6.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|