dsmq 1.3.1__tar.gz → 1.4.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.
- {dsmq-1.3.1 → dsmq-1.4.0}/PKG-INFO +11 -1
- {dsmq-1.3.1 → dsmq-1.4.0}/README.md +10 -0
- dsmq-1.4.0/post.md +244 -0
- {dsmq-1.3.1 → dsmq-1.4.0}/pyproject.toml +1 -1
- dsmq-1.4.0/src/dsmq/.client.py.swp +0 -0
- dsmq-1.4.0/src/dsmq/.server.py.swp +0 -0
- {dsmq-1.3.1 → dsmq-1.4.0}/src/dsmq/client.py +33 -2
- {dsmq-1.3.1 → dsmq-1.4.0}/src/dsmq/demo.py +8 -3
- {dsmq-1.3.1 → dsmq-1.4.0}/src/dsmq/server.py +88 -38
- {dsmq-1.3.1 → dsmq-1.4.0}/src/dsmq/tests/integration_test.py +44 -17
- {dsmq-1.3.1 → dsmq-1.4.0}/src/dsmq/tests/performance_suite.py +11 -2
- dsmq-1.4.0/uv.lock +177 -0
- dsmq-1.3.1/uv.lock +0 -177
- {dsmq-1.3.1 → dsmq-1.4.0}/.gitignore +0 -0
- {dsmq-1.3.1 → dsmq-1.4.0}/.python-version +0 -0
- {dsmq-1.3.1 → dsmq-1.4.0}/LICENSE +0 -0
- {dsmq-1.3.1 → dsmq-1.4.0}/src/dsmq/__init__.py +0 -0
- {dsmq-1.3.1 → dsmq-1.4.0}/src/dsmq/example_get_client.py +0 -0
- {dsmq-1.3.1 → dsmq-1.4.0}/src/dsmq/example_put_client.py +0 -0
- {dsmq-1.3.1 → dsmq-1.4.0}/src/dsmq/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dsmq
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.4.0
|
4
4
|
Summary: A dead simple message queue
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.10
|
@@ -152,6 +152,16 @@ connected to the server.
|
|
152
152
|
in the topic, or the topic doesn't yet exist,
|
153
153
|
returns `""`.
|
154
154
|
|
155
|
+
### `get_latest(topic)`
|
156
|
+
|
157
|
+
Get the *most recent* eligible message from the queue named `topic`.
|
158
|
+
All the messages older than that in the queue become ineligible and never
|
159
|
+
get seen by the client.
|
160
|
+
- `topic` (str)
|
161
|
+
- returns str, the content of the message. If there was no eligble message
|
162
|
+
in the topic, or the topic doesn't yet exist,
|
163
|
+
returns `""`.
|
164
|
+
|
155
165
|
### `get_wait(topic)`
|
156
166
|
|
157
167
|
A variant of `get()` that retries a few times until it gets
|
@@ -142,6 +142,16 @@ connected to the server.
|
|
142
142
|
in the topic, or the topic doesn't yet exist,
|
143
143
|
returns `""`.
|
144
144
|
|
145
|
+
### `get_latest(topic)`
|
146
|
+
|
147
|
+
Get the *most recent* eligible message from the queue named `topic`.
|
148
|
+
All the messages older than that in the queue become ineligible and never
|
149
|
+
get seen by the client.
|
150
|
+
- `topic` (str)
|
151
|
+
- returns str, the content of the message. If there was no eligble message
|
152
|
+
in the topic, or the topic doesn't yet exist,
|
153
|
+
returns `""`.
|
154
|
+
|
145
155
|
### `get_wait(topic)`
|
146
156
|
|
147
157
|
A variant of `get()` that retries a few times until it gets
|
dsmq-1.4.0/post.md
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
# dsmq
|
2
|
+
|
3
|
+
I'd like to introduce [dsmq](https://github.com/brohrer/dsmq),
|
4
|
+
the Dead Simple Message Queue, to the world.
|
5
|
+
|
6
|
+
Part mail room, part bulletin board, dsmq is a central location for sharing messages
|
7
|
+
between processes, even when they are running on different computers.
|
8
|
+
|
9
|
+
Its defining characteristic is bare-bones simplicity.
|
10
|
+
|
11
|
+

