limits 4.7.1__tar.gz → 5.0.0rc1__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.
- {limits-4.7.1 → limits-5.0.0rc1}/HISTORY.rst +24 -81
- {limits-4.7.1 → limits-5.0.0rc1}/PKG-INFO +7 -14
- {limits-4.7.1 → limits-5.0.0rc1}/README.rst +4 -3
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/_static/custom.css +1 -1
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/api.rst +0 -12
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/async.rst +3 -6
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/conf.py +12 -14
- limits-5.0.0rc1/doc/source/ext/_static/benchmark-chart.css +61 -0
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/ext/_static/js/benchmark-chart.js +46 -21
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/ext/_static/js/benchmark-details.js +22 -6
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/ext/_static/js/benchmark-loader.js +4 -5
- limits-5.0.0rc1/doc/source/ext/_templates/git_info.js +2 -0
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/ext/bench_chart.py +15 -4
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/index.rst +2 -1
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/installation.rst +0 -20
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/performance.rst +1 -1
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/quickstart.rst +42 -27
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/storage.rst +3 -36
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/strategies.rst +0 -11
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/theme_config.py +2 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/_version.py +3 -3
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/__init__.py +0 -2
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/base.py +1 -5
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/memcached.py +34 -58
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/memory.py +20 -38
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/mongodb.py +26 -31
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/__init__.py +2 -4
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/bridge.py +0 -1
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/coredis.py +2 -6
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/redispy.py +1 -8
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/strategies.py +1 -28
- {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/acquire_moving_window.lua +5 -2
- limits-5.0.0rc1/limits/resources/redis/lua_scripts/moving_window.lua +30 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/__init__.py +0 -2
- {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/base.py +1 -5
- {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/memcached.py +6 -29
- {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/memory.py +16 -35
- {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/mongodb.py +25 -34
- {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/redis.py +1 -7
- {limits-4.7.1 → limits-5.0.0rc1}/limits/strategies.py +1 -31
- {limits-4.7.1 → limits-5.0.0rc1}/limits/typing.py +0 -50
- {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/PKG-INFO +7 -14
- {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/SOURCES.txt +0 -4
- {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/requires.txt +2 -20
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/docs.txt +1 -1
- limits-5.0.0rc1/requirements/storage/async-memcached.txt +1 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/test.txt +1 -6
- {limits-4.7.1 → limits-5.0.0rc1}/setup.cfg +0 -6
- {limits-4.7.1 → limits-5.0.0rc1}/setup.py +0 -2
- {limits-4.7.1 → limits-5.0.0rc1}/tests/test_storage.py +0 -9
- {limits-4.7.1 → limits-5.0.0rc1}/tests/test_strategy.py +8 -43
- limits-4.7.1/doc/source/ext/_static/benchmark-chart.css +0 -10
- limits-4.7.1/doc/source/ext/_templates/git_info.js +0 -2
- limits-4.7.1/limits/aio/storage/etcd.py +0 -146
- limits-4.7.1/limits/resources/redis/lua_scripts/moving_window.lua +0 -21
- limits-4.7.1/limits/storage/etcd.py +0 -139
- limits-4.7.1/requirements/storage/async-etcd.txt +0 -1
- limits-4.7.1/requirements/storage/async-memcached.txt +0 -2
- limits-4.7.1/requirements/storage/etcd.txt +0 -1
- {limits-4.7.1 → limits-5.0.0rc1}/CLASSIFIERS +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/CONTRIBUTIONS.rst +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/LICENSE.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/MANIFEST.in +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/doc/Makefile +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/changelog.rst +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/doc/source/custom-storage.rst +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/__init__.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/__init__.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/valkey.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/errors.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/limits.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/py.typed +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/acquire_sliding_window.lua +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/clear_keys.lua +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/incr_expire.lua +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/sliding_window.lua +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/redis_cluster.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/redis_sentinel.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/registry.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/util.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits/version.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/dependency_links.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/not-zip-safe +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/top_level.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/pyproject.toml +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/ci.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/dev.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/main.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/async-mongodb.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/async-redis.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/async-valkey.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/memcached.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/mongodb.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/redis.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/rediscluster.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/valkey.txt +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/tests/test_limit_granularities.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/tests/test_limits.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/tests/test_ratelimit_parser.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/tests/test_utils.py +0 -0
- {limits-4.7.1 → limits-5.0.0rc1}/versioneer.py +0 -0
|
@@ -3,6 +3,30 @@
|
|
|
3
3
|
Changelog
|
|
4
4
|
=========
|
|
5
5
|
|
|
6
|
+
v5.0.0rc1
|
|
7
|
+
---------
|
|
8
|
+
Release Date: 2025-04-09
|
|
9
|
+
|
|
10
|
+
* Backward incompatible changes
|
|
11
|
+
|
|
12
|
+
* Dropped support for Fixed Window with Elastic Expiry strategy
|
|
13
|
+
* Dropped support for etcd
|
|
14
|
+
* Replaced async support for memached from :pypi:`emcache` to :pypi`:memcachio`
|
|
15
|
+
|
|
16
|
+
* Performance
|
|
17
|
+
|
|
18
|
+
* Improved performance of in-memory moving window ``test`` and ``get_window_stats`` operations.
|
|
19
|
+
* Improved performance of redis moving window ``test`` and ``get_window_stats`` operations.
|
|
20
|
+
* Improved performance of mongodb moving window ``test`` and ``get_window_stats`` operations.
|
|
21
|
+
|
|
22
|
+
v4.7.2
|
|
23
|
+
------
|
|
24
|
+
Release Date: 2025-04-09
|
|
25
|
+
|
|
26
|
+
* Documentation
|
|
27
|
+
|
|
28
|
+
* Improve presentation of benchmark docs
|
|
29
|
+
|
|
6
30
|
v4.7.1
|
|
7
31
|
------
|
|
8
32
|
Release Date: 2025-04-08
|
|
@@ -785,84 +809,3 @@ Release Date: 2015-01-08
|
|
|
785
809
|
|
|
786
810
|
* Initial import of common rate limiting code from `Flask-Limiter <https://github.com/alisaifee/flask-limiter>`_
|
|
787
811
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: limits
|
|
3
|
-
Version:
|
|
3
|
+
Version: 5.0.0rc1
|
|
4
4
|
Summary: Rate limiting utilities
|
|
5
5
|
Home-page: https://limits.readthedocs.org
|
|
6
6
|
Author: Ali-Akber Saifee
|
|
@@ -32,19 +32,14 @@ Provides-Extra: memcached
|
|
|
32
32
|
Requires-Dist: pymemcache<5.0.0,>3; extra == "memcached"
|
|
33
33
|
Provides-Extra: mongodb
|
|
34
34
|
Requires-Dist: pymongo<5,>4.1; extra == "mongodb"
|
|
35
|
-
Provides-Extra: etcd
|
|
36
|
-
Requires-Dist: etcd3; extra == "etcd"
|
|
37
35
|
Provides-Extra: valkey
|
|
38
36
|
Requires-Dist: valkey>=6; extra == "valkey"
|
|
39
37
|
Provides-Extra: async-redis
|
|
40
38
|
Requires-Dist: coredis<5,>=3.4.0; extra == "async-redis"
|
|
41
39
|
Provides-Extra: async-memcached
|
|
42
|
-
Requires-Dist:
|
|
43
|
-
Requires-Dist: emcache>=1; (python_version >= "3.11" and python_version < "3.13.0") and extra == "async-memcached"
|
|
40
|
+
Requires-Dist: memcachio>=0.3; extra == "async-memcached"
|
|
44
41
|
Provides-Extra: async-mongodb
|
|
45
42
|
Requires-Dist: motor<4,>=3; extra == "async-mongodb"
|
|
46
|
-
Provides-Extra: async-etcd
|
|
47
|
-
Requires-Dist: aetcd; extra == "async-etcd"
|
|
48
43
|
Provides-Extra: async-valkey
|
|
49
44
|
Requires-Dist: valkey>=6; extra == "async-valkey"
|
|
50
45
|
Provides-Extra: all
|
|
@@ -52,13 +47,10 @@ Requires-Dist: redis!=4.5.2,!=4.5.3,<6.0.0,>3; extra == "all"
|
|
|
52
47
|
Requires-Dist: redis!=4.5.2,!=4.5.3,>=4.2.0; extra == "all"
|
|
53
48
|
Requires-Dist: pymemcache<5.0.0,>3; extra == "all"
|
|
54
49
|
Requires-Dist: pymongo<5,>4.1; extra == "all"
|
|
55
|
-
Requires-Dist: etcd3; extra == "all"
|
|
56
50
|
Requires-Dist: valkey>=6; extra == "all"
|
|
57
51
|
Requires-Dist: coredis<5,>=3.4.0; extra == "all"
|
|
58
|
-
Requires-Dist:
|
|
59
|
-
Requires-Dist: emcache>=1; (python_version >= "3.11" and python_version < "3.13.0") and extra == "all"
|
|
52
|
+
Requires-Dist: memcachio>=0.3; extra == "all"
|
|
60
53
|
Requires-Dist: motor<4,>=3; extra == "all"
|
|
61
|
-
Requires-Dist: aetcd; extra == "all"
|
|
62
54
|
Requires-Dist: valkey>=6; extra == "all"
|
|
63
55
|
Dynamic: author
|
|
64
56
|
Dynamic: author-email
|
|
@@ -86,13 +78,14 @@ Dynamic: summary
|
|
|
86
78
|
.. |docs| image:: https://readthedocs.org/projects/limits/badge/?version=latest
|
|
87
79
|
:target: https://limits.readthedocs.org
|
|
88
80
|
|
|
81
|
+
######
|
|
89
82
|
limits
|
|
90
|
-
|
|
83
|
+
######
|
|
91
84
|
|docs| |ci| |codecov| |pypi| |pypi-versions| |license|
|
|
92
85
|
|
|
93
86
|
|
|
94
87
|
**limits** is a python library for rate limiting via multiple strategies
|
|
95
|
-
with commonly used storage backends (Redis, Memcached
|
|
88
|
+
with commonly used storage backends (Redis, Memcached & MongoDB).
|
|
96
89
|
|
|
97
90
|
The library provides identical APIs for use in sync and
|
|
98
91
|
`async <https://limits.readthedocs.io/en/stable/async.html>`_ codebases.
|
|
@@ -188,13 +181,13 @@ Scenario 2:
|
|
|
188
181
|
- ``weighted_count = floor(8 + (4 * 0.33)) = floor(8 + 1.32) = 9``.
|
|
189
182
|
- Since the weighted count is below the limit, the request is allowed.
|
|
190
183
|
|
|
184
|
+
|
|
191
185
|
Storage backends
|
|
192
186
|
================
|
|
193
187
|
|
|
194
188
|
- `Redis <https://limits.readthedocs.io/en/latest/storage.html#redis-storage>`_
|
|
195
189
|
- `Memcached <https://limits.readthedocs.io/en/latest/storage.html#memcached-storage>`_
|
|
196
190
|
- `MongoDB <https://limits.readthedocs.io/en/latest/storage.html#mongodb-storage>`_
|
|
197
|
-
- `Etcd <https://limits.readthedocs.io/en/latest/storage.html#etcd-storage>`_
|
|
198
191
|
- `In-Memory <https://limits.readthedocs.io/en/latest/storage.html#in-memory-storage>`_
|
|
199
192
|
|
|
200
193
|
Dive right in
|
|
@@ -11,13 +11,14 @@
|
|
|
11
11
|
.. |docs| image:: https://readthedocs.org/projects/limits/badge/?version=latest
|
|
12
12
|
:target: https://limits.readthedocs.org
|
|
13
13
|
|
|
14
|
+
######
|
|
14
15
|
limits
|
|
15
|
-
|
|
16
|
+
######
|
|
16
17
|
|docs| |ci| |codecov| |pypi| |pypi-versions| |license|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
**limits** is a python library for rate limiting via multiple strategies
|
|
20
|
-
with commonly used storage backends (Redis, Memcached
|
|
21
|
+
with commonly used storage backends (Redis, Memcached & MongoDB).
|
|
21
22
|
|
|
22
23
|
The library provides identical APIs for use in sync and
|
|
23
24
|
`async <https://limits.readthedocs.io/en/stable/async.html>`_ codebases.
|
|
@@ -113,13 +114,13 @@ Scenario 2:
|
|
|
113
114
|
- ``weighted_count = floor(8 + (4 * 0.33)) = floor(8 + 1.32) = 9``.
|
|
114
115
|
- Since the weighted count is below the limit, the request is allowed.
|
|
115
116
|
|
|
117
|
+
|
|
116
118
|
Storage backends
|
|
117
119
|
================
|
|
118
120
|
|
|
119
121
|
- `Redis <https://limits.readthedocs.io/en/latest/storage.html#redis-storage>`_
|
|
120
122
|
- `Memcached <https://limits.readthedocs.io/en/latest/storage.html#memcached-storage>`_
|
|
121
123
|
- `MongoDB <https://limits.readthedocs.io/en/latest/storage.html#mongodb-storage>`_
|
|
122
|
-
- `Etcd <https://limits.readthedocs.io/en/latest/storage.html#etcd-storage>`_
|
|
123
124
|
- `In-Memory <https://limits.readthedocs.io/en/latest/storage.html#in-memory-storage>`_
|
|
124
125
|
|
|
125
126
|
Dive right in
|
|
@@ -28,7 +28,6 @@ a single parameter: a subclass of :class:`~limits.storage.Storage`.
|
|
|
28
28
|
Provided by :mod:`limits.strategies`
|
|
29
29
|
|
|
30
30
|
.. autoclass:: FixedWindowRateLimiter
|
|
31
|
-
.. autoclass:: FixedWindowElasticExpiryRateLimiter
|
|
32
31
|
.. autoclass:: MovingWindowRateLimiter
|
|
33
32
|
.. autoclass:: SlidingWindowCounterRateLimiter
|
|
34
33
|
|
|
@@ -47,7 +46,6 @@ expose async variants and expect a subclass of :class:`limits.aio.storage.Storag
|
|
|
47
46
|
Provided by :mod:`limits.aio.strategies`
|
|
48
47
|
|
|
49
48
|
.. autoclass:: FixedWindowRateLimiter
|
|
50
|
-
.. autoclass:: FixedWindowElasticExpiryRateLimiter
|
|
51
49
|
.. autoclass:: MovingWindowRateLimiter
|
|
52
50
|
.. autoclass:: SlidingWindowCounterRateLimiter
|
|
53
51
|
|
|
@@ -101,11 +99,6 @@ MongoDB Storage
|
|
|
101
99
|
|
|
102
100
|
.. autoclass:: MongoDBStorage
|
|
103
101
|
|
|
104
|
-
Etcd Storage
|
|
105
|
-
^^^^^^^^^^^^
|
|
106
|
-
|
|
107
|
-
.. autoclass:: EtcdStorage
|
|
108
|
-
|
|
109
102
|
|
|
110
103
|
Async Storage
|
|
111
104
|
-------------
|
|
@@ -144,11 +137,6 @@ Async MongoDB Storage
|
|
|
144
137
|
|
|
145
138
|
.. autoclass:: MongoDBStorage
|
|
146
139
|
|
|
147
|
-
Async Etcd Storage
|
|
148
|
-
^^^^^^^^^^^^^^^^^^
|
|
149
|
-
|
|
150
|
-
.. autoclass:: EtcdStorage
|
|
151
|
-
|
|
152
140
|
Abstract storage classes
|
|
153
141
|
------------------------
|
|
154
142
|
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
Async Support
|
|
3
3
|
=============
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
A new namespace ``limits.aio`` is available which mirrors the original
|
|
8
|
-
``limits.storage`` and ``limits.strategies`` packages.
|
|
5
|
+
The namespace ``limits.aio`` mirrors ``limits.storage`` and ``limits.strategies``
|
|
6
|
+
with async variants.
|
|
9
7
|
|
|
10
8
|
The following async storage backends are implemented:
|
|
11
9
|
|
|
@@ -14,9 +12,8 @@ The following async storage backends are implemented:
|
|
|
14
12
|
or `redis-py <https://redis-py.readthedocs.io>`_. Refer to
|
|
15
13
|
:paramref:`limits.aio.storage.RedisStorage.implementation` for
|
|
16
14
|
details on selecting the dependency)
|
|
17
|
-
- Memcached (via `
|
|
15
|
+
- Memcached (via `memcachio <https://memcachio.readthedocs.org>`_)
|
|
18
16
|
- MongoDB (via `motor <https://motor.readthedocs.org>`_)
|
|
19
|
-
- Etcd (via `aetcd <https://aetcd.readthedocs.org>`_)
|
|
20
17
|
|
|
21
18
|
Quick start
|
|
22
19
|
===========
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
#
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
|
|
3
4
|
import os
|
|
4
5
|
import sys
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
|
-
from docutils import nodes
|
|
8
|
-
from sphinx.application import Sphinx
|
|
9
|
-
from sphinx.util.docutils import SphinxDirective
|
|
10
|
-
|
|
11
8
|
sys.path.insert(0, os.path.abspath("../../"))
|
|
12
9
|
sys.path.insert(0, os.path.abspath("./"))
|
|
13
10
|
|
|
14
|
-
from theme_config import *
|
|
11
|
+
from theme_config import * # noqa
|
|
15
12
|
|
|
16
13
|
import limits
|
|
17
14
|
|
|
@@ -28,16 +25,18 @@ release = version
|
|
|
28
25
|
|
|
29
26
|
|
|
30
27
|
if branch_from_env := os.environ.get("READTHEDOCS_VERSION", None):
|
|
28
|
+
branch_from_env = "master" if branch_from_env == "latest" else branch_from_env
|
|
31
29
|
benchmark_git_context = {
|
|
32
30
|
"branch": branch_from_env,
|
|
33
|
-
"sha": os.environ.get("READTHEDOCS_GIT_COMMIT_HASH", "")
|
|
31
|
+
"sha": os.environ.get("READTHEDOCS_GIT_COMMIT_HASH", ""),
|
|
34
32
|
}
|
|
35
33
|
else:
|
|
36
34
|
import limits._version
|
|
35
|
+
|
|
37
36
|
git_info = limits._version.git_pieces_from_vcs("", os.path.abspath("../../"), False)
|
|
38
37
|
benchmark_git_context = {
|
|
39
38
|
"branch": git_info.get("branch", ""),
|
|
40
|
-
"sha": git_info.get("long", None)
|
|
39
|
+
"sha": git_info.get("long", None),
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
html_static_path = ["_static"]
|
|
@@ -48,18 +47,19 @@ html_css_files = [
|
|
|
48
47
|
]
|
|
49
48
|
|
|
50
49
|
html_title = f"{project} <small><b style='color: var(--color-brand-primary)'>{{{release}}}</b></small>"
|
|
50
|
+
|
|
51
51
|
try:
|
|
52
52
|
ahead = int(ahead)
|
|
53
53
|
if ahead > 0:
|
|
54
|
-
html_theme_options[
|
|
54
|
+
html_theme_options[ # noqa
|
|
55
55
|
"announcement"
|
|
56
56
|
] = f"""
|
|
57
57
|
This is a development version. The documentation for the latest version: <b>{release}</b> can be found <a href="/en/stable">here</a>
|
|
58
58
|
"""
|
|
59
59
|
html_title = f"{project} <small><b style='color: var(--color-brand-primary)'>{{dev}}</b></small>"
|
|
60
|
-
except:
|
|
60
|
+
except ValueError:
|
|
61
61
|
pass
|
|
62
|
-
sys.path.append(str(Path(
|
|
62
|
+
sys.path.append(str(Path("ext").resolve()))
|
|
63
63
|
|
|
64
64
|
extensions = [
|
|
65
65
|
"sphinx.ext.autodoc",
|
|
@@ -93,18 +93,16 @@ autosectionlabel_prefix_document = True
|
|
|
93
93
|
|
|
94
94
|
extlinks = {"pypi": ("https://pypi.org/project/%s", "%s")}
|
|
95
95
|
|
|
96
|
-
copybutton_exclude =
|
|
96
|
+
copybutton_exclude = ".gp, .go"
|
|
97
97
|
|
|
98
98
|
intersphinx_mapping = {
|
|
99
99
|
"python": ("http://docs.python.org/", None),
|
|
100
100
|
"coredis": ("https://coredis.readthedocs.io/en/latest/", None),
|
|
101
|
-
"
|
|
101
|
+
"memcachio": ("https://memcachio.readthedocs.io/en/latest/", None),
|
|
102
102
|
"motor": ("https://motor.readthedocs.io/en/stable/", None),
|
|
103
103
|
"redis-py-cluster": ("https://redis-py-cluster.readthedocs.io/en/latest/", None),
|
|
104
104
|
"redis-py": ("https://redis-py.readthedocs.io/en/latest/", None),
|
|
105
105
|
"pymemcache": ("https://pymemcache.readthedocs.io/en/latest/", None),
|
|
106
106
|
"pymongo": ("https://pymongo.readthedocs.io/en/stable/", None),
|
|
107
|
-
"python-etcd3": ("https://python-etcd3.readthedocs.io/en/latest/", None),
|
|
108
|
-
"aetcd": ("https://aetcd.readthedocs.io/en/latest/", None),
|
|
109
107
|
"valkey-py": ("https://valkey-py.readthedocs.io/en/latest/", None),
|
|
110
108
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
.benchmark-chart {
|
|
2
|
+
width: 100%;
|
|
3
|
+
}
|
|
4
|
+
.benchmark-details {
|
|
5
|
+
.benchmark-details-section {
|
|
6
|
+
thead > tr {
|
|
7
|
+
color: var(--color-purple);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
.benchmark-chart-error,
|
|
12
|
+
.benchmark-details-error {
|
|
13
|
+
color: var(--color-red);
|
|
14
|
+
font-size: smaller;
|
|
15
|
+
padding: 2em;
|
|
16
|
+
text-align: center;
|
|
17
|
+
height: 5em;
|
|
18
|
+
}
|
|
19
|
+
.benchmark-chart-loading {
|
|
20
|
+
display: flex;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
align-items: center;
|
|
23
|
+
font-size: 1.2rem;
|
|
24
|
+
font-weight: bold;
|
|
25
|
+
color: var(--color-purple);
|
|
26
|
+
letter-spacing: 1px;
|
|
27
|
+
height: 200px;
|
|
28
|
+
animation: benchmark-chart-loading-animation;
|
|
29
|
+
animation-iteration-count: 10;
|
|
30
|
+
animation-duration: 2s;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@keyframes benchmark-chart-loading-animation {
|
|
34
|
+
0% {
|
|
35
|
+
opacity: 0;
|
|
36
|
+
}
|
|
37
|
+
,
|
|
38
|
+
25% {
|
|
39
|
+
opacity: 25%;
|
|
40
|
+
}
|
|
41
|
+
,
|
|
42
|
+
50% {
|
|
43
|
+
opacity: 50%;
|
|
44
|
+
}
|
|
45
|
+
,
|
|
46
|
+
90% {
|
|
47
|
+
opacity: 90%;
|
|
48
|
+
}
|
|
49
|
+
,
|
|
50
|
+
100% {
|
|
51
|
+
opacity: 100%;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.plot-container {
|
|
56
|
+
filter: invert(100%);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
body[data-theme="light"] .plot-container {
|
|
60
|
+
filter: invert(0);
|
|
61
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { render, html } from "https://unpkg.com/uhtml@3.2.1?module";
|
|
2
|
+
import { fetchBenchmarkData } from "./benchmark-loader.js";
|
|
1
3
|
const KNOWN_PARAMS = ["storage_type", "limit", "strategy", "async"];
|
|
2
4
|
|
|
3
5
|
function getBenchmarkData(result, query) {
|
|
@@ -44,7 +46,7 @@ function formatRateLimit(str) {
|
|
|
44
46
|
|
|
45
47
|
function nameTransform(benchmark, stripParams, query) {
|
|
46
48
|
let name = benchmark.name;
|
|
47
|
-
params = benchmark.params;
|
|
49
|
+
let params = benchmark.params;
|
|
48
50
|
name = name
|
|
49
51
|
.replace(/\[.*?\]/, "")
|
|
50
52
|
.replace("_async", "")
|
|
@@ -97,21 +99,6 @@ function getColorForStorage(storageType) {
|
|
|
97
99
|
return storageColorMap[storageType] || "#7f7f7f"; // gray
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
function sortBenchmarksByParams(benchmarks, sortKeys) {
|
|
101
|
-
return benchmarks.sort((a, b) => {
|
|
102
|
-
for (const key of sortKeys) {
|
|
103
|
-
let valA = (a.params?.[key] || "").toLowerCase();
|
|
104
|
-
let valB = (b.params?.[key] || "").toLowerCase();
|
|
105
|
-
if (key == "limit") {
|
|
106
|
-
valA = parseInt(valA.split(" ")[0]);
|
|
107
|
-
valB = parseInt(valB.split(" ")[0]);
|
|
108
|
-
}
|
|
109
|
-
return valA < valB ? -1 : valA > valB ? 1 : 0;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return a.name.localeCompare(b.name);
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
102
|
function sortBenchmarksByParams(benchmarks, sortKeys) {
|
|
116
103
|
return benchmarks.sort(function (a, b) {
|
|
117
104
|
for (const key of sortKeys) {
|
|
@@ -127,6 +114,7 @@ function sortBenchmarksByParams(benchmarks, sortKeys) {
|
|
|
127
114
|
return a.name.localeCompare(b.name);
|
|
128
115
|
});
|
|
129
116
|
}
|
|
117
|
+
|
|
130
118
|
let dispatched = new Set();
|
|
131
119
|
|
|
132
120
|
document.addEventListener("DOMContentLoaded", function () {
|
|
@@ -138,15 +126,38 @@ document.addEventListener("DOMContentLoaded", function () {
|
|
|
138
126
|
let sortBy = JSON.parse(
|
|
139
127
|
chart.dataset.sortBy || '["storage_type", "limit"]',
|
|
140
128
|
);
|
|
129
|
+
render(
|
|
130
|
+
chart,
|
|
131
|
+
html`
|
|
132
|
+
<div class="benchmark-chart-loading">
|
|
133
|
+
<span>Loading</span>
|
|
134
|
+
</div>
|
|
135
|
+
`,
|
|
136
|
+
);
|
|
141
137
|
if (!dispatched.has(source)) {
|
|
142
|
-
fetchBenchmarkData(`${source}.json`)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
138
|
+
fetchBenchmarkData(`${source}.json`)
|
|
139
|
+
.then((result) => {
|
|
140
|
+
window.Benchmarks[source] = result;
|
|
141
|
+
let event = new Event(`${source}-loaded`);
|
|
142
|
+
window.dispatchEvent(event);
|
|
143
|
+
})
|
|
144
|
+
.catch((error) => {
|
|
145
|
+
let event = new Event(`${source}-failed`);
|
|
146
|
+
window.dispatchEvent(event);
|
|
147
|
+
});
|
|
147
148
|
}
|
|
148
149
|
dispatched.add(source);
|
|
150
|
+
window.addEventListener(`${chart.dataset.source}-failed`, function () {
|
|
151
|
+
chart.querySelector(".benchmark-chart-loading")?.remove();
|
|
152
|
+
render(
|
|
153
|
+
chart,
|
|
154
|
+
html`
|
|
155
|
+
<div class="benchmark-chart-error">Benchmark data not available.</div>
|
|
156
|
+
`,
|
|
157
|
+
);
|
|
158
|
+
});
|
|
149
159
|
window.addEventListener(`${chart.dataset.source}-loaded`, function () {
|
|
160
|
+
chart.querySelector(".benchmark-chart-loading")?.remove();
|
|
150
161
|
let results = Benchmarks[chart.dataset.source];
|
|
151
162
|
let unsorted = getBenchmarkData(results, query);
|
|
152
163
|
let data = sortBenchmarksByParams(
|
|
@@ -188,7 +199,21 @@ document.addEventListener("DOMContentLoaded", function () {
|
|
|
188
199
|
return item;
|
|
189
200
|
}),
|
|
190
201
|
layout,
|
|
202
|
+
{ responsive: true, displaylogo: false },
|
|
191
203
|
);
|
|
204
|
+
let initial = true;
|
|
205
|
+
chart.on("plotly_afterplot", function () {
|
|
206
|
+
const { hash } = window.location;
|
|
207
|
+
if (hash && initial) {
|
|
208
|
+
initial = false;
|
|
209
|
+
const target = document.querySelector(hash);
|
|
210
|
+
if (target) {
|
|
211
|
+
setTimeout(function () {
|
|
212
|
+
target.scrollIntoView({ behavior: "instant" });
|
|
213
|
+
}, 10);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
192
217
|
});
|
|
193
218
|
});
|
|
194
219
|
});
|
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
import { render, html } from "https://unpkg.com/uhtml@3.2.1?module";
|
|
2
|
+
import { fetchBenchmarkData } from "./benchmark-loader.js";
|
|
2
3
|
document.addEventListener("DOMContentLoaded", function () {
|
|
3
4
|
const details = document.querySelectorAll(".benchmark-details");
|
|
5
|
+
let dispatched = new Set();
|
|
4
6
|
details.forEach((detail) => {
|
|
5
7
|
let source = detail.dataset.source;
|
|
6
8
|
if (!dispatched.has(source)) {
|
|
7
|
-
fetchBenchmarkData(`${source}.json`)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
fetchBenchmarkData(`${source}.json`)
|
|
10
|
+
.then((result) => {
|
|
11
|
+
window.Benchmarks[source] = result;
|
|
12
|
+
let event = new Event(`${source}-loaded`);
|
|
13
|
+
window.dispatchEvent(event);
|
|
14
|
+
})
|
|
15
|
+
.catch((error) => {
|
|
16
|
+
let event = new Event(`${source}-failed`);
|
|
17
|
+
window.dispatchEvent(event);
|
|
18
|
+
});
|
|
12
19
|
}
|
|
13
20
|
dispatched.add(source);
|
|
21
|
+
window.addEventListener(`${detail.dataset.source}-failed`, function () {
|
|
22
|
+
render(
|
|
23
|
+
detail,
|
|
24
|
+
html`
|
|
25
|
+
<div class="benchmark-details-error">
|
|
26
|
+
Benchmark data not available.
|
|
27
|
+
</div>
|
|
28
|
+
`,
|
|
29
|
+
);
|
|
30
|
+
});
|
|
14
31
|
window.addEventListener(`${detail.dataset.source}-loaded`, function () {
|
|
15
32
|
const machine_info = window.Benchmarks[source].machine_info;
|
|
16
33
|
const commit_info = window.Benchmarks[source].commit_info;
|
|
17
34
|
const cpu = window.Benchmarks[source].machine_info.cpu;
|
|
18
|
-
console.log(machine_info);
|
|
19
35
|
render(
|
|
20
36
|
detail,
|
|
21
37
|
html`
|
|
@@ -7,16 +7,13 @@ window.Benchmarks = new Map();
|
|
|
7
7
|
|
|
8
8
|
function fetchBenchmarkData(filename) {
|
|
9
9
|
let attempts = 0;
|
|
10
|
-
|
|
11
10
|
function tryFetch() {
|
|
12
11
|
if (attempts >= BENCHMARK_PATHS.length) {
|
|
13
|
-
return Promise.reject("All fetch attempts failed.");
|
|
12
|
+
return Promise.reject(new Error("All fetch attempts failed."));
|
|
14
13
|
}
|
|
15
|
-
|
|
16
14
|
const base = BENCHMARK_PATHS[attempts++];
|
|
17
15
|
const url = base + filename;
|
|
18
|
-
|
|
19
|
-
// First send a HEAD request to quietly check existence
|
|
16
|
+
console.log(`Testing ${url}`);
|
|
20
17
|
return fetch(url, { method: "HEAD" })
|
|
21
18
|
.then((headRes) => {
|
|
22
19
|
if (!headRes.ok) throw new Error("HEAD check failed");
|
|
@@ -30,3 +27,5 @@ function fetchBenchmarkData(filename) {
|
|
|
30
27
|
|
|
31
28
|
return tryFetch();
|
|
32
29
|
}
|
|
30
|
+
|
|
31
|
+
export { fetchBenchmarkData };
|