diff --git a/.gitignore b/.gitignore index f9d49a43ee06c8fff3cafedeb1a9cb8e2480eada..ad90b870040f2eb87f5c43f09d80bc0ee166e2ed 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ __pycache__/ coolamqp/framing/definitions.py .pycharm_helpers/ # Distribution / packaging +*.xml .Python env/ build/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c5d1d51872a8e3600f9fdb18b04c16765a4ef80..136fbf9ca279e5717a1c196a694a4d66d468352c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ Previous release notes are hosted on [GitHub](https://github.com/smok-serwis/coolamqp/releases). Since v1.3.2 they'll be put here and in release description. +v2.1.2 +====== + +* extra_properties passed to Cluster might now be a dict + +v2.1.1 +====== + +* fixed a bug in Queue's __repr__ +* fixed a bug in BasicContentPropertyList.typize +* removed Vagrantfile + v2.1.0 ====== diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 411519fff2cb111d7077a455887fb30cd545df95..14609d6faedb991461901af7d14d2e58e4d02226 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,16 +14,12 @@ docker-compose up --build unittest docker-compose up --build stress_tests ``` -If you want to debug things, you have RabbitMQ management enabled on Vagrant. -Go to [http://127.0.0.1:15672](http://127.0.0.1:15672) and log in with **user** / **user** - -RabbitMQ management is NOT enabled on Travis CI. +If you want to debug things, please install a RabbitMQ instance via Docker, expose the necessary ports and go from there. If you want to see a coverage report, run tests like this: ```bash nosetests --with-coverage --exe coverage html ``` -*--exe* is for the cases where you run on Windows, and everything in */vagrant* is 777. and then go to [http://127.0.0.1:8765](http://127.0.0.1:8765) diff --git a/Vagrantfile b/Vagrantfile deleted file mode 100644 index fd59ee2770b0e53802264e10ad6163a258fa7a4f..0000000000000000000000000000000000000000 --- a/Vagrantfile +++ /dev/null @@ -1,48 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure("2") do |config| - - config.vm.box = "debian/bullseye64" - - # Rabbit MQ management - config.vm.network "forwarded_port", guest: 15672, host: 15672, auto_correct: true - - # HTTP for viewing coverage reports - config.vm.network "forwarded_port", guest: 80, host: 8765 - - config.vm.provision "shell", inline: <<-SHELL - apt-get update - - # Python - apt-get install -y htop curl python python-setuptools python3-pip python-dev build-essential rabbitmq-server python3 python3-setuptools -# sudo python -m pip install --upgrade pip setuptools - sudo pip3 install --upgrade pip setuptools - - /usr/lib/rabbitmq/bin/rabbitmq-plugins enable rabbitmq_management - sudo service rabbitmq-server restart - rabbitmqctl add_user user user - rabbitmqctl set_permissions -p / user ".*" ".*" ".*" - rabbitmqctl set_permissions -p / guest ".*" ".*" ".*" - rabbitmqctl set_user_tags user administrator - - # Install deps -# sudo python -m pip install -r /vagrant/requirements.txt -# sudo python -m pip install nose coverage mock yapf - sudo pip3 install -r /vagrant/requirements.txt - sudo pip3 install nose2[coverage_plugin] coverage mock yapf nose2 - - sudo pip3 install -r /vagrant/stress_tests/requirements.txt - - # HTTP server for viewing coverage reports - apt-get -y install nginx - rm -rf /var/www/html - ln -s /vagrant/htmlcov /var/www/html - - # .bashrc for default user - echo """# .bashrc - cd /vagrant""" > /home/vagrant/.bashrc - - SHELL - -end diff --git a/compile_definitions/__main__.py b/compile_definitions/__main__.py index c3d26de1c705731c8f1c1a30cb7843307a7d7a26..7349656fc089298d87efc5fd9cf4f59224c40c3e 100644 --- a/compile_definitions/__main__.py +++ b/compile_definitions/__main__.py @@ -303,6 +303,16 @@ Field = collections.namedtuple('Field', ('name', 'type', 'basic_type', 'reserved line(u''' @staticmethod def typize(*fields): # type: (*str) -> type + """ + Return an autonomous class definition which is a header supporting only particular fields. + + Usage: + + >>> Headers = BasicContentPropertyList.typize('content_type', 'content_encoding') + >>> headers = Headers('application/json', 'gzip') + + The reason for this is speed. + """ ''') line(u' zpf = bytearray([\n') @@ -325,7 +335,7 @@ Field = collections.namedtuple('Field', ('name', 'type', 'basic_type', 'reserved if field.reserved or field.basic_type == 'bit': pass # zero else: - byte_chunk.append(u"int('%s' in kwargs)" % ( + byte_chunk.append(u"int('%s' in fields)" % ( format_field_name(field.name),)) else: # this is the "do we need moar flags" section diff --git a/coolamqp/framing/definitions.py b/coolamqp/framing/definitions.py index 12645c898bd832e965ac6b80b0c57669f4bbf0bc..8a19208b48b5a071f4976ec0e08866e13c09d817 100644 --- a/coolamqp/framing/definitions.py +++ b/coolamqp/framing/definitions.py @@ -1,9 +1,5 @@ # coding=UTF-8 from __future__ import print_function, absolute_import - -import coolamqp.argumentify -from coolamqp.argumentify import argumentify - """ A Python version of the AMQP machine-readable specification. @@ -2987,12 +2983,22 @@ class BasicContentPropertyList(AMQPContentPropertyList): @staticmethod def typize(*fields): # type: (*str) -> type + """ + Return an autonomous class definition which is a header supporting only particular fields. + + Usage: + + >>> Headers = BasicContentPropertyList.typize('content_type', 'content_encoding') + >>> headers = Headers('application/json', 'gzip') + + The reason for this is speed. + """ zpf = bytearray([ (('content_type' in fields) << 7) | (('content_encoding' in fields) << 6) | (('headers' in fields) << 5) | (('delivery_mode' in fields) << 4) | (('priority' in fields) << 3) | (('correlation_id' in fields) << 2) - | (('reply_to' in fields) << 1) | int('expiration' in kwargs), + | (('reply_to' in fields) << 1) | int('expiration' in fields), (('message_id' in fields) << 7) | (('timestamp' in fields) << 6) | (('type_' in fields) << 5) | (('user_id' in fields) << 4) | (('app_id' in fields) << 3) | (('reserved' in fields) << 2) @@ -3025,8 +3031,7 @@ class BasicContentPropertyList(AMQPContentPropertyList): while buf[offset + pfl - 1] & 1: pfl += 2 zpf = BasicContentPropertyList.zero_property_flags(buf[offset:offset + - pfl]).tobytes() - + pfl]).tobytes() if zpf in BasicContentPropertyList.PARTICULAR_CLASSES: return BasicContentPropertyList.PARTICULAR_CLASSES[ zpf].from_buffer(buf, offset) diff --git a/coolamqp/objects.py b/coolamqp/objects.py index b1547e4c22d449516906f2af3eacae7d11918c1f..2fa1fb008bdeef56999579e53d888b02bdbbf4b4 100644 --- a/coolamqp/objects.py +++ b/coolamqp/objects.py @@ -233,15 +233,15 @@ class Exchange(object): assert isinstance(self.type, six.binary_type) def __repr__(self): # type: () -> str - return u'Exchange(%s, %s, %s, %s)' % ( + return u'Exchange(%s, %s, %s, %s, %s)' % ( repr(self.name), repr(self.type), repr(self.durable), - repr(self.auto_delete)) + repr(self.auto_delete), repr(self.arguments)) def __hash__(self): # type: () -> int return self.name.__hash__() def __eq__(self, other): # type: (Exchange) -> bool - return (self.name == other.name) and (type(self) == type(other)) + return (self.name == other.name) and (self.type == other.type) and isinstance(other, self.__class__) Exchange.direct = Exchange() @@ -342,9 +342,6 @@ class Queue(object): if self.durable and self.anonymous: raise ValueError('Cannot declare an anonymous durable queue') - if self.auto_delete and not self.exclusive and not self.anonymous: - raise ValueError('Cannot create an auto_delete and durable queue non-anonymous') - self.consumer_tag = self.name if not self.anonymous else tobytes(uuid.uuid4().hex) if not self.exclusive and self.auto_delete: @@ -357,7 +354,9 @@ class Queue(object): return hash(self.name) def __repr__(self): - return 'Queue(%s, %s, %s, %s, %s, %s' % (self.name, self.durable, self.exchange, self.exclusive, self.arguments) + return 'Queue(%s, %s, %s, %s, %s, %s, %s, %s)' % (self.name, self.durable, repr(self.exchange), self.exclusive, + self.auto_delete, repr(self.arguments), self.routing_key, + repr(self.arguments_bind)) class QueueBind(object): diff --git a/docker-compose.yml b/docker-compose.yml index c93f04898bd736f4a89f673f2c49502fb7397380..dfb3f977744c3f8be99333ad9d8ed5f5e3df0638 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: amqp: image: rabbitmq:4.0-management unittest: - command: nose2 -vv tests.test_clustering.test_streams + command: nose2 -vv build: context: . dockerfile: tests/Dockerfile diff --git a/tests/test_clustering/test_things.py b/tests/test_clustering/test_things.py index c64d7ec0e65087ae014f1a39f22b1aaca4e142e7..08aafb5d511871874db2045b47a4d60ae3ae9a34 100644 --- a/tests/test_clustering/test_things.py +++ b/tests/test_clustering/test_things.py @@ -7,6 +7,8 @@ import os import time import unittest +from coolamqp.framing.definitions import BasicContentPropertyList + from coolamqp.clustering import Cluster from coolamqp.exceptions import ConnectionDead from coolamqp.objects import NodeDefinition, Queue, Exchange @@ -25,6 +27,7 @@ class TestConnecting(unittest.TestCase): def test_argumented_exchange(self): xchg = Exchange('test-wer', durable=True) + repr(xchg) c = Cluster([NODE]) c.start(wait=True, timeout=None) c.declare(xchg).result() @@ -34,11 +37,16 @@ class TestConnecting(unittest.TestCase): def test_argumented_queue(self): que = Queue(auto_delete=True, exclusive=True, arguments=[(b'x-max-priority', 10)]) + repr(que) c = Cluster([NODE]) c.start(wait=True, timeout=None) self.assertRaises(ValueError, c.declare, que) c.shutdown(True) + def test_typize(self): + bcpl = BasicContentPropertyList.typize('content_type', 'content_encoding') + bcpl2 = bcpl('application/json', 'text/plain') + def test_argumented_bind(self): c = Cluster([NODE]) c.start(wait=True, timeout=None) diff --git a/tests/test_objects.py b/tests/test_objects.py index 7127d87baeea4ed72dfc09c66c1328405c27b8da..15d55f9839b81151fc4f972bffacc649862e21ab 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -8,7 +8,7 @@ import warnings from coolamqp.framing.definitions import QueueDeclare -from coolamqp.objects import NodeDefinition, MessageProperties, Queue +from coolamqp.objects import NodeDefinition, MessageProperties, Queue, Exchange from coolamqp.argumentify import argumentify logger = logging.getLogger(__name__) @@ -19,11 +19,24 @@ IS_PY3 = sys.version.startswith('3') class TestObjects(unittest.TestCase): + def test_exchange_repr(self): + xchg = Exchange() + repr(xchg) + queue = Queue(exchange=xchg) + repr(queue) + + a = {xchg: 5, queue: 3} + self.assertEqual(a[xchg], 5) + self.assertEqual(a[queue], 3) + def test_queue_failures(self): - self.assertRaises(ValueError, Queue, None, durable=True) + Queue() + Queue('') + self.assertRaises(ValueError, Queue, durable=True) + self.assertRaises(ValueError, Queue, auto_delete=False, durable=True) 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) + self.assertRaises(ValueError, Queue, auto_delete=False) + repr(Queue()) def test_queue_repr(self): q = Queue('test')