limits 4.1__py3-none-any.whl → 4.3__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/__init__.py +8 -6
- limits/_version.py +4 -4
- limits/aio/__init__.py +2 -0
- limits/aio/storage/__init__.py +6 -4
- limits/aio/storage/base.py +5 -8
- limits/aio/storage/etcd.py +6 -4
- limits/aio/storage/memcached.py +6 -4
- limits/aio/storage/memory.py +42 -26
- limits/aio/storage/mongodb.py +4 -7
- limits/aio/storage/redis/__init__.py +402 -0
- limits/aio/storage/redis/bridge.py +120 -0
- limits/aio/storage/redis/coredis.py +209 -0
- limits/aio/storage/redis/redispy.py +257 -0
- limits/aio/storage/redis/valkey.py +9 -0
- limits/aio/strategies.py +4 -2
- limits/errors.py +2 -0
- limits/storage/__init__.py +14 -11
- limits/storage/base.py +5 -10
- limits/storage/etcd.py +6 -4
- limits/storage/memcached.py +6 -7
- limits/storage/memory.py +42 -31
- limits/storage/mongodb.py +7 -10
- limits/storage/redis.py +48 -18
- limits/storage/redis_cluster.py +31 -11
- limits/storage/redis_sentinel.py +35 -11
- limits/storage/registry.py +1 -3
- limits/strategies.py +11 -9
- limits/typing.py +45 -42
- limits/util.py +12 -12
- {limits-4.1.dist-info → limits-4.3.dist-info}/METADATA +52 -36
- limits-4.3.dist-info/RECORD +43 -0
- {limits-4.1.dist-info → limits-4.3.dist-info}/WHEEL +1 -1
- limits/aio/storage/redis.py +0 -555
- limits-4.1.dist-info/RECORD +0 -39
- {limits-4.1.dist-info → limits-4.3.dist-info}/LICENSE.txt +0 -0
- {limits-4.1.dist-info → limits-4.3.dist-info}/top_level.txt +0 -0
limits/typing.py
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from collections import Counter
|
|
2
|
-
from collections.abc import Awaitable, Iterable
|
|
4
|
+
from collections.abc import Awaitable, Callable, Iterable
|
|
3
5
|
from typing import (
|
|
4
6
|
TYPE_CHECKING,
|
|
5
7
|
Any,
|
|
6
|
-
Callable,
|
|
7
8
|
ClassVar,
|
|
9
|
+
Literal,
|
|
8
10
|
NamedTuple,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
ParamSpec,
|
|
12
|
+
Protocol,
|
|
13
|
+
TypeAlias,
|
|
11
14
|
TypeVar,
|
|
12
|
-
Union,
|
|
13
15
|
cast,
|
|
14
16
|
)
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Serializable = Union[int, str, float]
|
|
18
|
+
Serializable = int | str | float
|
|
19
19
|
|
|
20
20
|
R = TypeVar("R")
|
|
21
21
|
R_co = TypeVar("R_co", covariant=True)
|
|
@@ -24,16 +24,16 @@ P = ParamSpec("P")
|
|
|
24
24
|
|
|
25
25
|
if TYPE_CHECKING:
|
|
26
26
|
import coredis
|
|
27
|
-
import coredis.commands.script
|
|
28
27
|
import pymongo.collection
|
|
29
28
|
import pymongo.database
|
|
29
|
+
import pymongo.mongo_client
|
|
30
30
|
import redis
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class ItemP(Protocol):
|
|
34
34
|
value: bytes
|
|
35
|
-
flags:
|
|
36
|
-
cas:
|
|
35
|
+
flags: int | None
|
|
36
|
+
cas: int | None
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
class EmcacheClientP(Protocol):
|
|
@@ -47,19 +47,19 @@ class EmcacheClientP(Protocol):
|
|
|
47
47
|
noreply: bool = False,
|
|
48
48
|
) -> None: ...
|
|
49
49
|
|
|
50
|
-
async def get(self, key: bytes, return_flags: bool = False) ->
|
|
50
|
+
async def get(self, key: bytes, return_flags: bool = False) -> ItemP | None: ...
|
|
51
51
|
|
|
52
52
|
async def get_many(self, keys: Iterable[bytes]) -> dict[bytes, ItemP]: ...
|
|
53
53
|
|
|
54
|
-
async def gets(self, key: bytes, return_flags: bool = False) ->
|
|
54
|
+
async def gets(self, key: bytes, return_flags: bool = False) -> ItemP | None: ...
|
|
55
55
|
|
|
56
56
|
async def increment(
|
|
57
57
|
self, key: bytes, value: int, *, noreply: bool = False
|
|
58
|
-
) ->
|
|
58
|
+
) -> int | None: ...
|
|
59
59
|
|
|
60
60
|
async def decrement(
|
|
61
61
|
self, key: bytes, value: int, *, noreply: bool = False
|
|
62
|
-
) ->
|
|
62
|
+
) -> int | None: ...
|
|
63
63
|
|
|
64
64
|
async def delete(self, key: bytes, *, noreply: bool = False) -> None: ...
|
|
65
65
|
|
|
@@ -83,65 +83,72 @@ class MemcachedClientP(Protocol):
|
|
|
83
83
|
self,
|
|
84
84
|
key: str,
|
|
85
85
|
value: Serializable,
|
|
86
|
-
expire:
|
|
87
|
-
noreply:
|
|
88
|
-
flags:
|
|
86
|
+
expire: int | None = 0,
|
|
87
|
+
noreply: bool | None = None,
|
|
88
|
+
flags: int | None = None,
|
|
89
89
|
) -> bool: ...
|
|
90
90
|
|
|
91
|
-
def get(self, key: str, default:
|
|
91
|
+
def get(self, key: str, default: str | None = None) -> bytes: ...
|
|
92
92
|
|
|
93
93
|
def get_many(self, keys: Iterable[str]) -> dict[str, Any]: ... # type:ignore[explicit-any]
|
|
94
94
|
|
|
95
95
|
def incr(
|
|
96
|
-
self, key: str, value: int, noreply:
|
|
97
|
-
) ->
|
|
96
|
+
self, key: str, value: int, noreply: bool | None = False
|
|
97
|
+
) -> int | None: ...
|
|
98
98
|
|
|
99
99
|
def decr(
|
|
100
100
|
self,
|
|
101
101
|
key: str,
|
|
102
102
|
value: int,
|
|
103
|
-
noreply:
|
|
104
|
-
) ->
|
|
103
|
+
noreply: bool | None = False,
|
|
104
|
+
) -> int | None: ...
|
|
105
105
|
|
|
106
|
-
def delete(self, key: str, noreply:
|
|
106
|
+
def delete(self, key: str, noreply: bool | None = None) -> bool | None: ...
|
|
107
107
|
|
|
108
108
|
def set(
|
|
109
109
|
self,
|
|
110
110
|
key: str,
|
|
111
111
|
value: Serializable,
|
|
112
112
|
expire: int = 0,
|
|
113
|
-
noreply:
|
|
114
|
-
flags:
|
|
113
|
+
noreply: bool | None = None,
|
|
114
|
+
flags: int | None = None,
|
|
115
115
|
) -> bool: ...
|
|
116
116
|
|
|
117
117
|
def touch(
|
|
118
|
-
self, key: str, expire:
|
|
118
|
+
self, key: str, expire: int | None = 0, noreply: bool | None = None
|
|
119
119
|
) -> bool: ...
|
|
120
120
|
|
|
121
121
|
|
|
122
122
|
class RedisClientP(Protocol):
|
|
123
123
|
def incrby(self, key: str, amount: int) -> int: ...
|
|
124
|
-
def get(self, key: str) ->
|
|
124
|
+
def get(self, key: str) -> bytes | None: ...
|
|
125
125
|
def delete(self, key: str) -> int: ...
|
|
126
126
|
def ttl(self, key: str) -> int: ...
|
|
127
127
|
def expire(self, key: str, seconds: int) -> bool: ...
|
|
128
128
|
def ping(self) -> bool: ...
|
|
129
|
-
def register_script(self, script: bytes) ->
|
|
129
|
+
def register_script(self, script: bytes) -> redis.commands.core.Script: ...
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
class AsyncRedisClientP(Protocol):
|
|
133
|
+
async def incrby(self, key: str, amount: int) -> int: ...
|
|
134
|
+
async def get(self, key: str) -> bytes | None: ...
|
|
135
|
+
async def delete(self, key: str) -> int: ...
|
|
136
|
+
async def ttl(self, key: str) -> int: ...
|
|
137
|
+
async def expire(self, key: str, seconds: int) -> bool: ...
|
|
138
|
+
async def ping(self) -> bool: ...
|
|
139
|
+
def register_script(self, script: bytes) -> redis.commands.core.Script: ...
|
|
134
140
|
|
|
135
141
|
|
|
136
|
-
|
|
137
|
-
|
|
142
|
+
RedisClient: TypeAlias = RedisClientP
|
|
143
|
+
AsyncRedisClient: TypeAlias = AsyncRedisClientP
|
|
144
|
+
AsyncCoRedisClient: TypeAlias = "coredis.Redis[bytes] | coredis.RedisCluster[bytes]"
|
|
138
145
|
|
|
139
|
-
|
|
140
|
-
MongoClient: TypeAlias = "pymongo.MongoClient[dict[str, Any]]" # type:ignore[explicit-any]
|
|
146
|
+
MongoClient: TypeAlias = "pymongo.mongo_client.MongoClient[dict[str, Any]]" # type:ignore[explicit-any]
|
|
141
147
|
MongoDatabase: TypeAlias = "pymongo.database.Database[dict[str, Any]]" # type:ignore[explicit-any]
|
|
142
148
|
MongoCollection: TypeAlias = "pymongo.collection.Collection[dict[str, Any]]" # type:ignore[explicit-any]
|
|
143
149
|
|
|
144
150
|
__all__ = [
|
|
151
|
+
"TYPE_CHECKING",
|
|
145
152
|
"Any",
|
|
146
153
|
"AsyncRedisClient",
|
|
147
154
|
"Awaitable",
|
|
@@ -150,24 +157,20 @@ __all__ = [
|
|
|
150
157
|
"Counter",
|
|
151
158
|
"EmcacheClientP",
|
|
152
159
|
"ItemP",
|
|
160
|
+
"Literal",
|
|
153
161
|
"MemcachedClientP",
|
|
154
162
|
"MongoClient",
|
|
155
163
|
"MongoCollection",
|
|
156
164
|
"MongoDatabase",
|
|
157
165
|
"NamedTuple",
|
|
158
|
-
"Optional",
|
|
159
166
|
"P",
|
|
160
167
|
"ParamSpec",
|
|
161
168
|
"Protocol",
|
|
162
|
-
"ScriptP",
|
|
163
|
-
"Serializable",
|
|
164
|
-
"TypeVar",
|
|
165
169
|
"R",
|
|
166
170
|
"R_co",
|
|
167
171
|
"RedisClient",
|
|
168
|
-
"
|
|
172
|
+
"Serializable",
|
|
173
|
+
"TypeAlias",
|
|
169
174
|
"TypeVar",
|
|
170
|
-
"TYPE_CHECKING",
|
|
171
|
-
"Union",
|
|
172
175
|
"cast",
|
|
173
176
|
]
|
limits/util.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
""" """
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import dataclasses
|
|
4
6
|
import importlib.resources
|
|
5
7
|
import re
|
|
@@ -10,7 +12,7 @@ from typing import TYPE_CHECKING
|
|
|
10
12
|
|
|
11
13
|
from packaging.version import Version
|
|
12
14
|
|
|
13
|
-
from limits.typing import NamedTuple
|
|
15
|
+
from limits.typing import NamedTuple
|
|
14
16
|
|
|
15
17
|
from .errors import ConfigurationError
|
|
16
18
|
from .limits import GRANULARITIES, RateLimitItem
|
|
@@ -25,9 +27,7 @@ SINGLE_EXPR = re.compile(
|
|
|
25
27
|
re.IGNORECASE | re.VERBOSE,
|
|
26
28
|
)
|
|
27
29
|
EXPR = re.compile(
|
|
28
|
-
|
|
29
|
-
SINGLE=SINGLE_EXPR.pattern, SEPARATORS=SEPARATORS.pattern
|
|
30
|
-
),
|
|
30
|
+
rf"^{SINGLE_EXPR.pattern}(:?{SEPARATORS.pattern}{SINGLE_EXPR.pattern})*$",
|
|
31
31
|
re.IGNORECASE | re.VERBOSE,
|
|
32
32
|
)
|
|
33
33
|
|
|
@@ -46,8 +46,8 @@ class WindowStats(NamedTuple):
|
|
|
46
46
|
@dataclasses.dataclass
|
|
47
47
|
class Dependency:
|
|
48
48
|
name: str
|
|
49
|
-
version_required:
|
|
50
|
-
version_found:
|
|
49
|
+
version_required: Version | None
|
|
50
|
+
version_found: Version | None
|
|
51
51
|
module: ModuleType
|
|
52
52
|
|
|
53
53
|
|
|
@@ -96,7 +96,7 @@ class LazyDependency:
|
|
|
96
96
|
without having to import them explicitly.
|
|
97
97
|
"""
|
|
98
98
|
|
|
99
|
-
DEPENDENCIES:
|
|
99
|
+
DEPENDENCIES: dict[str, Version | None] | list[str] = []
|
|
100
100
|
"""
|
|
101
101
|
The python modules this class has a dependency on.
|
|
102
102
|
Used to lazily populate the :attr:`dependencies`
|
|
@@ -117,7 +117,7 @@ class LazyDependency:
|
|
|
117
117
|
|
|
118
118
|
if not getattr(self, "_dependencies", None):
|
|
119
119
|
dependencies = DependencyDict()
|
|
120
|
-
mapping: dict[str,
|
|
120
|
+
mapping: dict[str, Version | None]
|
|
121
121
|
|
|
122
122
|
if isinstance(self.DEPENDENCIES, list):
|
|
123
123
|
mapping = {dependency: None for dependency in self.DEPENDENCIES}
|
|
@@ -135,7 +135,7 @@ class LazyDependency:
|
|
|
135
135
|
return self._dependencies
|
|
136
136
|
|
|
137
137
|
|
|
138
|
-
def get_dependency(module_path: str) -> tuple[ModuleType,
|
|
138
|
+
def get_dependency(module_path: str) -> tuple[ModuleType, Version | None]:
|
|
139
139
|
"""
|
|
140
140
|
safe function to import a module at runtime
|
|
141
141
|
"""
|
|
@@ -165,7 +165,7 @@ def parse_many(limit_string: str) -> list[RateLimitItem]:
|
|
|
165
165
|
"""
|
|
166
166
|
|
|
167
167
|
if not (isinstance(limit_string, str) and EXPR.match(limit_string)):
|
|
168
|
-
raise ValueError("couldn't parse rate limit string '
|
|
168
|
+
raise ValueError(f"couldn't parse rate limit string '{limit_string}'")
|
|
169
169
|
limits = []
|
|
170
170
|
|
|
171
171
|
for limit in SEPARATORS.split(limit_string):
|
|
@@ -194,7 +194,7 @@ def parse(limit_string: str) -> RateLimitItem:
|
|
|
194
194
|
return list(parse_many(limit_string))[0]
|
|
195
195
|
|
|
196
196
|
|
|
197
|
-
def granularity_from_string(granularity_string: str) ->
|
|
197
|
+
def granularity_from_string(granularity_string: str) -> type[RateLimitItem]:
|
|
198
198
|
"""
|
|
199
199
|
|
|
200
200
|
:param granularity_string:
|
|
@@ -204,4 +204,4 @@ def granularity_from_string(granularity_string: str) -> Type[RateLimitItem]:
|
|
|
204
204
|
for granularity in GRANULARITIES.values():
|
|
205
205
|
if granularity.check_granularity_string(granularity_string):
|
|
206
206
|
return granularity
|
|
207
|
-
raise ValueError("no granularity matched for
|
|
207
|
+
raise ValueError(f"no granularity matched for {granularity_string}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: limits
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3
|
|
4
4
|
Summary: Rate limiting utilities
|
|
5
5
|
Home-page: https://limits.readthedocs.org
|
|
6
6
|
Author: Ali-Akber Saifee
|
|
@@ -14,47 +14,63 @@ Classifier: Operating System :: MacOS
|
|
|
14
14
|
Classifier: Operating System :: POSIX :: Linux
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
16
16
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
21
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
23
|
-
Requires-Python: >=3.
|
|
22
|
+
Requires-Python: >=3.10
|
|
24
23
|
License-File: LICENSE.txt
|
|
25
|
-
Requires-Dist: deprecated
|
|
26
|
-
Requires-Dist: packaging
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
Provides-Extra: all
|
|
29
|
-
Requires-Dist: redis !=4.5.2,!=4.5.3,<6.0.0,>3 ; extra == 'all'
|
|
30
|
-
Requires-Dist: redis !=4.5.2,!=4.5.3,>=4.2.0 ; extra == 'all'
|
|
31
|
-
Requires-Dist: pymemcache <5.0.0,>3 ; extra == 'all'
|
|
32
|
-
Requires-Dist: pymongo <5,>4.1 ; extra == 'all'
|
|
33
|
-
Requires-Dist: etcd3 ; extra == 'all'
|
|
34
|
-
Requires-Dist: coredis <5,>=3.4.0 ; extra == 'all'
|
|
35
|
-
Requires-Dist: motor <4,>=3 ; extra == 'all'
|
|
36
|
-
Requires-Dist: aetcd ; extra == 'all'
|
|
37
|
-
Requires-Dist: emcache >=0.6.1 ; (python_version < "3.11") and extra == 'all'
|
|
38
|
-
Requires-Dist: emcache >=1 ; (python_version >= "3.11" and python_version < "3.13.0") and extra == 'all'
|
|
39
|
-
Provides-Extra: async-etcd
|
|
40
|
-
Requires-Dist: aetcd ; extra == 'async-etcd'
|
|
41
|
-
Provides-Extra: async-memcached
|
|
42
|
-
Requires-Dist: emcache >=0.6.1 ; (python_version < "3.11") and extra == 'async-memcached'
|
|
43
|
-
Requires-Dist: emcache >=1 ; (python_version >= "3.11" and python_version < "3.13.0") and extra == 'async-memcached'
|
|
44
|
-
Provides-Extra: async-mongodb
|
|
45
|
-
Requires-Dist: motor <4,>=3 ; extra == 'async-mongodb'
|
|
46
|
-
Provides-Extra: async-redis
|
|
47
|
-
Requires-Dist: coredis <5,>=3.4.0 ; extra == 'async-redis'
|
|
48
|
-
Provides-Extra: etcd
|
|
49
|
-
Requires-Dist: etcd3 ; extra == 'etcd'
|
|
50
|
-
Provides-Extra: memcached
|
|
51
|
-
Requires-Dist: pymemcache <5.0.0,>3 ; extra == 'memcached'
|
|
52
|
-
Provides-Extra: mongodb
|
|
53
|
-
Requires-Dist: pymongo <5,>4.1 ; extra == 'mongodb'
|
|
24
|
+
Requires-Dist: deprecated>=1.2
|
|
25
|
+
Requires-Dist: packaging<25,>=21
|
|
26
|
+
Requires-Dist: typing_extensions
|
|
54
27
|
Provides-Extra: redis
|
|
55
|
-
Requires-Dist: redis
|
|
28
|
+
Requires-Dist: redis!=4.5.2,!=4.5.3,<6.0.0,>3; extra == "redis"
|
|
56
29
|
Provides-Extra: rediscluster
|
|
57
|
-
Requires-Dist: redis
|
|
30
|
+
Requires-Dist: redis!=4.5.2,!=4.5.3,>=4.2.0; extra == "rediscluster"
|
|
31
|
+
Provides-Extra: memcached
|
|
32
|
+
Requires-Dist: pymemcache<5.0.0,>3; extra == "memcached"
|
|
33
|
+
Provides-Extra: mongodb
|
|
34
|
+
Requires-Dist: pymongo<5,>4.1; extra == "mongodb"
|
|
35
|
+
Provides-Extra: etcd
|
|
36
|
+
Requires-Dist: etcd3; extra == "etcd"
|
|
37
|
+
Provides-Extra: valkey
|
|
38
|
+
Requires-Dist: valkey>=6; extra == "valkey"
|
|
39
|
+
Provides-Extra: async-redis
|
|
40
|
+
Requires-Dist: coredis<5,>=3.4.0; extra == "async-redis"
|
|
41
|
+
Provides-Extra: async-memcached
|
|
42
|
+
Requires-Dist: emcache>=0.6.1; python_version < "3.11" and extra == "async-memcached"
|
|
43
|
+
Requires-Dist: emcache>=1; (python_version >= "3.11" and python_version < "3.13.0") and extra == "async-memcached"
|
|
44
|
+
Provides-Extra: async-mongodb
|
|
45
|
+
Requires-Dist: motor<4,>=3; extra == "async-mongodb"
|
|
46
|
+
Provides-Extra: async-etcd
|
|
47
|
+
Requires-Dist: aetcd; extra == "async-etcd"
|
|
48
|
+
Provides-Extra: async-valkey
|
|
49
|
+
Requires-Dist: valkey>=6; extra == "async-valkey"
|
|
50
|
+
Provides-Extra: all
|
|
51
|
+
Requires-Dist: redis!=4.5.2,!=4.5.3,<6.0.0,>3; extra == "all"
|
|
52
|
+
Requires-Dist: redis!=4.5.2,!=4.5.3,>=4.2.0; extra == "all"
|
|
53
|
+
Requires-Dist: pymemcache<5.0.0,>3; extra == "all"
|
|
54
|
+
Requires-Dist: pymongo<5,>4.1; extra == "all"
|
|
55
|
+
Requires-Dist: etcd3; extra == "all"
|
|
56
|
+
Requires-Dist: valkey>=6; extra == "all"
|
|
57
|
+
Requires-Dist: coredis<5,>=3.4.0; extra == "all"
|
|
58
|
+
Requires-Dist: emcache>=0.6.1; python_version < "3.11" and extra == "all"
|
|
59
|
+
Requires-Dist: emcache>=1; (python_version >= "3.11" and python_version < "3.13.0") and extra == "all"
|
|
60
|
+
Requires-Dist: motor<4,>=3; extra == "all"
|
|
61
|
+
Requires-Dist: aetcd; extra == "all"
|
|
62
|
+
Requires-Dist: valkey>=6; extra == "all"
|
|
63
|
+
Dynamic: author
|
|
64
|
+
Dynamic: author-email
|
|
65
|
+
Dynamic: classifier
|
|
66
|
+
Dynamic: description
|
|
67
|
+
Dynamic: home-page
|
|
68
|
+
Dynamic: license
|
|
69
|
+
Dynamic: project-url
|
|
70
|
+
Dynamic: provides-extra
|
|
71
|
+
Dynamic: requires-dist
|
|
72
|
+
Dynamic: requires-python
|
|
73
|
+
Dynamic: summary
|
|
58
74
|
|
|
59
75
|
.. |ci| image:: https://github.com/alisaifee/limits/actions/workflows/main.yml/badge.svg?branch=master
|
|
60
76
|
:target: https://github.com/alisaifee/limits/actions?query=branch%3Amaster+workflow%3ACI
|
|
@@ -115,7 +131,7 @@ Moving Window
|
|
|
115
131
|
|
|
116
132
|
This strategy adds each request’s timestamp to a log if the ``nth`` oldest entry (where ``n``
|
|
117
133
|
is the limit) is either not present or is older than the duration of the window (for example with a rate limit of
|
|
118
|
-
``10 requests per minute`` if there are either less than 10 entries or the 10th oldest entry is
|
|
134
|
+
``10 requests per minute`` if there are either less than 10 entries or the 10th oldest entry is at least
|
|
119
135
|
60 seconds old). Upon adding a new entry to the log "expired" entries are truncated.
|
|
120
136
|
|
|
121
137
|
For example, with a rate limit of 10 requests per minute:
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
limits/__init__.py,sha256=gPUFrt02kHF_syLjiVRSs-S4UVGpRMcM2VMFNhF6G24,748
|
|
2
|
+
limits/_version.py,sha256=LXQLnVdyn9TpqfaPWYkIpMLktR3ythlsHOPlSYBiX70,495
|
|
3
|
+
limits/errors.py,sha256=s1el9Vg0ly-z92guvnvYNgKi3_aVqpiw_sufemiLLTI,662
|
|
4
|
+
limits/limits.py,sha256=YzzZP8_ay_zlMMnnY2xhAcFTTFvFe5HEk8NQlvUTru4,4907
|
|
5
|
+
limits/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
limits/strategies.py,sha256=14k8CFu9mfoVokEVxD48MjF61gBl-hr895brpL4XZUc,10899
|
|
7
|
+
limits/typing.py,sha256=7G4-1MIh0pLOjBMG-gjNhpAqmX-hgQRzhD5_8ROVkls,4459
|
|
8
|
+
limits/util.py,sha256=nk5QYvezFuXPq1OTEj04RrZFSWIH-khT0e_Dim6zGCw,6002
|
|
9
|
+
limits/version.py,sha256=YwkF3dtq1KGzvmL3iVGctA8NNtGlK_0arrzZkZGVjUs,47
|
|
10
|
+
limits/aio/__init__.py,sha256=yxvWb_ZmV245Hg2LqD365WC5IDllcGDMw6udJ1jNp1g,118
|
|
11
|
+
limits/aio/strategies.py,sha256=9jnVU_nynm0zL1EjQLE3fus1vFbLqA-19ZRQhhexAGo,10776
|
|
12
|
+
limits/aio/storage/__init__.py,sha256=gL4DGTV-XDksZxofaP__sGvwehN8MuuJQuRZeuGwiOQ,695
|
|
13
|
+
limits/aio/storage/base.py,sha256=376Bs7l285vRTRa3-DqcVRnqOPdf3BpoCqbJr3XA9u8,6439
|
|
14
|
+
limits/aio/storage/etcd.py,sha256=9Mp2mvLKOZhuozVC6pBB7-85WMbPytmtZyS6Wg7KUPI,5012
|
|
15
|
+
limits/aio/storage/memcached.py,sha256=kSX7B0CRS-qDVCQot4AW0rF3YwomXRyWg6W0_RyaHhM,10361
|
|
16
|
+
limits/aio/storage/memory.py,sha256=cBWk9P8_Dtm8YJpsZWScVuJQN93IJyno0fFVd5ubcRc,9759
|
|
17
|
+
limits/aio/storage/mongodb.py,sha256=EvwYBu9YoNX7j6A8XB8ik8SqMx0n4oWmBYhh4LHMYaI,19310
|
|
18
|
+
limits/aio/storage/redis/__init__.py,sha256=p6amEcujcImDUxcYCsfBaLBKp1qH9xDXDjv3FWWfGow,14203
|
|
19
|
+
limits/aio/storage/redis/bridge.py,sha256=cKs77RoCxUPfYD6_o1AiHfqpkeq_DFqMtVQKMLhEWdY,3183
|
|
20
|
+
limits/aio/storage/redis/coredis.py,sha256=YT8cBx25MeSy9ApSJBfOK8VKduABTRefsnd9GhWscsI,7494
|
|
21
|
+
limits/aio/storage/redis/redispy.py,sha256=ZAxHOFGAjRHsPzjfLowq5nMlVkK_YhVGHOOV8K4gMmU,8547
|
|
22
|
+
limits/aio/storage/redis/valkey.py,sha256=f_-HPZhzNspywGybMNIL0F5uDZk76v8_K9wuC5ZeKhc,248
|
|
23
|
+
limits/resources/redis/lua_scripts/acquire_moving_window.lua,sha256=5CFJX7D6T6RG5SFr6eVZ6zepmI1EkGWmKeVEO4QNrWo,483
|
|
24
|
+
limits/resources/redis/lua_scripts/acquire_sliding_window.lua,sha256=OhVI1MAN_gT92P6r-2CEmvy1yvQVjYCCZxWIxfXYceY,1329
|
|
25
|
+
limits/resources/redis/lua_scripts/clear_keys.lua,sha256=zU0cVfLGmapRQF9x9u0GclapM_IB2pJLszNzVQ1QRK4,184
|
|
26
|
+
limits/resources/redis/lua_scripts/incr_expire.lua,sha256=Uq9NcrrcDI-F87TDAJexoSJn2SDgeXIUEYozCp9S3oA,195
|
|
27
|
+
limits/resources/redis/lua_scripts/moving_window.lua,sha256=5hUZghISDh8Cbg8HJediM_OKjjNMF-0CBywWmsc93vA,430
|
|
28
|
+
limits/resources/redis/lua_scripts/sliding_window.lua,sha256=qG3Yg30Dq54QpRUcR9AOrKQ5bdJiaYpCacTm6Kxblvc,713
|
|
29
|
+
limits/storage/__init__.py,sha256=DArgeRfGilHWsfKz5qT_6OimP3S5u2E9lnzVst0n8Bw,2701
|
|
30
|
+
limits/storage/base.py,sha256=6MprvcdNaTIPyN0ei9emcJLajYq07vDGSIKrmiaU6dU,7003
|
|
31
|
+
limits/storage/etcd.py,sha256=-Zg3KUeXSI8m6VujgIUfa5VeaaiB8Ytbq30p7Voucxk,4676
|
|
32
|
+
limits/storage/memcached.py,sha256=NJqHpbfZjT7YpjlK0dUX1-k_nb7HxPMQvBBapgUaHhY,11217
|
|
33
|
+
limits/storage/memory.py,sha256=xLg3NDsnVEI3ds4QGS7MpH-VjjEJqwroOnz3LA8UQQ8,9226
|
|
34
|
+
limits/storage/mongodb.py,sha256=NqXFRj6h8fk8r_dznV-h9gqh95MLNtd5VRmtFncdzT0,18224
|
|
35
|
+
limits/storage/redis.py,sha256=b2m5TrPNwS7NBY5btwCN0esGyCVQTwwgCn6f-sTcgFQ,10613
|
|
36
|
+
limits/storage/redis_cluster.py,sha256=z6aONMl4p1AY78G3J0BbtK--uztz88krwnpiOsU61BM,4447
|
|
37
|
+
limits/storage/redis_sentinel.py,sha256=AN0WtwHN88TvXk0C2uUE8l5Jhsd1ZxU8XSqrEyQSR20,4327
|
|
38
|
+
limits/storage/registry.py,sha256=CxSaDBGR5aBJPFAIsfX9axCnbcThN3Bu-EH4wHrXtu8,650
|
|
39
|
+
limits-4.3.dist-info/LICENSE.txt,sha256=T6i7kq7F5gIPfcno9FCxU5Hcwm22Bjq0uHZV3ElcjsQ,1061
|
|
40
|
+
limits-4.3.dist-info/METADATA,sha256=ykP0e77goPvIVXKgonDLMcTA95Me_zpbrlfDtFC96Vs,11355
|
|
41
|
+
limits-4.3.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
|
42
|
+
limits-4.3.dist-info/top_level.txt,sha256=C7g5ahldPoU2s6iWTaJayUrbGmPK1d6e9t5Nn0vQ2jM,7
|
|
43
|
+
limits-4.3.dist-info/RECORD,,
|