limits 3.3.1__tar.gz → 3.5.0__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.
Files changed (83) hide show
  1. {limits-3.3.1 → limits-3.5.0}/HISTORY.rst +26 -0
  2. {limits-3.3.1 → limits-3.5.0}/PKG-INFO +1 -1
  3. {limits-3.3.1 → limits-3.5.0}/limits/_version.py +3 -3
  4. {limits-3.3.1 → limits-3.5.0}/limits/aio/storage/redis.py +0 -7
  5. {limits-3.3.1 → limits-3.5.0}/limits/aio/strategies.py +1 -2
  6. {limits-3.3.1 → limits-3.5.0}/limits/resources/redis/lua_scripts/acquire_moving_window.lua +4 -5
  7. {limits-3.3.1 → limits-3.5.0}/limits/storage/memory.py +1 -1
  8. {limits-3.3.1 → limits-3.5.0}/limits/storage/redis_sentinel.py +1 -6
  9. {limits-3.3.1 → limits-3.5.0}/limits/strategies.py +1 -2
  10. {limits-3.3.1 → limits-3.5.0}/limits.egg-info/PKG-INFO +1 -1
  11. {limits-3.3.1 → limits-3.5.0}/limits.egg-info/SOURCES.txt +0 -1
  12. {limits-3.3.1 → limits-3.5.0}/requirements/docs.txt +4 -4
  13. {limits-3.3.1 → limits-3.5.0}/tests/test_strategy.py +10 -0
  14. limits-3.3.1/limits/resources/redis/lua_scripts/gcra_consume.lua +0 -50
  15. {limits-3.3.1 → limits-3.5.0}/CLASSIFIERS +0 -0
  16. {limits-3.3.1 → limits-3.5.0}/CONTRIBUTIONS.rst +0 -0
  17. {limits-3.3.1 → limits-3.5.0}/LICENSE.txt +0 -0
  18. {limits-3.3.1 → limits-3.5.0}/MANIFEST.in +0 -0
  19. {limits-3.3.1 → limits-3.5.0}/README.rst +0 -0
  20. {limits-3.3.1 → limits-3.5.0}/doc/Makefile +0 -0
  21. {limits-3.3.1 → limits-3.5.0}/doc/source/_static/custom.css +0 -0
  22. {limits-3.3.1 → limits-3.5.0}/doc/source/api.rst +0 -0
  23. {limits-3.3.1 → limits-3.5.0}/doc/source/async.rst +0 -0
  24. {limits-3.3.1 → limits-3.5.0}/doc/source/changelog.rst +0 -0
  25. {limits-3.3.1 → limits-3.5.0}/doc/source/conf.py +0 -0
  26. {limits-3.3.1 → limits-3.5.0}/doc/source/custom-storage.rst +0 -0
  27. {limits-3.3.1 → limits-3.5.0}/doc/source/index.rst +0 -0
  28. {limits-3.3.1 → limits-3.5.0}/doc/source/installation.rst +0 -0
  29. {limits-3.3.1 → limits-3.5.0}/doc/source/quickstart.rst +0 -0
  30. {limits-3.3.1 → limits-3.5.0}/doc/source/storage.rst +0 -0
  31. {limits-3.3.1 → limits-3.5.0}/doc/source/strategies.rst +0 -0
  32. {limits-3.3.1 → limits-3.5.0}/doc/source/theme_config.py +0 -0
  33. {limits-3.3.1 → limits-3.5.0}/limits/__init__.py +0 -0
  34. {limits-3.3.1 → limits-3.5.0}/limits/aio/__init__.py +0 -0
  35. {limits-3.3.1 → limits-3.5.0}/limits/aio/storage/__init__.py +0 -0
  36. {limits-3.3.1 → limits-3.5.0}/limits/aio/storage/base.py +0 -0
  37. {limits-3.3.1 → limits-3.5.0}/limits/aio/storage/etcd.py +0 -0
  38. {limits-3.3.1 → limits-3.5.0}/limits/aio/storage/memcached.py +0 -0
  39. {limits-3.3.1 → limits-3.5.0}/limits/aio/storage/memory.py +0 -0
  40. {limits-3.3.1 → limits-3.5.0}/limits/aio/storage/mongodb.py +0 -0
  41. {limits-3.3.1 → limits-3.5.0}/limits/errors.py +0 -0
  42. {limits-3.3.1 → limits-3.5.0}/limits/limits.py +0 -0
  43. {limits-3.3.1 → limits-3.5.0}/limits/py.typed +0 -0
  44. {limits-3.3.1 → limits-3.5.0}/limits/resources/redis/lua_scripts/clear_keys.lua +0 -0
  45. {limits-3.3.1 → limits-3.5.0}/limits/resources/redis/lua_scripts/incr_expire.lua +0 -0
  46. {limits-3.3.1 → limits-3.5.0}/limits/resources/redis/lua_scripts/moving_window.lua +0 -0
  47. {limits-3.3.1 → limits-3.5.0}/limits/storage/__init__.py +0 -0
  48. {limits-3.3.1 → limits-3.5.0}/limits/storage/base.py +0 -0
  49. {limits-3.3.1 → limits-3.5.0}/limits/storage/etcd.py +0 -0
  50. {limits-3.3.1 → limits-3.5.0}/limits/storage/memcached.py +0 -0
  51. {limits-3.3.1 → limits-3.5.0}/limits/storage/mongodb.py +0 -0
  52. {limits-3.3.1 → limits-3.5.0}/limits/storage/redis.py +0 -0
  53. {limits-3.3.1 → limits-3.5.0}/limits/storage/redis_cluster.py +0 -0
  54. {limits-3.3.1 → limits-3.5.0}/limits/storage/registry.py +0 -0
  55. {limits-3.3.1 → limits-3.5.0}/limits/typing.py +0 -0
  56. {limits-3.3.1 → limits-3.5.0}/limits/util.py +0 -0
  57. {limits-3.3.1 → limits-3.5.0}/limits/version.py +0 -0
  58. {limits-3.3.1 → limits-3.5.0}/limits.egg-info/dependency_links.txt +0 -0
  59. {limits-3.3.1 → limits-3.5.0}/limits.egg-info/not-zip-safe +0 -0
  60. {limits-3.3.1 → limits-3.5.0}/limits.egg-info/requires.txt +0 -0
  61. {limits-3.3.1 → limits-3.5.0}/limits.egg-info/top_level.txt +0 -0
  62. {limits-3.3.1 → limits-3.5.0}/pyproject.toml +0 -0
  63. {limits-3.3.1 → limits-3.5.0}/requirements/ci.txt +0 -0
  64. {limits-3.3.1 → limits-3.5.0}/requirements/dev.txt +0 -0
  65. {limits-3.3.1 → limits-3.5.0}/requirements/main.txt +0 -0
  66. {limits-3.3.1 → limits-3.5.0}/requirements/storage/async-etcd.txt +0 -0
  67. {limits-3.3.1 → limits-3.5.0}/requirements/storage/async-memcached.txt +0 -0
  68. {limits-3.3.1 → limits-3.5.0}/requirements/storage/async-mongodb.txt +0 -0
  69. {limits-3.3.1 → limits-3.5.0}/requirements/storage/async-redis.txt +0 -0
  70. {limits-3.3.1 → limits-3.5.0}/requirements/storage/etcd.txt +0 -0
  71. {limits-3.3.1 → limits-3.5.0}/requirements/storage/memcached.txt +0 -0
  72. {limits-3.3.1 → limits-3.5.0}/requirements/storage/mongodb.txt +0 -0
  73. {limits-3.3.1 → limits-3.5.0}/requirements/storage/redis.txt +0 -0
  74. {limits-3.3.1 → limits-3.5.0}/requirements/storage/rediscluster.txt +0 -0
  75. {limits-3.3.1 → limits-3.5.0}/requirements/test.txt +0 -0
  76. {limits-3.3.1 → limits-3.5.0}/setup.cfg +0 -0
  77. {limits-3.3.1 → limits-3.5.0}/setup.py +0 -0
  78. {limits-3.3.1 → limits-3.5.0}/tests/test_limit_granularities.py +0 -0
  79. {limits-3.3.1 → limits-3.5.0}/tests/test_limits.py +0 -0
  80. {limits-3.3.1 → limits-3.5.0}/tests/test_ratelimit_parser.py +0 -0
  81. {limits-3.3.1 → limits-3.5.0}/tests/test_storage.py +0 -0
  82. {limits-3.3.1 → limits-3.5.0}/tests/test_utils.py +0 -0
  83. {limits-3.3.1 → limits-3.5.0}/versioneer.py +0 -0
