meta-memcache 2.2.0__tar.gz → 2.4.0__tar.gz

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.
Files changed (53) hide show
  1. {meta_memcache-2.2.0/src/meta_memcache.egg-info → meta_memcache-2.4.0}/PKG-INFO +20 -4
  2. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/README.md +19 -3
  3. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/pyproject.toml +11 -1
  4. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/__init__.py +1 -1
  5. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/commands/high_level_commands.py +30 -1
  6. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/commands/meta_commands.py +1 -1
  7. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/connection/pool.py +5 -5
  8. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/interfaces/high_level_commands.py +21 -1
  9. {meta_memcache-2.2.0 → meta_memcache-2.4.0/src/meta_memcache.egg-info}/PKG-INFO +20 -4
  10. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/LICENSE +0 -0
  11. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/setup.cfg +0 -0
  12. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/base/__init__.py +0 -0
  13. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/base/base_cache_client.py +0 -0
  14. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/base/base_serializer.py +0 -0
  15. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/cache_client.py +0 -0
  16. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/commands/__init__.py +0 -0
  17. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/compression/__init__.py +0 -0
  18. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/compression/zstd_manager.py +0 -0
  19. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/configuration.py +0 -0
  20. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/connection/__init__.py +0 -0
  21. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/connection/memcache_socket.py +0 -0
  22. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/connection/providers.py +0 -0
  23. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/errors.py +0 -0
  24. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/events/__init__.py +0 -0
  25. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/events/write_failure_event.py +0 -0
  26. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/executors/__init__.py +0 -0
  27. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/executors/default.py +0 -0
  28. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/extras/__init__.py +0 -0
  29. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/extras/client_wrapper.py +0 -0
  30. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/extras/migrating_cache_client.py +0 -0
  31. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/extras/probabilistic_hot_cache.py +0 -0
  32. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/interfaces/__init__.py +0 -0
  33. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/interfaces/cache_api.py +0 -0
  34. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/interfaces/commands.py +0 -0
  35. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/interfaces/executor.py +0 -0
  36. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/interfaces/meta_commands.py +0 -0
  37. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/interfaces/router.py +0 -0
  38. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/metrics/__init__.py +0 -0
  39. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/metrics/base.py +0 -0
  40. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/metrics/prometheus.py +0 -0
  41. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/protocol.py +0 -0
  42. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/py.typed +0 -0
  43. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/routers/__init__.py +0 -0
  44. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/routers/default.py +0 -0
  45. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/routers/ephemeral.py +0 -0
  46. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/routers/gutter.py +0 -0
  47. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/routers/helpers.py +0 -0
  48. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/serializer.py +0 -0
  49. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache/settings.py +0 -0
  50. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache.egg-info/SOURCES.txt +0 -0
  51. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache.egg-info/dependency_links.txt +0 -0
  52. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache.egg-info/requires.txt +0 -0
  53. {meta_memcache-2.2.0 → meta_memcache-2.4.0}/src/meta_memcache.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meta-memcache
3
- Version: 2.2.0
3
+ Version: 2.4.0
4
4
  Summary: Modern, pure python, memcache client with support for new meta commands.
5
5
  Author-email: Guillermo Perez <bisho@revenuecat.com>
6
6
  License: MIT License
@@ -388,13 +388,17 @@ Invalidation...
388
388
  lease_policy: LeasePolicy,
389
389
  touch_ttl: Optional[int] = None,
390
390
  recache_policy: Optional[RecachePolicy] = None,
391
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
391
392
  ) -> Optional[Any]:
392
393
  """
393
394
  Get a key. On miss try to get a lease.
394
395
 
395
396
  Guarantees only one cache client will get the miss and
396
397
  gets to repopulate cache, while the others are blocked
397
- waiting (according to the settings in the LeasePolicy)
398
+ waiting (according to the settings in the LeasePolicy).
399
+
400
+ ``lease_wait_fn`` is invoked with the number of seconds to wait
401
+ between lease retries. Defaults to ``time.sleep``.
398
402
  """
