limits 3.14.1__py3-none-any.whl → 4.0.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": "2024-11-30T11:04:11-0800",
11
+ "date": "2025-01-05T13:27:13-0800",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "0671723f54aed5692d4c9d9b47cf0326d5263de5",
15
- "version": "3.14.1"
14
+ "full-revisionid": "61f7d58d4f8588486cfc3b567210604f415878f2",
15
+ "version": "4.0.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -103,7 +103,7 @@ class Storage(LazyDependency, metaclass=StorageRegistry):
103
103
  raise NotImplementedError
104
104
 
105
105
  @abstractmethod
106
- async def get_expiry(self, key: str) -> int:
106
+ async def get_expiry(self, key: str) -> float:
107
107
  """
108
108
  :param key: the key to get the expiry for
109
109
  """
@@ -169,7 +169,7 @@ class MovingWindowSupport(ABC):
169
169
  @abstractmethod
170
170
  async def get_moving_window(
171
171
  self, key: str, limit: int, expiry: int
172
- ) -> Tuple[int, int]:
172
+ ) -> Tuple[float, int]:
173
173
  """
174
174
  returns the starting point and the number of entries in the moving
175
175
  window
@@ -116,12 +116,12 @@ class EtcdStorage(Storage):
116
116
  return int(amount)
117
117
  return 0
118
118
 
119
- async def get_expiry(self, key: str) -> int:
119
+ async def get_expiry(self, key: str) -> float:
120
120
  cur = await self.storage.get(self.prefixed_key(key))
121
121
  if cur:
122
122
  window_end = float(cur.value.split(b":")[1])
123
- return int(window_end)
124
- return int(time.time())
123
+ return window_end
124
+ return time.time()
125
125
 
126
126
  async def check(self) -> bool:
127
127
  try:
@@ -126,14 +126,14 @@ class MemcachedStorage(Storage):
126
126
 
127
127
  return amount
128
128
 
129
- async def get_expiry(self, key: str) -> int:
129
+ async def get_expiry(self, key: str) -> float:
130
130
  """
131
131
  :param key: the key to get the expiry for
132
132
  """
133
133
  storage = await self.get_storage()
134
134
  item = await storage.get(f"{key}/expires".encode())
135
135
 
136
- return int(item and float(item.value) or time.time())
136
+ return item and float(item.value) or time.time()
137
137
 
138
138
  async def check(self) -> bool:
139
139
  """
@@ -128,12 +128,12 @@ class MemoryStorage(Storage, MovingWindowSupport):
128
128
 
129
129
  return True
130
130
 
131
- async def get_expiry(self, key: str) -> int:
131
+ async def get_expiry(self, key: str) -> float:
132
132
  """
133
133
  :param key: the key to get the expiry for
134
134
  """
135
135
 
136
- return int(self.expirations.get(key, time.time()))
136
+ return self.expirations.get(key, time.time())
137
137
 
138
138
  async def get_num_acquired(self, key: str, expiry: int) -> int:
139
139
  """
@@ -153,7 +153,7 @@ class MemoryStorage(Storage, MovingWindowSupport):
153
153
  # FIXME: arg limit is not used
154
154
  async def get_moving_window(
155
155
  self, key: str, limit: int, expiry: int
156
- ) -> Tuple[int, int]:
156
+ ) -> Tuple[float, int]:
157
157
  """
158
158
  returns the starting point and the number of entries in the moving
159
159
  window
@@ -167,9 +167,9 @@ class MemoryStorage(Storage, MovingWindowSupport):
167
167
 
168
168
  for item in self.events.get(key, [])[::-1]:
169
169
  if item.atime >= timestamp - expiry:
170
- return int(item.atime), acquired
170
+ return item.atime, acquired
171
171
 
172
- return int(timestamp), acquired
172
+ return timestamp, acquired
173
173
 
174
174
  async def check(self) -> bool:
175
175
  """
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- import calendar
5
4
  import datetime
6
5
  import time
7
6
  from typing import Any, cast
@@ -135,21 +134,19 @@ class MongoDBStorage(Storage, MovingWindowSupport):
135
134
  ),
136
135
  )
137
136
 
138
- async def get_expiry(self, key: str) -> int:
137
+ async def get_expiry(self, key: str) -> float:
139
138
  """
140
139
  :param key: the key to get the expiry for