@@ -3,6 +3,30 @@
3
3
  Changelog
4
4
  =========
5
5
 
6
+ v3.5.0
7
+ ------
8
+ Release Date: 2023-05-16
9
+
10
+ * Bug Fix
11
+
12
+ * Handle ``cost`` > 8000 when using redis
13
+ * Remove arbitrary default timeout for redis+sentinel
14
+
15
+ v3.4.0
16
+ ------
17
+ Release Date: 2023-04-17
18
+
19
+ * Bug Fix
20
+
21
+ * Remove use of weakreferences to storages in strategy
22
+ classes as this was not documented or required and
23
+ led to usability issues.
24
+
25
+ * Chores
26
+
27
+ * Update documentation dependencies
28
+ * Remove unused gcra lua script
29
+
6
30
  v3.3.1
7
31
  ------
8
32
  Release Date: 2023-03-22
@@ -582,6 +606,8 @@ Release Date: 2015-01-08
582
606
 
583
607
 
584
608
 
609
+
610
+
585
611
 
586
612
 
587
613
 
@@ -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
@@ -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
@@ -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
 
@@ -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)
@@ -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
@@ -47,7 +47,6 @@ limits/aio/storage/mongodb.py
47
47
  limits/aio/storage/redis.py
48
48
  limits/resources/redis/lua_scripts/acquire_moving_window.lua
