DefStream-RabbitMQ 0.1.24__110-py3-none-any.whl
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.
- DefStream/Broker/Implements/RabbitMQ/Configuration.py +49 -0
- DefStream/Broker/Implements/RabbitMQ/Connection.py +550 -0
- DefStream/Broker/Implements/RabbitMQ/Consumer.py +416 -0
- DefStream/Broker/Implements/RabbitMQ/Event.py +146 -0
- DefStream/Broker/Implements/RabbitMQ/Exchange.py +277 -0
- DefStream/Broker/Implements/RabbitMQ/Queue.py +321 -0
- DefStream/Broker/Implements/RabbitMQ/Serializer.py +75 -0
- DefStream/Broker/Implements/RabbitMQ/Stream.py +181 -0
- DefStream/Broker/Implements/RabbitMQ/Subscription.py +90 -0
- DefStream/Broker/Implements/RabbitMQ/__init__.py +45 -0
- defstream_rabbitmq-0.1.24.dist-info/METADATA +92 -0
- defstream_rabbitmq-0.1.24.dist-info/RECORD +15 -0
- defstream_rabbitmq-0.1.24.dist-info/WHEEL +6 -0
- defstream_rabbitmq-0.1.24.dist-info/licenses/LICENSE +674 -0
- defstream_rabbitmq-0.1.24.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from DefStream.Broker import (
|
|
4
|
+
Sendable,
|
|
5
|
+
Readable,
|
|
6
|
+
)
|
|
7
|
+
from .Serializer import (
|
|
8
|
+
Encoder,
|
|
9
|
+
Decoder,
|
|
10
|
+
)
|
|
11
|
+
from .Event import Event
|
|
12
|
+
|
|
13
|
+
from pika import (
|
|
14
|
+
BlockingConnection,
|
|
15
|
+
BasicProperties,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from time import time
|
|
19
|
+
from logging import getLogger
|
|
20
|
+
from uuid import uuid4
|
|
21
|
+
|
|
22
|
+
from typing import (
|
|
23
|
+
Dict,
|
|
24
|
+
Generator,
|
|
25
|
+
Optional,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__all__ = (
|
|
29
|
+
'Stream',
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Stream(
|
|
34
|
+
Sendable,
|
|
35
|
+
Readable,
|
|
36
|
+
):
|
|
37
|
+
"""Stream of Event Broker for RabbitMQ"""
|
|
38
|
+
logger = getLogger('Broker.RabbitMQ.Stream')
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
connection: BlockingConnection,
|
|
43
|
+
encode: Encoder,
|
|
44
|
+
decode: Decoder,
|
|
45
|
+
name: str,
|
|
46
|
+
):
|
|
47
|
+
self.connection = connection
|
|
48
|
+
self.encode = encode
|
|
49
|
+
self.decode = decode
|
|
50
|
+
try:
|
|
51
|
+
self.channel = self.connection.channel()
|
|
52
|
+
except Exception as error:
|
|
53
|
+
self.logger.error('Stream channel creation failed: queue=%s error_type=%s', name, type(error).__name__)
|
|
54
|
+
raise
|
|
55
|
+
self.queue = name
|
|
56
|
+
self.event = None
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
def __del__(self):
|
|
60
|
+
channel = getattr(self, 'channel', None)
|
|
61
|
+
try:
|
|
62
|
+
if channel and channel.is_open:
|
|
63
|
+
channel.close()
|
|
64
|
+
self.logger.debug('Stream channel cleanup completed: queue=%s', self.queue)
|
|
65
|
+
except Exception as error:
|
|
66
|
+
self.logger.error('Stream channel cleanup failed: error_type=%s', type(error).__name__)
|
|
67
|
+
raise
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
def __str__(self): return self.queue
|
|
71
|
+
|
|
72
|
+
def send(
|
|
73
|
+
self,
|
|
74
|
+
body,
|
|
75
|
+
event: Optional[str] = None,
|
|
76
|
+
headers: Dict = {},
|
|
77
|
+
timestamp: Optional[int] = None,
|
|
78
|
+
id: Optional[str] = None,
|
|
79
|
+
):
|
|
80
|
+
if not timestamp: timestamp = int(time())
|
|
81
|
+
if not id: id = uuid4().hex
|
|
82
|
+
properties = BasicProperties(
|
|
83
|
+
type=event if event else '',
|
|
84
|
+
headers=headers,
|
|
85
|
+
content_type=self.encode.format,
|
|
86
|
+
content_encoding=self.encode.charset,
|
|
87
|
+
timestamp=timestamp,
|
|
88
|
+
message_id=id,
|
|
89
|
+
)
|
|
90
|
+
self.logger.debug('Publishing Stream message: queue=%s message_id=%s publisher_confirm=False', self.queue, id)
|
|
91
|
+
try:
|
|
92
|
+
self.channel.basic_publish(
|
|
93
|
+
exchange='',
|
|
94
|
+
routing_key=self.queue,
|
|
95
|
+
properties=properties,
|
|
96
|
+
body=self.encode(body)
|
|
97
|
+
)
|
|
98
|
+
except Exception as error:
|
|
99
|
+
self.logger.error('Stream publication failed: queue=%s message_id=%s error_type=%s', self.queue, id, type(error).__name__)
|
|
100
|
+
raise
|
|
101
|
+
self.logger.debug('Stream publish API call completed: queue=%s message_id=%s', self.queue, id)
|
|
102
|
+
return id
|
|
103
|
+
|
|
104
|
+
def read(self, offset: int = 0, timeout: Optional[int] = None) -> Generator[Event, None, None]:
|
|
105
|
+
channel = self.channel
|
|
106
|
+
self.logger.debug('Starting Stream read: queue=%s offset=%s timeout_ms=%s qos=1', self.queue, offset, timeout)
|
|
107
|
+
try:
|
|
108
|
+
channel.basic_qos(0, 1, False)
|
|
109
|
+
except Exception as error:
|
|
110
|
+
self.logger.error('Failed to apply Stream QoS: queue=%s error_type=%s', self.queue, type(error).__name__)
|
|
111
|
+
raise
|
|
112
|
+
|
|
113
|
+
deadline = time() + (timeout / 1000) if timeout else None
|
|
114
|
+
|
|
115
|
+
failure_observed = False
|
|
116
|
+
try:
|
|
117
|
+
for method, properties, body in channel.consume(
|
|
118
|
+
queue=self.queue,
|
|
119
|
+
auto_ack=False,
|
|
120
|
+
inactivity_timeout=1,
|
|
121
|
+
arguments={'x-stream-offset': offset},
|
|
122
|
+
):
|
|
123
|
+
if method is None:
|
|
124
|
+
if deadline and time() >= deadline:
|
|
125
|
+
break
|
|
126
|
+
continue
|
|
127
|
+
# pika delivers properties and body together with every non-empty method frame.
|
|
128
|
+
assert properties is not None and body is not None
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
decoded = self.decode(body, properties.content_type, properties.content_encoding)
|
|
132
|
+
except Exception as error:
|
|
133
|
+
failure_observed = True
|
|
134
|
+
self.logger.error('Stream decoding failed: queue=%s delivery_tag=%s error_type=%s', self.queue, method.delivery_tag, type(error).__name__)
|
|
135
|
+
raise
|
|
136
|
+
self.logger.debug('Stream message received and decoded: queue=%s consumer_tag=%s delivery_tag=%s message_id=%s', self.queue, method.consumer_tag, method.delivery_tag, properties.message_id)
|
|
137
|
+
event = Event(
|
|
138
|
+
channel,
|
|
139
|
+
self.queue,
|
|
140
|
+
method.consumer_tag,
|
|
141
|
+
method.delivery_tag,
|
|
142
|
+
properties,
|
|
143
|
+
decoded,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
failure_observed = True
|
|
148
|
+
yield event
|
|
149
|
+
failure_observed = False
|
|
150
|
+
self.logger.debug('Stream ack requested: queue=%s delivery_tag=%s', self.queue, method.delivery_tag)
|
|
151
|
+
try:
|
|
152
|
+
channel.basic_ack(delivery_tag=method.delivery_tag)
|
|
153
|
+
except Exception as error:
|
|
154
|
+
failure_observed = True
|
|
155
|
+
self.logger.error('Stream ack failed: queue=%s delivery_tag=%s error_type=%s', self.queue, method.delivery_tag, type(error).__name__)
|
|
156
|
+
raise
|
|
157
|
+
self.logger.debug('Stream ack API call completed: queue=%s delivery_tag=%s', self.queue, method.delivery_tag)
|
|
158
|
+
except Exception:
|
|
159
|
+
failure_observed = True
|
|
160
|
+
self.logger.warning('Attempting requeue after Stream processing exception: queue=%s delivery_tag=%s', self.queue, method.delivery_tag)
|
|
161
|
+
self.logger.debug('Stream nack requested: queue=%s delivery_tag=%s requeue=True', self.queue, method.delivery_tag)
|
|
162
|
+
try:
|
|
163
|
+
channel.basic_nack(delivery_tag=method.delivery_tag, requeue=True)
|
|
164
|
+
except Exception as error:
|
|
165
|
+
self.logger.error('Stream nack failed: queue=%s delivery_tag=%s error_type=%s', self.queue, method.delivery_tag, type(error).__name__)
|
|
166
|
+
raise
|
|
167
|
+
self.logger.debug('Stream nack API call completed: queue=%s delivery_tag=%s', self.queue, method.delivery_tag)
|
|
168
|
+
raise
|
|
169
|
+
except Exception as error:
|
|
170
|
+
if not failure_observed:
|
|
171
|
+
self.logger.error('Stream consumption loop failed: queue=%s error_type=%s', self.queue, type(error).__name__)
|
|
172
|
+
raise
|
|
173
|
+
finally:
|
|
174
|
+
self.logger.debug('Ending Stream read loop; requesting Consumer cancellation: queue=%s', self.queue)
|
|
175
|
+
try:
|
|
176
|
+
channel.cancel()
|
|
177
|
+
except Exception as error:
|
|
178
|
+
self.logger.error('Stream Consumer cancellation failed: queue=%s error_type=%s', self.queue, type(error).__name__)
|
|
179
|
+
raise
|
|
180
|
+
self.logger.debug('Stream Consumer cancelled: queue=%s', self.queue)
|
|
181
|
+
return
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from datetime import timedelta
|
|
4
|
+
from typing import (
|
|
5
|
+
Any,
|
|
6
|
+
Optional,
|
|
7
|
+
Union,
|
|
8
|
+
)
|
|
9
|
+
from DefStream.Broker import validate_priority
|
|
10
|
+
|
|
11
|
+
__all__ = (
|
|
12
|
+
'Subscription',
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class Subscription:
|
|
18
|
+
queue: str
|
|
19
|
+
offset: Optional[int] = None
|
|
20
|
+
qos: Optional[int] = None
|
|
21
|
+
error: Optional[str] = None
|
|
22
|
+
max_priority: Optional[int] = None
|
|
23
|
+
priority: Optional[int] = None
|
|
24
|
+
timeout: Optional[Union[int, timedelta]] = None
|
|
25
|
+
|
|
26
|
+
def __post_init__(self) -> None:
|
|
27
|
+
if self.timeout is not None:
|
|
28
|
+
if isinstance(self.timeout, timedelta):
|
|
29
|
+
if self.timeout <= timedelta(0) or self.timeout.microseconds % 1000:
|
|
30
|
+
raise ValueError('Subscription timeout must be positive with whole-millisecond precision')
|
|
31
|
+
object.__setattr__(
|
|
32
|
+
self,
|
|
33
|
+
'timeout',
|
|
34
|
+
self.timeout // timedelta(milliseconds=1),
|
|
35
|
+
)
|
|
36
|
+
elif isinstance(self.timeout, bool) or not isinstance(self.timeout, int):
|
|
37
|
+
raise TypeError('Subscription timeout must be integer milliseconds, a timedelta or None')
|
|
38
|
+
elif self.timeout <= 0:
|
|
39
|
+
raise ValueError('Subscription timeout must be positive')
|
|
40
|
+
if self.priority is not None and self.max_priority is None:
|
|
41
|
+
object.__setattr__(
|
|
42
|
+
self,
|
|
43
|
+
'max_priority',
|
|
44
|
+
255,
|
|
45
|
+
)
|
|
46
|
+
validate_priority(
|
|
47
|
+
self.max_priority,
|
|
48
|
+
255,
|
|
49
|
+
minimum=1,
|
|
50
|
+
name='max_priority',
|
|
51
|
+
)
|
|
52
|
+
self.validate_priority(self.priority)
|
|
53
|
+
if not isinstance(self.queue, str) or not self.queue:
|
|
54
|
+
raise ValueError('Subscription queue must be a non-empty string')
|
|
55
|
+
if self.error is not None:
|
|
56
|
+
if not isinstance(
|
|
57
|
+
self.error,
|
|
58
|
+
str,
|
|
59
|
+
) or not self.error:
|
|
60
|
+
raise ValueError('Subscription error must be a non-empty string or None')
|
|
61
|
+
if self.offset is not None and (isinstance(self.offset, bool) or not isinstance(self.offset, int)):
|
|
62
|
+
raise ValueError('Subscription offset must be an integer')
|
|
63
|
+
if self.qos is not None:
|
|
64
|
+
if isinstance(
|
|
65
|
+
self.qos,
|
|
66
|
+
bool,
|
|
67
|
+
) or not isinstance(
|
|
68
|
+
self.qos,
|
|
69
|
+
int,
|
|
70
|
+
) or not 0 <= self.qos <= 65535:
|
|
71
|
+
raise ValueError('Subscription qos must be an integer between 0 and 65535')
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
def validate_priority(
|
|
75
|
+
self,
|
|
76
|
+
priority: Optional[int],
|
|
77
|
+
) -> None:
|
|
78
|
+
validate_priority(
|
|
79
|
+
priority,
|
|
80
|
+
255 if self.max_priority is None else self.max_priority,
|
|
81
|
+
)
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def parse(cls, parameters: Any) -> 'Subscription':
|
|
86
|
+
if isinstance(parameters, cls):
|
|
87
|
+
return parameters
|
|
88
|
+
if isinstance(parameters, Mapping):
|
|
89
|
+
return cls(**dict(parameters))
|
|
90
|
+
raise TypeError('RabbitMQ subscriptions require a Subscription or mapping')
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from .Configuration import Configuration
|
|
4
|
+
from .Connection import (
|
|
5
|
+
Connection,
|
|
6
|
+
ExchangeType,
|
|
7
|
+
Parameters,
|
|
8
|
+
All,
|
|
9
|
+
Any,
|
|
10
|
+
)
|
|
11
|
+
from .Exchange import Exchange
|
|
12
|
+
from .Queue import Queue
|
|
13
|
+
from .Stream import Stream
|
|
14
|
+
from .Consumer import Consumer
|
|
15
|
+
from .Subscription import Subscription
|
|
16
|
+
from .Event import (
|
|
17
|
+
Event,
|
|
18
|
+
EventHandler,
|
|
19
|
+
Requeue,
|
|
20
|
+
Reject,
|
|
21
|
+
)
|
|
22
|
+
from .Serializer import (
|
|
23
|
+
Encoder,
|
|
24
|
+
Decoder,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = (
|
|
28
|
+
'Configuration',
|
|
29
|
+
'Connection',
|
|
30
|
+
'ExchangeType',
|
|
31
|
+
'Parameters',
|
|
32
|
+
'All',
|
|
33
|
+
'Any',
|
|
34
|
+
'Exchange',
|
|
35
|
+
'Queue',
|
|
36
|
+
'Stream',
|
|
37
|
+
'Consumer',
|
|
38
|
+
'Subscription',
|
|
39
|
+
'Requeue',
|
|
40
|
+
'Reject',
|
|
41
|
+
'Event',
|
|
42
|
+
'EventHandler',
|
|
43
|
+
'Encoder',
|
|
44
|
+
'Decoder',
|
|
45
|
+
)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: DefStream-RabbitMQ
|
|
3
|
+
Version: 0.1.24
|
|
4
|
+
Summary: Synchronous message processing with pluggable broker adapters
|
|
5
|
+
Home-page: https://github.com/yong5eon/DefStream
|
|
6
|
+
Author: Heo Yongseon
|
|
7
|
+
Project-URL: Source, https://github.com/yong5eon/DefStream
|
|
8
|
+
Project-URL: Issues, https://github.com/yong5eon/DefStream/issues
|
|
9
|
+
Project-URL: Releases, https://github.com/yong5eon/DefStream/releases
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: DefStream==0.1.24
|
|
20
|
+
Requires-Dist: pika>=1.3.2
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
Dynamic: project-url
|
|
28
|
+
Dynamic: requires-dist
|
|
29
|
+
Dynamic: requires-python
|
|
30
|
+
Dynamic: summary
|
|
31
|
+
|
|
32
|
+
# DefStream
|
|
33
|
+
|
|
34
|
+
Synchronous event/message processing with pluggable broker adapters
|
|
35
|
+
|
|
36
|
+
DefStream processes broker messages with ordinary Python task methods and can run them in thread or process pools. It requires Python 3.9 or later.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
Install the client extra for the broker you use. A broker server must be available separately.
|
|
41
|
+
|
|
42
|
+
```shell
|
|
43
|
+
python -m pip install "DefStream[RabbitMQ]"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
For Redis Streams, install `DefStream[Redis]`. To install both adapters and clients, use `DefStream[RabbitMQ,Redis]`. The plain `DefStream` installation includes neither broker implementation nor client. Each extra installs a separate, same-version adapter distribution, preserving existing import paths.
|
|
47
|
+
|
|
48
|
+
Before migrating an older integrated installation or historical standalone adapters, uninstall DefStream, DefStream-RabbitMQ and DefStream-Redis, then reinstall with the desired extras. Omitting an extra later does not remove an already installed adapter.
|
|
49
|
+
|
|
50
|
+
## Quick start
|
|
51
|
+
|
|
52
|
+
The following worker listens to a local RabbitMQ server at `127.0.0.1:5672`. The example credentials are for local development only.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from signal import SIGINT, signal
|
|
56
|
+
|
|
57
|
+
from DefStream.Broker.Implements.RabbitMQ import Configuration, Connection, Reject, Subscription
|
|
58
|
+
from DefStream.Worker import Run, ThreadPool, Worker, WorkerSetup, declare
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class Add(
|
|
62
|
+
Run,
|
|
63
|
+
parameters=Subscription(queue='example.add', error='example.add.error'),
|
|
64
|
+
on_error=Reject(),
|
|
65
|
+
):
|
|
66
|
+
def run(self, a: int, b: int):
|
|
67
|
+
print(a + b)
|
|
68
|
+
return a + b
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Prepare(WorkerSetup):
|
|
72
|
+
def __call__(self, worker: Worker) -> None:
|
|
73
|
+
for task in worker.tasks:
|
|
74
|
+
declare(task=task, broker=worker.broker)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == '__main__':
|
|
78
|
+
worker = Worker(
|
|
79
|
+
Connection(Configuration(host='127.0.0.1', port=5672, username='guest', password='guest')),
|
|
80
|
+
ThreadPool(4),
|
|
81
|
+
setups=Prepare(),
|
|
82
|
+
)
|
|
83
|
+
worker.add(Add)
|
|
84
|
+
signal(SIGINT, lambda *_: worker.stop())
|
|
85
|
+
worker.run()
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Run the script after starting RabbitMQ. The worker declares its task queue and waits for messages. Store production credentials outside source code.
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
See the `LICENSE` file included with the source distribution for the license terms.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
DefStream/Broker/Implements/RabbitMQ/Configuration.py,sha256=sHysXc1nlJHbSjWD3BZxlXjKBAbz2AKDtr7ACVVVj0c,1094
|
|
2
|
+
DefStream/Broker/Implements/RabbitMQ/Connection.py,sha256=XzPDDHXENClRzKh7rKRPHm2zYpsYhoxo9BcIF-jasdI,14317
|
|
3
|
+
DefStream/Broker/Implements/RabbitMQ/Consumer.py,sha256=pISQZqK5KB_5dvuiL0NVzG-Je7o6nd746Mu5lZcalXQ,11265
|
|
4
|
+
DefStream/Broker/Implements/RabbitMQ/Event.py,sha256=r4r7XT_-2N6XSPz8hBiGNS5di6OYe37q3INYxJAYQCk,3362
|
|
5
|
+
DefStream/Broker/Implements/RabbitMQ/Exchange.py,sha256=EblUpf1SKUfmESREWNargJwGpoSwA5v0Th5MHcwW4Xg,8444
|
|
6
|
+
DefStream/Broker/Implements/RabbitMQ/Queue.py,sha256=XXypscxJNVrNuMAOgSI93lQkiW6EV5GWEcfYeiLH11w,9446
|
|
7
|
+
DefStream/Broker/Implements/RabbitMQ/Serializer.py,sha256=PbL_V89GHPjqh1zvOM-apExhD7Bgau2jinpVCsVUg00,1718
|
|
8
|
+
DefStream/Broker/Implements/RabbitMQ/Stream.py,sha256=vhfnIhpCe1gduT09VIfp6ZhpQtHyqz6bjWhlWAjNy9E,5698
|
|
9
|
+
DefStream/Broker/Implements/RabbitMQ/Subscription.py,sha256=DyjbZ0ZiYBuJDJxVTL_tzsvJluwvsCrcowYMRPcPnzA,2553
|
|
10
|
+
DefStream/Broker/Implements/RabbitMQ/__init__.py,sha256=-0Cj2PyjAVhPSP4w1geyLzwRioAYOuFaGMrp1Le5z4I,647
|
|
11
|
+
defstream_rabbitmq-0.1.24.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
12
|
+
defstream_rabbitmq-0.1.24.dist-info/METADATA,sha256=V9mxCrN0Ej1VQOxZWYGjt6XZCwuR5fWzRtTho3x_omw,3255
|
|
13
|
+
defstream_rabbitmq-0.1.24.dist-info/WHEEL,sha256=p9NQTHLf2esq-Cr7VaqNOmqf-kvOy68UMCeyjVxLzY8,102
|
|
14
|
+
defstream_rabbitmq-0.1.24.dist-info/top_level.txt,sha256=zsnisIu5wHL4b7VM8e9AggG9KTSdUU4morFqpb8YWFs,10
|
|
15
|
+
defstream_rabbitmq-0.1.24.dist-info/RECORD,,
|