limits 5.3.0__tar.gz → 5.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 (98) hide show
  1. {limits-5.3.0 → limits-5.5.0}/HISTORY.rst +28 -0
  2. {limits-5.3.0 → limits-5.5.0}/PKG-INFO +6 -6
  3. {limits-5.3.0 → limits-5.5.0}/limits/_version.py +3 -3
  4. {limits-5.3.0 → limits-5.5.0}/limits/aio/strategies.py +16 -0
  5. {limits-5.3.0 → limits-5.5.0}/limits/limits.py +4 -1
  6. {limits-5.3.0 → limits-5.5.0}/limits/strategies.py +16 -1
  7. {limits-5.3.0 → limits-5.5.0}/limits/util.py +4 -2
  8. {limits-5.3.0 → limits-5.5.0}/limits.egg-info/PKG-INFO +6 -6
  9. {limits-5.3.0 → limits-5.5.0}/limits.egg-info/requires.txt +5 -5
  10. {limits-5.3.0 → limits-5.5.0}/requirements/docs.txt +2 -2
  11. {limits-5.3.0 → limits-5.5.0}/requirements/main.txt +1 -1
  12. limits-5.5.0/requirements/storage/async-redis.txt +1 -0
  13. limits-5.5.0/requirements/storage/redis.txt +1 -0
  14. {limits-5.3.0 → limits-5.5.0}/tests/test_limits.py +14 -1
  15. limits-5.3.0/requirements/storage/async-redis.txt +0 -1
  16. limits-5.3.0/requirements/storage/redis.txt +0 -1
  17. {limits-5.3.0 → limits-5.5.0}/CLASSIFIERS +0 -0
  18. {limits-5.3.0 → limits-5.5.0}/CONTRIBUTIONS.rst +0 -0
  19. {limits-5.3.0 → limits-5.5.0}/LICENSE.txt +0 -0
  20. {limits-5.3.0 → limits-5.5.0}/MANIFEST.in +0 -0
  21. {limits-5.3.0 → limits-5.5.0}/README.rst +0 -0
  22. {limits-5.3.0 → limits-5.5.0}/doc/Makefile +0 -0
  23. {limits-5.3.0 → limits-5.5.0}/doc/source/_static/custom.css +0 -0
  24. {limits-5.3.0 → limits-5.5.0}/doc/source/api.rst +0 -0
  25. {limits-5.3.0 → limits-5.5.0}/doc/source/async.rst +0 -0
  26. {limits-5.3.0 → limits-5.5.0}/doc/source/changelog.rst +0 -0
  27. {limits-5.3.0 → limits-5.5.0}/doc/source/conf.py +0 -0
  28. {limits-5.3.0 → limits-5.5.0}/doc/source/custom-storage.rst +0 -0
  29. {limits-5.3.0 → limits-5.5.0}/doc/source/ext/_static/benchmark-chart.css +0 -0
  30. {limits-5.3.0 → limits-5.5.0}/doc/source/ext/_static/js/benchmark-chart.js +0 -0
  31. {limits-5.3.0 → limits-5.5.0}/doc/source/ext/_static/js/benchmark-details.js +0 -0
  32. {limits-5.3.0 → limits-5.5.0}/doc/source/ext/_static/js/benchmark-loader.js +0 -0
  33. {limits-5.3.0 → limits-5.5.0}/doc/source/ext/_templates/git_info.js +0 -0
  34. {limits-5.3.0 → limits-5.5.0}/doc/source/ext/bench_chart.py +0 -0
  35. {limits-5.3.0 → limits-5.5.0}/doc/source/index.rst +0 -0
  36. {limits-5.3.0 → limits-5.5.0}/doc/source/installation.rst +0 -0
  37. {limits-5.3.0 → limits-5.5.0}/doc/source/performance.rst +0 -0
  38. {limits-5.3.0 → limits-5.5.0}/doc/source/quickstart.rst +0 -0
  39. {limits-5.3.0 → limits-5.5.0}/doc/source/storage.rst +0 -0
  40. {limits-5.3.0 → limits-5.5.0}/doc/source/strategies.rst +0 -0
  41. {limits-5.3.0 → limits-5.5.0}/doc/source/theme_config.py +0 -0
  42. {limits-5.3.0 → limits-5.5.0}/limits/__init__.py +0 -0
  43. {limits-5.3.0 → limits-5.5.0}/limits/aio/__init__.py +0 -0
  44. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/__init__.py +0 -0
  45. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/base.py +0 -0
  46. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/memcached/__init__.py +0 -0
  47. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/memcached/bridge.py +0 -0
  48. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/memcached/emcache.py +0 -0
  49. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/memcached/memcachio.py +0 -0
  50. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/memory.py +0 -0
  51. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/mongodb.py +0 -0
  52. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/redis/__init__.py +0 -0
  53. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/redis/bridge.py +0 -0
  54. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/redis/coredis.py +0 -0
  55. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/redis/redispy.py +0 -0
  56. {limits-5.3.0 → limits-5.5.0}/limits/aio/storage/redis/valkey.py +0 -0
  57. {limits-5.3.0 → limits-5.5.0}/limits/errors.py +0 -0
  58. {limits-5.3.0 → limits-5.5.0}/limits/py.typed +0 -0
  59. {limits-5.3.0 → limits-5.5.0}/limits/resources/redis/lua_scripts/acquire_moving_window.lua +0 -0
  60. {limits-5.3.0 → limits-5.5.0}/limits/resources/redis/lua_scripts/acquire_sliding_window.lua +0 -0
  61. {limits-5.3.0 → limits-5.5.0}/limits/resources/redis/lua_scripts/clear_keys.lua +0 -0
  62. {limits-5.3.0 → limits-5.5.0}/limits/resources/redis/lua_scripts/incr_expire.lua +0 -0
  63. {limits-5.3.0 → limits-5.5.0}/limits/resources/redis/lua_scripts/moving_window.lua +0 -0
  64. {limits-5.3.0 → limits-5.5.0}/limits/resources/redis/lua_scripts/sliding_window.lua +0 -0
  65. {limits-5.3.0 → limits-5.5.0}/limits/storage/__init__.py +0 -0
  66. {limits-5.3.0 → limits-5.5.0}/limits/storage/base.py +0 -0
  67. {limits-5.3.0 → limits-5.5.0}/limits/storage/memcached.py +0 -0
  68. {limits-5.3.0 → limits-5.5.0}/limits/storage/memory.py +0 -0
  69. {limits-5.3.0 → limits-5.5.0}/limits/storage/mongodb.py +0 -0
  70. {limits-5.3.0 → limits-5.5.0}/limits/storage/redis.py +0 -0
  71. {limits-5.3.0 → limits-5.5.0}/limits/storage/redis_cluster.py +0 -0
  72. {limits-5.3.0 → limits-5.5.0}/limits/storage/redis_sentinel.py +0 -0
  73. {limits-5.3.0 → limits-5.5.0}/limits/storage/registry.py +0 -0
  74. {limits-5.3.0 → limits-5.5.0}/limits/typing.py +0 -0
  75. {limits-5.3.0 → limits-5.5.0}/limits/version.py +0 -0
  76. {limits-5.3.0 → limits-5.5.0}/limits.egg-info/SOURCES.txt +0 -0
  77. {limits-5.3.0 → limits-5.5.0}/limits.egg-info/dependency_links.txt +0 -0
  78. {limits-5.3.0 → limits-5.5.0}/limits.egg-info/not-zip-safe +0 -0
  79. {limits-5.3.0 → limits-5.5.0}/limits.egg-info/top_level.txt +0 -0
  80. {limits-5.3.0 → limits-5.5.0}/pyproject.toml +0 -0
  81. {limits-5.3.0 → limits-5.5.0}/requirements/ci.txt +0 -0
  82. {limits-5.3.0 → limits-5.5.0}/requirements/dev.txt +0 -0
  83. {limits-5.3.0 → limits-5.5.0}/requirements/storage/async-memcached.txt +0 -0
  84. {limits-5.3.0 → limits-5.5.0}/requirements/storage/async-mongodb.txt +0 -0
  85. {limits-5.3.0 → limits-5.5.0}/requirements/storage/async-valkey.txt +0 -0
  86. {limits-5.3.0 → limits-5.5.0}/requirements/storage/memcached.txt +0 -0
  87. {limits-5.3.0 → limits-5.5.0}/requirements/storage/mongodb.txt +0 -0
  88. {limits-5.3.0 → limits-5.5.0}/requirements/storage/rediscluster.txt +0 -0
  89. {limits-5.3.0 → limits-5.5.0}/requirements/storage/valkey.txt +0 -0
  90. {limits-5.3.0 → limits-5.5.0}/requirements/test.txt +0 -0
  91. {limits-5.3.0 → limits-5.5.0}/setup.cfg +0 -0
  92. {limits-5.3.0 → limits-5.5.0}/setup.py +0 -0
  93. {limits-5.3.0 → limits-5.5.0}/tests/test_limit_granularities.py +0 -0
  94. {limits-5.3.0 → limits-5.5.0}/tests/test_ratelimit_parser.py +0 -0
  95. {limits-5.3.0 → limits-5.5.0}/tests/test_storage.py +0 -0
  96. {limits-5.3.0 → limits-5.5.0}/tests/test_strategy.py +0 -0
  97. {limits-5.3.0 → limits-5.5.0}/tests/test_utils.py +0 -0
  98. {limits-5.3.0 → limits-5.5.0}/versioneer.py +0 -0