141
140
  """
142
141
  counter = await self.database[self.__collection_mapping["counters"]].find_one(
143
142
  {"_id": key}
144
143
  )
145
- expiry = (
146
- counter["expireAt"]
147
- if counter
148
- else datetime.datetime.now(datetime.timezone.utc)
144
+ return (
145
+ (counter["expireAt"] if counter else datetime.datetime.now())
146
+ .replace(tzinfo=datetime.timezone.utc)
147
+ .timestamp()
149
148
  )
150
149
 
151
- return calendar.timegm(expiry.timetuple())
152
-
153
150
  async def get(self, key: str) -> int:
154
151
  """
155
152
  :param key: the key to get the counter value for
@@ -227,7 +224,7 @@ class MongoDBStorage(Storage, MovingWindowSupport):
227
224
 
228
225
  async def get_moving_window(
229
226
  self, key: str, limit: int, expiry: int
230
- ) -> Tuple[int, int]:
227
+ ) -> Tuple[float, int]:
231
228
  """
232
229
  returns the starting point and the number of entries in the moving
233
230
  window
@@ -237,7 +234,7 @@ class MongoDBStorage(Storage, MovingWindowSupport):
237
234
  :return: (start of window, number of acquired entries)
238
235
  """
239
236
  timestamp = time.time()
240
- result = (
237
+ if result := (
241
238
  await self.database[self.__collection_mapping["windows"]]
242
239
  .aggregate(
243
240
  [
@@ -264,12 +261,9 @@ class MongoDBStorage(Storage, MovingWindowSupport):
264
261
  ]
265
262
  )
266
263
  .to_list(length=1)
267
- )
268
-
269
- if result:
270
- return (int(result[0]["min"]), result[0]["count"])
271
-
272
- return (int(timestamp), 0)
264
+ ):
265
+ return result[0]["min"], result[0]["count"]
266
+ return timestamp, 0
273
267
 
274
268
  async def acquire_entry(
275
269
  self, key: str, limit: int, expiry: int, amount: int = 1
@@ -78,7 +78,7 @@ class RedisInteractor:
78
78
 
79
79
  async def get_moving_window(
80
80
  self, key: str, limit: int, expiry: int
81
- ) -> Tuple[int, int]:
81
+ ) -> Tuple[float, int]:
82
82
  """
83
83
  returns the starting point and the number of entries in the moving
84
84
  window
@@ -88,12 +88,12 @@ class RedisInteractor:
88
88
  :return: (start of window, number of acquired entries)
89
89
  """
90
90
  key = self.prefixed_key(key)
91
- timestamp = int(time.time())
91
+ timestamp = time.time()
92
92
  window = await self.lua_moving_window.execute(
93
- [key], [int(timestamp - expiry), limit]
93
+ [key], [timestamp - expiry, limit]
94
94
  )
95
95
  if window:
96
- return tuple(window) # type: ignore
96
+ return float(window[0]), window[1] # type: ignore
97
97
  return timestamp, 0
98
98
 
