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.
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/PKG-INFO +3 -1
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/_version.py +2 -2
- locust-2.43.4.dev10/locust/contrib/qdrant.py +239 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/pyproject.toml +3 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/.gitignore +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/LICENSE +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/README.md +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/hatch_build.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/__init__.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/__main__.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/argument_parser.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/clients.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/__init__.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/dns.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/fasthttp.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/milvus.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/mongodb.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/mqtt.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/oai.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/postgres.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/contrib/socketio.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/debug.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/dispatch.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/env.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/event.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/exception.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/html.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/input_events.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/log.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/main.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/opentelemetry.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/py.typed +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/rpc/__init__.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/rpc/protocol.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/rpc/zmqrpc.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/runners.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/shape.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/stats.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/__init__.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/inspectuser.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/markov_taskset.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/sequential_taskset.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/task.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/users.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/user/wait_time.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/__init__.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/cache.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/date.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/deprecation.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/directory.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/exception_handler.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/load_locustfile.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/rounding.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/timespan.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/util/url.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/web.py +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/favicon-dark.png +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/favicon-light.png +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/graphs-dark.png +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/graphs-light.png +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/index-Bl8icIRq.js +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/terminal.gif +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/testruns-dark.png +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/assets/testruns-light.png +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/auth.html +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/index.html +0 -0
- {locust-2.43.4.dev7 → locust-2.43.4.dev10}/locust/webui/dist/report.html +0 -0
- {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.
|
|
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.
|
|
32
|
-
__version_tuple__ = version_tuple = (2, 43, 4, '
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|