@@ -3,6 +3,32 @@
3
3
  Changelog
4
4
  =========
5
5
 
6
+ v5.5.0
7
+ ------
8
+ Release Date: 2025-08-05
9
+
10
+ * Compatibility
11
+
12
+ * Relax upper bound of ``packaging`` requirement
13
+ * Increase upper bound of ``coredis`` requirement
14
+ * Increase upper bound of ``redis`` requirement
15
+
16
+ v5.4.0
17
+ ------
18
+ Release Date: 2025-06-16
19
+
20
+ * Feature
21
+
22
+ * Relax regular expression used in ``limits.parse`` and
23
+ ``limits.parse_many`` to capture any granularity instead of
24
+ just the hardcoded ones so that custom rate limits can
25
+ also be extracted using the utility functions.
26
+ `Issue 279 <https://github.com/alisaifee/limits/issues/279>`_
27
+
28
+ * Compatibility
29
+
30
+ * Add redis 8.0 to CI
31
+
6
32
  v5.3.0
7
33
  ------
8
34
  Release Date: 2025-06-13
@@ -860,3 +886,5 @@ Release Date: 2015-01-08
860
886
 
861
887
 
862
888
 
889
+
890
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: limits
3
- Version: 5.3.0
3
+ Version: 5.5.0
4
4
  Summary: Rate limiting utilities