49
49
  limits/resources/redis/lua_scripts/clear_keys.lua
50
- limits/resources/redis/lua_scripts/gcra_consume.lua
51
50
  limits/resources/redis/lua_scripts/incr_expire.lua
52
51
  limits/resources/redis/lua_scripts/moving_window.lua
53
52
  limits/storage/__init__.py
@@ -1,10 +1,10 @@
1
1
  -r main.txt
2
- furo==2022.12.7
2
+ furo==2023.3.27
3
3
  Sphinx>=5
4
- sphinx-copybutton==0.5.1
4
+ sphinx-copybutton==0.5.2
5
5
  sphinx-autobuild==2021.3.14
6
- sphinxext-opengraph==0.8.1
7
- sphinx-inline-tabs==2022.1.2b11
6
+ sphinxext-opengraph==0.8.2
7
+ sphinx-inline-tabs==2023.4.21
8
8
  sphinx-paramlinks==0.5.4
9
9
  sphinxcontrib-programoutput==0.17
10
10
 
@@ -134,6 +134,16 @@ class TestWindow:
134
134
  limiter.clear(five_per_min)
135
135
  assert limiter.hit(five_per_min)
136
136
 
137
+ @moving_window_storage
138
+ def test_moving_window_huge_cost_sync(self, uri, args, fixture):
139
+ storage = storage_from_string(uri, **args)
140
+ limiter = MovingWindowRateLimiter(storage)
141
+ many_per_min = RateLimitItemPerMinute(1_000_000)
142
+ limiter.hit(many_per_min, cost=1_000_000)
143
+ assert not limiter.hit(many_per_min, cost=2)
144
+ limiter.clear(many_per_min)
145
+ assert limiter.hit(many_per_min)
146
+
137
147
  @pytest.mark.memcached
138
148
  def test_moving_window_memcached(self, memcached):
139
149
  storage = MemcachedStorage("memcached://localhost:22122")
@@ -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
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