99
99
  async def _acquire_entry(
@@ -118,14 +118,14 @@ class RedisInteractor:
118
118
 
119
119
  return bool(acquired)
120
120
 
121
- async def _get_expiry(self, key: str, connection: AsyncRedisClient) -> int:
121
+ async def _get_expiry(self, key: str, connection: AsyncRedisClient) -> float:
122
122
  """
123
123
  :param key: the key to get the expiry for
124
124
  :param connection: Redis connection
125
125
  """
126
126
 
127
127
  key = self.prefixed_key(key)
128
- return int(max(await connection.ttl(key), 0) + time.time())
128
+ return max(await connection.ttl(key), 0) + time.time()
129
129
 
130
130
  async def _check(self, connection: AsyncRedisClient) -> bool:
131
131
  """
@@ -261,7 +261,7 @@ class RedisStorage(RedisInteractor, Storage, MovingWindowSupport):
261
261
 
262
262
  return await super()._acquire_entry(key, limit, expiry, self.storage, amount)
263
263
 
264
- async def get_expiry(self, key: str) -> int:
264
+ async def get_expiry(self, key: str) -> float:
265
265
  """
266
266
  :param key: the key to get the expiry for
267
267
  """
@@ -450,7 +450,7 @@ class RedisSentinelStorage(RedisStorage):
450
450
  key, self.storage_replica if self.use_replicas else self.storage
451
451
  )
452
452
 
453
- async def get_expiry(self, key: str) -> int:
453
+ async def get_expiry(self, key: str) -> float:
454
454
  """
455
455
  :param key: the key to get the expiry for
456
456
  """
@@ -16,4 +16,6 @@ for idx=1,#items do
16
16
  end
17
17
  end
18
18
 
19
- return {oldest, a}
19
+ if oldest then
20
+ return {tostring(oldest), a}
21
+ end
limits/storage/base.py CHANGED
@@ -99,7 +99,7 @@ class Storage(LazyDependency, metaclass=StorageRegistry):
99
99
  raise NotImplementedError
100
100
 
101
101
  @abstractmethod
102
- def get_expiry(self, key: str) -> int:
102
+ def get_expiry(self, key: str) -> float:
103
103
  """
104
104
  :param key: the key to get the expiry for
105
105
  """
@@ -161,7 +161,7 @@ class MovingWindowSupport(ABC):
161
161
  raise NotImplementedError
162
162
 
163
163
  @abstractmethod
164
- def get_moving_window(self, key: str, limit: int, expiry: int) -> Tuple[int, int]:
164
+ def get_moving_window(self, key: str, limit: int, expiry: int) -> Tuple[float, int]:
165
165
  """
166
166
  returns the starting point and the number of entries in the moving
167
167
  window
limits/storage/etcd.py CHANGED
@@ -110,12 +110,11 @@ class EtcdStorage(Storage):
110
110
  return int(amount)
111
111
  return 0
112
112
 
113
- def get_expiry(self, key: str) -> int:
113
+ def get_expiry(self, key: str) -> float:
114
114
  value, _ = self.storage.get(self.prefixed_key(key))
115
115
  if value:
116
- window_end = float(value.split(b":")[1])
117
- return int(window_end)
118
- return int(time.time())
116
+ return float(value.split(b":")[1])
117
+ return time.time()
119
118
 
120
119
  def check(self) -> bool:
121
120
  try:
@@ -192,12 +192,12 @@ class MemcachedStorage(Storage):
192
192
 
193
193
  return amount
194
194
 
195
- def get_expiry(self, key: str) -> int:
195
+ def get_expiry(self, key: str) -> float:
196
196
  """
197
197
  :param key: the key to get the expiry for
198
198
  """
199
199
 
200
- return int(float(self.storage.get(key + "/expires") or time.time()))
200
+ return float(self.storage.get(key + "/expires") or time.time())
201
201
 
202
202
  def check(self) -> bool:
203
203
  """
limits/storage/memory.py CHANGED
@@ -121,12 +121,12 @@ class MemoryStorage(Storage, MovingWindowSupport):
121
121
  self.events[key][:0] = [LockableEntry(expiry) for _ in range(amount)]
122
122
  return True
123
123
 
124
- def get_expiry(self, key: str) -> int:
124
+ def get_expiry(self, key: str) -> float:
125
125
  """
126
126
  :param key: the key to get the expiry for
127
127
  """
128
128
 
129
- return int(self.expirations.get(key, time.time()))
129
+ return self.expirations.get(key, time.time())
130
130
 
131
131
  def get_num_acquired(self, key: str, expiry: int) -> int:
132
132
  """
@@ -143,7 +143,7 @@ class MemoryStorage(Storage, MovingWindowSupport):
143
143
  else 0
144
144
  )
145
145
 
146
- def get_moving_window(self, key: str, limit: int, expiry: int) -> Tuple[int, int]:
146
+ def get_moving_window(self, key: str, limit: int, expiry: int) -> Tuple[float, int]:
147
147
  """
148
148
  returns the starting point and the number of entries in the moving
149
149
  window
@@ -157,9 +157,9 @@ class MemoryStorage(Storage, MovingWindowSupport):
157
157
 
158
158
  for item in self.events.get(key, [])[::-1]:
159
159
  if item.atime >= timestamp - expiry:
160
- return int(item.atime), acquired
160
+ return item.atime, acquired
161
161
 
162
- return int(timestamp), acquired
162
+ return timestamp, acquired
163
163
 
164
164
  def check(self) -> bool:
165
165
  """
limits/storage/mongodb.py CHANGED
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import calendar
4
3
  import datetime
5
4
  import time
6
5
  from abc import ABC, abstractmethod
@@ -122,19 +121,17 @@ class MongoDBStorageBase(Storage, MovingWindowSupport, ABC):
122
121
  self.counters.find_one_and_delete({"_id": key})