5
5
  Home-page: https://limits.readthedocs.org
6
6
  Author: Ali-Akber Saifee
@@ -22,10 +22,10 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
22
22
  Requires-Python: >=3.10
23
23
  License-File: LICENSE.txt
24
24
  Requires-Dist: deprecated>=1.2
25
- Requires-Dist: packaging<26,>=21
25
+ Requires-Dist: packaging>=21
26
26
  Requires-Dist: typing_extensions
27
27
  Provides-Extra: redis
28
- Requires-Dist: redis!=4.5.2,!=4.5.3,<6.0.0,>3; extra == "redis"
28
+ Requires-Dist: redis!=4.5.2,!=4.5.3,<7.0.0,>3; extra == "redis"
29
29
  Provides-Extra: rediscluster
30
30
  Requires-Dist: redis!=4.5.2,!=4.5.3,>=4.2.0; extra == "rediscluster"
31
31
  Provides-Extra: memcached
@@ -35,7 +35,7 @@ Requires-Dist: pymongo<5,>4.1; extra == "mongodb"
35
35
  Provides-Extra: valkey
36
36
  Requires-Dist: valkey>=6; extra == "valkey"
37
37
  Provides-Extra: async-redis
38
- Requires-Dist: coredis<5,>=3.4.0; extra == "async-redis"
38
+ Requires-Dist: coredis<6,>=3.4.0; extra == "async-redis"
39
39
  Provides-Extra: async-memcached
