rapyer 1.1.7__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rapyer/__init__.py CHANGED
@@ -6,7 +6,6 @@ from rapyer.base import (
6
6
  afind,
7
7
  find_redis_models,
8
8
  ainsert,
9
- get,
10
9
  alock_from_key,
11
10
  )
12
11
  from rapyer.init import init_rapyer, teardown_rapyer
@@ -17,7 +16,6 @@ __all__ = [
17
16
  "teardown_rapyer",
18
17
  "aget",
19
18
  "afind",
20
- "get",
21
19
  "find_redis_models",
22
20
  "ainsert",
23
21
  "alock_from_key",
rapyer/base.py CHANGED
@@ -21,7 +21,6 @@ from pydantic_core.core_schema import FieldSerializationInfo, ValidationInfo
21
21
  from redis.commands.search.index_definition import IndexDefinition, IndexType
22
22
  from redis.commands.search.query import Query
23
23
  from redis.exceptions import NoScriptError, ResponseError
24
- from typing_extensions import deprecated
25
24
 
26
25
  from rapyer.config import RedisConfig
27
26
  from rapyer.context import _context_var, _context_xx_pipe
@@ -104,25 +103,6 @@ def make_pickle_field_serializer(
104
103
  return pickle_field_serializer, pickle_field_validator
105
104
 
106
105
 
107
- # TODO: Remove in next major version (2.0) - backward compatibility for pickled data
108
- # This validator handles loading old pickled data for fields that are now JSON-serializable.
109
- # In 2.0, remove this function and the validator registration in __init_subclass__.
110
- def make_backward_compat_validator(field: str):
111
- @field_validator(field, mode="before")
112
- def backward_compat_validator(v, info: ValidationInfo):
113
- ctx = info.context or {}
114
- should_deserialize_redis = ctx.get(REDIS_DUMP_FLAG_NAME, False)
115
- if should_deserialize_redis and isinstance(v, str):
116
- try:
117
- return pickle.loads(base64.b64decode(v))
118
- except Exception:
119
- pass
120
- return v
121
-
122
- backward_compat_validator.__name__ = f"__backward_compat_{field}"
123
- return backward_compat_validator
124
-
125
-
126
106
  class AtomicRedisModel(BaseModel):
127
107
  _pk: str = PrivateAttr(default_factory=lambda: str(uuid.uuid4()))
128
108
  _base_model_link: Self | RedisType = PrivateAttr(default=None)
@@ -302,11 +282,6 @@ class AtomicRedisModel(BaseModel):
302
282
  )
303
283
  setattr(cls, serializer.__name__, serializer)
304
284
  setattr(cls, validator.__name__, validator)
305
- else:
306
- # TODO: Remove in 2.0 - backward compatibility for old pickled data
307
- validator = make_backward_compat_validator(attr_name)
308
- setattr(cls, validator.__name__, validator)
309
- continue
310
285
 
311
286
  # Update the redis model list for initialization
312
287
  # Skip dynamically created classes from type conversion
@@ -335,12 +310,6 @@ class AtomicRedisModel(BaseModel):
335
310
  def is_inner_model(self) -> bool:
336
311
  return bool(self.field_name)
337
312
 
338
- @deprecated(
339
- f"save function is deprecated and will become sync function in rapyer 1.2.0, use asave() instead"
340
- )
341
- async def save(self):
342
- return await self.asave() # pragma: no cover
343
-
344
313
  async def asave(self) -> Self:
345
314
  model_dump = self.redis_dump()
346
315
  await self.Meta.redis.json().set(self.key, self.json_path, model_dump)
@@ -355,12 +324,6 @@ class AtomicRedisModel(BaseModel):
355
324
  def redis_dump_json(self):
356
325
  return self.model_dump_json(context={REDIS_DUMP_FLAG_NAME: True})
357
326
 
358
- @deprecated(
359
- "duplicate function is deprecated and will be removed in rapyer 1.2.0, use aduplicate instead"
360
- )
361
- async def duplicate(self) -> Self:
362
- return await self.aduplicate() # pragma: no cover
363
-
364
327
  async def aduplicate(self) -> Self:
365
328
  if self.is_inner_model():
366
329
  raise RuntimeError("Can only duplicate from top level model")
@@ -369,12 +332,6 @@ class AtomicRedisModel(BaseModel):
369
332
  await duplicated.asave()
370
333
  return duplicated
371
334
 
372
- @deprecated(
373
- "duplicate_many function is deprecated and will be removed in rapyer 1.2.0, use aduplicate_many instead"
374
- )
375
- async def duplicate_many(self, num: int) -> list[Self]:
376
- return await self.aduplicate_many(num) # pragma: no cover
377
-
378
335
  async def aduplicate_many(self, num: int) -> list[Self]:
379
336
  if self.is_inner_model():
380
337
  raise RuntimeError("Can only duplicate from top level model")
@@ -401,7 +358,7 @@ class AtomicRedisModel(BaseModel):
401
358
  for field_name in kwargs.keys()
402
359
  }
