locust 2.43.4.dev7__tar.gz → 2.43.4.dev10__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 (68) hide show
  1. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/PKG-INFO +3 -1
  2. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/_version.py +2 -2
  3. locust-2.43.4.dev10/locust/contrib/qdrant.py +239 -0
  4. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/pyproject.toml +3 -0
  5. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/.gitignore +0 -0
  6. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/LICENSE +0 -0
  7. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/README.md +0 -0
  8. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/hatch_build.py +0 -0
  9. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/__init__.py +0 -0
  10. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/__main__.py +0 -0
  11. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/argument_parser.py +0 -0
  12. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/clients.py +0 -0
  13. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/__init__.py +0 -0
  14. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/dns.py +0 -0
  15. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/fasthttp.py +0 -0
  16. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/milvus.py +0 -0
  17. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/mongodb.py +0 -0
  18. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/mqtt.py +0 -0
  19. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/oai.py +0 -0
  20. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/postgres.py +0 -0
  21. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/socketio.py +0 -0
  22. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/debug.py +0 -0
  23. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/dispatch.py +0 -0
  24. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/env.py +0 -0
  25. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/event.py +0 -0
  26. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/exception.py +0 -0
  27. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/html.py +0 -0
  28. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/input_events.py +0 -0
  29. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/log.py +0 -0
  30. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/main.py +0 -0
  31. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/opentelemetry.py +0 -0
  32. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/py.typed +0 -0
  33. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/rpc/__init__.py +0 -0
  34. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/rpc/protocol.py +0 -0
  35. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/rpc/zmqrpc.py +0 -0
  36. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/runners.py +0 -0
  37. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/shape.py +0 -0
  38. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/stats.py +0 -0
  39. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/__init__.py +0 -0
  40. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/inspectuser.py +0 -0
  41. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/markov_taskset.py +0 -0
  42. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/sequential_taskset.py +0 -0
  43. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/task.py +0 -0
  44. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/users.py +0 -0
  45. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/wait_time.py +0 -0
  46. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/__init__.py +0 -0
  47. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/cache.py +0 -0
  48. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/date.py +0 -0
  49. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/deprecation.py +0 -0
  50. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/directory.py +0 -0
  51. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/exception_handler.py +0 -0
  52. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/load_locustfile.py +0 -0
  53. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/rounding.py +0 -0
  54. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/timespan.py +0 -0
  55. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/url.py +0 -0
  56. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/web.py +0 -0
  57. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/favicon-dark.png +0 -0
  58. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/favicon-light.png +0 -0
  59. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/graphs-dark.png +0 -0
  60. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/graphs-light.png +0 -0
  61. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/index-Bl8icIRq.js +0 -0
  62. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/terminal.gif +0 -0
  63. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/testruns-dark.png +0 -0
  64. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/testruns-light.png +0 -0
  65. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/auth.html +0 -0
  66. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/index.html +0 -0
  67. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/report.html +0 -0
  68. {locust-2.43.4.dev7 → locust-2.43.4.dev10}/pytest_locust/plugin.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: locust
3
- Version: 2.43.4.dev7
3
+ Version: 2.43.4.dev10
4
4
  Summary: Developer-friendly load testing framework
5
5
  Project-URL: homepage, https://locust.io/
6
6
  Project-URL: repository, https://github.com/locustio/locust
@@ -54,6 +54,8 @@ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.38.0; extra == 'otel'
54
54
  Requires-Dist: opentelemetry-instrumentation-requests>=0.59b0; extra == 'otel'
55
55
  Requires-Dist: opentelemetry-instrumentation-urllib3>=0.59b0; extra == 'otel'
56
56
  Requires-Dist: opentelemetry-sdk>=1.38.0; extra == 'otel'
57
+ Provides-Extra: qdrant
58
+ Requires-Dist: qdrant-client>=1.16.2; extra == 'qdrant'
57
59
  Description-Content-Type: text/markdown
58
60
 