123
122
  self.windows.find_one_and_delete({"_id": key})
124
123
 
125
- def get_expiry(self, key: str) -> int:
124
+ def get_expiry(self, key: str) -> float:
126
125
  """
127
126
  :param key: the key to get the expiry for
128
127
  """
129
128
  counter = self.counters.find_one({"_id": key})
130
- expiry = (
131
- counter["expireAt"]
132
- if counter
133
- else datetime.datetime.now(datetime.timezone.utc)
129
+ return (
130
+ (counter["expireAt"] if counter else datetime.datetime.now())
131
+ .replace(tzinfo=datetime.timezone.utc)
132
+ .timestamp()
134
133
  )
135
134
 
136
- return calendar.timegm(expiry.timetuple())
137
-
138
135
  def get(self, key: str) -> int:
139
136
  """
140
137
  :param key: the key to get the counter value for
@@ -205,7 +202,7 @@ class MongoDBStorageBase(Storage, MovingWindowSupport, ABC):
205
202
  except: # noqa: E722
206
203
  return False
207
204
 
208
- def get_moving_window(self, key: str, limit: int, expiry: int) -> Tuple[int, int]:
205
+ def get_moving_window(self, key: str, limit: int, expiry: int) -> Tuple[float, int]:
209
206
  """
210
207
  returns the starting point and the number of entries in the moving
211
208
  window
@@ -243,9 +240,9 @@ class MongoDBStorageBase(Storage, MovingWindowSupport, ABC):
243
240
  )
244
241
 
245
242
  if result:
246
- return int(result[0]["min"]), result[0]["count"]
243
+ return result[0]["min"], result[0]["count"]
247
244
 
248
- return int(timestamp), 0
245
+ return timestamp, 0
249
246
 
250
247
  def acquire_entry(self, key: str, limit: int, expiry: int, amount: int = 1) -> bool:
251
248
  """
limits/storage/redis.py CHANGED
@@ -32,7 +32,7 @@ class RedisInteractor:
32
32
  def prefixed_key(self, key: str) -> str:
33
33
  return f"{self.PREFIX}:{key}"
34
34
 
35
- def get_moving_window(self, key: str, limit: int, expiry: int) -> Tuple[int, int]:
35
+ def get_moving_window(self, key: str, limit: int, expiry: int) -> Tuple[float, int]:
36
36
  """
37
37
  returns the starting point and the number of entries in the moving
38
38
  window
@@ -43,9 +43,10 @@ class RedisInteractor:
43
43
  """
44
44
  key = self.prefixed_key(key)
45
45
  timestamp = time.time()
46
- window = self.lua_moving_window([key], [int(timestamp - expiry), limit])
46
+ if window := self.lua_moving_window([key], [timestamp - expiry, limit]):
47
+ return float(window[0]), window[1]
47
48
 
48
- return window or (int(timestamp), 0)
49
+ return timestamp, 0
49
50
 
50
51
  def _incr(
51
52
  self,
@@ -109,14 +110,14 @@ class RedisInteractor:
109
110
 
110
111
  return bool(acquired)
111
112
 
112
- def _get_expiry(self, key: str, connection: RedisClient) -> int:
113
+ def _get_expiry(self, key: str, connection: RedisClient) -> float:
113
114
  """
114
115
  :param key: the key to get the expiry for
115
116
  :param connection: Redis connection
116
117
  """
117
118
 
118
119
  key = self.prefixed_key(key)
119
- return int(max(connection.ttl(key), 0) + time.time())
120
+ return max(connection.ttl(key), 0) + time.time()
120
121
 
121
122
  def _check(self, connection: RedisClient) -> bool:
122
123
  """
@@ -232,7 +233,7 @@ class RedisStorage(RedisInteractor, Storage, MovingWindowSupport):
232
233
 
233
234
  return super()._acquire_entry(key, limit, expiry, self.storage, amount)
234
235
 
235
- def get_expiry(self, key: str) -> int:
236
+ def get_expiry(self, key: str) -> float:
236
237
  """
237
238
  :param key: the key to get the expiry for
238
239
  """
@@ -101,7 +101,7 @@ class RedisSentinelStorage(RedisStorage):
101
101
  key, self.storage_slave if self.use_replicas else self.storage
102
102
  )
103
103
 
104
- def get_expiry(self, key: str) -> int:
104
+ def get_expiry(self, key: str) -> float:
105
105
  """
106
106
  :param key: the key to get the expiry for
107
107
  """