403
360
 
404
- async with self.Meta.redis.pipeline() as pipe:
361
+ async with self.Meta.redis.pipeline(transaction=True) as pipe:
405
362
  update_keys_in_pipeline(pipe, self.key, **json_path_kwargs)
406
363
  await pipe.execute()
407
364
  await self.refresh_ttl_if_needed()
@@ -409,14 +366,11 @@ class AtomicRedisModel(BaseModel):
409
366
  async def aset_ttl(self, ttl: int) -> None:
410
367
  if self.is_inner_model():
411
368
  raise RuntimeError("Can only set TTL from top level model")
412
- await self.Meta.redis.expire(self.key, ttl)
413
-
414
- @classmethod
415
- @deprecated(
416
- "get() classmethod is deprecated and will be removed in rapyer 1.2.0, use aget instead"
417
- )
418
- async def get(cls, key: str) -> Self:
419
- return await cls.aget(key) # pragma: no cover
369
+ pipeline = _context_var.get()
370
+ if pipeline is not None:
371
+ pipeline.expire(self.key, ttl)
372
+ else:
373
+ await self.Meta.redis.expire(self.key, ttl)
420
374
 
421
375
  @classmethod
422
376
  async def aget(cls, key: str) -> Self:
@@ -435,12 +389,6 @@ class AtomicRedisModel(BaseModel):
435
389
  await cls.Meta.redis.expire(key, cls.Meta.ttl)
436
390
  return instance
437
391
 
438
- @deprecated(
439
- "load function is deprecated and will be removed in rapyer 1.2.0, use aload() instead"
440
- )
441
- async def load(self):
442
- return await self.aload() # pragma: no cover
443
-
444
392
  async def aload(self) -> Self:
445
393
  model_dump = await self.Meta.redis.json().get(self.key, self.json_path)
446
394
  if not model_dump:
@@ -543,24 +491,11 @@ class AtomicRedisModel(BaseModel):
543
491
  pipe.expire(model.key, cls.Meta.ttl)
544
492
  await pipe.execute()
545
493
 
546
- @classmethod
547
- @deprecated(
548
- "function delete is deprecated and will be removed in rapyer 1.2.0, use adelete instead"
549
- )
550
- async def delete_by_key(cls, key: str) -> bool:
551
- return await cls.adelete_by_key(key) # pragma: no cover
552
-
553
494
  @classmethod
554
495
  async def adelete_by_key(cls, key: str) -> bool:
555
496
  client = _context_var.get() or cls.Meta.redis
556
497
  return await client.delete(key) == 1
557
498
 
558
- @deprecated(
559
- "function delete is deprecated and will be removed in rapyer 1.2.0, use adelete instead"
560
- )
561
- async def delete(self):
562
- return await self.adelete() # pragma: no cover
563
-
564
499
  async def adelete(self):
565
500
  if self.is_inner_model():
566
501
  raise RuntimeError("Can only delete from inner model")
@@ -572,19 +507,6 @@ class AtomicRedisModel(BaseModel):
572
507
  *[model if isinstance(model, str) else model.key for model in args]
573
508
  )
574
509
 
575
- @classmethod
576
- @contextlib.asynccontextmanager
577
- @deprecated(
578
- "lock_from_key function is deprecated and will be removed in rapyer 1.2.0, use alock_from_key instead"
579
- )
580
- async def lock_from_key(
581
- cls, key: str, action: str = "default", save_at_end: bool = False
582
- ) -> AbstractAsyncContextManager[Self]:
583
- async with cls.alock_from_key( # pragma: no cover
584
- key, action, save_at_end # pragma: no cover
585
- ) as redis_model: # pragma: no cover
586
- yield redis_model # pragma: no cover
587
-
588
510
  @classmethod
589
511
  @contextlib.asynccontextmanager