40
40
  Requires-Dist: memcachio>=0.3; extra == "async-memcached"
41
41
  Provides-Extra: async-mongodb
@@ -43,12 +43,12 @@ Requires-Dist: motor<4,>=3; extra == "async-mongodb"
43
43
  Provides-Extra: async-valkey
44
44
  Requires-Dist: valkey>=6; extra == "async-valkey"
45
45
  Provides-Extra: all
46
- Requires-Dist: redis!=4.5.2,!=4.5.3,<6.0.0,>3; extra == "all"
46
+ Requires-Dist: redis!=4.5.2,!=4.5.3,<7.0.0,>3; extra == "all"
47
47
  Requires-Dist: redis!=4.5.2,!=4.5.3,>=4.2.0; extra == "all"
48
48
  Requires-Dist: pymemcache<5.0.0,>3; extra == "all"
49
49
  Requires-Dist: pymongo<5,>4.1; extra == "all"
50
50
  Requires-Dist: valkey>=6; extra == "all"
51
- Requires-Dist: coredis<5,>=3.4.0; extra == "all"
51
+ Requires-Dist: coredis<6,>=3.4.0; extra == "all"
52
52
  Requires-Dist: memcachio>=0.3; extra == "all"
53
53
  Requires-Dist: motor<4,>=3; extra == "all"
54
54
  Requires-Dist: valkey>=6; extra == "all"
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2025-06-13T16:23:24-0700",
11
+ "date": "2025-08-05T10:27:25-0700",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "311fe101b2d63c03e8c6a8f0ab363dd49f3e733b",
15
- "version": "5.3.0"
14
+ "full-revisionid": "a5d3f81d1ead51586a42b8c843884603cb19bb7f",
15
+ "version": "5.5.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -32,6 +32,8 @@ class RateLimiter(ABC):
32
32
  :param identifiers: variable list of strings to uniquely identify the
33
33
  limit
34
34
  :param cost: The cost of this hit, default 1
35
+
36
+ :return: True if ``cost`` could be deducted from the rate limit without exceeding it
35
37
  """
36
38
  raise NotImplementedError
37
39
 
@@ -44,6 +46,8 @@ class RateLimiter(ABC):
44
46
  :param identifiers: variable list of strings to uniquely identify the
45
47
  limit
46
48
  :param cost: The expected cost to be consumed, default 1
49
+
50
+ :return: True if the rate limit is not depleted
47
51
  """
48
52
  raise NotImplementedError
49
53
 
@@ -88,6 +92,8 @@ class MovingWindowRateLimiter(RateLimiter):
88
92
  :param identifiers: variable list of strings to uniquely identify the
89
93
  limit
90
94
  :param cost: The cost of this hit, default 1
95
+
96
+ :return: True if ``cost`` could be deducted from the rate limit without exceeding it
91
97
  """
92
98
 
93
99
  return await cast(MovingWindowSupport, self.storage).acquire_entry(
@@ -102,6 +108,8 @@ class MovingWindowRateLimiter(RateLimiter):
102
108
  :param identifiers: variable list of strings to uniquely identify the
103
109
  limit
104
110
  :param cost: The expected cost to be consumed, default 1
111
+
112
+ :return: True if the rate limit is not depleted
105
113
  """