|
27
|
+
|
28
|
+
## What dsmq does
|
29
|
+
|
30
|
+
A message queue lets different processes talk to each other, within or across machines.
|
31
|
+
Message queues are a waystation, a place to publish messages and hold them until
|
32
|
+
they get picked up by the process that needs them.
|
33
|
+
|
34
|
+
In dsmq, a program running the message queue starts up first (the server).
|
35
|
+
It handles all the
|
36
|
+
receiving, delivering, sorting, and storing of messages.
|
37
|
+
|
38
|
+
Other programs (the clients) connect to the server. They add messages to a queue
|
39
|
+
or read messages from a queue. Each queue is a separate topic.
|
40
|
+
|
41
|
+
## Why message queues?
|
42
|
+
Message queues are invaluable for distributed systems of all sorts,
|
43
|
+
but my favorite application is robotics.
|
44
|
+
Robots typically have several (or many) processes doing different things at different
|
45
|
+
speeds. Communication between processes is a fundamental part of any moderately
|
46
|
+
complex automated system.
|
47
|
+
When [ROS](https://www.ros.org) (the Robot Operating System) was
|
48
|
+
released, one of the big gifts it gave to robot builders was a reliable way to
|
49
|
+
pass messages.
|
50
|
+
|
51
|
+
## Why another message queue?
|
52
|
+
|
53
|
+
There are lots of [message queues](https://en.wikipedia.org/wiki/Message_queue)
|
54
|
+
in the world, and some are quite well known--Amazon SQS,
|
55
|
+
RabbitMQ, Apache Kafka to name a few. It's fair to ask why this one was created.
|
56
|
+
|
57
|
+
The official reason for dsmq's existence is that all the other available options
|
58
|
+
are pretty heavy. Take RabbitMQ for instance, a popular open source message queue.
|
59
|
+
It has hundreds of associated repositories and it's core
|
60
|
+
[rabbitmq-server](https://github.com/rabbitmq/rabbitmq-server) repo has many thousands
|
61
|
+
of lines of code. It's a heavy lift to import this to support a small robotics project,
|
62
|
+
and code running on small edge devices may struggle to run it at all.
|
63
|
+
|
64
|
+
RabbitMQ is also mature and optimized and dockerized and multi-platform
|
65
|
+
and fully featured and a lot of other things a robot doesn't need. It would
|
66
|
+
be out of balance to use it for a small project.
|
67
|
+
|
68
|
+

|
71
|
+
|
72
|
+
dsmq is only about 200 lines of Python, including client and server code. It's *tiny*.
|
73
|
+
Good for reading and understanding front-to-back when you're integrating it with
|
74
|
+
your project.
|
75
|
+
|
76
|
+
But the real reason is that I wanted to understand how a message queue might work
|
77
|
+
and the best way I know to learn this is to build one.
|
78
|
+
|
79
|
+
## How to use dsmq
|
80
|
+
|
81
|
+
### Install it
|
82
|
+
|
83
|
+
```
|
84
|
+
pip install dsmq
|
85
|
+
```
|
86
|
+
or
|
87
|
+
```
|
88
|
+
uv add dsmq
|
89
|
+
```
|
90
|
+
|
91
|
+
### Spin up a dsmq server
|
92
|
+
|
93
|
+
```python
|
94
|
+
from dsmq import dsmq
|
95
|
+
dsmq.start_server(host="127.0.0.1", port=12345)
|
96
|
+
```
|
97
|
+
|
98
|
+
### Connect a client to a dsmq server
|
99
|
+
|
100
|
+
```python
|
101
|
+
mq = dsmq.connect_to_server(host="127.0.0.1", port=12345)
|
102
|
+
```
|
103
|
+
|
104
|
+
### Add a message to a topic queue
|
105
|
+
|
106
|
+
```python
|
107
|
+
topic = "greetings"
|
108
|
+
msg = "hello world!"
|
109
|
+
mq.put(topic, msg)
|
110
|
+
```
|
111
|
+
|
112
|
+
### Read a message from a topic queue
|
113
|
+
|
114
|
+
```python
|
115
|
+
topic = "greetings"
|
116
|
+
msg = mq.get(topic)
|
117
|
+
```
|
118
|
+
|
119
|
+
### Run a demo
|
120
|
+
|
121
|
+
0. Open 3 separate terminal windows.
|
122
|
+
1. In the first, run `src/dsmq/dsmq.py`.
|
123
|
+
2. In the second, run `src/dsmq/example_put_client.py`.
|
124
|
+
3. In the third, run `src/dsmq/example_get_client.py`.
|
125
|
+
|
126
|
+
Alternatively, if you're on Linux just run `src/dsmq/demo_linux.py`.
|
127
|
+
(Linux has some process forking capabilities that Windows doesn't and
|
128
|
+
that macOS forbids. It makes for a nice self-contained multiprocess demo.)
|
129
|
+
|
130
|
+
## How it works
|
131
|
+
|
132
|
+
- Many clients can read messages from the same topic queue. dsmq uses a one-to-many
|
133
|
+
publication model.
|
134
|
+
|
135
|
+
- A client will get the oldest message available on a requested topic.
|
136
|
+
Queues are first-in-first-out.
|
137
|
+
|
138
|
+
- Clients will only be able to get messages that were added to a queue after the
|
139
|
+
time they connected to the server. Any messages older that that won't be visible.
|
140
|
+
|
141
|
+
- dsmq is asyncronous. There are no guarantees about how soon a message will arrive
|
142
|
+
at its intended client.
|
143
|
+
|
144
|
+
- dsmq is backed by an in-memory SQLite database. If your message volumes
|
145
|
+
get larger than your RAM, you will reach an out-of-memory condition.
|
146
|
+
```python
|
147
|
+
sqlite_conn = sqlite3.connect("file:mem1?mode=memory&cache=shared")
|
148
|
+
```
|
149
|
+
- `put()` and `get()` operations are fairly quick--less than 100 $`\mu`$s of processing
|
150
|
+
time plus any network latency--so it can comfortably handle requests at rates of
|
151
|
+
hundreds of times per second. But if you have several clients reading and writing
|
152
|
+
at 1 kHz or more, you may overload the queue.
|
153
|
+
|
154
|
+
- A client will not be able to read any of the messages that were put into
|
155
|
+
a queue before it connected.
|
156
|
+
|
157
|
+
- Messages older than 600 seconds will be deleted from the queue.
|
158
|
+
- In case of contention for the lock on the database, failed queries will be
|
159
|
+
retried several times, with exponential backoff. None of this is visible to
|
160
|
+
the clients, but it helps keep the internal operations reliable.
|
161
|
+
|
162
|
+
```python
|
163
|
+
for i_retry in range(_n_retries):
|
164
|
+
try:
|
165
|
+
cursor.execute("""...
|
166
|
+
```
|
167
|
+
|
168
|
+
- To keep things bare bones, the connections are all implemented in the
|
169
|
+
socket layer, rather than WebSockets or http in the application layer.
|
170
|
+
```python
|
171
|
+
self.dsmq_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
172
|
+
self.dsmq_conn.connect((host, port))
|
173
|
+
```
|
174
|
+
- ...however, working on this lower level meant dsmq had to reinvent the wheel of
|
175
|
+
message headers. Each dsmq message is sent with a header that tells it exactly
|
176
|
+
how many bytes to expect in it. The header format is simplistic--a message
|
177
|
+
with one million plus the number of byes in the following message. Doing it this
|
178
|
+
way means that the header is
|
179
|
+
exactly 23 bytes long every time. (As long as the message is less than nine million
|
180
|
+
bytes long.)
|
181
|
+
|
182
|
+
- Every time a new client connects to the server, a new thread is created.
|
183
|
+
That thread listens for any `get()` or `put()` requests the client might make
|
184
|
+
and handles them immediately.
|
185
|
+
```python
|
186
|
+
Thread(target=_handle_client_connection, args=(socket_conn,)).start()
|
187
|
+
```
|
188
|
+
|
189
|
+
- dsmq retrieves the oldest eligible message from the queue. If a client wants
|
190
|
+
to ensure it is getting the most recent message from the queue, it will need
|
191
|
+
to iteratively get messages until there are no more left to be gotten.
|
192
|
+
```python
|
193
|
+
msg_str = "<no response>"
|
194
|
+
response = None
|
195
|
+
while response != "":
|
196
|
+
msg_str = response
|
197
|
+
response = self.mq.get("<topic>")
|
198
|
+
```
|
199
|
+
|
200
|
+
- dsmq messages are text fields, but Python dictionaries are a very convenient and
|
201
|
+
common format for passing structured messages. Use the `json` library to convert
|
202
|
+
from dictionaries to strings and back.
|
203
|
+
```python
|
204
|
+
topic = "update"
|
205
|
+
msg_dict = {"timestep": 374, "value": 3.897}
|
206
|
+
msg_str = json.dumps(msg_dict)
|
207
|
+
dsmq.put(topic, msg_str)
|
208
|
+
|
209
|
+
msg_str = dsmq.get(topic)
|
210
|
+
msg_dict = json.loads(msg_str)
|
211
|
+
```
|
212
|
+
|
213
|
+
- dsmq is opinionated. Parameters for controlling behavior are set to reasonable
|
214
|
+
defaults and not exposed to the user. The additional complexity in the API is
|
215
|
+
not worth the value of making them user-controlled.
|
216
|
+
However they are also clearly labeled and very easy to find. If anyone cares enough to
|
217
|
+
play with them, they are strongly encouraged to fork dsmq and make it their own.
|
218
|
+
|
219
|
+
```python
|
220
|
+
_message_length_offset = 1_000_000
|
221
|
+
_header_length = 23
|
222
|
+
_n_retries = 5
|
223
|
+
_first_retry = 0.01 # seconds
|
224
|
+
_time_to_live = 600.0 # seconds
|
225
|
+
```
|
226
|
+
|
227
|
+
- dsmq is deliberately built to have as few dependencies as it can get away with.
|
228
|
+
As of this writing, it doesn't depend on any third party packages and just a handful
|
229
|
+
of core packages: `json`, `socket`, `sqlite3`, `sys`, and `threading`.
|
230
|
+
|
231
|
+
# Dead Simple
|
232
|
+
|
233
|
+
Dead simple is an aesthetic.
|
234
|
+
It says that the ideal is achieved not when nothing more can be added,
|
235
|
+
but when nothing more can be taken away.
|
236
|
+
It is the aims to follow the apocryphal advice of Albert Einstein, to make
|
237
|
+
a thing as simple as possible, but no simpler.
|
238
|
+
|
239
|
+
Dead simple is like keystroke golfing, but instead of minimizing the number of
|
240
|
+
characters, it minimizes the number of concepts a developer or a user
|
241
|
+
has to hold in their head.
|
242
|
+
|
243
|
+
I've tried to embody it in dsmq.
|
244
|
+
dsmq has fewer lines of code than RabbitMQ has *repositories*. And that tickles me.
|
Binary file
|
Binary file
|
@@ -18,6 +18,7 @@ def connect(host=_default_host, port=_default_port, verbose=False):
|
|
18
18
|
class DSMQClientSideConnection:
|
19
19
|
def __init__(self, host, port, verbose=False):
|
20
20
|
self.uri = f"ws://{host}:{port}"
|
21
|
+
self.port = port
|
21
22
|
self.verbose = verbose
|
22
23
|
if self.verbose:
|
23
24
|
print(f"Connecting to dsmq server at {self.uri}")
|
@@ -40,7 +41,11 @@ class DSMQClientSideConnection:
|
|
40
41
|
|
41
42
|
def get(self, topic):
|
42
43
|
msg = {"action": "get", "topic": topic}
|
43
|
-
|
44
|
+
try:
|
45
|
+
self.websocket.send(json.dumps(msg))
|
46
|
+
except ConnectionClosedError:
|
47
|
+
return ""
|
48
|
+
|
44
49
|
try:
|
45
50
|
msg_text = self.websocket.recv()
|
46
51
|
except ConnectionClosedError:
|
@@ -50,6 +55,29 @@ class DSMQClientSideConnection:
|
|
50
55
|
msg = json.loads(msg_text)
|
51
56
|
return msg["message"]
|
52
57
|
|
58
|
+
def get_latest(self, topic):
|
59
|
+
"""
|
60
|
+
A variant of `get()` that grabs the latest available message
|
61
|
+
(if there is one) rather than grabbing the oldest unread message.
|
62
|
+
It will not go back to read older ones on subsequent calls;
|
63
|
+
it will leave them unread.
|
64
|
+
"""
|
65
|
+
msg = {"action": "get_latest", "topic": topic}
|
66
|
+
try:
|
67
|
+
self.websocket.send(json.dumps(msg))
|
68
|
+
except ConnectionClosedError:
|
69
|
+
return ""
|
70
|
+
|
71
|
+
try:
|
72
|
+
msg_text = self.websocket.recv()
|
73
|
+
except ConnectionClosedError:
|
74
|
+
self.close()
|
75
|
+
return ""
|
76
|
+
|
77
|
+
msg = json.loads(msg_text)
|
78
|
+
|
79
|
+
return msg["message"]
|
80
|
+
|
53
81
|
def get_wait(self, topic):
|
54
82
|
"""
|
55
83
|
A variant of `get()` that retries a few times until it gets
|
@@ -65,7 +93,10 @@ class DSMQClientSideConnection:
|
|
65
93
|
|
66
94
|
def put(self, topic, msg_body):
|
67
95
|
msg_dict = {"action": "put", "topic": topic, "message": msg_body}
|
68
|
-
|
96
|
+
try:
|
97
|
+
self.websocket.send(json.dumps(msg_dict))
|
98
|
+
except ConnectionClosedError:
|
99
|
+
return
|
69
100
|
|
70
101
|
def shutdown_server(self):
|
71
102
|
msg_dict = {"action": "shutdown", "topic": ""}
|
@@ -1,7 +1,12 @@
|
|
1
1
|
import multiprocessing as mp
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
|
3
|
+
# spawn is the default method on macOS,
|
4
|
+
# starting in Python 3.14 it will be the default in Linux too.
|
5
|
+
mp.set_start_method("spawn")
|
6
|
+
|
7
|
+
from dsmq.server import serve # noqa: E402
|
8
|
+
import dsmq.example_get_client # noqa: E402
|
9
|
+
import dsmq.example_put_client # noqa: E402
|
5
10
|
|
6
11
|
HOST = "127.0.0.1"
|
7
12
|
PORT = 25252
|
@@ -9,10 +9,10 @@ from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK
|
|
9
9
|
|
10
10
|
_default_host = "127.0.0.1"
|
11
11
|
_default_port = 30008
|
12
|
-
_n_retries = 20
|
13
|
-
_first_retry = 0.005 # seconds
|
14
|
-
_time_between_cleanup = 0.05 # seconds
|
15
12
|
_max_queue_length = 10
|
13
|
+
_shutdown_pause = 1.0 # seconds
|
14
|
+
_time_between_cleanup = 3.0 # seconds
|
15
|
+
_time_to_keep = 0.3 # seconds
|
16
16
|
|
17
17
|
# Make this global so it's easy to share
|
18
18
|
dsmq_server = None
|
@@ -42,7 +42,11 @@ def serve(
|
|
42
42
|
# and keep long-term latency more predictable.
|
43
43
|
# These also make it more susceptible to corruption during shutdown,
|
44
44
|
# but since dsmq is meant to be ephemeral, that's not a concern.
|
45
|
+
# See https://www.sqlite.org/pragma.html
|
46
|
+
#
|
45
47
|
cursor.execute("PRAGMA journal_mode = OFF")
|
48
|
+
# cursor.execute("PRAGMA journal_mode = MEMORY")
|
49
|
+
# cursor.execute("PRAGMA synchronous = NORMAL")
|
46
50
|
cursor.execute("PRAGMA synchronous = OFF")
|
47
51
|
cursor.execute("PRAGMA secure_delete = OFF")
|
48
52
|
cursor.execute("PRAGMA temp_store = MEMORY")
|
@@ -56,36 +60,33 @@ CREATE TABLE IF NOT EXISTS messages (timestamp DOUBLE, topic TEXT, message TEXT)
|
|
56
60
|
# and a method of last resort.
|
57
61
|
global dsmq_server
|
58
62
|
|
59
|
-
|
60
|
-
|
63
|
+
try:
|
64
|
+
with ws_serve(request_handler, host, port) as dsmq_server:
|
65
|
+
dsmq_server.serve_forever()
|
66
|
+
|
67
|
+
except OSError:
|
68
|
+
# Catch the case where the address is already in use
|
69
|
+
if verbose:
|
70
|
+
print()
|
71
|
+
print(f"Found a dsmq server already running on {host} on port {port}.")
|
72
|
+
print(" Closing it down.")
|
73
|
+
|
74
|
+
def shutdown_gracefully(server_to_shutdown):
|
75
|
+
server_to_shutdown.shutdown()
|
76
|
+
|
77
|
+
Thread(target=shutdown_gracefully, args=(dsmq_server,)).start()
|
78
|
+
time.sleep(_shutdown_pause)
|
79
|
+
|
61
80
|
with ws_serve(request_handler, host, port) as dsmq_server:
|
62
81
|
dsmq_server.serve_forever()
|
63
82
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
break
|
70
|
-
|
71
|
-
except OSError:
|
72
|
-
# Catch the case where the address is already in use
|
73
|
-
if verbose:
|
74
|
-
print()
|
75
|
-
if i_retry < _n_retries - 1:
|
76
|
-
print(f"Couldn't start dsmq server on {host} on port {port}.")
|
77
|
-
print(f" Trying again ({i_retry}) ...")
|
78
|
-
else:
|
79
|
-
print()
|
80
|
-
print(f"Failed to start dsmq server on {host} on port {port}.")
|
81
|
-
print()
|
82
|
-
raise
|
83
|
-
|
84
|
-
wait_time = _first_retry * 2**i_retry
|
85
|
-
time.sleep(wait_time)
|
83
|
+
if verbose:
|
84
|
+
print()
|
85
|
+
print(f"Server started at {host} on port {port}.")
|
86
|
+
print("Waiting for clients...")
|
86
87
|
|
87
88
|
sqlite_conn.close()
|
88
|
-
time.sleep(
|
89
|
+
time.sleep(_shutdown_pause)
|
89
90
|
cleanup_temp_files()
|
90
91
|
|
91
92
|
|
@@ -121,9 +122,10 @@ def request_handler(websocket):
|
|
121
122
|
for msg_text in websocket:
|
122
123
|
msg = json.loads(msg_text)
|
123
124
|
topic = msg["topic"]
|
125
|
+
action = msg["action"]
|
124
126
|
timestamp = time.time()
|
125
127
|
|
126
|
-
if
|
128
|
+
if action == "put":
|
127
129
|
msg["timestamp"] = timestamp
|
128
130
|
|
129
131
|
try:
|
@@ -138,7 +140,7 @@ def request_handler(websocket):
|
|
138
140
|
except sqlite3.OperationalError:
|
139
141
|
pass
|
140
142
|
|
141
|
-
elif
|
143
|
+
elif action == "get":
|
142
144
|
try:
|
143
145
|
last_read_time = last_read_times[topic]
|
144
146
|
except KeyError:
|
@@ -151,15 +153,46 @@ def request_handler(websocket):
|
|
151
153
|
"""
|
152
154
|
SELECT message,
|
153
155
|
timestamp
|
154
|
-
FROM messages,
|
155
|
-
(
|
156
|
-
SELECT MIN(timestamp) AS min_time
|
157
156
|
FROM messages
|
158
157
|
WHERE topic = :topic
|
159
158
|
AND timestamp > :last_read_time
|
160
|
-
|
159
|
+
ORDER BY timestamp ASC
|
160
|
+
LIMIT 1
|
161
|
+
""",
|
162
|
+
msg,
|
163
|
+
)
|
164
|
+
except sqlite3.OperationalError:
|
165
|
+
pass
|
166
|
+
|
167
|
+
try:
|
168
|
+
result = cursor.fetchall()[0]
|
169
|
+
message = result[0]
|
170
|
+
timestamp = result[1]
|
171
|
+
last_read_times[topic] = timestamp
|
172
|
+
except IndexError:
|
173
|
+
# Handle the case where no results are returned
|
174
|
+
message = ""
|
175
|
+
|
176
|
+
websocket.send(json.dumps({"message": message}))
|
177
|
+
|
178
|
+
elif action == "get_latest":
|
179
|
+
try:
|
180
|
+
last_read_time = last_read_times[topic]
|
181
|
+
except KeyError:
|
182
|
+
last_read_times[topic] = client_creation_time
|
183
|
+
last_read_time = last_read_times[topic]
|
184
|
+
msg["last_read_time"] = last_read_time
|
185
|
+
|
186
|
+
try:
|
187
|
+
cursor.execute(
|
188
|
+
"""
|
189
|
+
SELECT message,
|
190
|
+
timestamp
|
191
|
+
FROM messages
|
161
192
|
WHERE topic = :topic
|
162
|
-
AND timestamp
|
193
|
+
AND timestamp > :last_read_time
|
194
|
+
ORDER BY timestamp DESC
|
195
|
+
LIMIT 1;
|
163
196
|
""",
|
164
197
|
msg,
|
165
198
|
)
|
@@ -177,25 +210,41 @@ def request_handler(websocket):
|
|
177
210
|
|
178
211
|
websocket.send(json.dumps({"message": message}))
|
179
212
|
|
180
|
-
elif
|
213
|
+
elif action == "shutdown":
|
181
214
|
# Run this from a separate thread to prevent deadlock
|
182
215
|
global dsmq_server
|
183
216
|
|
184
217
|
def shutdown_gracefully(server_to_shutdown):
|
185
218
|
server_to_shutdown.shutdown()
|
186
|
-
# cleanup_temp_files()
|
187
219
|
|
188
220
|
Thread(target=shutdown_gracefully, args=(dsmq_server,)).start()
|
189
221
|
break
|
190
222
|
else:
|
191
223
|
raise RuntimeWarning(
|
192
|
-
"dsmq client action must either be
|
224
|
+
"dsmq client action must either be\n"
|
225
|
+
+ "'put', 'get', 'get_wait', 'get_latest', or 'shutdown'"
|
193
226
|
)
|
194
227
|
|
195
228
|
# Periodically clean out messages to keep individual queues at
|
196
229
|
# a manageable length and the overall mq small.
|
197
230
|
if time.time() - time_of_last_purge > _time_between_cleanup:
|
231
|
+
cutoff_time = time.time() - _time_to_keep
|
198
232
|
try:
|
233
|
+
cursor.execute(
|
234
|
+
"""
|
235
|
+
DELETE
|
236
|
+
FROM messages
|
237
|
+
WHERE topic = :topic
|
238
|
+
AND timestamp < :cutoff_time
|
239
|
+
""",
|
240
|
+
{
|
241
|
+
"cutoff_time": cutoff_time,
|
242
|
+
"topic": topic,
|
243
|
+
},
|
244
|
+
)
|
245
|
+
sqlite_conn.commit()
|
246
|
+
time_of_last_purge = time.time()
|
247
|
+
|
199
248
|
cursor.execute(
|
200
249
|
"""
|
201
250
|
DELETE
|
@@ -219,6 +268,7 @@ def request_handler(websocket):
|
|
219
268
|
)
|
220
269
|
sqlite_conn.commit()
|
221
270
|
time_of_last_purge = time.time()
|
271
|
+
|
222
272
|
except sqlite3.OperationalError:
|
223
273
|
# Database may be locked. Try again next time.
|
224
274
|
pass
|
@@ -1,10 +1,17 @@
|
|
1
1
|
import multiprocessing as mp
|
2
|
+
|
3
|
+
try:
|
4
|
+
# spawn is the default method on macOS,
|
5
|
+
# starting in Python 3.14 it will be the default in Linux too.
|
6
|
+
mp.set_start_method("spawn")
|
7
|
+
except RuntimeError:
|
8
|
+
# Will throw an error if the start method has alraedy been set.
|
9
|
+
pass
|
10
|
+
|
2
11
|
import time
|
3
12
|
from dsmq.server import serve
|
4
13
|
from dsmq.client import connect
|
5
14
|
|
6
|
-
# spawn is the default method on macOS
|
7
|
-
# mp.set_start_method('spawn')
|
8
15
|
|
9
16
|
host = "127.0.0.1"
|
10
17
|
port = 30303
|
@@ -53,6 +60,10 @@ def test_write_one_read_one():
|
|
53
60
|
write_client = connect(host, port)
|
54
61
|
read_client = connect(host, port)
|
55
62
|
|
63
|
+
msg = read_client.get("test")
|
64
|
+
|
65
|
+
assert msg == ""
|
66
|
+
|
56
67
|
write_client.put("test", "test_msg")
|
57
68
|
|
58
69
|
# It takes a moment for the write to complete
|
@@ -61,6 +72,10 @@ def test_write_one_read_one():
|
|
61
72
|
|
62
73
|
assert msg == "test_msg"
|
63
74
|
|
75
|
+
msg = read_client.get("test")
|
76
|
+
|
77
|
+
assert msg == ""
|
78
|
+
|
64
79
|
write_client.shutdown_server()
|
65
80
|
write_client.close()
|
66
81
|
read_client.close()
|
@@ -83,6 +98,29 @@ def test_get_wait():
|
|
83
98
|
read_client.close()
|
84
99
|
|
85
100
|
|
101
|
+
def test_get_latest():
|
102
|
+
p_server = mp.Process(target=serve, args=(host, port))
|
103
|
+
p_server.start()
|
104
|
+
write_client = connect(host, port)
|
105
|
+
read_client = connect(host, port)
|
106
|
+
|
107
|
+
for i in range(5):
|
108
|
+
write_client.put("test", f"test_msg {i}")
|
109
|
+
|
110
|
+
time.sleep(_pause)
|
111
|
+
msg = read_client.get_latest("test")
|
112
|
+
|
113
|
+
assert msg == "test_msg 4"
|
114
|
+
|
115
|
+
msg = read_client.get_latest("test")
|
116
|
+
|
117
|
+
assert msg == ""
|
118
|
+
|
119
|
+
write_client.shutdown_server()
|
120
|
+
write_client.close()
|
121
|
+
read_client.close()
|
122
|
+
|
123
|
+
|
86
124
|
def test_multitopics():
|
87
125
|
p_server = mp.Process(target=serve, args=(host, port))
|
88
126
|
p_server.start()
|
@@ -183,15 +221,8 @@ def test_speed_writing():
|
|
183
221
|
p_speed_write.start()
|
184
222
|
time.sleep(_pause)
|
185
223
|
|
186
|
-
# time_a = time.time()
|
187
224
|
write_client.put("test", "test_msg")
|
188
|
-
# time_b = time.time()
|
189
225
|
msg = read_client.get_wait("test")
|
190
|
-
# time_c = time.time()
|
191
|
-
|
192
|
-
# write_time = int((time_b - time_a) * 1e6)
|
193
|
-
# read_time = int((time_c - time_b) * 1e6)
|
194
|
-
# print(f"write time: {write_time} us, read time: {read_time} us")
|
195
226
|
|
196
227
|
assert msg == "test_msg"
|
197
228
|
|
@@ -221,15 +252,8 @@ def test_speed_reading():
|
|
221
252
|
p_speed_read = mp.Process(target=speed_read, args=(stop_flag,))
|
222
253
|
p_speed_read.start()
|
223
254
|
|
224
|
-
# time_a = time.time()
|
225
255
|
write_client.put("test", "test_msg")
|
226
|
-
# time_b = time.time()
|
227
256
|
msg = read_client.get_wait("test")
|
228
|
-
# time_c = time.time()
|
229
|
-
|
230
|
-
# write_time = int((time_b - time_a) * 1e6)
|
231
|
-
# read_time = int((time_c - time_b) * 1e6)
|
232
|
-
# print(f"write time: {write_time} us, read time: {read_time} us")
|
233
257
|
|
234
258
|
assert msg == "test_msg"
|
235
259
|
|
@@ -238,5 +262,8 @@ def test_speed_reading():
|
|
238
262
|
p_speed_read.kill()
|
239
263
|
read_client.close()
|
240
264
|
write_client.shutdown_server()
|
241
|
-
# time.sleep(_pause)
|
242
265
|
write_client.close()
|
266
|
+
|
267
|
+
|
268
|
+
if __name__ == "__main__":
|
269
|
+
test_get_latest()
|
@@ -1,4 +1,13 @@
|
|
1
1
|
import multiprocessing as mp
|
2
|
+
|
3
|
+
# spawn is the default method on macOS,
|
4
|
+
# starting in Python 3.14 it will be the default in Linux too.
|
5
|
+
try:
|
6
|
+
mp.set_start_method("spawn")
|
7
|
+
except RuntimeError as e:
|
8
|
+
print(e)
|
9
|
+
print(f"Using multiprocessing start method: {mp.get_start_method()}")
|
10
|
+
|
2
11
|
import time
|
3
12
|
|
4
13
|
from dsmq.server import serve
|
@@ -11,8 +20,8 @@ verbose = False
|
|
11
20
|
_pause = 0.01
|
12
21
|
_very_long_pause = 1.0
|
13
22
|
|
14
|
-
_n_iter = int(
|
15
|
-
_n_long_char = int(
|
23
|
+
_n_iter = int(1e4)
|
24
|
+
_n_long_char = int(1e5)
|
16
25
|
|
17
26
|
_short_msg = "q"
|
18
27
|
_long_msg = str(["q"] * _n_long_char)
|
dsmq-1.4.0/uv.lock
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
version = 1
|
2
|
+
requires-python = ">=3.10"
|
3
|
+
|
4
|
+
[[package]]
|
5
|
+
name = "colorama"
|
6
|
+
version = "0.4.6"
|
7
|
+
source = { registry = "https://pypi.org/simple" }
|
8
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
|
9
|
+
wheels = [
|
10
|
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
|
11
|
+
]
|
12
|
+
|
13
|
+
[[package]]
|
14
|
+
name = "dsmq"
|
15
|
+
version = "1.4.0"
|
16
|
+
source = { editable = "." }
|
17
|
+
dependencies = [
|
18
|
+
{ name = "pytest" },
|
19
|
+
{ name = "websockets" },
|
20
|
+
]
|
21
|
+
|
22
|
+
[package.metadata]
|
23
|
+
requires-dist = [
|
24
|
+
{ name = "pytest", specifier = ">=8.3.4" },
|
25
|
+
{ name = "websockets", specifier = ">=14.1" },
|
26
|
+
]
|
27
|
+
|
28
|
+
[[package]]
|
29
|
+
name = "exceptiongroup"
|
30
|
+
version = "1.2.2"
|
31
|
+
source = { registry = "https://pypi.org/simple" }
|
32
|
+
sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
|
33
|
+
wheels = [
|
34
|
+
{ url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
|
35
|
+
]
|
36
|
+
|
37
|
+
[[package]]
|
38
|
+
name = "iniconfig"
|
39
|
+
version = "2.0.0"
|
40
|
+
source = { registry = "https://pypi.org/simple" }
|
41
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
|
42
|
+
wheels = [
|
43
|
+
{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
|
44
|
+
]
|
45
|
+
|
46
|
+
[[package]]
|
47
|
+
name = "packaging"
|
48
|
+
version = "24.2"
|
49
|
+
source = { registry = "https://pypi.org/simple" }
|
50
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 }
|
51
|
+
wheels = [
|
52
|
+
{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 },
|
53
|
+
]
|
54
|
+
|
55
|
+
[[package]]
|
56
|
+
name = "pluggy"
|
57
|
+
version = "1.5.0"
|
58
|
+
source = { registry = "https://pypi.org/simple" }
|
59
|
+
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
|
60
|
+
wheels = [
|
61
|
+
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
|
62
|
+
]
|
63
|
+
|
64
|
+
[[package]]
|
65
|
+
name = "pytest"
|
66
|
+
version = "8.3.5"
|
67
|
+
source = { registry = "https://pypi.org/simple" }
|
68
|
+
dependencies = [
|
69
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
70
|
+
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
71
|
+
{ name = "iniconfig" },
|
72
|
+
{ name = "packaging" },
|
73
|
+
{ name = "pluggy" },
|
74
|
+
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
75
|
+
]
|
76
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 }
|
77
|
+
wheels = [
|
78
|
+
{ url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 },
|
79
|
+
]
|
80
|
+
|
81
|
+
[[package]]
|
82
|
+
name = "tomli"
|
83
|
+
version = "2.2.1"
|
84
|
+
source = { registry = "https://pypi.org/simple" }
|
85
|
+
sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 }
|
86
|
+
wheels = [
|
87
|
+
{ url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 },
|
88
|
+
{ url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 },
|
89
|
+
{ url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 },
|
90
|
+
{ url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 },
|
91
|
+
{ url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 },
|
92
|
+
{ url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 },
|
93
|
+
{ url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 },
|
94
|
+
{ url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 },
|
95
|
+
{ url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 },
|
96
|
+
{ url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 },
|
97
|
+
{ url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 },
|
98
|
+
{ url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 },
|
99
|
+
{ url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 },
|
100
|
+
{ url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 },
|
101
|
+
{ url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 },
|
102
|
+
{ url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 },
|
103
|
+
{ url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 },
|
104
|
+
{ url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 },
|
105
|
+
{ url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 },
|
106
|
+
{ url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 },
|
107
|
+
{ url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 },
|
108
|
+
{ url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 },
|
109
|
+
{ url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 },
|
110
|
+
{ url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 },
|
111
|
+
{ url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 },
|
112
|
+
{ url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 },
|
113
|
+
{ url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 },
|
114
|
+
{ url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 },
|
115
|
+
{ url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 },
|
116
|
+
{ url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 },
|
117
|
+
{ url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 },
|
118
|
+
]
|
119
|
+
|
120
|
+
[[package]]
|
121
|
+
name = "websockets"
|
122
|
+
version = "14.1"
|
123
|
+
source = { registry = "https://pypi.org/simple" }
|
124
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f4/1b/380b883ce05bb5f45a905b61790319a28958a9ab1e4b6b95ff5464b60ca1/websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8", size = 162840 }
|
125
|
+
wheels = [
|
126
|
+
{ url = "https://files.pythonhosted.org/packages/af/91/b1b375dbd856fd5fff3f117de0e520542343ecaf4e8fc60f1ac1e9f5822c/websockets-14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a0adf84bc2e7c86e8a202537b4fd50e6f7f0e4a6b6bf64d7ccb96c4cd3330b29", size = 161950 },
|
127
|
+
{ url = "https://files.pythonhosted.org/packages/61/8f/4d52f272d3ebcd35e1325c646e98936099a348374d4a6b83b524bded8116/websockets-14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90b5d9dfbb6d07a84ed3e696012610b6da074d97453bd01e0e30744b472c8179", size = 159601 },
|
128
|
+
{ url = "https://files.pythonhosted.org/packages/c4/b1/29e87b53eb1937992cdee094a0988aadc94f25cf0b37e90c75eed7123d75/websockets-14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2177ee3901075167f01c5e335a6685e71b162a54a89a56001f1c3e9e3d2ad250", size = 159854 },
|
129
|
+
{ url = "https://files.pythonhosted.org/packages/3f/e6/752a2f5e8321ae2a613062676c08ff2fccfb37dc837a2ee919178a372e8a/websockets-14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f14a96a0034a27f9d47fd9788913924c89612225878f8078bb9d55f859272b0", size = 168835 },
|
130
|
+
{ url = "https://files.pythonhosted.org/packages/60/27/ca62de7877596926321b99071639275e94bb2401397130b7cf33dbf2106a/websockets-14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f874ba705deea77bcf64a9da42c1f5fc2466d8f14daf410bc7d4ceae0a9fcb0", size = 167844 },
|
131
|
+
{ url = "https://files.pythonhosted.org/packages/7e/db/f556a1d06635c680ef376be626c632e3f2bbdb1a0189d1d1bffb061c3b70/websockets-14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9607b9a442392e690a57909c362811184ea429585a71061cd5d3c2b98065c199", size = 168157 },
|
132
|
+
{ url = "https://files.pythonhosted.org/packages/b3/bc/99e5f511838c365ac6ecae19674eb5e94201aa4235bd1af3e6fa92c12905/websockets-14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bea45f19b7ca000380fbd4e02552be86343080120d074b87f25593ce1700ad58", size = 168561 },
|
133
|
+
{ url = "https://files.pythonhosted.org/packages/c6/e7/251491585bad61c79e525ac60927d96e4e17b18447cc9c3cfab47b2eb1b8/websockets-14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:219c8187b3ceeadbf2afcf0f25a4918d02da7b944d703b97d12fb01510869078", size = 167979 },
|
134
|
+
{ url = "https://files.pythonhosted.org/packages/ac/98/7ac2e4eeada19bdbc7a3a66a58e3ebdf33648b9e1c5b3f08c3224df168cf/websockets-14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad2ab2547761d79926effe63de21479dfaf29834c50f98c4bf5b5480b5838434", size = 167925 },
|
135
|
+
{ url = "https://files.pythonhosted.org/packages/ab/3d/09e65c47ee2396b7482968068f6e9b516221e1032b12dcf843b9412a5dfb/websockets-14.1-cp310-cp310-win32.whl", hash = "sha256:1288369a6a84e81b90da5dbed48610cd7e5d60af62df9851ed1d1d23a9069f10", size = 162831 },
|
136
|
+
{ url = "https://files.pythonhosted.org/packages/8a/67/59828a3d09740e6a485acccfbb66600632f2178b6ed1b61388ee96f17d5a/websockets-14.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0744623852f1497d825a49a99bfbec9bea4f3f946df6eb9d8a2f0c37a2fec2e", size = 163266 },
|
137
|
+
{ url = "https://files.pythonhosted.org/packages/97/ed/c0d03cb607b7fe1f7ff45e2cd4bb5cd0f9e3299ced79c2c303a6fff44524/websockets-14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:449d77d636f8d9c17952628cc7e3b8faf6e92a17ec581ec0c0256300717e1512", size = 161949 },
|
138
|
+
{ url = "https://files.pythonhosted.org/packages/06/91/bf0a44e238660d37a2dda1b4896235d20c29a2d0450f3a46cd688f43b239/websockets-14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a35f704be14768cea9790d921c2c1cc4fc52700410b1c10948511039be824aac", size = 159606 },
|
139
|
+
{ url = "https://files.pythonhosted.org/packages/ff/b8/7185212adad274c2b42b6a24e1ee6b916b7809ed611cbebc33b227e5c215/websockets-14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b1f3628a0510bd58968c0f60447e7a692933589b791a6b572fcef374053ca280", size = 159854 },
|
140
|
+
{ url = "https://files.pythonhosted.org/packages/5a/8a/0849968d83474be89c183d8ae8dcb7f7ada1a3c24f4d2a0d7333c231a2c3/websockets-14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c3deac3748ec73ef24fc7be0b68220d14d47d6647d2f85b2771cb35ea847aa1", size = 169402 },
|
141
|
+
{ url = "https://files.pythonhosted.org/packages/bd/4f/ef886e37245ff6b4a736a09b8468dae05d5d5c99de1357f840d54c6f297d/websockets-14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7048eb4415d46368ef29d32133134c513f507fff7d953c18c91104738a68c3b3", size = 168406 },
|
142
|
+
{ url = "https://files.pythonhosted.org/packages/11/43/e2dbd4401a63e409cebddedc1b63b9834de42f51b3c84db885469e9bdcef/websockets-14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6", size = 168776 },
|
143
|
+
{ url = "https://files.pythonhosted.org/packages/6d/d6/7063e3f5c1b612e9f70faae20ebaeb2e684ffa36cb959eb0862ee2809b32/websockets-14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cc1fc87428c1d18b643479caa7b15db7d544652e5bf610513d4a3478dbe823d0", size = 169083 },
|
144
|
+
{ url = "https://files.pythonhosted.org/packages/49/69/e6f3d953f2fa0f8a723cf18cd011d52733bd7f6e045122b24e0e7f49f9b0/websockets-14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89", size = 168529 },
|
145
|
+
{ url = "https://files.pythonhosted.org/packages/70/ff/f31fa14561fc1d7b8663b0ed719996cf1f581abee32c8fb2f295a472f268/websockets-14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9481a6de29105d73cf4515f2bef8eb71e17ac184c19d0b9918a3701c6c9c4f23", size = 168475 },
|
146
|
+
{ url = "https://files.pythonhosted.org/packages/f1/15/b72be0e4bf32ff373aa5baef46a4c7521b8ea93ad8b49ca8c6e8e764c083/websockets-14.1-cp311-cp311-win32.whl", hash = "sha256:368a05465f49c5949e27afd6fbe0a77ce53082185bbb2ac096a3a8afaf4de52e", size = 162833 },
|
147
|
+
{ url = "https://files.pythonhosted.org/packages/bc/ef/2d81679acbe7057ffe2308d422f744497b52009ea8bab34b6d74a2657d1d/websockets-14.1-cp311-cp311-win_amd64.whl", hash = "sha256:6d24fc337fc055c9e83414c94e1ee0dee902a486d19d2a7f0929e49d7d604b09", size = 163263 },
|
148
|
+
{ url = "https://files.pythonhosted.org/packages/55/64/55698544ce29e877c9188f1aee9093712411a8fc9732cca14985e49a8e9c/websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed", size = 161957 },
|
149
|
+
{ url = "https://files.pythonhosted.org/packages/a2/b1/b088f67c2b365f2c86c7b48edb8848ac27e508caf910a9d9d831b2f343cb/websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d", size = 159620 },
|
150
|
+
{ url = "https://files.pythonhosted.org/packages/c1/89/2a09db1bbb40ba967a1b8225b07b7df89fea44f06de9365f17f684d0f7e6/websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707", size = 159852 },
|
151
|
+
{ url = "https://files.pythonhosted.org/packages/ca/c1/f983138cd56e7d3079f1966e81f77ce6643f230cd309f73aa156bb181749/websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a", size = 169675 },
|
152
|
+
{ url = "https://files.pythonhosted.org/packages/c1/c8/84191455d8660e2a0bdb33878d4ee5dfa4a2cedbcdc88bbd097303b65bfa/websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45", size = 168619 },
|
153
|
+
{ url = "https://files.pythonhosted.org/packages/8d/a7/62e551fdcd7d44ea74a006dc193aba370505278ad76efd938664531ce9d6/websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58", size = 169042 },
|
154
|
+
{ url = "https://files.pythonhosted.org/packages/ad/ed/1532786f55922c1e9c4d329608e36a15fdab186def3ca9eb10d7465bc1cc/websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058", size = 169345 },
|
155
|
+
{ url = "https://files.pythonhosted.org/packages/ea/fb/160f66960d495df3de63d9bcff78e1b42545b2a123cc611950ffe6468016/websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4", size = 168725 },
|
156
|
+
{ url = "https://files.pythonhosted.org/packages/cf/53/1bf0c06618b5ac35f1d7906444b9958f8485682ab0ea40dee7b17a32da1e/websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05", size = 168712 },
|
157
|
+
{ url = "https://files.pythonhosted.org/packages/e5/22/5ec2f39fff75f44aa626f86fa7f20594524a447d9c3be94d8482cd5572ef/websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0", size = 162838 },
|
158
|
+
{ url = "https://files.pythonhosted.org/packages/74/27/28f07df09f2983178db7bf6c9cccc847205d2b92ced986cd79565d68af4f/websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f", size = 163277 },
|
159
|
+
{ url = "https://files.pythonhosted.org/packages/34/77/812b3ba5110ed8726eddf9257ab55ce9e85d97d4aa016805fdbecc5e5d48/websockets-14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9", size = 161966 },
|
160
|
+
{ url = "https://files.pythonhosted.org/packages/8d/24/4fcb7aa6986ae7d9f6d083d9d53d580af1483c5ec24bdec0978307a0f6ac/websockets-14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b", size = 159625 },
|
161
|
+
{ url = "https://files.pythonhosted.org/packages/f8/47/2a0a3a2fc4965ff5b9ce9324d63220156bd8bedf7f90824ab92a822e65fd/websockets-14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3", size = 159857 },
|
162
|
+
{ url = "https://files.pythonhosted.org/packages/dd/c8/d7b425011a15e35e17757e4df75b25e1d0df64c0c315a44550454eaf88fc/websockets-14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59", size = 169635 },
|
163
|
+
{ url = "https://files.pythonhosted.org/packages/93/39/6e3b5cffa11036c40bd2f13aba2e8e691ab2e01595532c46437b56575678/websockets-14.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2", size = 168578 },
|
164
|
+
{ url = "https://files.pythonhosted.org/packages/cf/03/8faa5c9576299b2adf34dcccf278fc6bbbcda8a3efcc4d817369026be421/websockets-14.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da", size = 169018 },
|
165
|
+
{ url = "https://files.pythonhosted.org/packages/8c/05/ea1fec05cc3a60defcdf0bb9f760c3c6bd2dd2710eff7ac7f891864a22ba/websockets-14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9", size = 169383 },
|
166
|
+
{ url = "https://files.pythonhosted.org/packages/21/1d/eac1d9ed787f80754e51228e78855f879ede1172c8b6185aca8cef494911/websockets-14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7", size = 168773 },
|
167
|
+
{ url = "https://files.pythonhosted.org/packages/0e/1b/e808685530185915299740d82b3a4af3f2b44e56ccf4389397c7a5d95d39/websockets-14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a", size = 168757 },
|
168
|
+
{ url = "https://files.pythonhosted.org/packages/b6/19/6ab716d02a3b068fbbeb6face8a7423156e12c446975312f1c7c0f4badab/websockets-14.1-cp313-cp313-win32.whl", hash = "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6", size = 162834 },
|
169
|
+
{ url = "https://files.pythonhosted.org/packages/6c/fd/ab6b7676ba712f2fc89d1347a4b5bdc6aa130de10404071f2b2606450209/websockets-14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0", size = 163277 },
|
170
|
+
{ url = "https://files.pythonhosted.org/packages/fb/cd/382a05a1ba2a93bd9fb807716a660751295df72e77204fb130a102fcdd36/websockets-14.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e5dc25a9dbd1a7f61eca4b7cb04e74ae4b963d658f9e4f9aad9cd00b688692c8", size = 159633 },
|
171
|
+
{ url = "https://files.pythonhosted.org/packages/b7/a0/fa7c62e2952ef028b422fbf420f9353d9dd4dfaa425de3deae36e98c0784/websockets-14.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:04a97aca96ca2acedf0d1f332c861c5a4486fdcba7bcef35873820f940c4231e", size = 159867 },
|
172
|
+
{ url = "https://files.pythonhosted.org/packages/c1/94/954b4924f868db31d5f0935893c7a8446515ee4b36bb8ad75a929469e453/websockets-14.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df174ece723b228d3e8734a6f2a6febbd413ddec39b3dc592f5a4aa0aff28098", size = 161121 },
|
173
|
+
{ url = "https://files.pythonhosted.org/packages/7a/2e/f12bbb41a8f2abb76428ba4fdcd9e67b5b364a3e7fa97c88f4d6950aa2d4/websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:034feb9f4286476f273b9a245fb15f02c34d9586a5bc936aff108c3ba1b21beb", size = 160731 },
|
174
|
+
{ url = "https://files.pythonhosted.org/packages/13/97/b76979401f2373af1fe3e08f960b265cecab112e7dac803446fb98351a52/websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c308dabd2b380807ab64b62985eaccf923a78ebc572bd485375b9ca2b7dc7", size = 160681 },
|
175
|
+
{ url = "https://files.pythonhosted.org/packages/39/9c/16916d9a436c109a1d7ba78817e8fee357b78968be3f6e6f517f43afa43d/websockets-14.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a42d3ecbb2db5080fc578314439b1d79eef71d323dc661aa616fb492436af5d", size = 163316 },
|
176
|
+
{ url = "https://files.pythonhosted.org/packages/b0/0b/c7e5d11020242984d9d37990310520ed663b942333b83a033c2f20191113/websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e", size = 156277 },
|
177
|
+
]
|
dsmq-1.3.1/uv.lock
DELETED
@@ -1,177 +0,0 @@
|
|
1
|
-
version = 1
|
2
|
-
requires-python = ">=3.10"
|
3
|
-
|
4
|
-
[[package]]
|
5
|
-
name = "colorama"
|
6
|
-
version = "0.4.6"
|
7
|
-
source = { registry = "https://pypi.org/simple" }
|
8
|
-
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
|
9
|
-
wheels = [
|
10
|
-
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
|
11
|
-
]
|
12
|
-
|
13
|
-
[[package]]
|
14
|
-
name = "dsmq"
|
15
|
-
version = "1.2.6"
|
16
|
-
source = { editable = "." }
|
17
|
-
dependencies = [
|
18
|
-
{ name = "pytest" },
|
19
|
-
{ name = "websockets" },
|
20
|
-
]
|
21
|
-
|
22
|
-
[package.metadata]
|
23
|
-
requires-dist = [
|
24
|
-
{ name = "pytest", specifier = ">=8.3.4" },
|
25
|
-
{ name = "websockets", specifier = ">=14.1" },
|
26
|
-
]
|
27
|
-
|
28
|
-
[[package]]
|
29
|
-
name = "exceptiongroup"
|
30
|
-
version = "1.2.2"
|
31
|
-
source = { registry = "https://pypi.org/simple" }
|
32
|
-
sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
|
33
|
-
wheels = [
|
34
|
-
{ url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
|
35
|
-
]
|
36
|
-
|
37
|
-
[[package]]
|
38
|
-
name = "iniconfig"
|
39
|
-
version = "2.0.0"
|
40
|
-
source = { registry = "https://pypi.org/simple" }
|
41
|
-
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
|
42
|
-
wheels = [
|
43
|
-
{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
|
44
|
-
]
|
45
|
-
|
46
|
-
[[package]]
|
47
|
-
name = "packaging"
|
48
|
-
version = "24.2"
|
49
|
-
source = { registry = "https://pypi.org/simple" }
|
50
|
-
sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 }
|
51
|
-
wheels = [
|
52
|
-
{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 },
|
53
|
-
]
|
54
|
-
|
55
|
-
[[package]]
|
56
|
-
name = "pluggy"
|
57
|
-
version = "1.5.0"
|
58
|
-
source = { registry = "https://pypi.org/simple" }
|
59
|
-
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
|
60
|
-
wheels = [
|
61
|
-
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
|
62
|
-
]
|
63
|
-
|
64
|
-
[[package]]
|
65
|
-
name = "pytest"
|
66
|
-
version = "8.3.4"
|
67
|
-
source = { registry = "https://pypi.org/simple" }
|
68
|
-
dependencies = [
|
69
|
-
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
70
|
-
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
71
|
-
{ name = "iniconfig" },
|
72
|
-
{ name = "packaging" },
|
73
|
-
{ name = "pluggy" },
|
74
|
-
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
75
|
-
]
|
76
|
-
sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 }
|
77
|
-
wheels = [
|
78
|
-
{ url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 },
|
79
|
-
]
|
80
|
-
|
81
|
-
[[package]]
|
82
|
-
name = "tomli"
|
83
|
-
version = "2.2.1"
|
84
|
-
source = { registry = "https://pypi.org/simple" }
|
85
|
-
sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 }
|
86
|
-
wheels = [
|
87
|
-
{ url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 },
|
88
|
-
{ url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 },
|
89
|
-
{ url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 },
|
90
|
-
{ url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 },
|
91
|
-
{ url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 },
|
92
|
-
{ url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 },
|
93
|
-
{ url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 },
|
94
|
-
{ url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 },
|
95
|
-
{ url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 },
|
96
|
-
{ url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 },
|
97
|
-
{ url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 },
|
98
|
-
{ url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 },
|
99
|
-
{ url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 },
|
100
|
-
{ url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 },
|
101
|
-
{ url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 },
|
102
|
-
{ url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 },
|
103
|
-
{ url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 },
|
104
|
-
{ url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 },
|
105
|
-
{ url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 },
|
106
|
-
{ url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 },
|
107
|
-
{ url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 },
|
108
|
-
{ url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 },
|
109
|
-
{ url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 },
|
110
|
-
{ url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 },
|
111
|
-
{ url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 },
|
112
|
-
{ url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 },
|
113
|
-
{ url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 },
|
114
|
-
{ url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 },
|
115
|
-
{ url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 },
|
116
|
-
{ url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 },
|
117
|
-
{ url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 },
|
118
|
-
]
|
119
|
-
|
120
|
-
[[package]]
|
121
|
-
name = "websockets"
|
122
|
-
version = "14.2"
|
123
|
-
source = { registry = "https://pypi.org/simple" }
|
124
|
-
sdist = { url = "https://files.pythonhosted.org/packages/94/54/8359678c726243d19fae38ca14a334e740782336c9f19700858c4eb64a1e/websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5", size = 164394 }
|
125
|
-
wheels = [
|
126
|
-
{ url = "https://files.pythonhosted.org/packages/28/fa/76607eb7dcec27b2d18d63f60a32e60e2b8629780f343bb83a4dbb9f4350/websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885", size = 163089 },
|
127
|
-
{ url = "https://files.pythonhosted.org/packages/9e/00/ad2246b5030575b79e7af0721810fdaecaf94c4b2625842ef7a756fa06dd/websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397", size = 160741 },
|
128
|
-
{ url = "https://files.pythonhosted.org/packages/72/f7/60f10924d333a28a1ff3fcdec85acf226281331bdabe9ad74947e1b7fc0a/websockets-14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:714a9b682deb4339d39ffa674f7b674230227d981a37d5d174a4a83e3978a610", size = 160996 },
|
129
|
-
{ url = "https://files.pythonhosted.org/packages/63/7c/c655789cf78648c01ac6ecbe2d6c18f91b75bdc263ffee4d08ce628d12f0/websockets-14.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e53c72052f2596fb792a7acd9704cbc549bf70fcde8a99e899311455974ca3", size = 169974 },
|
130
|
-
{ url = "https://files.pythonhosted.org/packages/fb/5b/013ed8b4611857ac92ac631079c08d9715b388bd1d88ec62e245f87a39df/websockets-14.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fbd68850c837e57373d95c8fe352203a512b6e49eaae4c2f4088ef8cf21980", size = 168985 },
|
131
|
-
{ url = "https://files.pythonhosted.org/packages/cd/33/aa3e32fd0df213a5a442310754fe3f89dd87a0b8e5b4e11e0991dd3bcc50/websockets-14.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b27ece32f63150c268593d5fdb82819584831a83a3f5809b7521df0685cd5d8", size = 169297 },
|
132
|
-
{ url = "https://files.pythonhosted.org/packages/93/17/dae0174883d6399f57853ac44abf5f228eaba86d98d160f390ffabc19b6e/websockets-14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4daa0faea5424d8713142b33825fff03c736f781690d90652d2c8b053345b0e7", size = 169677 },
|
133
|
-
{ url = "https://files.pythonhosted.org/packages/42/e2/0375af7ac00169b98647c804651c515054b34977b6c1354f1458e4116c1e/websockets-14.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bc63cee8596a6ec84d9753fd0fcfa0452ee12f317afe4beae6b157f0070c6c7f", size = 169089 },
|
134
|
-
{ url = "https://files.pythonhosted.org/packages/73/8d/80f71d2a351a44b602859af65261d3dde3a0ce4e76cf9383738a949e0cc3/websockets-14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a570862c325af2111343cc9b0257b7119b904823c675b22d4ac547163088d0d", size = 169026 },
|
135
|
-
{ url = "https://files.pythonhosted.org/packages/48/97/173b1fa6052223e52bb4054a141433ad74931d94c575e04b654200b98ca4/websockets-14.2-cp310-cp310-win32.whl", hash = "sha256:75862126b3d2d505e895893e3deac0a9339ce750bd27b4ba515f008b5acf832d", size = 163967 },
|
136
|
-
{ url = "https://files.pythonhosted.org/packages/c0/5b/2fcf60f38252a4562b28b66077e0d2b48f91fef645d5f78874cd1dec807b/websockets-14.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc45afb9c9b2dc0852d5c8b5321759cf825f82a31bfaf506b65bf4668c96f8b2", size = 164413 },
|
137
|
-
{ url = "https://files.pythonhosted.org/packages/15/b6/504695fb9a33df0ca56d157f5985660b5fc5b4bf8c78f121578d2d653392/websockets-14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3bdc8c692c866ce5fefcaf07d2b55c91d6922ac397e031ef9b774e5b9ea42166", size = 163088 },
|
138
|
-
{ url = "https://files.pythonhosted.org/packages/81/26/ebfb8f6abe963c795122439c6433c4ae1e061aaedfc7eff32d09394afbae/websockets-14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c93215fac5dadc63e51bcc6dceca72e72267c11def401d6668622b47675b097f", size = 160745 },
|
139
|
-
{ url = "https://files.pythonhosted.org/packages/a1/c6/1435ad6f6dcbff80bb95e8986704c3174da8866ddb751184046f5c139ef6/websockets-14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c9b6535c0e2cf8a6bf938064fb754aaceb1e6a4a51a80d884cd5db569886910", size = 160995 },
|
140
|
-
{ url = "https://files.pythonhosted.org/packages/96/63/900c27cfe8be1a1f2433fc77cd46771cf26ba57e6bdc7cf9e63644a61863/websockets-14.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a52a6d7cf6938e04e9dceb949d35fbdf58ac14deea26e685ab6368e73744e4c", size = 170543 },
|
141
|
-
{ url = "https://files.pythonhosted.org/packages/00/8b/bec2bdba92af0762d42d4410593c1d7d28e9bfd952c97a3729df603dc6ea/websockets-14.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f05702e93203a6ff5226e21d9b40c037761b2cfb637187c9802c10f58e40473", size = 169546 },
|
142
|
-
{ url = "https://files.pythonhosted.org/packages/6b/a9/37531cb5b994f12a57dec3da2200ef7aadffef82d888a4c29a0d781568e4/websockets-14.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22441c81a6748a53bfcb98951d58d1af0661ab47a536af08920d129b4d1c3473", size = 169911 },
|
143
|
-
{ url = "https://files.pythonhosted.org/packages/60/d5/a6eadba2ed9f7e65d677fec539ab14a9b83de2b484ab5fe15d3d6d208c28/websockets-14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd9b868d78b194790e6236d9cbc46d68aba4b75b22497eb4ab64fa640c3af56", size = 170183 },
|
144
|
-
{ url = "https://files.pythonhosted.org/packages/76/57/a338ccb00d1df881c1d1ee1f2a20c9c1b5b29b51e9e0191ee515d254fea6/websockets-14.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a5a20d5843886d34ff8c57424cc65a1deda4375729cbca4cb6b3353f3ce4142", size = 169623 },
|
145
|
-
{ url = "https://files.pythonhosted.org/packages/64/22/e5f7c33db0cb2c1d03b79fd60d189a1da044e2661f5fd01d629451e1db89/websockets-14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34277a29f5303d54ec6468fb525d99c99938607bc96b8d72d675dee2b9f5bf1d", size = 169583 },
|
146
|
-
{ url = "https://files.pythonhosted.org/packages/aa/2e/2b4662237060063a22e5fc40d46300a07142afe30302b634b4eebd717c07/websockets-14.2-cp311-cp311-win32.whl", hash = "sha256:02687db35dbc7d25fd541a602b5f8e451a238ffa033030b172ff86a93cb5dc2a", size = 163969 },
|
147
|
-
{ url = "https://files.pythonhosted.org/packages/94/a5/0cda64e1851e73fc1ecdae6f42487babb06e55cb2f0dc8904b81d8ef6857/websockets-14.2-cp311-cp311-win_amd64.whl", hash = "sha256:862e9967b46c07d4dcd2532e9e8e3c2825e004ffbf91a5ef9dde519ee2effb0b", size = 164408 },
|
148
|
-
{ url = "https://files.pythonhosted.org/packages/c1/81/04f7a397653dc8bec94ddc071f34833e8b99b13ef1a3804c149d59f92c18/websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c", size = 163096 },
|
149
|
-
{ url = "https://files.pythonhosted.org/packages/ec/c5/de30e88557e4d70988ed4d2eabd73fd3e1e52456b9f3a4e9564d86353b6d/websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967", size = 160758 },
|
150
|
-
{ url = "https://files.pythonhosted.org/packages/e5/8c/d130d668781f2c77d106c007b6c6c1d9db68239107c41ba109f09e6c218a/websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990", size = 160995 },
|
151
|
-
{ url = "https://files.pythonhosted.org/packages/a6/bc/f6678a0ff17246df4f06765e22fc9d98d1b11a258cc50c5968b33d6742a1/websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda", size = 170815 },
|
152
|
-
{ url = "https://files.pythonhosted.org/packages/d8/b2/8070cb970c2e4122a6ef38bc5b203415fd46460e025652e1ee3f2f43a9a3/websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95", size = 169759 },
|
153
|
-
{ url = "https://files.pythonhosted.org/packages/81/da/72f7caabd94652e6eb7e92ed2d3da818626e70b4f2b15a854ef60bf501ec/websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3", size = 170178 },
|
154
|
-
{ url = "https://files.pythonhosted.org/packages/31/e0/812725b6deca8afd3a08a2e81b3c4c120c17f68c9b84522a520b816cda58/websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9", size = 170453 },
|
155
|
-
{ url = "https://files.pythonhosted.org/packages/66/d3/8275dbc231e5ba9bb0c4f93144394b4194402a7a0c8ffaca5307a58ab5e3/websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267", size = 169830 },
|
156
|
-
{ url = "https://files.pythonhosted.org/packages/a3/ae/e7d1a56755ae15ad5a94e80dd490ad09e345365199600b2629b18ee37bc7/websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe", size = 169824 },
|
157
|
-
{ url = "https://files.pythonhosted.org/packages/b6/32/88ccdd63cb261e77b882e706108d072e4f1c839ed723bf91a3e1f216bf60/websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205", size = 163981 },
|
158
|
-
{ url = "https://files.pythonhosted.org/packages/b3/7d/32cdb77990b3bdc34a306e0a0f73a1275221e9a66d869f6ff833c95b56ef/websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce", size = 164421 },
|
159
|
-
{ url = "https://files.pythonhosted.org/packages/82/94/4f9b55099a4603ac53c2912e1f043d6c49d23e94dd82a9ce1eb554a90215/websockets-14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f1372e511c7409a542291bce92d6c83320e02c9cf392223272287ce55bc224e", size = 163102 },
|
160
|
-
{ url = "https://files.pythonhosted.org/packages/8e/b7/7484905215627909d9a79ae07070057afe477433fdacb59bf608ce86365a/websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad", size = 160766 },
|
161
|
-
{ url = "https://files.pythonhosted.org/packages/a3/a4/edb62efc84adb61883c7d2c6ad65181cb087c64252138e12d655989eec05/websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03", size = 160998 },
|
162
|
-
{ url = "https://files.pythonhosted.org/packages/f5/79/036d320dc894b96af14eac2529967a6fc8b74f03b83c487e7a0e9043d842/websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f", size = 170780 },
|
163
|
-
{ url = "https://files.pythonhosted.org/packages/63/75/5737d21ee4dd7e4b9d487ee044af24a935e36a9ff1e1419d684feedcba71/websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5", size = 169717 },
|
164
|
-
{ url = "https://files.pythonhosted.org/packages/2c/3c/bf9b2c396ed86a0b4a92ff4cdaee09753d3ee389be738e92b9bbd0330b64/websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a", size = 170155 },
|
165
|
-
{ url = "https://files.pythonhosted.org/packages/75/2d/83a5aca7247a655b1da5eb0ee73413abd5c3a57fc8b92915805e6033359d/websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20", size = 170495 },
|
166
|
-
{ url = "https://files.pythonhosted.org/packages/79/dd/699238a92761e2f943885e091486378813ac8f43e3c84990bc394c2be93e/websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2", size = 169880 },
|
167
|
-
{ url = "https://files.pythonhosted.org/packages/c8/c9/67a8f08923cf55ce61aadda72089e3ed4353a95a3a4bc8bf42082810e580/websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307", size = 169856 },
|
168
|
-
{ url = "https://files.pythonhosted.org/packages/17/b1/1ffdb2680c64e9c3921d99db460546194c40d4acbef999a18c37aa4d58a3/websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc", size = 163974 },
|
169
|
-
{ url = "https://files.pythonhosted.org/packages/14/13/8b7fc4cb551b9cfd9890f0fd66e53c18a06240319915533b033a56a3d520/websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f", size = 164420 },
|
170
|
-
{ url = "https://files.pythonhosted.org/packages/10/3d/91d3d2bb1325cd83e8e2c02d0262c7d4426dc8fa0831ef1aa4d6bf2041af/websockets-14.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7d9cafbccba46e768be8a8ad4635fa3eae1ffac4c6e7cb4eb276ba41297ed29", size = 160773 },
|
171
|
-
{ url = "https://files.pythonhosted.org/packages/33/7c/cdedadfef7381939577858b1b5718a4ab073adbb584e429dd9d9dc9bfe16/websockets-14.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c76193c1c044bd1e9b3316dcc34b174bbf9664598791e6fb606d8d29000e070c", size = 161007 },
|
172
|
-
{ url = "https://files.pythonhosted.org/packages/ca/35/7a20a3c450b27c04e50fbbfc3dfb161ed8e827b2a26ae31c4b59b018b8c6/websockets-14.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2", size = 162264 },
|
173
|
-
{ url = "https://files.pythonhosted.org/packages/e8/9c/e3f9600564b0c813f2448375cf28b47dc42c514344faed3a05d71fb527f9/websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6c0097a41968b2e2b54ed3424739aab0b762ca92af2379f152c1aef0187e1c", size = 161873 },
|
174
|
-
{ url = "https://files.pythonhosted.org/packages/3f/37/260f189b16b2b8290d6ae80c9f96d8b34692cf1bb3475df54c38d3deb57d/websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7ff794c8b36bc402f2e07c0b2ceb4a2424147ed4785ff03e2a7af03711d60a", size = 161818 },
|
175
|
-
{ url = "https://files.pythonhosted.org/packages/ff/1e/e47dedac8bf7140e59aa6a679e850c4df9610ae844d71b6015263ddea37b/websockets-14.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dec254fcabc7bd488dab64846f588fc5b6fe0d78f641180030f8ea27b76d72c3", size = 164465 },
|
176
|
-
{ url = "https://files.pythonhosted.org/packages/7b/c8/d529f8a32ce40d98309f4470780631e971a5a842b60aec864833b3615786/websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b", size = 157416 },
|
177
|
-
]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|