590
512
  async def alock_from_key(
@@ -596,18 +518,6 @@ class AtomicRedisModel(BaseModel):
596
518
  if save_at_end:
597
519
  await redis_model.asave()
598
520
 
599
- @contextlib.asynccontextmanager
600
- @deprecated(
601
- "lock function is deprecated and will be removed in rapyer 1.2.0, use alock instead"
602
- )
603
- async def lock(
604
- self, action: str = "default", save_at_end: bool = False
605
- ) -> AbstractAsyncContextManager[Self]:
606
- async with self.alock_from_key( # pragma: no cover
607
- self.key, action, save_at_end # pragma: no cover
608
- ) as redis_model: # pragma: no cover
609
- yield redis_model # pragma: no cover
610
-
611
521
  @contextlib.asynccontextmanager
612
522
  async def alock(
613
523
  self, action: str = "default", save_at_end: bool = False
@@ -619,21 +529,9 @@ class AtomicRedisModel(BaseModel):
619
529
  self.__dict__.update(unset_fields)
620
530
  yield redis_model
621
531
 
622
- @contextlib.asynccontextmanager
623
- @deprecated(
624
- "pipeline function is deprecated and will be removed in rapyer 1.2.0, use apipeline instead"
625
- )
626
- async def pipeline(
627
- self, ignore_if_deleted: bool = False
628
- ) -> AbstractAsyncContextManager[Self]:
629
- async with self.apipeline( # pragma: no cover
630
- ignore_if_deleted=ignore_if_deleted # pragma: no cover
631
- ) as redis_model: # pragma: no cover
632
- yield redis_model # pragma: no cover
633
-
634
532
  @contextlib.asynccontextmanager
635
533
  async def apipeline(
636
- self, ignore_if_deleted: bool = False
534
+ self, ignore_redis_error: bool = False
637
535
  ) -> AbstractAsyncContextManager[Self]:
638
536
  async with self.Meta.redis.pipeline(transaction=True) as pipe:
639
537
  try:
@@ -643,12 +541,12 @@ class AtomicRedisModel(BaseModel):
643
541
  }
644
542
  self.__dict__.update(unset_fields)
645
543
  except (TypeError, KeyNotFound):
646
- if ignore_if_deleted:
544
+ if ignore_redis_error:
647
545
  redis_model = self
648
546
  else:
649
547
  raise
650
548
  _context_var.set(pipe)
651
- _context_xx_pipe.set(ignore_if_deleted)
549
+ _context_xx_pipe.set(ignore_redis_error)
652
550
  yield redis_model
653
551
  commands_backup = list(pipe.command_stack)
654
552
  noscript_on_first_attempt = False
@@ -661,10 +559,10 @@ class AtomicRedisModel(BaseModel):
661
559
  except NoScriptError:
662
560
  noscript_on_first_attempt = True
663
561
  except ResponseError as exc:
664
- if ignore_if_deleted:
562
+ if ignore_redis_error:
665
563
  logger.warning(
666
564
  "Swallowed ResponseError during pipeline.execute() with "
667
- "ignore_if_deleted=True for key %r: %s",
565
+ "ignore_redis_error=True for key %r: %s",
668
566
  getattr(self, "key", None),
669
567
  exc,
670
568
  )
@@ -744,13 +642,6 @@ class AtomicRedisModel(BaseModel):
744
642
  REDIS_MODELS: list[type[AtomicRedisModel]] = []
745
643
 
746
644
 
747
- @deprecated(
748
- "get function is deprecated and will be removed in rapyer 1.2.0, use aget instead"
749
- )
750
- async def get(redis_key: str) -> AtomicRedisModel:
751
- return await aget(redis_key) # pragma: no cover
752
-
753
-
754
645
  async def aget(redis_key: str) -> AtomicRedisModel:
755
646
  redis_model_mapping = {klass.__name__: klass for klass in REDIS_MODELS}
756
647
  class_name = redis_key.split(":")[0]
@@ -1,5 +1,7 @@
1
1
  from rapyer.scripts.constants import (
2
2
  DATETIME_ADD_SCRIPT_NAME,
3
+ DICT_POP_SCRIPT_NAME,
4
+ DICT_POPITEM_SCRIPT_NAME,
3
5
  NUM_FLOORDIV_SCRIPT_NAME,
4
6
  NUM_MOD_SCRIPT_NAME,
5
7
  NUM_MUL_SCRIPT_NAME,
@@ -12,6 +14,7 @@ from rapyer.scripts.constants import (
12
14
  )
13
15
  from rapyer.scripts.registry import (
14
16
  _REGISTERED_SCRIPT_SHAS,
17
+ arun_sha,
15
18
  get_scripts,
16
19
  get_scripts_fakeredis,
17
20
  handle_noscript_error,
@@ -24,6 +27,8 @@ SCRIPTS_FAKEREDIS = get_scripts_fakeredis()
24
27
 
25
28
  __all__ = [
26
29
  "DATETIME_ADD_SCRIPT_NAME",
30
+ "DICT_POP_SCRIPT_NAME",
31
+ "DICT_POPITEM_SCRIPT_NAME",
27
32
  "NUM_FLOORDIV_SCRIPT_NAME",
28
33
  "NUM_MOD_SCRIPT_NAME",
29
34
  "NUM_MUL_SCRIPT_NAME",
@@ -35,6 +40,7 @@ __all__ = [
35
40
  "SCRIPTS_FAKEREDIS",
36
41
  "STR_APPEND_SCRIPT_NAME",
37
42
  "STR_MUL_SCRIPT_NAME",
43
+ "arun_sha",
38
44
  "handle_noscript_error",
39
45
  "register_scripts",
40
46
  "run_sha",
@@ -8,3 +8,5 @@ NUM_TRUEDIV_SCRIPT_NAME = "num_truediv"
8
8
  STR_APPEND_SCRIPT_NAME = "str_append"
9
9
  STR_MUL_SCRIPT_NAME = "str_mul"
10
10
  DATETIME_ADD_SCRIPT_NAME = "datetime_add"
11
+ DICT_POP_SCRIPT_NAME = "dict_pop"
12
+ DICT_POPITEM_SCRIPT_NAME = "dict_popitem"
rapyer/scripts/loader.py CHANGED
@@ -8,12 +8,32 @@ VARIANTS = {
8
8
  "EXTRACT_VALUE": "local value = tonumber(cjson.decode(current_json)[1])",
9
9
  "EXTRACT_STR": "local value = cjson.decode(current_json)[1]",
10
10
  "EXTRACT_DATETIME": "local value = cjson.decode(current_json)[1]",
11
+ "DICT_EXTRACT_VALUE": "local extracted = cjson.decode(value)[1]",
12
+ "DICT_EXTRACT_POPITEM": """local parsed = cjson.decode(value)
13
+ if type(parsed) == 'table' then
14
+ for _, v in pairs(parsed) do
15
+ extracted = v
16
+ break
17
+ end
18
+ else
19
+ extracted = parsed
20
+ end""",
11
21
  },
12
22
  "fakeredis": {
13
23
  "EXTRACT_ARRAY": "local arr = cjson.decode(arr_json)",
14
24
  "EXTRACT_VALUE": "local value = tonumber(cjson.decode(current_json)[1])",
15
25
  "EXTRACT_STR": "local value = cjson.decode(current_json)[1]",
16
26
  "EXTRACT_DATETIME": "local value = cjson.decode(current_json)[1]",
27
+ "DICT_EXTRACT_VALUE": "local extracted = cjson.decode(value)[1]",
28
+ "DICT_EXTRACT_POPITEM": """local parsed = cjson.decode(value)
29
+ if type(parsed) == 'table' then
30
+ for _, v in pairs(parsed) do
31
+ extracted = v
32
+ break
33
+ end
34
+ else
35
+ extracted = parsed
36
+ end""",
17
37
  },
18
38
  }
19
39
 
File without changes
@@ -0,0 +1,13 @@
1
+ local key = KEYS[1]
2
+ local path = ARGV[1]
3
+ local target_key = ARGV[2]
4
+
5
+ local value = redis.call('JSON.GET', key, path .. '.' .. target_key)
6
+
7
+ if value and value ~= '[]' and value ~= 'null' then
8
+ redis.call('JSON.DEL', key, path .. '.' .. target_key)
9
+ --[[DICT_EXTRACT_VALUE]]
10
+ return extracted
11
+ else
12
+ return nil
13
+ end
@@ -0,0 +1,29 @@
1
+ local key = KEYS[1]
2
+ local path = ARGV[1]
3
+
4
+ local keys = redis.call('JSON.OBJKEYS', key, path)
5
+
6
+ if not keys or #keys == 0 then
7
+ return nil
8
+ end
9
+
10
+ if type(keys[1]) == 'table' then
11
+ keys = keys[1]
12
+ end
13
+
14
+ if not keys or #keys == 0 then
15
+ return nil
16
+ end
17
+
18
+ local first_key = tostring(keys[1])
19
+ local value = redis.call('JSON.GET', key, path .. '.' .. first_key)
20
+
21
+ if not value then
22
+ return nil
23
+ end
24
+
25
+ redis.call('JSON.DEL', key, path .. '.' .. first_key)
26
+
27
+ local extracted
28
+ --[[DICT_EXTRACT_POPITEM]]
29
+ return {first_key, extracted}
@@ -1,6 +1,8 @@
1
1
  from rapyer.errors import ScriptsNotInitializedError
2
2
  from rapyer.scripts.constants import (
3
3
  DATETIME_ADD_SCRIPT_NAME,
4
+ DICT_POP_SCRIPT_NAME,
5
+ DICT_POPITEM_SCRIPT_NAME,
4
6
  NUM_FLOORDIV_SCRIPT_NAME,
5
7
  NUM_MOD_SCRIPT_NAME,
6
8
  NUM_MUL_SCRIPT_NAME,
@@ -24,6 +26,8 @@ SCRIPT_REGISTRY: list[tuple[str, str, str]] = [
24
26
  ("string", "append", STR_APPEND_SCRIPT_NAME),
25
27
  ("string", "mul", STR_MUL_SCRIPT_NAME),
26
28
  ("datetime", "add", DATETIME_ADD_SCRIPT_NAME),
29
+ ("dict", "pop", DICT_POP_SCRIPT_NAME),
30
+ ("dict", "popitem", DICT_POPITEM_SCRIPT_NAME),
27
31
  ]
28
32
 
29
33
  _REGISTERED_SCRIPT_SHAS: dict[str, str] = {}
@@ -52,14 +56,24 @@ async def register_scripts(redis_client, is_fakeredis: bool = False) -> None:
52
56
  _REGISTERED_SCRIPT_SHAS[name] = sha
53
57
 
54
58
 
55
- def run_sha(pipeline, script_name: str, keys: int, *args) -> None:
59
+ def get_script(script_name: str):
56
60
  sha = _REGISTERED_SCRIPT_SHAS.get(script_name)
57
61
  if sha is None:
58
62
  raise ScriptsNotInitializedError(
59
63
  f"Script '{script_name}' not loaded. Did you forget to call init_rapyer()?"
60
64
  )
65
+ return sha
66
+
67
+
68
+ def run_sha(pipeline, script_name: str, keys: int, *args):
69
+ sha = get_script(script_name)
61
70
  pipeline.evalsha(sha, keys, *args)
62
71
 
63
72
 
73
+ async def arun_sha(client, script_name: str, keys: int, *args):
74
+ sha = get_script(script_name)
75
+ return await client.evalsha(sha, keys, *args)
76
+
77
+
64
78
  async def handle_noscript_error(redis_client) -> None:
65
79
  await register_scripts(redis_client)
rapyer/types/base.py CHANGED
@@ -9,7 +9,6 @@ from pydantic import GetCoreSchemaHandler, TypeAdapter
9
9
  from pydantic_core import core_schema
10
10
  from pydantic_core.core_schema import ValidationInfo, CoreSchema, SerializationInfo
11
11
  from redis.commands.search.field import TextField
12
- from typing_extensions import deprecated
13
12
 
14
13
  from rapyer.context import _context_var
15
14
  from rapyer.errors.base import CantSerializeRedisValueError
@@ -74,12 +73,6 @@ class RedisType(ABC):
74
73
  def json_field_path(self, field_name: str):
75
74
  return f"${self.sub_field_path(field_name)}"
76
75
 
77
- @deprecated(
78
- f"save function is deprecated and will become sync function in rapyer 1.2.0, use asave() instead"
79
- )
80
- async def save(self):
81
- return await self.asave() # pragma: no cover
82
-
83
76
  async def asave(self) -> Self:
84
77
  model_dump = self._adapter.dump_python(
85
78
  self, mode="json", context={REDIS_DUMP_FLAG_NAME: True}
@@ -90,12 +83,6 @@ class RedisType(ABC):
90
83
  await self.client.expire(self.key, self.Meta.ttl, nx=nx)
91
84
  return self
92
85
 
93
- @deprecated(
94
- "load function is deprecated and will be removed in rapyer 1.2.0, use aload() instead"
95
- )
96
- async def load(self):
97
- return await self.aload() # pragma: no cover
98
-
99
86
  async def aload(self):
100
87
  redis_value = await self.client.json().get(self.key, self.field_path)
101
88
  if redis_value is None:
rapyer/types/dct.py CHANGED
@@ -2,6 +2,7 @@ from typing import TypeVar, Generic, get_args, Any, TypeAlias, TYPE_CHECKING
2
2
 
3
3
  from pydantic_core import core_schema
4
4
 
5
+ from rapyer.scripts import arun_sha, DICT_POP_SCRIPT_NAME, DICT_POPITEM_SCRIPT_NAME
5
6
  from rapyer.types.base import (
6
7
  GenericRedisType,
7
8
  RedisType,
@@ -12,80 +13,6 @@ from rapyer.utils.redis import update_keys_in_pipeline
12
13
 
13
14
  T = TypeVar("T")
14
15
 
15
- # Redis Lua script for atomic get-and-delete operation
16
- POP_SCRIPT = """
17
- local key = KEYS[1]
18
- local path = ARGV[1]
19
- local target_key = ARGV[2]
20
-
21
- -- Get the value from the JSON object
22
- local value = redis.call('JSON.GET', key, path .. '.' .. target_key)
23
-
24
- if value and value ~= '[]' and value ~= 'null' then
25
- -- Delete the key from the JSON object
26
- redis.call('JSON.DEL', key, path .. '.' .. target_key)
27
-
28
- -- Parse and return the actual value
29
- local parsed = cjson.decode(value)
30
- return parsed[1] -- Return first element if it's an array
31
- else
32
- return nil
33
- end
34
- """
35
-
36
-
37
- # Redis Lua script for atomic get-arbitrary-key-and-delete operation
38
- POPITEM_SCRIPT = """
39
- local key = KEYS[1]
40
- local path = ARGV[1]
41
-
42
- -- Get all the keys from the JSON object
43
- local keys = redis.call('JSON.OBJKEYS', key, path)
44
-
45
- -- Return nil if no keys exist
46
- if not keys or #keys == 0 then
47
- return nil
48
- end
49
-
50
- -- Handle nested arrays - Redis sometimes wraps results
51
- if type(keys[1]) == 'table' then
52
- keys = keys[1]
53
- end
54
-
55
- -- Check again after unwrapping
56
- if not keys or #keys == 0 then
57
- return nil
58
- end
59
-
60
- local first_key = tostring(keys[1])
61
-
62
- -- Get the value for this key
63
- local value = redis.call('JSON.GET', key, path .. '.' .. first_key)
64
-
65
- -- Return nil if value doesn't exist
66
- if not value then
67
- return nil
68
- end
69
-
70
- -- Delete the key from the JSON object
71
- redis.call('JSON.DEL', key, path .. '.' .. first_key)
72
-
73
- -- Parse the JSON string
74
- local parsed_value = cjson.decode(value)
75
-
76
- -- If it's a table/object, return the first value
77
- if type(parsed_value) == 'table' then
78
- for _, v in pairs(parsed_value) do
79
- return {first_key, v} -- Return first value found
80
- end
81
- -- If table is empty, return nil
82
- return nil
83
- end
84
-
85
- -- Otherwise return the parsed value as-is
86
- return {first_key, parsed_value}
87
- """
88
-
89
16
 
90
17
  class RedisDict(dict[str, T], GenericRedisType, Generic[T]):
91
18
  original_type = dict
@@ -108,10 +35,13 @@ class RedisDict(dict[str, T], GenericRedisType, Generic[T]):
108
35
 
109
36
  def update(self, m=None, /, **kwargs):
110
37
  if self.pipeline:
111
- m_redis_val = self._adapter.dump_python(
112
- m, mode="json", context={REDIS_DUMP_FLAG_NAME: True}
38
+ m_redis_val = (
39
+ self._adapter.dump_python(
40
+ m, mode="json", context={REDIS_DUMP_FLAG_NAME: True}
41
+ )
42
+ if m
43
+ else {}
113
44
  )
114
- m_redis_val = m_redis_val or {}
115
45
  kwargs_redis_val = self._adapter.dump_python(
116
46
  kwargs, mode="json", context={REDIS_DUMP_FLAG_NAME: True}
117
47
  )
@@ -175,14 +105,13 @@ class RedisDict(dict[str, T], GenericRedisType, Generic[T]):
175
105
  await self.refresh_ttl_if_needed()
176
106
 
177
107
  async def apop(self, key, default=None):
178
- # Execute the script atomically
179
- result = await self.client.eval(POP_SCRIPT, 1, self.key, self.json_path, key)
180
- # Key exists in Redis, pop from local dict (it should exist there too)
108
+ result = await arun_sha(
109
+ self.client, DICT_POP_SCRIPT_NAME, 1, self.key, self.json_path, key
110
+ )
181
111
  super().pop(key, None)
182
112
  await self.refresh_ttl_if_needed()
183
113
 
184
114
  if result is None:
185
- # Key doesn't exist in Redis
186
115
  return default
187
116
 
188
117
  return self._adapter.validate_python(
@@ -190,8 +119,9 @@ class RedisDict(dict[str, T], GenericRedisType, Generic[T]):
190
119
  )[key]
191
120
 
192
121
  async def apopitem(self):
193
- # Execute the script atomically
194
- result = await self.client.eval(POPITEM_SCRIPT, 1, self.key, self.json_path)
122
+ result = await arun_sha(
123
+ self.client, DICT_POPITEM_SCRIPT_NAME, 1, self.key, self.json_path
124
+ )
195
125
  await self.refresh_ttl_if_needed()
196
126
 
197
127
  if result is not None:
rapyer/types/integer.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from typing import TypeAlias, TYPE_CHECKING
2
2
 
3
3
  from redis.commands.search.field import NumericField
4
- from typing_extensions import deprecated
5
4
 
6
5
  from rapyer.scripts import (
7
6
  run_sha,
@@ -20,12 +19,6 @@ class RedisInt(int, RedisType):
20
19
  def redis_schema(cls, field_name: str):
21
20
  return NumericField(f"$.{field_name}", as_name=field_name)
22
21
 
23
- @deprecated(
24
- f"increase function is deprecated and will become sync function in rapyer 1.2.0, use aincrease() instead"
25
- )
26
- async def increase(self, amount: int = 1):
27
- return await self.aincrease(amount)
28
-
29
22
  async def aincrease(self, amount: int = 1):
30
23
  result = await self.client.json().numincrby(self.key, self.json_path, amount)
31
24
  await self.refresh_ttl_if_needed()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rapyer
3
- Version: 1.1.7
3
+ Version: 1.2.0
4
4
  Summary: Pydantic models with Redis as the backend
5
5
  License: MIT
6
6
  Keywords: redis,redis-json,pydantic,pydantic-v2,orm,database,async,nosql,cache,key-value,data-modeling,python,backend,storage,serialization,validation
@@ -1,5 +1,5 @@
1
- rapyer/__init__.py,sha256=frhW-pZEFUDc_zCNKzxui_W7uK4Wivt7mLCzT0s3dLI,435
2
- rapyer/base.py,sha256=bcvmCBpUepIiwFpjUJl3rFUztm1U2RKh0Zxv4RfECMI,31336
1
+ rapyer/__init__.py,sha256=vgrOQkqvf0UBQMPpWSLvd9TxXXCQ8Oyt0g5E6nkhbPY,415
2
+ rapyer/base.py,sha256=KeaRO5btbeV95CNeJHkS18Q5jmAkyxa11Ttsu0V5C-4,27004
3
3
  rapyer/config.py,sha256=Js1FGfyKfS16eOTgsPEhFfi1yTM_UkR8v2z_Vv6C3Bo,978
4
4
  rapyer/context.py,sha256=yuD_EGZB04gJv9YDlqeo7VD70J0Ldx5tE3NEGTcNdwA,357
5
5
  rapyer/errors/__init__.py,sha256=P-DIYe85wySkCpuyWufwF7zOOOL8NUiMaHZROsciG1M,530
@@ -11,12 +11,15 @@ rapyer/fields/key.py,sha256=JDE82nhSk7VPkKanNI8M5Djqm2Kocv5ENgtN_TqsmBk,554
11
11
  rapyer/fields/safe_load.py,sha256=xS3PwOe9K2D7az-ctNV798cTSIb7bcviWHQ1kL1tbBo,599
12
12
  rapyer/init.py,sha256=R6xncUnBeq07gtM_iWqH4SHLquH7MNQgTbVbC6xIA6U,2133
13
13
  rapyer/links.py,sha256=A0usszwvwXI7FqwTEYquGYrqyNQqT4HUWhqmLteGXWU,121
14
- rapyer/scripts/__init__.py,sha256=4aBtdgaU9rNFZ4pTlI1ppx0AsoDsZHw8Ulr0P5-CtIU,984
15
- rapyer/scripts/constants.py,sha256=UDZO4sve8V7T8Q3CD4jjtrtLx_Mk_iDf7Z-RoeN9c9c,376
16
- rapyer/scripts/loader.py,sha256=rdqVMHzIPvswK5y0DGXIBaVVQtaomJaTSIabpVJsypU,1249
14
+ rapyer/scripts/__init__.py,sha256=FvTJvulDxVnVqc8JK4GmHXeS-lMis4_cudaQYe7_VKg,1130
15
+ rapyer/scripts/constants.py,sha256=TMbBxw3Kufsmn_tWxpfzTVIdS89cHOreo2Z-RbY8koc,452
16
+ rapyer/scripts/loader.py,sha256=9aYRIwnmZ60lLToLKLK07vLBnWARsTkoBZQnrnjLVHw,1827
17
17
  rapyer/scripts/lua/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  rapyer/scripts/lua/datetime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  rapyer/scripts/lua/datetime/add.lua,sha256=wMhBkAr9KoDRtDR0qG0ofA8BENO1Ykr7f437kVLIUww,1536
20
+ rapyer/scripts/lua/dict/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ rapyer/scripts/lua/dict/pop.lua,sha256=653j4Ty7jwvX7q2Cr6sDbCrjIUaIdhoUvNkArUBlBM0,324
22
+ rapyer/scripts/lua/dict/popitem.lua,sha256=3GT1eanvRmz8kuoHjRBMRcd029i2onPI7qSZL7Zm2hE,524
20
23
  rapyer/scripts/lua/list/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
24
  rapyer/scripts/lua/list/remove_range.lua,sha256=sH9ySbvfUtMAktt741uyX6O3yoJQbKqmr0QiFQT9vsU,816
22
25
  rapyer/scripts/lua/numeric/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -29,16 +32,16 @@ rapyer/scripts/lua/numeric/truediv.lua,sha256=lQv6YuPb7YHsg50x7b_zDuQ3S1Oa3oeydO
29
32
  rapyer/scripts/lua/string/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
33
  rapyer/scripts/lua/string/append.lua,sha256=JfSt21qCQzIMB_0dLmN58s9MFBDaOkiA8dBSBDO77bU,310
31
34
  rapyer/scripts/lua/string/mul.lua,sha256=rABORn6gxXobY44S1JYeLnLPeTZu26otemB0s6tBfx8,328
32
- rapyer/scripts/registry.py,sha256=Gk2OEwHj0ftuABK2ttSoGIlJ6KTotXc5NU-4oDqCmFk,2096
35
+ rapyer/scripts/registry.py,sha256=RWGJdye4_UsirvsFM5gfOjBtMI-6Hx6PebcJmSs2N8k,2473
33
36
  rapyer/types/__init__.py,sha256=lM2ZdpkgWW_7eh0AXoabtgA9CGhzWUHOi9W0_RTqu6I,484
34
- rapyer/types/base.py,sha256=K2pSnVSTJx49iv9RfL48MRUbwCuWWH_grAXar3hdiAg,6484
37
+ rapyer/types/base.py,sha256=AA7E0knCy9dJd78O0APG5FEUXvHSqWknzkp3Rpj1O30,6034
35
38
  rapyer/types/byte.py,sha256=cnV-XMMPKv03tV0oKSJ1mlrpwdAygs4H_EhOVheu-2Q,1791
36
39
  rapyer/types/convert.py,sha256=nyElDMWaWXtI_dXpAAg5elqWo439HsZ6u6wLj9WuHsI,3548
37
40
  rapyer/types/datetime.py,sha256=EuT6XhFPfQWNtGRd_8bX3DWm6_EGo-HqMef9Fr3fiNQ,4294
38
- rapyer/types/dct.py,sha256=6mD33ylHL0RO-rxGDZZjA3Q2oJDzXCpZcRl71zfp0EA,8216
41
+ rapyer/types/dct.py,sha256=-PKZoQuBXrT7wcHlss-Oc3mQqAQq2buI8aqrSoN5F7U,6431
39
42
  rapyer/types/float.py,sha256=4TEKOJ778MFogULlfRq8iQV9bYdx-eArgRTtmeRzeP4,2864
40
43
  rapyer/types/init.py,sha256=SGH2uH9dIkWfaTMdiD-YV053nwRPaxUs4jTG1gOA2dg,495
41
- rapyer/types/integer.py,sha256=EWI0oQ3cRG9vxt9XAOUUX7Z25ibdcWQNXsEHrE2Q5tw,2651
44
+ rapyer/types/integer.py,sha256=TvpFehA4LNvYWapaOph9izkWuf9eAAKqkPicjsKaz9s,2381
42
45
  rapyer/types/lst.py,sha256=RJ_IE2ZCE-NzfLRhYw2oTHy1zp_Kbx3u-wMYYOfU71Y,7160
43
46
  rapyer/types/string.py,sha256=2JrNSF6OaodPg6e4VK5qqJYU2c-er7M6jVD0Gr8CAUk,1024
44
47
  rapyer/typing_support.py,sha256=48ka9BxDSUdqYBQdFxxncWFOp3kdKqzVe7RXf4k-nb4,204
@@ -47,6 +50,6 @@ rapyer/utils/annotation.py,sha256=MB01l2k9g10AOSfttVfDIUc7JBzZWdH_Cn9FDe0IEGo,30
47
50
  rapyer/utils/fields.py,sha256=LhIhnuRBNrtE3RyFI-AiScXTzqYmOfcm-rdtmcdaHM0,2815
48
51
  rapyer/utils/pythonic.py,sha256=Xiv7RLqLozgLuwZSPIxBlsypIyoIYmPG_lV78TI4r80,141
49
52
  rapyer/utils/redis.py,sha256=d4qhR7QsER0572NMis_ATUUC17Jo4h9r8TKHTF8OIds,441
50
- rapyer-1.1.7.dist-info/METADATA,sha256=4okDftW1WAKvp9_FuJx1hbfu9uhTO1A14D6Z399AS9E,11418
51
- rapyer-1.1.7.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
52
- rapyer-1.1.7.dist-info/RECORD,,
53
+ rapyer-1.2.0.dist-info/METADATA,sha256=nYKTAQnSHNKFqU1x-RwLtYP3v93v-CSYinIZkabg1uI,11418
54
+ rapyer-1.2.0.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
55
+ rapyer-1.2.0.dist-info/RECORD,,
File without changes