399
403
 
400
404
  def get_or_lease_cas(
@@ -403,6 +407,7 @@ Invalidation...
403
407
  lease_policy: LeasePolicy,
404
408
  touch_ttl: Optional[int] = None,
405
409
  recache_policy: Optional[RecachePolicy] = None,
410
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
406
411
  ) -> Tuple[Optional[Any], Optional[int]]:
407
412
  """
408
413
  Same as get_or_lease(), but also return the CAS token so
@@ -429,6 +434,17 @@ Invalidation...
429
434
  Get multiple keys at once
430
435
  """
431
436
 
437
+ def multi_get_cas(
438
+ self,
439
+ keys: List[Union[Key, str]],
440
+ touch_ttl: Optional[int] = None,
441
+ recache_policy: Optional[RecachePolicy] = None,
442
+ ) -> Dict[Key, Tuple[Optional[Any], Optional[int]]]:
443
+ """
444
+ Same as multi_get(), but also return the CAS tokens so
445
+ they can be used during writes and detect races
446
+ """
447
+
432
448
  def get_cas(
433
449
  self,
434
450
  key: Union[Key, str],
@@ -643,8 +659,8 @@ class PoolCounters(NamedTuple):
643
659
  available: int
644
660
  # The # of connections active, currently in use, out of the pool
645
661
  active: int
646
- # Current stablished connections (available + active)
647
- stablished: int
662
+ # Current established connections (available + active)
663
+ established: int
648
664
  # Total # of connections created. If this keeps growing
649
665
  # might mean the pool size is too small and we are
650
666
  # constantly needing to create new connections:
@@ -370,13 +370,17 @@ Invalidation...
370
370
  lease_policy: LeasePolicy,
371
371
  touch_ttl: Optional[int] = None,
372
372
  recache_policy: Optional[RecachePolicy] = None,
373
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
373
374
  ) -> Optional[Any]:
374
375
  """
375
376
  Get a key. On miss try to get a lease.
376
377
 
377
378
  Guarantees only one cache client will get the miss and
378
379
  gets to repopulate cache, while the others are blocked
379
- waiting (according to the settings in the LeasePolicy)
380
+ waiting (according to the settings in the LeasePolicy).
381
+
382
+ ``lease_wait_fn`` is invoked with the number of seconds to wait
383
+ between lease retries. Defaults to ``time.sleep``.
380
384
  """
381
385
 
382
386
  def get_or_lease_cas(
@@ -385,6 +389,7 @@ Invalidation...
385
389
  lease_policy: LeasePolicy,
386
390
  touch_ttl: Optional[int] = None,
387
391
  recache_policy: Optional[RecachePolicy] = None,
392
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
388
393
  ) -> Tuple[Optional[Any], Optional[int]]:
389
394
  """
390
395
  Same as get_or_lease(), but also return the CAS token so
@@ -411,6 +416,17 @@ Invalidation...
411
416
  Get multiple keys at once
412
417
  """
413
418
 