limits/util.py CHANGED
@@ -38,7 +38,7 @@ class WindowStats(NamedTuple):
38
38
  """
39
39
 
40
40
  #: Time as seconds since the Epoch when this window will be reset
41
- reset_time: int
41
+ reset_time: float
42
42
  #: Quantity remaining in this window
43
43
  remaining: int
44
44
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: limits
3
- Version: 3.14.1
3
+ Version: 4.0.0
4
4
  Summary: Rate limiting utilities
5
5
  Home-page: https://limits.readthedocs.org
6
6
  Author: Ali-Akber Saifee
@@ -172,6 +172,18 @@ Check specific limits without hitting them
172
172
  time.sleep(0.01)
173
173
  assert True == moving_window.hit(one_per_second, "test_namespace", "foo")
174
174
 
175
+ Query available capacity and reset time for a limit
176
+
177
+ .. code-block:: python
178
+
179
+ assert True == moving_window.hit(one_per_minute, "test_namespace", "foo")
180
+ window = moving_window.get_window_stats(one_per_minute, "test_namespace", "foo")
181
+ assert window.remaining == 0
182
+ assert False == moving_window.hit(one_per_minute, "test_namespace", "foo")
183
+ time.sleep(window.reset_time - time.time())
184
+ assert True == moving_window.hit(one_per_minute, "test_namespace", "foo")
185
+
186
+
175
187
  Links
176
188
  =====
177
189
 
@@ -0,0 +1,37 @@
1
+ limits/__init__.py,sha256=j_yVhgN9pdz8o5rQjVwdJTBSq8F-CTzof9kkiYgjRbw,728
2
+ limits/_version.py,sha256=bGcuGXkHFvjcc-8fCFZ7Jl28gop0tHquuV_Enu505jw,497
3
+ limits/errors.py,sha256=xCKGOVJiD-g8FlsQQb17AW2pTUvalYSuizPpvEVoYJE,626
4
+ limits/limits.py,sha256=ZsXESq2e1ji7c2ZKjSkIAasCjiLdjVLPUa9oah_I8U4,4943
5
+ limits/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ limits/strategies.py,sha256=Zy6PIhkysPbxnMzFjyXEsxMM6jhRoQ5XT5WskTNruK0,6949
7
+ limits/typing.py,sha256=4yitf6iwDK-QEfSxv3EbTdGLOrqowLFffHAqYRUqiYY,3275
8
+ limits/util.py,sha256=fTx0JQBT6ZY3fxGefjT07CLimUVCFjS1jLqskXmb7Eo,5726
9
+ limits/version.py,sha256=YwkF3dtq1KGzvmL3iVGctA8NNtGlK_0arrzZkZGVjUs,47
10
+ limits/aio/__init__.py,sha256=IOetunwQy1c5GefzitK8lewbTzHGiE-kmE9NlqSdr3U,82
11
+ limits/aio/strategies.py,sha256=SHjmJnmy7Nh4tBydkA-0qPaULYcLOAM91T4RPybq0Sg,6768
12
+ limits/aio/storage/__init__.py,sha256=CbtuSlVl1jPyN_vsEI_ApWblDblVaL46xcZ2M_oM0V8,595
13
+ limits/aio/storage/base.py,sha256=V1Ur9Cu29_vP5IYBIsWHTgrc4riW8FEyz5Dcvv6fPoc,4821
14
+ limits/aio/storage/etcd.py,sha256=krqjWujvybuaFa2g_FkPr2ZtX9Ac1-oJzErfGW3h27o,4783
15
+ limits/aio/storage/memcached.py,sha256=n8b9GVtXMWdc-w4-xP1_MPJ9dgVcgoJ5j53mTdU6E3E,4799
16
+ limits/aio/storage/memory.py,sha256=4ah9RpE5r7Q2yOLT-OndhP4ZHmvcwV3rKvCicnK2CJc,5845
17
+ limits/aio/storage/mongodb.py,sha256=pXS2JFqMPkfPLYhQatG2ImAeYas8CelTwiOGo-3eFpM,10701
18
+ limits/aio/storage/redis.py,sha256=JQm4pkwynSo1k6wFVB7SyRsh7yav0_61Px1FqUwuGl4,15658
19
+ limits/resources/redis/lua_scripts/acquire_moving_window.lua,sha256=5CFJX7D6T6RG5SFr6eVZ6zepmI1EkGWmKeVEO4QNrWo,483
20
+ limits/resources/redis/lua_scripts/clear_keys.lua,sha256=zU0cVfLGmapRQF9x9u0GclapM_IB2pJLszNzVQ1QRK4,184
21
+ limits/resources/redis/lua_scripts/incr_expire.lua,sha256=Uq9NcrrcDI-F87TDAJexoSJn2SDgeXIUEYozCp9S3oA,195
22
+ limits/resources/redis/lua_scripts/moving_window.lua,sha256=5hUZghISDh8Cbg8HJediM_OKjjNMF-0CBywWmsc93vA,430
23
+ limits/storage/__init__.py,sha256=XAW1jVDMLFkPr_Tl1SXpg_p4Y3nhEatTSYq1MlnYJcA,2564
24
+ limits/storage/base.py,sha256=E7ZInoGZqoM1QIpd1f8lvytlic4sMOQdl_eTzD-mlWk,4631
25
+ limits/storage/etcd.py,sha256=Q1tndCAAJp0jnir-b-ZBN3-7Kf3v_uwNAqQJLmqB96Q,4440
26
+ limits/storage/memcached.py,sha256=1maTeD7EbSWq0NgSZcukn-4QdVGcU7-sxZIpUDuh3kw,6637
27
+ limits/storage/memory.py,sha256=ButyS6v7o7DB55bwM3CltFK4Fc5mwKuFEBPgat51CXU,5550
28
+ limits/storage/mongodb.py,sha256=7z5I2kkPaGDKKkQqHD9vp1z1G6842SbtHFaHfVRQUF0,9830
29
+ limits/storage/redis.py,sha256=R7UbE5ng1NjIHEO17gu-vIZ4qgy91JctbPYGEkZ2iM0,8483
30
+ limits/storage/redis_cluster.py,sha256=MsiEpwHphQd0P88AwGw1NVSi3UwVrhsg-pvzkHxU2kw,3739
31
+ limits/storage/redis_sentinel.py,sha256=665CvL3UZYB2sB_vVkZ4CCaPKcbIXvQUWuDWnBoSOLU,4124
32
+ limits/storage/registry.py,sha256=xcBcxuu6srqmoS4WqDpkCXnRLB19ctH98v21P8S9kS8,708
33
+ limits-4.0.0.dist-info/LICENSE.txt,sha256=T6i7kq7F5gIPfcno9FCxU5Hcwm22Bjq0uHZV3ElcjsQ,1061
34
+ limits-4.0.0.dist-info/METADATA,sha256=KraoprBoY3V_JScEnVSxHI5KRbmc3rkwsMZiPhwfgeM,7662
35
+ limits-4.0.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
36
+ limits-4.0.0.dist-info/top_level.txt,sha256=C7g5ahldPoU2s6iWTaJayUrbGmPK1d6e9t5Nn0vQ2jM,7
37
+ limits-4.0.0.dist-info/RECORD,,
@@ -1,37 +0,0 @@
1
- limits/__init__.py,sha256=j_yVhgN9pdz8o5rQjVwdJTBSq8F-CTzof9kkiYgjRbw,728
2
- limits/_version.py,sha256=WbNixYn5JfqVMNZ6ag1B3zh5evGgXTIqinJPk2vcWH0,498
3
- limits/errors.py,sha256=xCKGOVJiD-g8FlsQQb17AW2pTUvalYSuizPpvEVoYJE,626
4
- limits/limits.py,sha256=ZsXESq2e1ji7c2ZKjSkIAasCjiLdjVLPUa9oah_I8U4,4943
5
- limits/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- limits/strategies.py,sha256=Zy6PIhkysPbxnMzFjyXEsxMM6jhRoQ5XT5WskTNruK0,6949
7
- limits/typing.py,sha256=4yitf6iwDK-QEfSxv3EbTdGLOrqowLFffHAqYRUqiYY,3275
8
- limits/util.py,sha256=fi2XoUBoEk0T-le41VQn3x-BJ3QqrLeIcP52Bj-qwpg,5724
9
- limits/version.py,sha256=YwkF3dtq1KGzvmL3iVGctA8NNtGlK_0arrzZkZGVjUs,47
10
- limits/aio/__init__.py,sha256=IOetunwQy1c5GefzitK8lewbTzHGiE-kmE9NlqSdr3U,82
11
- limits/aio/strategies.py,sha256=SHjmJnmy7Nh4tBydkA-0qPaULYcLOAM91T4RPybq0Sg,6768
12
- limits/aio/storage/__init__.py,sha256=CbtuSlVl1jPyN_vsEI_ApWblDblVaL46xcZ2M_oM0V8,595
13
- limits/aio/storage/base.py,sha256=xdYpBBonyMjxE9iT-2oZjm6x29aDU6Xd09MeBYbZcMo,4817
14
- limits/aio/storage/etcd.py,sha256=Rjb_EYKFRr4F2Z6zvAPP9vQOyXJQHaju3VjxxUs75_c,4791
15
- limits/aio/storage/memcached.py,sha256=6aTlACfCtchdcZqoisnei0MOlCH7yLV9A1yCjOE5f9g,4802
16
- limits/aio/storage/memory.py,sha256=DlmWluqUwBUWQIQ6XZi-mPrb15vfzBhA4iAKhBELDnE,5856
17
- limits/aio/storage/mongodb.py,sha256=gZq9Ky3J7j0xfqIqB3ULBbQ5VjHzIyT1c7aNFp01VKk,10764
18
- limits/aio/storage/redis.py,sha256=jkqtdIwTpfXTXwgTWTA1Jlc3Lpc-vnu4XRy6CIptiZA,15651
19
- limits/resources/redis/lua_scripts/acquire_moving_window.lua,sha256=5CFJX7D6T6RG5SFr6eVZ6zepmI1EkGWmKeVEO4QNrWo,483
20
- limits/resources/redis/lua_scripts/clear_keys.lua,sha256=zU0cVfLGmapRQF9x9u0GclapM_IB2pJLszNzVQ1QRK4,184
21
- limits/resources/redis/lua_scripts/incr_expire.lua,sha256=Uq9NcrrcDI-F87TDAJexoSJn2SDgeXIUEYozCp9S3oA,195
22
- limits/resources/redis/lua_scripts/moving_window.lua,sha256=iAInenlVd_fFDi15APpRWbOuPUz_G3nFnVAqb7wOedA,398
23
- limits/storage/__init__.py,sha256=XAW1jVDMLFkPr_Tl1SXpg_p4Y3nhEatTSYq1MlnYJcA,2564
24
- limits/storage/base.py,sha256=fDdYLa-RrnjhBTO1hE5aTTM8q8n3M5HD-65KyWWXBtg,4627
25
- limits/storage/etcd.py,sha256=wkC_mj4Tsf2nwUKByMiHiGzA40N3mDepEwdLmvH8wmw,4484
26
- limits/storage/memcached.py,sha256=bMzfZgYa_EWcZAjSZLcygpk3hpeOAErBpRE8dVwyXQs,6640
27
- limits/storage/memory.py,sha256=R16E-Ccnmn1-LlolkFf-kB1-QHh8eiwFFLYVv0PuFD0,5561
28
- limits/storage/mongodb.py,sha256=t8ey5-gYrJcmyvwJkqje0-TR-UMYvBF900a_zEXAYPI,9873
29
- limits/storage/redis.py,sha256=3zJ1gDMDepT_pGN9d2aAN7Pea7tMBI49VK60IHv-Ooc,8452
30
- limits/storage/redis_cluster.py,sha256=MsiEpwHphQd0P88AwGw1NVSi3UwVrhsg-pvzkHxU2kw,3739
31
- limits/storage/redis_sentinel.py,sha256=lI7y7x9VGDCGq_-WRb6jR6cDgnzsOC1KGaRbwE69DNk,4122
32
- limits/storage/registry.py,sha256=xcBcxuu6srqmoS4WqDpkCXnRLB19ctH98v21P8S9kS8,708
33
- limits-3.14.1.dist-info/LICENSE.txt,sha256=T6i7kq7F5gIPfcno9FCxU5Hcwm22Bjq0uHZV3ElcjsQ,1061
34
- limits-3.14.1.dist-info/METADATA,sha256=iaF5tB4JgLvdzKk1-BNDZ1jkNo_3j-QidH4Ar7h218o,7189
35
- limits-3.14.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
36
- limits-3.14.1.dist-info/top_level.txt,sha256=C7g5ahldPoU2s6iWTaJayUrbGmPK1d6e9t5Nn0vQ2jM,7
37
- limits-3.14.1.dist-info/RECORD,,