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 +3 -3
- limits/aio/storage/redis.py +0 -7
- limits/aio/strategies.py +1 -2
- limits/resources/redis/lua_scripts/acquire_moving_window.lua +4 -5
- limits/storage/memory.py +1 -1
- limits/storage/redis_sentinel.py +1 -6
- limits/strategies.py +1 -2
- {limits-3.3.1.dist-info → limits-3.5.0.dist-info}/METADATA +1 -1
- {limits-3.3.1.dist-info → limits-3.5.0.dist-info}/RECORD +12 -13
- limits/resources/redis/lua_scripts/gcra_consume.lua +0 -50
- {limits-3.3.1.dist-info → limits-3.5.0.dist-info}/LICENSE.txt +0 -0
- {limits-3.3.1.dist-info → limits-3.5.0.dist-info}/WHEEL +0 -0
- {limits-3.3.1.dist-info → limits-3.5.0.dist-info}/top_level.txt +0 -0
limits/_version.py
CHANGED
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2023-
|
|
11
|
+
"date": "2023-05-16T15:04:57-0700",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "3.
|
|
14
|
+
"full-revisionid": "d61ade38645d742e4614dd1c1c0283d6ace40bf0",
|
|
15
|
+
"version": "3.5.0"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
limits/aio/storage/redis.py
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
17
|
-
for i=1, amount do
|
|
18
|
-
|
|
15
|
+
|
|
16
|
+
for i = 1, amount do
|
|
17
|
+
redis.call('lpush', KEYS[1], timestamp)
|
|
19
18
|
end
|
|
20
|
-
|
|
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
|
limits/storage/redis_sentinel.py
CHANGED
|
@@ -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
|
-
**{**
|
|
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 =
|
|
16
|
+
self.storage: Storage = storage
|
|
18
17
|
|
|
19
18
|
@abstractmethod
|
|
20
19
|
def hit(self, item: RateLimitItem, *identifiers: str, cost: int = 1) -> bool:
|
|
@@ -1,38 +1,37 @@
|
|
|
1
1
|
limits/__init__.py,sha256=j_yVhgN9pdz8o5rQjVwdJTBSq8F-CTzof9kkiYgjRbw,728
|
|
2
|
-
limits/_version.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
19
|
-
limits/resources/redis/lua_scripts/acquire_moving_window.lua,sha256
|
|
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=
|
|
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=
|
|
31
|
+
limits/storage/redis_sentinel.py,sha256=AxbtYZQXCNL-4yu7dQ8i6MhwO2PNLMRLHe3JcHkMKvA,3647
|
|
33
32
|
limits/storage/registry.py,sha256=xcBcxuu6srqmoS4WqDpkCXnRLB19ctH98v21P8S9kS8,708
|
|
34
|
-
limits-3.
|
|
35
|
-
limits-3.
|
|
36
|
-
limits-3.
|
|
37
|
-
limits-3.
|
|
38
|
-
limits-3.
|
|
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
|
|
File without changes
|
|
File without changes
|