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.
Files changed (101) hide show
  1. {limits-4.7.1 → limits-5.0.0rc1}/HISTORY.rst +24 -81
  2. {limits-4.7.1 → limits-5.0.0rc1}/PKG-INFO +7 -14
  3. {limits-4.7.1 → limits-5.0.0rc1}/README.rst +4 -3
  4. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/_static/custom.css +1 -1
  5. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/api.rst +0 -12
  6. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/async.rst +3 -6
  7. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/conf.py +12 -14
  8. limits-5.0.0rc1/doc/source/ext/_static/benchmark-chart.css +61 -0
  9. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/ext/_static/js/benchmark-chart.js +46 -21
  10. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/ext/_static/js/benchmark-details.js +22 -6
  11. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/ext/_static/js/benchmark-loader.js +4 -5
  12. limits-5.0.0rc1/doc/source/ext/_templates/git_info.js +2 -0
  13. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/ext/bench_chart.py +15 -4
  14. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/index.rst +2 -1
  15. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/installation.rst +0 -20
  16. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/performance.rst +1 -1
  17. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/quickstart.rst +42 -27
  18. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/storage.rst +3 -36
  19. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/strategies.rst +0 -11
  20. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/theme_config.py +2 -0
  21. {limits-4.7.1 → limits-5.0.0rc1}/limits/_version.py +3 -3
  22. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/__init__.py +0 -2
  23. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/base.py +1 -5
  24. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/memcached.py +34 -58
  25. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/memory.py +20 -38
  26. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/mongodb.py +26 -31
  27. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/__init__.py +2 -4
  28. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/bridge.py +0 -1
  29. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/coredis.py +2 -6
  30. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/redispy.py +1 -8
  31. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/strategies.py +1 -28
  32. {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/acquire_moving_window.lua +5 -2
  33. limits-5.0.0rc1/limits/resources/redis/lua_scripts/moving_window.lua +30 -0
  34. {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/__init__.py +0 -2
  35. {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/base.py +1 -5
  36. {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/memcached.py +6 -29
  37. {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/memory.py +16 -35
  38. {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/mongodb.py +25 -34
  39. {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/redis.py +1 -7
  40. {limits-4.7.1 → limits-5.0.0rc1}/limits/strategies.py +1 -31
  41. {limits-4.7.1 → limits-5.0.0rc1}/limits/typing.py +0 -50
  42. {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/PKG-INFO +7 -14
  43. {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/SOURCES.txt +0 -4
  44. {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/requires.txt +2 -20
  45. {limits-4.7.1 → limits-5.0.0rc1}/requirements/docs.txt +1 -1
  46. limits-5.0.0rc1/requirements/storage/async-memcached.txt +1 -0
  47. {limits-4.7.1 → limits-5.0.0rc1}/requirements/test.txt +1 -6
  48. {limits-4.7.1 → limits-5.0.0rc1}/setup.cfg +0 -6
  49. {limits-4.7.1 → limits-5.0.0rc1}/setup.py +0 -2
  50. {limits-4.7.1 → limits-5.0.0rc1}/tests/test_storage.py +0 -9
  51. {limits-4.7.1 → limits-5.0.0rc1}/tests/test_strategy.py +8 -43
  52. limits-4.7.1/doc/source/ext/_static/benchmark-chart.css +0 -10
  53. limits-4.7.1/doc/source/ext/_templates/git_info.js +0 -2
  54. limits-4.7.1/limits/aio/storage/etcd.py +0 -146
  55. limits-4.7.1/limits/resources/redis/lua_scripts/moving_window.lua +0 -21
  56. limits-4.7.1/limits/storage/etcd.py +0 -139
  57. limits-4.7.1/requirements/storage/async-etcd.txt +0 -1
  58. limits-4.7.1/requirements/storage/async-memcached.txt +0 -2
  59. limits-4.7.1/requirements/storage/etcd.txt +0 -1
  60. {limits-4.7.1 → limits-5.0.0rc1}/CLASSIFIERS +0 -0
  61. {limits-4.7.1 → limits-5.0.0rc1}/CONTRIBUTIONS.rst +0 -0
  62. {limits-4.7.1 → limits-5.0.0rc1}/LICENSE.txt +0 -0
  63. {limits-4.7.1 → limits-5.0.0rc1}/MANIFEST.in +0 -0
  64. {limits-4.7.1 → limits-5.0.0rc1}/doc/Makefile +0 -0
  65. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/changelog.rst +0 -0
  66. {limits-4.7.1 → limits-5.0.0rc1}/doc/source/custom-storage.rst +0 -0
  67. {limits-4.7.1 → limits-5.0.0rc1}/limits/__init__.py +0 -0
  68. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/__init__.py +0 -0
  69. {limits-4.7.1 → limits-5.0.0rc1}/limits/aio/storage/redis/valkey.py +0 -0
  70. {limits-4.7.1 → limits-5.0.0rc1}/limits/errors.py +0 -0
  71. {limits-4.7.1 → limits-5.0.0rc1}/limits/limits.py +0 -0
  72. {limits-4.7.1 → limits-5.0.0rc1}/limits/py.typed +0 -0
  73. {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/acquire_sliding_window.lua +0 -0
  74. {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/clear_keys.lua +0 -0
  75. {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/incr_expire.lua +0 -0
  76. {limits-4.7.1 → limits-5.0.0rc1}/limits/resources/redis/lua_scripts/sliding_window.lua +0 -0
  77. {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/redis_cluster.py +0 -0
  78. {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/redis_sentinel.py +0 -0
  79. {limits-4.7.1 → limits-5.0.0rc1}/limits/storage/registry.py +0 -0
  80. {limits-4.7.1 → limits-5.0.0rc1}/limits/util.py +0 -0
  81. {limits-4.7.1 → limits-5.0.0rc1}/limits/version.py +0 -0
  82. {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/dependency_links.txt +0 -0
  83. {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/not-zip-safe +0 -0
  84. {limits-4.7.1 → limits-5.0.0rc1}/limits.egg-info/top_level.txt +0 -0
  85. {limits-4.7.1 → limits-5.0.0rc1}/pyproject.toml +0 -0
  86. {limits-4.7.1 → limits-5.0.0rc1}/requirements/ci.txt +0 -0
  87. {limits-4.7.1 → limits-5.0.0rc1}/requirements/dev.txt +0 -0
  88. {limits-4.7.1 → limits-5.0.0rc1}/requirements/main.txt +0 -0
  89. {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/async-mongodb.txt +0 -0
  90. {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/async-redis.txt +0 -0
  91. {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/async-valkey.txt +0 -0
  92. {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/memcached.txt +0 -0
  93. {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/mongodb.txt +0 -0
  94. {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/redis.txt +0 -0
  95. {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/rediscluster.txt +0 -0
  96. {limits-4.7.1 → limits-5.0.0rc1}/requirements/storage/valkey.txt +0 -0
  97. {limits-4.7.1 → limits-5.0.0rc1}/tests/test_limit_granularities.py +0 -0
  98. {limits-4.7.1 → limits-5.0.0rc1}/tests/test_limits.py +0 -0
  99. {limits-4.7.1 → limits-5.0.0rc1}/tests/test_ratelimit_parser.py +0 -0
  100. {limits-4.7.1 → limits-5.0.0rc1}/tests/test_utils.py +0 -0
  101. {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: 4.7.1
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: emcache>=0.6.1; python_version < "3.11" and extra == "async-memcached"
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: emcache>=0.6.1; python_version < "3.11" and extra == "all"
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, MongoDB & Etcd).
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, MongoDB & Etcd).
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
@@ -1,7 +1,7 @@
1
1
  .badges {
2
2
  display: flex;
3
3
  padding: 5px;
4
- flex-direction: rootow;
4
+ flex-direction: row;
5
5
  justify-content: center;
6
6
  }
7
7
  .header-badge {
@@ -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
- .. versionadded:: 2.1
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 `emcache <https://emcache.readthedocs.org>`_)
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('ext').resolve()))
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 = '.gp, .go'
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
- "emcache": ("https://emcache.readthedocs.io/en/latest/", None),
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`).then((result) => {
143
- window.Benchmarks[source] = result;
144
- event = new Event(`${source}-loaded`);
145
- window.dispatchEvent(event);
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`).then((result) => {
8
- window.Benchmarks[source] = result;
9
- event = new Event(`${source}-loaded`);
10
- window.dispatchEvent(event);
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 };
@@ -0,0 +1,2 @@
1
+ window.GITBRANCH = "{{branch | replace('.', '-')}}";
2
+ window.GITSHA = "{{sha}}";