106
114
  res = await cast(MovingWindowSupport, self.storage).get_moving_window(
107
115
  item.key_for(*identifiers),
@@ -144,6 +152,8 @@ class FixedWindowRateLimiter(RateLimiter):
144
152
  :param identifiers: variable list of strings to uniquely identify the
145
153
  limit
146
154
  :param cost: The cost of this hit, default 1
155
+
156
+ :return: True if ``cost`` could be deducted from the rate limit without exceeding it
147
157
  """
148
158
 
149
159
  return (
@@ -163,6 +173,8 @@ class FixedWindowRateLimiter(RateLimiter):
163
173
  :param identifiers: variable list of strings to uniquely identify the
164
174
  limit
165
175
  :param cost: The expected cost to be consumed, default 1
176
+
177
+ :return: True if the rate limit is not depleted
166
178
  """
167
179
 
168
180
  return (
@@ -225,6 +237,8 @@ class SlidingWindowCounterRateLimiter(RateLimiter):
225
237
  :param identifiers: variable list of strings to uniquely identify this
226
238
  instance of the limit
227
239
  :param cost: The cost of this hit, default 1
240
+
241
+ :return: True if ``cost`` could be deducted from the rate limit without exceeding it
228
242
  """
229
243
  return await cast(
230
244
  SlidingWindowCounterSupport, self.storage
@@ -243,6 +257,8 @@ class SlidingWindowCounterRateLimiter(RateLimiter):
243
257
  :param identifiers: variable list of strings to uniquely identify this
244
258
  instance of the limit
245
259
  :param cost: The expected cost to be consumed, default 1
260
+
261
+ :return: True if the rate limit is not depleted
246
262
  """
247
263
 
248
264
  previous_count, previous_expires_in, current_count, _ = await cast(
@@ -91,7 +91,10 @@ class RateLimitItem(metaclass=RateLimitItemMeta):
91
91
 
92
92
  """
93
93
 
94
- return granularity_string.lower() in cls.GRANULARITY.name
94
+ return granularity_string.lower() in {
95
+ cls.GRANULARITY.name,
96
+ f"{cls.GRANULARITY.name}s", # allow plurals like days, hours etc.
97
+ }
95
98
 
96
99
  def get_expiry(self) -> int:
97
100
  """
@@ -32,6 +32,8 @@ class RateLimiter(metaclass=ABCMeta):
32
32
  :param identifiers: variable list of strings to uniquely identify this
33
33
  instance of the limit
34
34
  :param cost: The cost of this hit, default 1
35
+
36
+ :return: True if ``cost`` could be deducted from the rate limit without exceeding it
35
37
  """
36
38
  raise NotImplementedError
37
39
 
@@ -44,6 +46,8 @@ class RateLimiter(metaclass=ABCMeta):
44
46
  :param identifiers: variable list of strings to uniquely identify this
45
47
  instance of the limit
46
48
  :param cost: The expected cost to be consumed, default 1
49
+
50
+ :return: True if the rate limit is not depleted
47
51
  """
48
52
  raise NotImplementedError
49
53
 
@@ -86,7 +90,8 @@ class MovingWindowRateLimiter(RateLimiter):
86
90
  :param identifiers: variable list of strings to uniquely identify this
87
91
  instance of the limit
88
92
  :param cost: The cost of this hit, default 1
89
- :return: (reset time, remaining)
93
+
94
+ :return: True if ``cost`` could be deducted from the rate limit without exceeding it
90
95
  """
91
96
 
92
97
  return cast(MovingWindowSupport, self.storage).acquire_entry(
@@ -101,6 +106,8 @@ class MovingWindowRateLimiter(RateLimiter):
101
106
  :param identifiers: variable list of strings to uniquely identify this
102
107
  instance of the limit
103
108
  :param cost: The expected cost to be consumed, default 1
109
+
110
+ :return: True if the rate limit is not depleted
104
111
  """
105
112
 
106
113
  return (
@@ -142,6 +149,8 @@ class FixedWindowRateLimiter(RateLimiter):
142
149
  :param identifiers: variable list of strings to uniquely identify this
143
150
  instance of the limit
144
151
  :param cost: The cost of this hit, default 1
152
+
153
+ :return: True if ``cost`` could be deducted from the rate limit without exceeding it
145
154
  """
146
155
 
147
156
  return (
@@ -161,6 +170,8 @@ class FixedWindowRateLimiter(RateLimiter):
161
170
  :param identifiers: variable list of strings to uniquely identify this
162
171
  instance of the limit
163
172
  :param cost: The expected cost to be consumed, default 1
173
+
174
+ :return: True if the rate limit is not depleted
164
175
  """
165
176
 
166
177
  return self.storage.get(item.key_for(*identifiers)) < item.amount - cost + 1
@@ -216,6 +227,8 @@ class SlidingWindowCounterRateLimiter(RateLimiter):
216
227
  :param identifiers: variable list of strings to uniquely identify this
217
228
  instance of the limit
218
229
  :param cost: The cost of this hit, default 1
230
+
231
+ :return: True if ``cost`` could be deducted from the rate limit without exceeding it
219
232
  """
220
233
  return cast(
221
234
  SlidingWindowCounterSupport, self.storage
@@ -234,6 +247,8 @@ class SlidingWindowCounterRateLimiter(RateLimiter):
234
247
  :param identifiers: variable list of strings to uniquely identify this
235
248
  instance of the limit
236
249
  :param cost: The expected cost to be consumed, default 1
250
+
251
+ :return: True if the rate limit is not depleted
237
252
  """
238
253
  previous_count, previous_expires_in, current_count, _ = cast(
239
254
  SlidingWindowCounterSupport, self.storage
@@ -22,8 +22,10 @@ SINGLE_EXPR = re.compile(
22
22
  r"""
23
23
  \s*([0-9]+)
24
24
  \s*(/|\s*per\s*)
25
- \s*([0-9]+)
26
- *\s*(hour|minute|second|day|month|year)s?\s*""",
25
+ \s*([0-9]+)?
26
+ \s*([a-z]+)
27
+ \s*
28
+ """,
27
29
  re.IGNORECASE | re.VERBOSE,
28
30
  )
29
31
  EXPR = re.compile(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: limits
3
- Version: 5.3.0
3
+ Version: 5.5.0
4
4
  Summary: Rate limiting utilities
5
5
  Home-page: https://limits.readthedocs.org
6
6
  Author: Ali-Akber Saifee
@@ -22,10 +22,10 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
22
22
  Requires-Python: >=3.10
23
23
  License-File: LICENSE.txt
24
24
  Requires-Dist: deprecated>=1.2
25
- Requires-Dist: packaging<26,>=21
25
+ Requires-Dist: packaging>=21
26
26
  Requires-Dist: typing_extensions
27
27
  Provides-Extra: redis
28
- Requires-Dist: redis!=4.5.2,!=4.5.3,<6.0.0,>3; extra == "redis"
28
+ Requires-Dist: redis!=4.5.2,!=4.5.3,<7.0.0,>3; extra == "redis"
29
29
  Provides-Extra: rediscluster
30
30
  Requires-Dist: redis!=4.5.2,!=4.5.3,>=4.2.0; extra == "rediscluster"
31
31
  Provides-Extra: memcached
@@ -35,7 +35,7 @@ Requires-Dist: pymongo<5,>4.1; extra == "mongodb"
35
35
  Provides-Extra: valkey
36
36
  Requires-Dist: valkey>=6; extra == "valkey"
37
37
  Provides-Extra: async-redis
38
- Requires-Dist: coredis<5,>=3.4.0; extra == "async-redis"
38
+ Requires-Dist: coredis<6,>=3.4.0; extra == "async-redis"
39
39
  Provides-Extra: async-memcached
40
40
  Requires-Dist: memcachio>=0.3; extra == "async-memcached"
41
41
  Provides-Extra: async-mongodb
@@ -43,12 +43,12 @@ Requires-Dist: motor<4,>=3; extra == "async-mongodb"
43
43
  Provides-Extra: async-valkey
44
44
  Requires-Dist: valkey>=6; extra == "async-valkey"
45
45
  Provides-Extra: all
46
- Requires-Dist: redis!=4.5.2,!=4.5.3,<6.0.0,>3; extra == "all"
46
+ Requires-Dist: redis!=4.5.2,!=4.5.3,<7.0.0,>3; extra == "all"
47
47
  Requires-Dist: redis!=4.5.2,!=4.5.3,>=4.2.0; extra == "all"
48
48
  Requires-Dist: pymemcache<5.0.0,>3; extra == "all"
49
49
  Requires-Dist: pymongo<5,>4.1; extra == "all"
50
50
  Requires-Dist: valkey>=6; extra == "all"
51
- Requires-Dist: coredis<5,>=3.4.0; extra == "all"
51
+ Requires-Dist: coredis<6,>=3.4.0; extra == "all"
52
52
  Requires-Dist: memcachio>=0.3; extra == "all"
53
53
  Requires-Dist: motor<4,>=3; extra == "all"
54
54
  Requires-Dist: valkey>=6; extra == "all"
@@ -1,14 +1,14 @@
1
1
  deprecated>=1.2
2
- packaging<26,>=21
2
+ packaging>=21
3
3
  typing_extensions
4
4
 
5
5
  [all]
6
- redis!=4.5.2,!=4.5.3,<6.0.0,>3
6
+ redis!=4.5.2,!=4.5.3,<7.0.0,>3
7
7
  redis!=4.5.2,!=4.5.3,>=4.2.0
8
8
  pymemcache<5.0.0,>3
9
9
  pymongo<5,>4.1
10
10
  valkey>=6
11
- coredis<5,>=3.4.0
11
+ coredis<6,>=3.4.0
12
12
  memcachio>=0.3
13
13
  motor<4,>=3
14
14
 
@@ -19,7 +19,7 @@ memcachio>=0.3
19
19
  motor<4,>=3
20
20
 
21
21
  [async-redis]
22
- coredis<5,>=3.4.0
22
+ coredis<6,>=3.4.0
23
23
 
24
24
  [async-valkey]
25
25
  valkey>=6
@@ -31,7 +31,7 @@ pymemcache<5.0.0,>3
31
31
  pymongo<5,>4.1
32
32
 
33
33
  [redis]
34
- redis!=4.5.2,!=4.5.3,<6.0.0,>3
34
+ redis!=4.5.2,!=4.5.3,<7.0.0,>3
35
35
 
36
36
  [rediscluster]
37
37
  redis!=4.5.2,!=4.5.3,>=4.2.0
@@ -1,11 +1,11 @@
1
1
  -r main.txt
2
- furo==2024.8.6
2
+ furo==2025.7.19
3
3
  Sphinx>=4,<9
4
4
  sphinx-autobuild==2024.10.3
5
5
  sphinx-copybutton==0.5.2
6
6
  sphinx-design==0.6.1
7
7
  sphinx-inline-tabs==2023.4.21
8
- sphinxext-opengraph==0.10.0
8
+ sphinxext-opengraph==0.11.0
9
9
  sphinx-paramlinks==0.6.0
10
10
  sphinxcontrib-programoutput==0.17
11
11
 
@@ -1,3 +1,3 @@
1
1
  deprecated>=1.2
2
- packaging>=21,<26
2
+ packaging>=21
3
3
  typing_extensions
@@ -0,0 +1 @@
1
+ coredis>=3.4.0,<6
@@ -0,0 +1 @@
1
+ redis>3,!=4.5.2,!=4.5.3,<7.0.0
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from collections import defaultdict
4
4
 
5
- from limits import limits
5
+ from limits import RateLimitItemPerMinute, limits, parse, parse_many
6
6
 
7
7
 
8
8
  class TestLimits:
@@ -33,6 +33,7 @@ class TestLimits:
33
33
  assert item == self.FakeLimit(1, 1)
34
34
  assert item != self.FakeLimit(1, 2)
35
35
  assert item != self.FakeLimit(2, 1)
36
+ assert item != RateLimitItemPerMinute(1, 1)
36
37
  assert item != "someething else"
37
38
 
38
39
  def test_hashabilty(self):
@@ -44,3 +45,15 @@ class TestLimits:
44
45
  mapping[self.OtherFakeLimit(1, 2)] += 1
45
46
 
46
47
  assert len(mapping) == 3
48
+
49
+ def test_parse_custom_limit(self):
50
+ item = parse("1/fake")
51
+ assert item == self.FakeLimit(1, 1)
52
+ item = parse("5/10 fake")
53
+ assert item == self.FakeLimit(5, 10)
54
+ items = parse_many("1/fake,10/minute,10 per 10 fakes")
55
+ assert items == [
56
+ self.FakeLimit(1, 1),
57
+ RateLimitItemPerMinute(10, 1),
58
+ self.FakeLimit(10, 10),
59
+ ]
@@ -1 +0,0 @@
1
- coredis>=3.4.0,<5
@@ -1 +0,0 @@
1
- redis>3,!=4.5.2,!=4.5.3,<6.0.0
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