pycurb 0.2.2__tar.gz → 0.2.3__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.
- {pycurb-0.2.2 → pycurb-0.2.3}/PKG-INFO +1 -1
- {pycurb-0.2.2 → pycurb-0.2.3}/pyproject.toml +1 -1
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/storage/memory.py +8 -2
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/storage/memory_async.py +8 -2
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/storage/redis.py +7 -2
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/storage/redis_async.py +7 -2
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb.egg-info/PKG-INFO +1 -1
- {pycurb-0.2.2 → pycurb-0.2.3}/LICENSE +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/README.md +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/setup.cfg +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/__init__.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/django/__init__.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/django/decorators.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/django/extractors.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/django/middleware.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/fastapi/__init__.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/fastapi/dependencies.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/fastapi/extractors.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/fastapi/middleware.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/flask/__init__.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/flask/decorators.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/flask/extractors.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/adapters/flask/middleware.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/__init__.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/__init__.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/base.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/base_async.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/fixed_window.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/fixed_window_async.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/gcra.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/gcra_async.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/leaky_bucket.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/leaky_bucket_async.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/sliding_window.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/sliding_window_async.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/token_bucket.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/algorithms/token_bucket_async.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/decorators.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/limiter.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/limiter_async.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/models.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/resolver.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/storage/__init__.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/storage/base.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/core/storage/base_async.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/py.typed +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb/utils.py +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb.egg-info/SOURCES.txt +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb.egg-info/dependency_links.txt +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb.egg-info/requires.txt +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/src/pycurb.egg-info/top_level.txt +0 -0
- {pycurb-0.2.2 → pycurb-0.2.3}/tests/test_utils.py +0 -0
|
@@ -79,7 +79,9 @@ class MemoryStorage(Storage):
|
|
|
79
79
|
with lock:
|
|
80
80
|
tokens, last_refill_time = self._token.get(key, (float(capacity), now))
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
# Clamp elapsed at zero: a clock regression must not silently
|
|
83
|
+
# refill tokens (negative elapsed would drain them).
|
|
84
|
+
time_elapsed = max(now - last_refill_time, 0.0)
|
|
83
85
|
tokens_during_elapsed = time_elapsed * refill_rate
|
|
84
86
|
|
|
85
87
|
new_tokens = min(tokens + tokens_during_elapsed, float(capacity))
|
|
@@ -102,7 +104,11 @@ class MemoryStorage(Storage):
|
|
|
102
104
|
with lock:
|
|
103
105
|
queue_size, last_leak_time = self._leaky.get(key, (0, now))
|
|
104
106
|
|
|
105
|
-
|
|
107
|
+
# Clamp elapsed at zero: with negative elapsed, floor() of a
|
|
108
|
+
# negative number yields -1 and the queue would silently grow
|
|
109
|
+
# (queue - (-1)) on every clock regression.
|
|
110
|
+
elapsed = max(now - last_leak_time, 0.0)
|
|
111
|
+
leaked = math.floor(elapsed * leak_rate)
|
|
106
112
|
new_queue = max(queue_size - leaked, 0)
|
|
107
113
|
|
|
108
114
|
# Preserve fractional leak tracking history
|
|
@@ -79,7 +79,9 @@ class AsyncMemoryStorage(AsyncStorage):
|
|
|
79
79
|
async with lock:
|
|
80
80
|
tokens, last_refill_time = self._token.get(key, (float(capacity), now))
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
# Clamp elapsed at zero: a clock regression must not silently
|
|
83
|
+
# refill tokens (negative elapsed would drain them).
|
|
84
|
+
time_elapsed = max(now - last_refill_time, 0.0)
|
|
83
85
|
tokens_during_elapsed = time_elapsed * refill_rate
|
|
84
86
|
|
|
85
87
|
new_tokens = min(tokens + tokens_during_elapsed, float(capacity))
|
|
@@ -102,7 +104,11 @@ class AsyncMemoryStorage(AsyncStorage):
|
|
|
102
104
|
async with lock:
|
|
103
105
|
queue_size, last_leak_time = self._leaky.get(key, (0, now))
|
|
104
106
|
|
|
105
|
-
|
|
107
|
+
# Clamp elapsed at zero: with negative elapsed, floor() of a
|
|
108
|
+
# negative number yields -1 and the queue would silently grow
|
|
109
|
+
# (queue - (-1)) on every clock regression.
|
|
110
|
+
elapsed = max(now - last_leak_time, 0.0)
|
|
111
|
+
leaked = math.floor(elapsed * leak_rate)
|
|
106
112
|
new_queue = max(queue_size - leaked, 0)
|
|
107
113
|
|
|
108
114
|
# Preserve fractional leak tracking history
|
|
@@ -184,7 +184,9 @@ class RedisStorage(Storage):
|
|
|
184
184
|
last_refill = now
|
|
185
185
|
end
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
-- Clamp elapsed at zero: a clock regression or out-of-order
|
|
188
|
+
-- timestamp must not silently refill tokens.
|
|
189
|
+
local elapsed = math.max(now - last_refill, 0)
|
|
188
190
|
local tokens_during_elapsed = elapsed * rate
|
|
189
191
|
local new_tokens = math.min(capacity, tokens + tokens_during_elapsed)
|
|
190
192
|
|
|
@@ -249,7 +251,10 @@ class RedisStorage(Storage):
|
|
|
249
251
|
last_leak = now
|
|
250
252
|
end
|
|
251
253
|
|
|
252
|
-
|
|
254
|
+
-- Clamp elapsed at zero: with negative elapsed, floor() of a
|
|
255
|
+
-- negative number yields -1 and the queue would silently grow
|
|
256
|
+
-- (queue - (-1)) on every clock regression.
|
|
257
|
+
local elapsed = math.max(now - last_leak, 0)
|
|
253
258
|
local leaked = math.floor(elapsed * rate)
|
|
254
259
|
local new_queue = math.max(queue_size - leaked, 0)
|
|
255
260
|
|
|
@@ -188,7 +188,9 @@ class AsyncRedisStorage(AsyncStorage):
|
|
|
188
188
|
last_refill = now
|
|
189
189
|
end
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
-- Clamp elapsed at zero: a clock regression or out-of-order
|
|
192
|
+
-- timestamp must not silently refill tokens.
|
|
193
|
+
local elapsed = math.max(now - last_refill, 0)
|
|
192
194
|
local tokens_during_elapsed = elapsed * rate
|
|
193
195
|
local new_tokens = math.min(capacity, tokens + tokens_during_elapsed)
|
|
194
196
|
|
|
@@ -257,7 +259,10 @@ class AsyncRedisStorage(AsyncStorage):
|
|
|
257
259
|
last_leak = now
|
|
258
260
|
end
|
|
259
261
|
|
|
260
|
-
|
|
262
|
+
-- Clamp elapsed at zero: with negative elapsed, floor() of a
|
|
263
|
+
-- negative number yields -1 and the queue would silently grow
|
|
264
|
+
-- (queue - (-1)) on every clock regression.
|
|
265
|
+
local elapsed = math.max(now - last_leak, 0)
|
|
261
266
|
local leaked = math.floor(elapsed * rate)
|
|
262
267
|
local new_queue = math.max(queue_size - leaked, 0)
|
|
263
268
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|