59
61
  # Locust
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '2.43.4.dev7'
32
- __version_tuple__ = version_tuple = (2, 43, 4, 'dev7')
31
+ __version__ = version = '2.43.4.dev10'
32
+ __version_tuple__ = version_tuple = (2, 43, 4, 'dev10')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -0,0 +1,239 @@
1
+ from locust import User, events
2
+
3
+ import time
4
+ from typing import Any
5
+
6
+ from qdrant_client import QdrantClient
7
+ from qdrant_client.models import VectorParams
8
+
9
+
10
+ class QdrantLocustClient:
11
+ """Qdrant Client Wrapper"""
12
+
13
+ def __init__(self, url, collection_name, api_key=None, timeout=60, **kwargs):
14
+ self.url = url
15
+ self.collection_name = collection_name
16
+ self.api_key = api_key
17
+ self.timeout = timeout
18
+
19
+ self.client = QdrantClient(
20
+ url=self.url,
21
+ api_key=self.api_key,
22
+ timeout=self.timeout,
23
+ **kwargs,
24
+ )
25
+
26
+ def close(self):
27
+ self.client.close()
28
+
29
+ def create_collection(self, vectors_config, **kwargs):
30
+ if not self.client.collection_exists(collection_name=self.collection_name):
31
+ self.client.create_collection(
32
+ collection_name=self.collection_name,
33
+ vectors_config=vectors_config,
34
+ **kwargs,
35
+ )
36
+
37
+ def upsert(self, points):
38
+ start = time.time()
39
+ try:
40
+ result = self.client.upsert(
41
+ collection_name=self.collection_name,
42
+ points=points,
43
+ )
44
+ total_time = (time.time() - start) * 1000
45
+ return {"success": True, "response_time": total_time, "result": result}
46
+ except Exception as e:
47
+ return {
48
+ "success": False,
49
+ "response_time": (time.time() - start) * 1000,
50
+ "exception": e,
51
+ }
52
+
53
+ def search(
54
+ self,
55
+ query,
56
+ limit=10,
57
+ query_filter=None,
58
+ search_params=None,
59
+ with_payload=True,
60
+ ):
61
+ start = time.time()
62
+ try:
63
+ result = self.client.query_points(
64
+ collection_name=self.collection_name,
65
+ query=query,
66
+ limit=limit,
67
+ query_filter=query_filter,
68
+ search_params=search_params,
69
+ with_payload=with_payload,
70
+ )
71
+ total_time = (time.time() - start) * 1000
72
+ empty = len(result.points) == 0
73
+ return {
74
+ "success": not empty,
75
+ "response_time": total_time,
76
+ "empty": empty,
77
+ "result": result,
78
+ }
79
+ except Exception as e:
80
+ return {
81
+ "success": False,
82
+ "response_time": (time.time() - start) * 1000,
83
+ "exception": e,
84
+ }
85
+
86
+ def scroll(
87
+ self,
88
+ scroll_filter=None,
89
+ limit=10,
90
+ with_payload=True,
91
+ ):
92
+ start = time.time()
93
+ try:
94
+ result, next_offset = self.client.scroll(
95
+ collection_name=self.collection_name,
96
+ scroll_filter=scroll_filter,
97
+ limit=limit,
98
+ with_payload=with_payload,
99
+ )
100
+ total_time = (time.time() - start) * 1000
101
+ empty = len(result) == 0
102
+ return {
103
+ "success": not empty,
104
+ "response_time": total_time,
105
+ "empty": empty,
106
+ "result": result,
107
+ "next_offset": next_offset,
108
+ }
109
+ except Exception as e:
110
+ return {
111
+ "success": False,
112
+ "response_time": (time.time() - start) * 1000,
113
+ "exception": e,
114
+ }
115
+
116
+ def delete(self, points_selector):
117
+ start = time.time()
118
+ try:
119
+ result = self.client.delete(
120
+ collection_name=self.collection_name,
121
+ points_selector=points_selector,
122
+ )
123
+ total_time = (time.time() - start) * 1000
124
+ return {"success": True, "response_time": total_time, "result": result}
125
+ except Exception as e:
126
+ return {
127
+ "success": False,
128
+ "response_time": (time.time() - start) * 1000,
129
+ "exception": e,
130
+ }
131
+
132
+
133
+ # ----------------------------------
134
+ # Locust User wrapper
135
+ # ----------------------------------
136
+
137
+
138
+ class QdrantUser(User):
139
+ """Locust User implementation for Qdrant operations.
140
+
141
+ This class wraps the QdrantLocustClient implementation and translates
142
+ client method results into Locust request events so that performance
143
+ statistics are collected properly.
144
+
145
+ Parameters
146
+ ----------
147
+ host : str
148
+ Qdrant server URL, e.g. ``"http://localhost:6333"``.
149
+ collection_name : str
150
+ The name of the collection to operate on.
151
+ **client_kwargs
152
+ Additional keyword arguments forwarded to the client.
153
+ **collection_kwargs
154
+ Additional keyword arguments forwarded to ``create_collection``.
155
+ """
156
+
157
+ abstract = True
158
+
159
+ url: str = "http://localhost:6333"
160
+ api_key: str | None = None
161
+ collection_name: str | None = None
162
+ timeout: int = 60
163
+ vectors_config: VectorParams | None = None
164
+ client_kwargs: dict | None = None
165
+ collection_kwargs: dict | None = None
166
+
167
+ def __init__(self, environment):
168
+ super().__init__(environment)
169
+
170
+ if self.collection_name is None:
171
+ raise ValueError("'collection_name' must be provided for QdrantUser")
172
+
173
+ self.client_type = "qdrant"
174
+ self.client = QdrantLocustClient(
175
+ url=self.url,
176
+ api_key=self.api_key,
177
+ collection_name=self.collection_name,
178
+ timeout=self.timeout,
179
+ **(self.client_kwargs or {}),
180
+ )
181
+ if self.vectors_config is not None:
182
+ self.client.create_collection(vectors_config=self.vectors_config, **(self.collection_kwargs or {}))
183
+
184
+ @staticmethod
185
+ def _fire_event(request_type: str, name: str, result: dict[str, Any]):
186
+ """Emit a Locust request event from a Qdrant client result dict."""
187
+ response_time = int(result.get("response_time", 0))
188
+ events.request.fire(
189
+ request_type=f"{request_type}",
190
+ name=name,
191
+ response_time=response_time,
192
+ response_length=0,
193
+ exception=result.get("exception"),
194
+ )
195
+
196
+ def upsert(self, points):
197
+ result = self.client.upsert(points)
198
+ self._fire_event(self.client_type, "upsert", result)
199
+ return result
200
+
201
+ def search(
202
+ self,
203
+ query,
204
+ limit=10,
205
+ query_filter=None,
206
+ search_params=None,
207
+ with_payload=True,
208
+ ):
209
+ result = self.client.search(
210
+ query=query,
211
+ limit=limit,
212
+ query_filter=query_filter,
213
+ search_params=search_params,
214
+ with_payload=with_payload,
215
+ )
216
+ self._fire_event(self.client_type, "search", result)
217
+ return result
218
+
219
+ def scroll(
220
+ self,
221
+ scroll_filter=None,
222
+ limit=10,
223
+ with_payload=True,
224
+ ):
225
+ result = self.client.scroll(
226
+ scroll_filter=scroll_filter,
227
+ limit=limit,
228
+ with_payload=with_payload,
229
+ )
230
+ self._fire_event(self.client_type, "scroll", result)
231
+ return result
232
+
233
+ def delete(self, points_selector):
234
+ result = self.client.delete(points_selector)
235
+ self._fire_event(self.client_type, "delete", result)
236
+ return result
237
+
238
+ def on_stop(self):
239
+ self.client.close()
@@ -63,6 +63,7 @@ otel = [
63
63
  "opentelemetry-instrumentation-requests>=0.59b0",
64
64
  "opentelemetry-instrumentation-urllib3>=0.59b0",
65
65
  ]
66
+ qdrant = ["qdrant-client>=1.16.2"]
66
67
 
67
68
  [project.urls]
68
69
  homepage = "https://locust.io/"
@@ -109,6 +110,7 @@ docs = [
109
110
  "pymilvus>=2.5.0",
110
111
  "psycopg[binary]>=3.2.1",
111
112
  "pymongo>=4.8.0",
113
+ "qdrant-client>=1.16.2",
112
114
  ]
113
115
  milvus = ["pymilvus>=2.5.0"]
114
116
  mqtt = ["paho-mqtt>=2.1.0"]
@@ -120,6 +122,7 @@ otel = [
120
122
  "opentelemetry-instrumentation-requests>=0.59b0",
121
123
  "opentelemetry-instrumentation-urllib3>=0.59b0",
122
124
  ]
125
+ qdrant = ["qdrant-client>=1.16.2"]
123
126
 
124
127
  [project.scripts]
125
128
  locust = "locust.main:main"
File without changes
File without changes
File without changes