419
+ def multi_get_cas(
420
+ self,
421
+ keys: List[Union[Key, str]],
422
+ touch_ttl: Optional[int] = None,
423
+ recache_policy: Optional[RecachePolicy] = None,
424
+ ) -> Dict[Key, Tuple[Optional[Any], Optional[int]]]:
425
+ """
426
+ Same as multi_get(), but also return the CAS tokens so
427
+ they can be used during writes and detect races
428
+ """
429
+
414
430
  def get_cas(
415
431
  self,
416
432
  key: Union[Key, str],
@@ -625,8 +641,8 @@ class PoolCounters(NamedTuple):
625
641
  available: int
626
642
  # The # of connections active, currently in use, out of the pool
627
643
  active: int
628
- # Current stablished connections (available + active)
629
- stablished: int
644
+ # Current established connections (available + active)
645
+ established: int
630
646
  # Total # of connections created. If this keeps growing
631
647
  # might mean the pool size is too small and we are
632
648
  # constantly needing to create new connections:
@@ -8,7 +8,7 @@ dependencies = [
8
8
  authors = [{ name = "Guillermo Perez", email = "bisho@revenuecat.com" }]
9
9
  license = { text = "MIT License" }
10
10
  name = "meta-memcache"
11
- version = "2.2.0"
11
+ version = "2.4.0"
12
12
  description = "Modern, pure python, memcache client with support for new meta commands."
13
13
  readme = "README.md"
14
14
  requires-python = ">=3.10"
@@ -19,6 +19,11 @@ metrics = ["prometheus-client >= 0.17.1"]
19
19
  [project.urls]
20
20
  homepage = "https://github.com/RevenueCat/meta-memcache-py"
21
21
 
22
+ [tool.uv]
23
+ # Dependency cooldown: only resolve releases that are at least 7 days old.
24
+ # Mitigates supply-chain risk from compromised fresh package versions.
25
+ exclude-newer = "P7D"
26
+
22
27
  [tool.pytest.ini_options]
23
28
  addopts = "-ra"
24
29
  testpaths = ["tests"]
@@ -36,6 +41,11 @@ show_missing = true
36
41
  [tool.ruff]
37
42
  line-length = 88
38
43
 
44
+ [tool.ruff.lint]
45
+ # Ruff 0.16 expanded the default rule set from 59 to 413 rules. Pin the selection
46
+ # to the pre-0.16 default so version bumps don't silently add new rules.
47
+ select = ["E4", "E7", "E9", "F"]
48
+
39
49
  [tool.ruff.lint.per-file-ignores]
40
50
  "tests/*.py" = ["E731"]
41
51
  "src/meta_memcache/__init__.py" = ["F401"]
@@ -1,4 +1,4 @@
1
- __version__ = "2.2.0"
1
+ __version__ = "2.4.0"
2
2
 
3
3
  from meta_memcache.cache_client import CacheClient
4
4
  from meta_memcache.configuration import (
@@ -1,6 +1,7 @@
1
1
  import time
2
2
  from typing import (
3
3
  Any,
4
+ Callable,
4
5
  Dict,
5
6
  Iterable,
6
7
  Optional,
@@ -236,6 +237,7 @@ class HighLevelCommandsMixin:
236
237
  lease_policy: LeasePolicy,
237
238
  touch_ttl: Optional[int] = None,
238
239
  recache_policy: Optional[RecachePolicy] = None,
240
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
239
241
  ) -> Optional[Any]:
240
242
  """
241
243
  Get a key. On miss try to get a lease.
@@ -243,12 +245,16 @@ class HighLevelCommandsMixin:
243
245
  Guarantees only one cache client will get the miss and
244
246
  gets to repopulate cache, while the others are blocked
245
247
  waiting (according to the settings in the LeasePolicy)
248
+
249
+ ``lease_wait_fn`` is invoked with the number of seconds to wait
250
+ between lease retries. Defaults to ``time.sleep``.
246
251
  """
247
252
  value, _ = self.get_or_lease_cas(
248
253
  key=key,
249
254
  lease_policy=lease_policy,
250
255
  touch_ttl=touch_ttl,
251
256
  recache_policy=recache_policy,
257
+ lease_wait_fn=lease_wait_fn,
252
258
  )
253
259
  return value
254
260
 
@@ -258,6 +264,7 @@ class HighLevelCommandsMixin:
258
264
  lease_policy: LeasePolicy,
259
265
  touch_ttl: Optional[int] = None,
260
266
  recache_policy: Optional[RecachePolicy] = None,
267
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
261
268
  ) -> Tuple[Optional[Any], Optional[int]]:
262
269
  """
263
270
  Same as get_or_lease(), but also return the CAS token so
@@ -267,10 +274,11 @@ class HighLevelCommandsMixin:
267
274
  raise ValueError(
268
275
  "Wrong lease_policy: miss_retries needs to be greater than 0"
269
276
  )
277
+ wait = lease_wait_fn if lease_wait_fn is not None else time.sleep
270
278
  i = 0
271
279
  while True:
272
280
  if i > 0:
273
- time.sleep(
281
+ wait(
274
282
  min(
275
283
  lease_policy.miss_max_retry_wait,
276
284
  lease_policy.miss_retry_wait
@@ -344,6 +352,27 @@ class HighLevelCommandsMixin:
344
352
  )
345
353
  return {k: v.value if v is not None else None for k, v in results.items()}
346
354
 
355
+ def multi_get_cas(
356
+ self: HighLevelCommandMixinWithMetaCommands,
357
+ keys: Iterable[Union[Key, str]],
358
+ touch_ttl: Optional[int] = None,
359
+ recache_policy: Optional[RecachePolicy] = None,
360
+ ) -> Dict[Key, Tuple[Optional[Any], Optional[int]]]:
361
+ """
362
+ Same as multi_get(), but also return the CAS tokens so
363
+ they can be used during writes and detect races
364
+ """
365
+ results = self._multi_get(
366
+ keys=keys,
367
+ touch_ttl=touch_ttl,
368
+ recache_policy=recache_policy,
369
+ return_cas_token=True,
370
+ )
371
+ return {
372
+ k: (v.value, v.flags.cas_token) if v is not None else (None, None)
373
+ for k, v in results.items()
374
+ }
375
+
347
376
  def _multi_get(
348
377
  self: HighLevelCommandMixinWithMetaCommands,
349
378
  keys: Iterable[Union[Key, str]],
@@ -110,6 +110,6 @@ class MetaCommandsMixin:
110
110
  )
111
111
  if not isinstance(result, (Success, NotStored, Conflict, Miss, Value)):
112
112
  raise MemcacheError(
113
- f"Unexpected response for Meta Delete command: {result}"
113
+ f"Unexpected response for Meta Arithmetic command: {result}"
114
114
  )
115
115
  return result
@@ -52,8 +52,8 @@ class PoolCounters(NamedTuple):
52
52
  available: int
53
53
  # The # of connections active, currently in use, out of the pool
54
54
  active: int
55
- # Current stablished connections (available + active)
56
- stablished: int
55
+ # Current established connections (available + active)
56
+ established: int
57
57
  # Total # of connections created. If this keeps growing
58
58
  # might meen the pool size is too small and we are
59
59
  # constantly needing to create new connections:
@@ -125,13 +125,13 @@ class ConnectionPool:
125
125
  def get_counters(self) -> PoolCounters:
126
126
  available = len(self._pool)
127
127
  total_created, total_destroyed = self._created, self._destroyed
128
- stablished = total_created - total_destroyed
129
- active = available - stablished
128
+ established = total_created - total_destroyed
129
+ active = established - available
130
130
 
131
131
  return PoolCounters(
132
132
  available=available,
133
133
  active=active,
134
- stablished=stablished,
134
+ established=established,
135
135
  total_created=total_created,
136
136
  total_errors=self._errors,
137
137
  )
@@ -1,4 +1,15 @@
1
- from typing import Any, Dict, Iterable, Optional, Protocol, Tuple, Type, TypeVar, Union
1
+ from typing import (
2
+ Any,
3
+ Callable,
4
+ Dict,
5
+ Iterable,
6
+ Optional,
7
+ Protocol,
8
+ Tuple,
9
+ Type,
10
+ TypeVar,
11
+ Union,
12
+ )
2
13
 
3
14
  from meta_memcache.configuration import LeasePolicy, RecachePolicy, StalePolicy
4
15
  from meta_memcache.protocol import Key, SetMode, Value
@@ -83,6 +94,7 @@ class HighLevelCommandsProtocol(Protocol):
83
94
  lease_policy: LeasePolicy,
84
95
  touch_ttl: Optional[int] = None,
85
96
  recache_policy: Optional[RecachePolicy] = None,
97
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
86
98
  ) -> Optional[Any]: ... # pragma: no cover
87
99
 
88
100
  def get_or_lease_cas(
@@ -91,6 +103,7 @@ class HighLevelCommandsProtocol(Protocol):
91
103
  lease_policy: LeasePolicy,
92
104
  touch_ttl: Optional[int] = None,
93
105
  recache_policy: Optional[RecachePolicy] = None,
106
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
94
107
  ) -> Tuple[Optional[Any], Optional[int]]: ... # pragma: no cover
95
108
 
96
109
  def get(
@@ -107,6 +120,13 @@ class HighLevelCommandsProtocol(Protocol):
107
120
  recache_policy: Optional[RecachePolicy] = None,
108
121
  ) -> Dict[Key, Optional[Any]]: ... # pragma: no cover
109
122
 
123
+ def multi_get_cas(
124
+ self,
125
+ keys: Iterable[Union[Key, str]],
126
+ touch_ttl: Optional[int] = None,
127
+ recache_policy: Optional[RecachePolicy] = None,
128
+ ) -> Dict[Key, Tuple[Optional[Any], Optional[int]]]: ... # pragma: no cover
129
+
110
130
  def _multi_get(
111
131
  self,
112
132
  keys: Iterable[Union[Key, str]],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meta-memcache
3
- Version: 2.2.0
3
+ Version: 2.4.0
4
4
  Summary: Modern, pure python, memcache client with support for new meta commands.
5
5
  Author-email: Guillermo Perez <bisho@revenuecat.com>
6
6
  License: MIT License
@@ -388,13 +388,17 @@ Invalidation...
388
388
  lease_policy: LeasePolicy,
389
389
  touch_ttl: Optional[int] = None,
390
390
  recache_policy: Optional[RecachePolicy] = None,
391
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
391
392
  ) -> Optional[Any]:
392
393
  """
393
394
  Get a key. On miss try to get a lease.
394
395
 
395
396
  Guarantees only one cache client will get the miss and
396
397
  gets to repopulate cache, while the others are blocked
397
- waiting (according to the settings in the LeasePolicy)
398
+ waiting (according to the settings in the LeasePolicy).
399
+
400
+ ``lease_wait_fn`` is invoked with the number of seconds to wait
401
+ between lease retries. Defaults to ``time.sleep``.
398
402
  """
399
403
 
400
404
  def get_or_lease_cas(
@@ -403,6 +407,7 @@ Invalidation...
403
407
  lease_policy: LeasePolicy,
404
408
  touch_ttl: Optional[int] = None,
405
409
  recache_policy: Optional[RecachePolicy] = None,
410
+ lease_wait_fn: Optional[Callable[[float], None]] = None,
406
411
  ) -> Tuple[Optional[Any], Optional[int]]:
407
412
  """
408
413
  Same as get_or_lease(), but also return the CAS token so
@@ -429,6 +434,17 @@ Invalidation...
429
434
  Get multiple keys at once
430
435
  """
431
436
 
437
+ def multi_get_cas(
438
+ self,
439
+ keys: List[Union[Key, str]],
440
+ touch_ttl: Optional[int] = None,
441
+ recache_policy: Optional[RecachePolicy] = None,
442
+ ) -> Dict[Key, Tuple[Optional[Any], Optional[int]]]:
443
+ """
444
+ Same as multi_get(), but also return the CAS tokens so
445
+ they can be used during writes and detect races
446
+ """
447
+
432
448
  def get_cas(
433
449
  self,
434
450
  key: Union[Key, str],
@@ -643,8 +659,8 @@ class PoolCounters(NamedTuple):
643
659
  available: int
644
660
  # The # of connections active, currently in use, out of the pool
645
661
  active: int
646
- # Current stablished connections (available + active)
647
- stablished: int
662
+ # Current established connections (available + active)
663
+ established: int
648
664
  # Total # of connections created. If this keeps growing
649
665
  # might mean the pool size is too small and we are
650
666
  # constantly needing to create new connections:
File without changes
File without changes