diff --git a/CHANGELOG.md b/CHANGELOG.md index 24a56d88173ee2b198012684ea3494de8f55d144..599e743bb111e7d1034c151525492c6df65abce7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ Since v1.3.2 they'll be put here and in release description. * PendingDeprecationWarning changed into a DeprecationWarning * changes to Cluster: * declare will refuse to declare an anonymous queue - * removed publish(tx) + * renamed publish(tx) to publish(confirm) # v1.5.0 ======== diff --git a/coolamqp/__init__.py b/coolamqp/__init__.py index ab3d1d537bd594a3541bdc7e29aa0d0e0a40680f..a790050877d8a8b41632471a0228d1ffa856d5bc 100644 --- a/coolamqp/__init__.py +++ b/coolamqp/__init__.py @@ -1 +1 @@ -__version__ = '1.5.1a1' +__version__ = '2.0.0a1' diff --git a/coolamqp/clustering/cluster.py b/coolamqp/clustering/cluster.py index d8eeb8b65ba9ffa99d3d86bc17db4c768006e9ab..3be5d873691ac33ca01de620f8564e2b51c87f11 100644 --- a/coolamqp/clustering/cluster.py +++ b/coolamqp/clustering/cluster.py @@ -103,7 +103,12 @@ class Cluster(object): dont_trace=False, arguments=None): """ Bind a queue to an exchange + + :raise ValueError: cannot bind to anonymous queues """ + if queue.anonymous: + raise ValueError('Canoot bind to anonymous queue') + if span is not None and not dont_trace: child_span = self._make_span('bind', span) else: @@ -121,6 +126,8 @@ class Cluster(object): """ Declare a Queue/Exchange. + Non-anonymous queues have to be declared. Anonymous can't. + .. note:: Note that if your queue relates to an exchange that has not yet been declared you'll be faced with AMQP error 404: NOT_FOUND, so try to declare your exchanges before your queues. diff --git a/coolamqp/objects.py b/coolamqp/objects.py index 6261633ec8a648ea24712f9b9c40546959a2ac51..22fd7962a224c8a92f2eb97d1ff75be211df5b3f 100644 --- a/coolamqp/objects.py +++ b/coolamqp/objects.py @@ -269,7 +269,7 @@ class Queue(object): :param arguments: either a list of (bytes, values) or a dict of (str, value) to pass as an extra argument :raises ValueError: tried to create a queue that was not durable or auto_delete :raises ValueError: tried to create a queue that was not exclusive or auto_delete and not anonymous - :raises ValueError: tried to create a queue that was anonymous and not auto_delete + :raises ValueError: tried to create a queue that was anonymous and not auto_delete or durable :warning DeprecationWarning: if a non-exclusive auto_delete queue is created or some other combinations that will be soon unavailable (eg. RabbitMQ 4.0). :warning UserWarning: if you're declaring an auto_delete or exclusive, anonymous queue @@ -298,7 +298,10 @@ class Queue(object): self.anonymous = self.name is None # if this queue is anonymous, it must be regenerated upon reconnect if self.auto_delete and self.durable: - raise ValueError('Cannot create an auto_delete and exclusive queue') + raise ValueError('Cannot create an auto_delete and durable queue') + + if self.anonymous and (not self.auto_delete or self.durable): + raise ValueError('Zero sense to make a anonymous non-auto-delete or durable queue') if not self.anonymous: if self.auto_delete or self.exclusive: diff --git a/docs/index.rst b/docs/index.rst index f7237ce1327a5e9ff07f2fef4c5f7cd082bda8b7..626a0b774f67c40c03a2b120a637dbdf8c57344a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -5,6 +5,7 @@ Welcome to CoolAMQP's documentation! :maxdepth: 2 :caption: Contents + whatsnew cluster tutorial caveats diff --git a/docs/whatsnew.rst b/docs/whatsnew.rst index ff6ef631240236e13b872ceae0d6afbff43f12b7..97a15f4f298d037cb5d40b61d4733f6ee079bb16 100644 --- a/docs/whatsnew.rst +++ b/docs/whatsnew.rst @@ -5,4 +5,26 @@ CoolAMQP 2.0.0 marks a slight philosophy shift. Whereas 1.x used auto-generated pick their names for themselves. It also forbids some combinations of Queue arguments, and makes the default values more palatable, so for example -a naked :class:`coolamqp.objects.Queue` will be anonymous, non-durable, exclusive and auto-delete. \ No newline at end of file +a naked :class:`coolamqp.objects.Queue` will be anonymous, non-durable, exclusive and auto-delete. + +Queues +------ + +Following queues will fail now: + +* auto_delete and durable +* anonymous and durables +* anonymous and not exclusives +* anonymous and not auto_delete +* auto_delete and not exclusive and not anonymous + +Following will emit a warning: + +* exclusive and auto_delete - DeprecationWarning, since they're removing it in RabbitMQ 4.0 +* not anonymous, auto_delete and not exclusive - UserWarning, since this makes little sense + +Anonymous queues +---------------- + +They are back. Besides, anything that you will pass to :meth:`coolamqp.clustering.Cluster.consume` will be declared, be +it an exchange, a queue or such shit. This allows you to declare anonymous queues. \ No newline at end of file diff --git a/tests/test_clustering/test_a.py b/tests/test_clustering/test_a.py index 27f5d69e58d3fe620b7cc85764546fac9d67caf6..1012f3a1d5590da3f2187dd0f2478f8d4b8a3858 100644 --- a/tests/test_clustering/test_a.py +++ b/tests/test_clustering/test_a.py @@ -85,7 +85,7 @@ class TestA(unittest.TestCase): def test_declare_anonymous(self): xchg = Exchange('wtfzomg', type='fanout') - q = Queue(exchange=xchg) + q = Queue('', exchange=xchg) self.c.declare(xchg).result() self.c.declare(q).result() self.assertTrue(q.name) @@ -110,7 +110,7 @@ class TestA(unittest.TestCase): con, fut = self.c.consume(Queue(u'hello3', exclusive=True), on_message=ok, no_ack=True) fut.result() - self.c.publish(Message(b''), routing_key=u'hello3', tx=True).result() + self.c.publish(Message(b''), routing_key=u'hello3', confirm=True).result() time.sleep(1) @@ -133,7 +133,7 @@ class TestA(unittest.TestCase): con, fut = self.c.consume(Queue(u'hello3', exclusive=True), on_message=ok, no_ack=False) fut.result() - self.c.publish(Message(b''), routing_key=u'hello3', tx=True).result() + self.c.publish(Message(b''), routing_key=u'hello3', confirm=True).result() time.sleep(1) @@ -159,13 +159,6 @@ class TestA(unittest.TestCase): 'content_encoding': b'utf8' }), routing_key=u'hello4', confirm=True).result() - self.assertRaises(RuntimeError, - lambda: self.c.publish(Message(b'hello4', properties={ - 'content_type': b'text/plain', - 'content_encoding': b'utf8' - }), routing_key=u'hello4', confirm=True, - tx=True).result()) - time.sleep(1) self.assertTrue(p['q']) @@ -187,7 +180,7 @@ class TestA(unittest.TestCase): self.c.publish(Message(b'hello5', properties={ 'content_type': b'text/plain', 'content_encoding': b'utf8' - }), routing_key=u'hello5', tx=True).result() + }), routing_key=u'hello5', confirm=True).result() time.sleep(2) @@ -207,7 +200,7 @@ class TestA(unittest.TestCase): on_message=ok, no_ack=True) fut.result() self.c.publish(Message(b'hello6'), routing_key=u'hello6', - tx=True).result() + confirm=True).result() time.sleep(1) diff --git a/tests/test_clustering/test_exchanges.py b/tests/test_clustering/test_exchanges.py index f6e8f932fd8b141bc06b2b4e39c8177db1c84343..070825dc1f108285c146e23d6cb35e6f889551a5 100644 --- a/tests/test_clustering/test_exchanges.py +++ b/tests/test_clustering/test_exchanges.py @@ -36,7 +36,7 @@ class TestExchanges(unittest.TestCase): grave_queue_name = uuid.uuid4().hex DEADLETTER = Exchange(xchg_name, type=b'direct') QUEUE = Queue(dead_queue_name, durable=True, auto_delete=False, exclusive=False) - GRAVEYARD_QUEUE = Queue(grave_queue_name, durable=True, arguments={'x-dead-letter-exchange': xchg_name, + GRAVEYARD_QUEUE = Queue(grave_queue_name, durable=True, auto_delete=False, arguments={'x-dead-letter-exchange': xchg_name, 'x-message-ttl': 1000}) self.c.declare(DEADLETTER).result() self.c.declare(QUEUE).result() @@ -66,7 +66,7 @@ class TestExchanges(unittest.TestCase): f1.result() f2.result() - self.c.publish(Message(b'hello'), exchange=x, tx=True).result() + self.c.publish(Message(b'hello'), exchange=x, confirm=True).result() self.assertIsInstance(self.c.drain(2), MessageReceived) self.assertIsInstance(self.c.drain(2), MessageReceived) diff --git a/tests/test_clustering/test_things.py b/tests/test_clustering/test_things.py index e49fa12b7ddad7d9b0e3bcd81409dc58a1e47636..dee2bafe64df486159702c76a9771206ad01e830 100644 --- a/tests/test_clustering/test_things.py +++ b/tests/test_clustering/test_things.py @@ -29,17 +29,15 @@ class TestConnecting(unittest.TestCase): def test_argumented_queue(self): que = Queue(auto_delete=True, exclusive=True, arguments=[(b'x-max-priority', 10)]) - que2 = Queue(auto_delete=True, exclusive=True, arguments={'x-max-priority': 10}) c = Cluster([NODE]) c.start(wait=True, timeout=None) - c.declare(que).result() - c.declare(que2).result() + self.assertRaises(ValueError, c.declare, que) c.shutdown(True) def test_argumented_bind(self): c = Cluster([NODE]) c.start(wait=True, timeout=None) - que = Queue(auto_delete=True, exclusive=True, arguments=[(b'x-max-priority', 10)]) + que = Queue('', auto_delete=True, exclusive=True, arguments=[(b'x-max-priority', 10)]) xchg = Exchange('test3-wertest', type='headers', durable=True) c.declare(que).result() c.declare(xchg).result() diff --git a/tests/test_clustering/test_topic_exchanges.py b/tests/test_clustering/test_topic_exchanges.py index 45ef2f361d312bf1fc03307c97418f7a15d5e45a..dc8c18ea29c1178c54286560b3ac3f17ca55a175 100644 --- a/tests/test_clustering/test_topic_exchanges.py +++ b/tests/test_clustering/test_topic_exchanges.py @@ -11,7 +11,7 @@ from coolamqp.objects import Exchange, Queue, NodeDefinition, Message XCHG = Exchange('smok5.results', type='topic', durable=True) -QUEUE = Queue(exchange=XCHG, exclusive=True, auto_delete=True) +QUEUE = Queue('', exchange=XCHG, exclusive=True, auto_delete=True) logger = logging.getLogger(__name__) NODE = NodeDefinition(os.environ.get('AMQP_HOST', '127.0.0.1'), 'guest', 'guest', heartbeat=20) @@ -33,8 +33,8 @@ class TestTopic(unittest.TestCase): self.c.shutdown() def test_bind_stuff(self): + self.c.declare(QUEUE) self.c.declare(XCHG).result() - self.c.declare(QUEUE).result() self.c.bind(QUEUE, XCHG, routing_key='hello-world').result() global did_receive diff --git a/tests/test_objects.py b/tests/test_objects.py index 49e119f7fcad9d18a2eee015b964a66b63df19d8..b7fa700ab48bb1c46b98b7d271ea7a102233ebc7 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -21,6 +21,14 @@ class TestObjects(unittest.TestCase): self.assertRaises(ValueError, Queue, 'test', auto_delete=True, durable=True) self.assertRaises(ValueError, Queue, None, auto_delete=False) self.assertRaises(ValueError, Queue, 'test', auto_delete=True, exclusive=False) + warnings.resetwarnings() + + with warnings.catch_warnings(record=True) as w: + Queue('test', auto_delete=True, exclusive=True) + Queue(auto_delete=True, exclusive=False) + self.assertEqual(len(w), 2) + self.assertTrue(issubclass(w[0].category, UserWarning)) + self.assertTrue(issubclass(w[1].category, DeprecationWarning)) def test_queue_declare(self): args = argumentify({'x-dead-letter-exchange': 'deadletter', @@ -38,13 +46,6 @@ class TestObjects(unittest.TestCase): ce_p_msg = MessageProperties(content_encoding=b'wtf') self.assertIn('wtf', str(ce_p_msg)) - def test_warning(self): - warnings.resetwarnings() - with warnings.catch_warnings(record=True) as w: - Queue(auto_delete=True, exclusive=False) - self.assertEqual(len(w), 1) - self.assertTrue(issubclass(w[0].category, PendingDeprecationWarning)) - def test_node_definition_from_amqp(self): n1 = NodeDefinition(u'amqp://ala:ma@kota/psa')