rabbitmq-amqp-python-client 0.3.0__tar.gz → 0.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.
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/PKG-INFO +2 -2
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/pyproject.toml +3 -3
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/__init__.py +2 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/connection.py +6 -6
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/consumer.py +59 -26
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/entities.py +18 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/options.py +24 -3
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/publisher.py +1 -1
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_utils.py +14 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/LICENSE +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/README.md +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/address_helper.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/amqp_consumer_handler.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/asyncio/__init__.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/asyncio/connection.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/asyncio/consumer.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/asyncio/environment.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/asyncio/management.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/asyncio/publisher.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/common.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/delivery_context.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/environment.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/exceptions.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/management.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/py.typed +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/__init__.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_common.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_condition.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_data.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_delivery.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_endpoints.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_events.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_exceptions.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_handler.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_handlers.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_io.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_message.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_reactor.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_selectable.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_tracing.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_transport.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_url.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/_wrapper.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/handlers.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/py.typed +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/reactor.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/tracing.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/qpid/proton/utils.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/queues.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/ssl_configuration.py +0 -0
- {rabbitmq_amqp_python_client-0.3.0 → rabbitmq_amqp_python_client-0.4.0}/rabbitmq_amqp_python_client/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rabbitmq-amqp-python-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Python RabbitMQ client for AMQP 1.0 protocol
|
|
5
5
|
License: Apache-2.0 license
|
|
6
6
|
License-File: LICENSE
|
|
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.14
|
|
17
17
|
Requires-Dist: packaging (>=23.0,<24.0)
|
|
18
|
-
Requires-Dist: python-qpid-proton (>=0.
|
|
18
|
+
Requires-Dist: python-qpid-proton (>=0.40.0,<0.41.0)
|
|
19
19
|
Requires-Dist: typing-extensions (>=4.13.0,<5.0.0)
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "rabbitmq-amqp-python-client"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Python RabbitMQ client for AMQP 1.0 protocol"
|
|
5
5
|
authors = ["RabbitMQ team"]
|
|
6
6
|
license = "Apache-2.0 license"
|
|
@@ -8,7 +8,7 @@ readme = "README.md"
|
|
|
8
8
|
|
|
9
9
|
[tool.poetry.dependencies]
|
|
10
10
|
python = "^3.9"
|
|
11
|
-
python-qpid-proton = "^0.
|
|
11
|
+
python-qpid-proton = "^0.40.0"
|
|
12
12
|
typing-extensions = "^4.13.0"
|
|
13
13
|
packaging = "^23.0"
|
|
14
14
|
|
|
@@ -21,7 +21,7 @@ isort = "^5.9.3"
|
|
|
21
21
|
mypy = "^0.910"
|
|
22
22
|
pytest = "^8.3.4"
|
|
23
23
|
black = "^24.3.0"
|
|
24
|
-
python-qpid-proton = "^0.
|
|
24
|
+
python-qpid-proton = "^0.40.0"
|
|
25
25
|
requests = "^2.31.0"
|
|
26
26
|
pytest-asyncio = "^1.2.0"
|
|
27
27
|
|
|
@@ -14,6 +14,7 @@ from .connection import Connection
|
|
|
14
14
|
from .consumer import Consumer
|
|
15
15
|
from .entities import (
|
|
16
16
|
ConsumerOptions,
|
|
17
|
+
DirectReplyToConsumerOptions,
|
|
17
18
|
ExchangeCustomSpecification,
|
|
18
19
|
ExchangeSpecification,
|
|
19
20
|
ExchangeToExchangeBindingSpecification,
|
|
@@ -72,6 +73,7 @@ __all__ = [
|
|
|
72
73
|
"QuorumQueueSpecification",
|
|
73
74
|
"ClassicQueueSpecification",
|
|
74
75
|
"StreamSpecification",
|
|
76
|
+
"DirectReplyToConsumerOptions",
|
|
75
77
|
"ExchangeToQueueBindingSpecification",
|
|
76
78
|
"ExchangeToExchangeBindingSpecification",
|
|
77
79
|
"QueueType",
|
|
@@ -379,7 +379,7 @@ class Connection:
|
|
|
379
379
|
|
|
380
380
|
def consumer(
|
|
381
381
|
self,
|
|
382
|
-
destination: str,
|
|
382
|
+
destination: Optional[str] = None,
|
|
383
383
|
message_handler: Optional[MessagingHandler] = None,
|
|
384
384
|
consumer_options: Optional[ConsumerOptions] = None,
|
|
385
385
|
credit: Optional[int] = None,
|
|
@@ -388,7 +388,7 @@ class Connection:
|
|
|
388
388
|
Create a new consumer instance.
|
|
389
389
|
|
|
390
390
|
Args:
|
|
391
|
-
destination: The address to consume from
|
|
391
|
+
destination: Optional The address to consume from
|
|
392
392
|
message_handler: Optional handler for processing messages
|
|
393
393
|
consumer_options: Optional configuration for queue consumption. Each queue has its own consumer options.
|
|
394
394
|
credit: Optional credit value for flow control
|
|
@@ -397,9 +397,11 @@ class Connection:
|
|
|
397
397
|
Consumer: A new consumer instance
|
|
398
398
|
|
|
399
399
|
Raises:
|
|
400
|
-
ArgumentOutOfRangeException: If destination address format is invalid
|
|
400
|
+
ArgumentOutOfRangeException: If destination address format is invalid.
|
|
401
|
+
Only applies if not using Direct Reply-to.
|
|
402
|
+
The server will provide the queue name in that case.
|
|
401
403
|
"""
|
|
402
|
-
if not validate_address(destination):
|
|
404
|
+
if destination is not None and not validate_address(destination):
|
|
403
405
|
raise ArgumentOutOfRangeException(
|
|
404
406
|
"destination address must start with /queues or /exchanges"
|
|
405
407
|
)
|
|
@@ -438,9 +440,7 @@ class Connection:
|
|
|
438
440
|
time.sleep(delay.total_seconds())
|
|
439
441
|
|
|
440
442
|
try:
|
|
441
|
-
|
|
442
443
|
self._open_connections(reconnect_handlers=True)
|
|
443
|
-
|
|
444
444
|
self._connections.append(self)
|
|
445
445
|
|
|
446
446
|
except ConnectionException as e:
|
|
@@ -2,7 +2,11 @@ import logging
|
|
|
2
2
|
from typing import Literal, Optional, Union, cast
|
|
3
3
|
|
|
4
4
|
from .amqp_consumer_handler import AMQPMessagingHandler
|
|
5
|
-
from .entities import
|
|
5
|
+
from .entities import (
|
|
6
|
+
ConsumerOptions,
|
|
7
|
+
DirectReplyToConsumerOptions,
|
|
8
|
+
StreamConsumerOptions,
|
|
9
|
+
)
|
|
6
10
|
from .options import (
|
|
7
11
|
ReceiverOptionUnsettled,
|
|
8
12
|
ReceiverOptionUnsettledWithFilters,
|
|
@@ -29,16 +33,16 @@ class Consumer:
|
|
|
29
33
|
_conn (BlockingConnection): The underlying connection to RabbitMQ
|
|
30
34
|
_addr (str): The address to consume from
|
|
31
35
|
_handler (Optional[MessagingHandler]): Optional message handling callback
|
|
32
|
-
|
|
36
|
+
_consumer_options (Optional[StreamConsumerOptions]): Configuration for stream consumption
|
|
33
37
|
_credit (Optional[int]): Flow control credit value
|
|
34
38
|
"""
|
|
35
39
|
|
|
36
40
|
def __init__(
|
|
37
41
|
self,
|
|
38
42
|
conn: BlockingConnection,
|
|
39
|
-
addr: str,
|
|
43
|
+
addr: Optional[str] = None,
|
|
40
44
|
handler: Optional[AMQPMessagingHandler] = None,
|
|
41
|
-
|
|
45
|
+
consumer_options: Optional[ConsumerOptions] = None,
|
|
42
46
|
credit: Optional[int] = None,
|
|
43
47
|
):
|
|
44
48
|
"""
|
|
@@ -48,14 +52,14 @@ class Consumer:
|
|
|
48
52
|
conn: The blocking connection to use for consuming
|
|
49
53
|
addr: The address to consume from
|
|
50
54
|
handler: Optional message handler for processing received messages
|
|
51
|
-
|
|
55
|
+
consumer_options: Optional configuration for stream-based consumption
|
|
52
56
|
credit: Optional credit value for flow control
|
|
53
57
|
"""
|
|
54
58
|
self._receiver: Optional[BlockingReceiver] = None
|
|
55
59
|
self._conn = conn
|
|
56
60
|
self._addr = addr
|
|
57
61
|
self._handler = handler
|
|
58
|
-
self.
|
|
62
|
+
self._consumer_options = consumer_options
|
|
59
63
|
self._credit = credit
|
|
60
64
|
self._consumers: list[Consumer] = []
|
|
61
65
|
self._open()
|
|
@@ -66,21 +70,25 @@ class Consumer:
|
|
|
66
70
|
self._receiver = self._create_receiver(self._addr)
|
|
67
71
|
|
|
68
72
|
def _update_connection(self, conn: BlockingConnection) -> None:
|
|
73
|
+
addr = ""
|
|
74
|
+
if self._addr is not None:
|
|
75
|
+
addr = self._addr
|
|
76
|
+
|
|
69
77
|
self._conn = conn
|
|
70
|
-
if self.
|
|
78
|
+
if self._consumer_options is None:
|
|
71
79
|
logger.debug("creating new receiver without stream")
|
|
72
80
|
self._receiver = self._conn.create_receiver(
|
|
73
|
-
|
|
74
|
-
options=ReceiverOptionUnsettled(
|
|
81
|
+
addr,
|
|
82
|
+
options=ReceiverOptionUnsettled(addr),
|
|
75
83
|
handler=self._handler,
|
|
76
84
|
)
|
|
77
85
|
else:
|
|
78
86
|
logger.debug("creating new stream receiver")
|
|
79
|
-
self.
|
|
87
|
+
self._consumer_options.offset(self._handler.offset - 1) # type: ignore
|
|
80
88
|
self._receiver = self._conn.create_receiver(
|
|
81
|
-
|
|
89
|
+
addr,
|
|
82
90
|
options=ReceiverOptionUnsettledWithFilters(
|
|
83
|
-
|
|
91
|
+
addr, self._consumer_options
|
|
84
92
|
),
|
|
85
93
|
handler=self._handler,
|
|
86
94
|
)
|
|
@@ -142,29 +150,54 @@ class Consumer:
|
|
|
142
150
|
self._receiver.container.stop_events()
|
|
143
151
|
self._receiver.container.stop()
|
|
144
152
|
|
|
145
|
-
def _create_receiver(self, addr: str) -> BlockingReceiver:
|
|
146
|
-
|
|
147
|
-
if self.
|
|
148
|
-
|
|
149
|
-
addr, options=ReceiverOptionUnsettled(addr), handler=self._handler
|
|
150
|
-
)
|
|
153
|
+
def _create_receiver(self, addr: Optional[str] = None) -> BlockingReceiver:
|
|
154
|
+
credit = 10
|
|
155
|
+
if self._credit is not None:
|
|
156
|
+
credit = self._credit
|
|
151
157
|
|
|
158
|
+
if self._consumer_options is not None:
|
|
159
|
+
logger.debug(
|
|
160
|
+
"Creating the receiver, with options: %s",
|
|
161
|
+
type(self._consumer_options).__name__,
|
|
162
|
+
)
|
|
152
163
|
else:
|
|
153
|
-
receiver
|
|
164
|
+
logger.debug("Creating the receiver, without options")
|
|
165
|
+
|
|
166
|
+
if self._consumer_options is None:
|
|
167
|
+
return self._conn.create_receiver(
|
|
154
168
|
addr,
|
|
155
|
-
options=
|
|
169
|
+
options=ReceiverOptionUnsettled(addr),
|
|
156
170
|
handler=self._handler,
|
|
171
|
+
credit=credit,
|
|
157
172
|
)
|
|
158
173
|
|
|
159
|
-
if self.
|
|
160
|
-
|
|
174
|
+
if isinstance(self._consumer_options, DirectReplyToConsumerOptions):
|
|
175
|
+
logger.debug("Creating dynamic receiver for direct reply-to")
|
|
176
|
+
dynamic_receiver = self._conn.create_dynamic_receiver(
|
|
177
|
+
credit, handler=self._handler
|
|
178
|
+
)
|
|
179
|
+
dynamic_receiver.credit = credit
|
|
180
|
+
return dynamic_receiver
|
|
161
181
|
|
|
162
|
-
|
|
182
|
+
if isinstance(self._consumer_options, StreamConsumerOptions):
|
|
183
|
+
return self._conn.create_receiver(
|
|
184
|
+
addr,
|
|
185
|
+
options=ReceiverOptionUnsettledWithFilters(
|
|
186
|
+
addr, self._consumer_options
|
|
187
|
+
),
|
|
188
|
+
handler=self._handler,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
raise Exception(
|
|
192
|
+
"Receiver is not initialized. No valid consumer options provided."
|
|
193
|
+
)
|
|
163
194
|
|
|
164
195
|
@property
|
|
165
|
-
def address(self) -> str:
|
|
166
|
-
|
|
167
|
-
|
|
196
|
+
def address(self) -> Optional[str]:
|
|
197
|
+
if self._receiver is not None:
|
|
198
|
+
return cast(Optional[str], self._receiver.link.remote_source.address)
|
|
199
|
+
else:
|
|
200
|
+
raise Exception("Receiver is not initialized")
|
|
168
201
|
|
|
169
202
|
@property
|
|
170
203
|
def handler(self) -> Optional[AMQPMessagingHandler]:
|
|
@@ -160,6 +160,9 @@ class ConsumerOptions:
|
|
|
160
160
|
def filter_set(self) -> Dict[symbol, Described]:
|
|
161
161
|
raise NotImplementedError("Subclasses should implement this method")
|
|
162
162
|
|
|
163
|
+
def direct_reply_to(self) -> bool:
|
|
164
|
+
return False
|
|
165
|
+
|
|
163
166
|
|
|
164
167
|
@dataclass
|
|
165
168
|
class MessageProperties:
|
|
@@ -400,6 +403,21 @@ class StreamConsumerOptions(ConsumerOptions):
|
|
|
400
403
|
)
|
|
401
404
|
|
|
402
405
|
|
|
406
|
+
class DirectReplyToConsumerOptions(ConsumerOptions):
|
|
407
|
+
|
|
408
|
+
def validate(self, versions: Dict[str, bool]) -> None:
|
|
409
|
+
if not versions.get("4.2.0", False):
|
|
410
|
+
raise ValidationCodeException(
|
|
411
|
+
"Direct Reply-To requires RabbitMQ 4.2.0 or higher"
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
def filter_set(self) -> Dict[symbol, Described]:
|
|
415
|
+
return {}
|
|
416
|
+
|
|
417
|
+
def direct_reply_to(self) -> bool:
|
|
418
|
+
return True
|
|
419
|
+
|
|
420
|
+
|
|
403
421
|
@dataclass
|
|
404
422
|
class RecoveryConfiguration:
|
|
405
423
|
"""
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
1
3
|
from .entities import ConsumerOptions
|
|
2
4
|
from .qpid.proton._data import ( # noqa: E402
|
|
5
|
+
Data,
|
|
3
6
|
PropertyDict,
|
|
4
7
|
symbol,
|
|
5
8
|
)
|
|
6
|
-
from .qpid.proton._endpoints import
|
|
9
|
+
from .qpid.proton._endpoints import ( # noqa: E402
|
|
10
|
+
Link,
|
|
11
|
+
Terminus,
|
|
12
|
+
)
|
|
7
13
|
from .qpid.proton.reactor import ( # noqa: E402
|
|
8
14
|
Filter,
|
|
9
15
|
LinkOption,
|
|
@@ -52,8 +58,23 @@ class ReceiverOption(LinkOption): # type: ignore
|
|
|
52
58
|
link.source.dynamic = False
|
|
53
59
|
|
|
54
60
|
|
|
61
|
+
class DynamicReceiverOption(LinkOption): # type: ignore
|
|
62
|
+
|
|
63
|
+
def apply(self, link: Link) -> None:
|
|
64
|
+
link.snd_settle_mode = Link.SND_SETTLED
|
|
65
|
+
# link.rcv_settle_mode = Link.RCV_FIRST
|
|
66
|
+
link.source.expiry_policy = Terminus.EXPIRE_WITH_LINK
|
|
67
|
+
link.properties = PropertyDict({symbol("paired"): True})
|
|
68
|
+
link.source.dynamic = True
|
|
69
|
+
data = link.source.capabilities
|
|
70
|
+
data.put_array(False, Data.SYMBOL)
|
|
71
|
+
data.enter()
|
|
72
|
+
data.put_string("rabbitmq:volatile-queue")
|
|
73
|
+
data.exit()
|
|
74
|
+
|
|
75
|
+
|
|
55
76
|
class ReceiverOptionUnsettled(LinkOption): # type: ignore
|
|
56
|
-
def __init__(self, addr: str):
|
|
77
|
+
def __init__(self, addr: Optional[str]):
|
|
57
78
|
self._addr = addr
|
|
58
79
|
|
|
59
80
|
def apply(self, link: Link) -> None:
|
|
@@ -68,7 +89,7 @@ class ReceiverOptionUnsettled(LinkOption): # type: ignore
|
|
|
68
89
|
|
|
69
90
|
|
|
70
91
|
class ReceiverOptionUnsettledWithFilters(Filter): # type: ignore
|
|
71
|
-
def __init__(self, addr: str, consumer_options: ConsumerOptions):
|
|
92
|
+
def __init__(self, addr: Optional[str], consumer_options: ConsumerOptions):
|
|
72
93
|
super().__init__(consumer_options.filter_set())
|
|
73
94
|
self._addr = addr
|
|
74
95
|
|
|
@@ -94,7 +94,7 @@ class Publisher:
|
|
|
94
94
|
return self._sender.send(message)
|
|
95
95
|
else:
|
|
96
96
|
if message.address != "":
|
|
97
|
-
if validate_address(message.address)
|
|
97
|
+
if not validate_address(message.address):
|
|
98
98
|
raise ArgumentOutOfRangeException(
|
|
99
99
|
"destination address must start with /queues or /exchanges"
|
|
100
100
|
)
|
|
@@ -44,6 +44,7 @@ from ._handlers import (
|
|
|
44
44
|
)
|
|
45
45
|
from ._reactor import Container
|
|
46
46
|
from ._url import Url
|
|
47
|
+
from ...options import DynamicReceiverOption
|
|
47
48
|
|
|
48
49
|
try:
|
|
49
50
|
from typing import Literal
|
|
@@ -505,6 +506,17 @@ class BlockingConnection(Handler):
|
|
|
505
506
|
),
|
|
506
507
|
)
|
|
507
508
|
|
|
509
|
+
def create_dynamic_receiver(
|
|
510
|
+
self, credit: Optional[int] = None, handler: Optional[Handler] = None
|
|
511
|
+
):
|
|
512
|
+
return self.create_receiver(
|
|
513
|
+
credit=credit,
|
|
514
|
+
dynamic=True,
|
|
515
|
+
options=DynamicReceiverOption(),
|
|
516
|
+
handler=handler,
|
|
517
|
+
name="dynamic-receiver_" + str(id(self)),
|
|
518
|
+
)
|
|
519
|
+
|
|
508
520
|
def create_receiver(
|
|
509
521
|
self,
|
|
510
522
|
address: Optional[str] = None,
|
|
@@ -514,6 +526,8 @@ class BlockingConnection(Handler):
|
|
|
514
526
|
name: Optional[str] = None,
|
|
515
527
|
options: Optional[
|
|
516
528
|
Union[
|
|
529
|
+
"DynamicReceiverOption",
|
|
530
|
+
List["DynamicReceiverOption"],
|
|
517
531
|
"ReceiverOption",
|
|
518
532
|
List["ReceiverOption"],
|
|
519
533
|
"LinkOption",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|