limits 3.3.1__py3-none-any.whl → 3.5.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.
limits/_version.py CHANGED
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2023-03-22T15:09:18-0700",
11
+ "date": "2023-05-16T15:04:57-0700",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "6ddfa53a1f4aff34642e487607fa071b673a40ef",
15
- "version": "3.3.1"
14
+ "full-revisionid": "d61ade38645d742e4614dd1c1c0283d6ace40bf0",
15
+ "version": "3.5.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -349,11 +349,6 @@ class RedisSentinelStorage(RedisStorage):
349
349
  STORAGE_SCHEME = ["async+redis+sentinel"]
350
350
  """The storage scheme for redis accessed via a redis sentinel installation"""
351
351
 
352
- DEFAULT_OPTIONS: Dict[str, Union[float, str, bool]] = {
353
- "stream_timeout": 0.2,
354
- }
355
- "Default options passed to :class:`~coredis.sentinel.Sentinel`"
356
-
357
352
  DEPENDENCIES = {"coredis.sentinel": Version("3.4.0")}
358
353
 
359
354
  def __init__(
@@ -402,8 +397,6 @@ class RedisSentinelStorage(RedisStorage):
402
397
  if self.service_name is None:
403
398
  raise ConfigurationError("'service_name' not provided")
404
399
 
405
- connection_options.setdefault("stream_timeout", 0.2)
406
-
407
400
  super(RedisStorage, self).__init__()
408
401
 
409
402
  self.dependency = self.dependencies["coredis.sentinel"].module
limits/aio/strategies.py CHANGED
@@ -2,7 +2,6 @@
2
2
  Asynchronous rate limiting strategies
3
3
  """
4
4
 
5
- import weakref
6
5
  from abc import ABC, abstractmethod
7
6
  from typing import cast
8
7
 
@@ -15,7 +14,7 @@ from .storage import MovingWindowSupport, Storage
15
14
  class RateLimiter(ABC):
16
15
  def __init__(self, storage: StorageTypes):
17
16
  assert isinstance(storage, Storage)
18
- self.storage: Storage = weakref.proxy(storage)
17
+ self.storage: Storage = storage
19
18
 
20
19
  @abstractmethod
21
20
  async def hit(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool:
@@ -9,15 +9,14 @@ end
9
9
 
10
10
  local entry = redis.call('lindex', KEYS[1], limit - amount)
11
11
 
12
-
13
12
  if entry and tonumber(entry) >= timestamp - expiry then
14
13
  return false
15
14
  end
16
- local entries= {}
17
- for i=1, amount do
18
- entries[i] = timestamp
15
+
16
+ for i = 1, amount do
17
+ redis.call('lpush', KEYS[1], timestamp)
19
18
  end
20
- redis.call('lpush', KEYS[1], unpack(entries))
19
+
21
20
  redis.call('ltrim', KEYS[1], 0, limit - 1)
22
21
  redis.call('expire', KEYS[1], expiry)
23
22
 
limits/storage/memory.py CHANGED
@@ -7,7 +7,7 @@ from limits.storage.base import MovingWindowSupport, Storage
7
7
  from limits.typing import Dict, List, Optional, Tuple
8
8
 
9
9
 
10
- class LockableEntry(threading._RLock):
10
+ class LockableEntry(threading._RLock): # type: ignore
11
11
  def __init__(self, expiry: float) -> None:
12
12
  self.atime = time.time()
13
13
  self.expiry = self.atime + expiry
@@ -21,11 +21,6 @@ class RedisSentinelStorage(RedisStorage):
21
21
  STORAGE_SCHEME = ["redis+sentinel"]
22
22
  """The storage scheme for redis accessed via a redis sentinel installation"""
23
23
 
24
- DEFAULT_OPTIONS: Dict[str, Union[float, str, bool]] = {
25
- "socket_timeout": 0.2,
26
- }
27
- "Default options passed to :class:`~redis.sentinel.Sentinel`"
28
-
29
24
  DEPENDENCIES = {"redis.sentinel": Version("3.0")}
30
25
 
31
26
  def __init__(
@@ -79,7 +74,7 @@ class RedisSentinelStorage(RedisStorage):
79
74
  self.sentinel: "redis.sentinel.Sentinel" = sentinel_dep.Sentinel(
80
75
  sentinel_configuration,
81
76
  sentinel_kwargs={**parsed_auth, **sentinel_options},
82
- **{**self.DEFAULT_OPTIONS, **parsed_auth, **options}
77
+ **{**parsed_auth, **options}
83
78
  )
84
79
  self.storage = self.sentinel.master_for(self.service_name)
85
80
  self.storage_slave = self.sentinel.slave_for(self.service_name)
limits/strategies.py CHANGED
@@ -2,7 +2,6 @@
2
2
  Rate limiting strategies
3
3
  """
4
4
 
5
- import weakref
6
5
  from abc import ABCMeta, abstractmethod
7
6
  from typing import Dict, Type, Union, cast
8
7
 
@@ -14,7 +13,7 @@ from .util import WindowStats
14
13
  class RateLimiter(metaclass=ABCMeta):
15
14
  def __init__(self, storage: StorageTypes):
16
15
  assert isinstance(storage, Storage)
17
- self.storage: Storage = weakref.proxy(storage)
16
+ self.storage: Storage = storage
18
17
 
19
18
  @abstractmethod
20
19
  def hit(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: limits
3
- Version: 3.3.1
3
+ Version: 3.5.0
4
4
  Summary: Rate limiting utilities
5
5
  Home-page: https://limits.readthedocs.org
6
6
  Author: Ali-Akber Saifee
@@ -1,38 +1,37 @@
1
1
  limits/__init__.py,sha256=j_yVhgN9pdz8o5rQjVwdJTBSq8F-CTzof9kkiYgjRbw,728
2
- limits/_version.py,sha256=e_K66W5uXJiAuk7fwDi5QpUGkuokyZ32nTQVKOndcIA,497
2
+ limits/_version.py,sha256=pRgzWhjWD3Hv3aQNYQ7qUpaxhRxo3wRSGt5p6uMLXpk,497
3
3
  limits/errors.py,sha256=sUolBUfTFLQSzo6dfE2E9j_0K7_8Nr9_Hx-v5C4D0EU,416
4
4
  limits/limits.py,sha256=lwQnA5wegkW_AXtplOH3tLuQ1LByMX9hqHJquYVYdTs,4943
5
5
  limits/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- limits/strategies.py,sha256=P0ZukQIJb-KA7_gTpNRwez4a7kF-mZSjE0GCgVjM5Zk,6720
6
+ limits/strategies.py,sha256=7pr2V34KdOEfxnYOf882Cl2qKY-KK6HwKjdYo_IsD4c,6690
7
7
  limits/typing.py,sha256=EhzmTl0x-RHsc_TRmP9vJooxV94nMisw3vnUtkB2NBI,2962
8
8
  limits/util.py,sha256=LRsn6i3KmQE33Ea4FTf4IxD9SMtwiKVXN5iDxTEuOuc,5743
9
9
  limits/version.py,sha256=YwkF3dtq1KGzvmL3iVGctA8NNtGlK_0arrzZkZGVjUs,47
10
10
  limits/aio/__init__.py,sha256=IOetunwQy1c5GefzitK8lewbTzHGiE-kmE9NlqSdr3U,82
11
- limits/aio/strategies.py,sha256=7s_0VEVCjybKSzNxl4VeKo2QCTK0Q94VcRZk2mOiUrc,6515
11
+ limits/aio/strategies.py,sha256=REaQ-lqgqkN5wrFZ26AZ3sCHO8oZBL_mWhI6nMRaBz8,6485
12
12
  limits/aio/storage/__init__.py,sha256=CbtuSlVl1jPyN_vsEI_ApWblDblVaL46xcZ2M_oM0V8,595
13
13
  limits/aio/storage/base.py,sha256=gsy_91lvm53AoAKi1plaegcEOSZXK3OiMP0mxA6lPAw,2941
14
14
  limits/aio/storage/etcd.py,sha256=iGGuKHN5cCW9r4nLeiZ4TnoU1pfSXXLZhS2YOWznryw,4568
15
15
  limits/aio/storage/memcached.py,sha256=aR7f5NY-mXtFFjphbaxoL7z1cAHZuRYjpGUVOktoI4A,4296
16
16
  limits/aio/storage/memory.py,sha256=A506i0vncBmsaL9GGAqepQkPAXyc-HxmJ8gS8kJtqpE,5597
17
17
  limits/aio/storage/mongodb.py,sha256=s_eUawyITOT7nPHeI_fgMVmDhm9XxhoQ_bmYD2aXius,9057
18
- limits/aio/storage/redis.py,sha256=PCLPvogKNhtK89LWiG8-l_k7luVgDh5gBKFkxIsQlZ4,14858
19
- limits/resources/redis/lua_scripts/acquire_moving_window.lua,sha256=-YmVj_MHE5N6WazXmkAw4j-CtAOWk4XroTXloXSdHrA,527
18
+ limits/aio/storage/redis.py,sha256=eBfTtk5w0s8IQKWUBeqbVFrKFr5xTIcRC7eim7uoYnA,14630
19
+ limits/resources/redis/lua_scripts/acquire_moving_window.lua,sha256=5CFJX7D6T6RG5SFr6eVZ6zepmI1EkGWmKeVEO4QNrWo,483
20
20
  limits/resources/redis/lua_scripts/clear_keys.lua,sha256=zU0cVfLGmapRQF9x9u0GclapM_IB2pJLszNzVQ1QRK4,184
21
- limits/resources/redis/lua_scripts/gcra_consume.lua,sha256=bqTDE6_7LYqvqJCSo7mmJ_tGedL9CyWMwwBNXFuHdMk,1251
22
21
  limits/resources/redis/lua_scripts/incr_expire.lua,sha256=Uq9NcrrcDI-F87TDAJexoSJn2SDgeXIUEYozCp9S3oA,195
23
22
  limits/resources/redis/lua_scripts/moving_window.lua,sha256=ir0SkuRVnrqkVSFNIuedTV_KW6zG70Z56u6-_FpR_20,352
24
23
  limits/storage/__init__.py,sha256=8i1-SoTEV_XGAMYDepcLra7do-Tx4rUPbPrUQVVJgTw,2518
25
24
  limits/storage/base.py,sha256=-JV-zAkss7pOETZyPYjo8ZZqTMGs-DPqgz_gcfArXfs,2818
26
25
  limits/storage/etcd.py,sha256=SlDHRItliRaR2j5Rf_v_oQ57ITpmNMYQJSamM3SbwCA,4258
27
26
  limits/storage/memcached.py,sha256=qMvRIEtRRzZXSgcZSUTBgUlBDeNOpIr_gDTV2r5SPak,6005
28
- limits/storage/memory.py,sha256=mwNOkPyXnTAUdxOnXVf7yqDqry-G_IwpI0jkrQ6tfo0,5286
27
+ limits/storage/memory.py,sha256=plPsyLB26QN9I6jQq00fra-cdh8xoDAgaoM-kWuECtk,5302
29
28
  limits/storage/mongodb.py,sha256=ZdFr2-MTtdPcOZE5XKd-XxNmbl9dHLZbU2PmqmH9CA4,7942
30
29
  limits/storage/redis.py,sha256=nysRkOIK9pKTC1p0mBpIu5wHjmihLsFbwOx8nfFMpaI,7560
31
30
  limits/storage/redis_cluster.py,sha256=8578Slo-cwh5GdbuUDhYjQfBsWTwJyGoQ1d_mxVfcIM,5342
32
- limits/storage/redis_sentinel.py,sha256=fbTHyxeNsnGG4ll3hMDejE2C2DqWPpKwE3JklUY9pHA,3835
31
+ limits/storage/redis_sentinel.py,sha256=AxbtYZQXCNL-4yu7dQ8i6MhwO2PNLMRLHe3JcHkMKvA,3647
33
32
  limits/storage/registry.py,sha256=xcBcxuu6srqmoS4WqDpkCXnRLB19ctH98v21P8S9kS8,708
34
- limits-3.3.1.dist-info/LICENSE.txt,sha256=T6i7kq7F5gIPfcno9FCxU5Hcwm22Bjq0uHZV3ElcjsQ,1061
35
- limits-3.3.1.dist-info/METADATA,sha256=vVYvd4iWIg9KVeRwoWm6badxSFTWa7ZOgjD9WN3l87o,7486
36
- limits-3.3.1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
37
- limits-3.3.1.dist-info/top_level.txt,sha256=C7g5ahldPoU2s6iWTaJayUrbGmPK1d6e9t5Nn0vQ2jM,7
38
- limits-3.3.1.dist-info/RECORD,,
33
+ limits-3.5.0.dist-info/LICENSE.txt,sha256=T6i7kq7F5gIPfcno9FCxU5Hcwm22Bjq0uHZV3ElcjsQ,1061
34
+ limits-3.5.0.dist-info/METADATA,sha256=jQV7tH4J9f2a2hoVe96tDgetCi4npIq5Hq8Fhn0oFi8,7486
35
+ limits-3.5.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
36
+ limits-3.5.0.dist-info/top_level.txt,sha256=C7g5ahldPoU2s6iWTaJayUrbGmPK1d6e9t5Nn0vQ2jM,7
37
+ limits-3.5.0.dist-info/RECORD,,
@@ -1,50 +0,0 @@
1
- local rate_limit_key = KEYS[1]
2
- local burst = ARGV[1]
3
- local rate = ARGV[2]
4
- local period = ARGV[3]
5
- local cost = ARGV[4]
6
-
7
- local emission_interval = period / rate
8
- local increment = emission_interval * cost
9
- local burst_offset = emission_interval * burst
10
-
11
- local tat = redis.call("GET", rate_limit_key)
12
-
13
- local time = redis.call("TIME")
14
- local now = tonumber(time[1]) + tonumber(time[2])/1000000.0
15
-
16
- if not tat then
17
- tat = now
18
- else
19
- tat = tonumber(tat)
20
- end
21
-
22
- tat = math.max(tat, now)
23
-
24
- local new_tat = tat + increment
25
- local allow_at = new_tat - burst_offset
26
- local diff = now - allow_at
27
-
28
- local consumed = 0
29
- local retry_in = 0
30
- local reset_in
31
-
32
- local remaining = math.floor(diff / emission_interval) -- poor man's round
33
- if remaining < 0 then
34
- consumed = 0
35
- remaining = math.floor((now - (tat - burst_offset)) / emission_interval)
36
- reset_in = math.ceil(tat - now)
37
- retry_in = math.ceil(diff * -1)
38
- elseif remaining == 0 and increment <= 0 then
39
- consumed = 1
40
- remaining = 0
41
- reset_in = math.ceil(tat - now)
42
- else
43
- consumed = 1
44
- reset_in = math.ceil(new_tat - now)
45
- if increment > 0 then
46
- redis.call("SET", rate_limit_key, new_tat, "PX", reset_in)
47
- end
48
- end
49
-
50
- return {consumed, remaining, retry_in, reset_in}
File without changes