Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-amqp for openSUSE:Factory checked in at 2021-12-21 18:40:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-amqp (Old) and /work/SRC/openSUSE:Factory/.python-amqp.new.2520 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-amqp" Tue Dec 21 18:40:16 2021 rev:38 rq:941637 version:5.0.8 Changes: -------- --- /work/SRC/openSUSE:Factory/python-amqp/python-amqp.changes 2021-07-10 22:53:34.864185233 +0200 +++ /work/SRC/openSUSE:Factory/.python-amqp.new.2520/python-amqp.changes 2021-12-21 18:40:18.321856269 +0100 @@ -1,0 +2,10 @@ +Mon Dec 20 11:07:31 UTC 2021 - Dirk M??ller <dmuel...@suse.com> + +- update to 5.0.8: + - Reduce memory usage of Connection (#377) + - Add additional error handling around code where an OSError + may be raised on failed connections. Fixes (#378) + - Remove dependency to case + - Bugfix: not closing socket after server disconnect + +------------------------------------------------------------------- Old: ---- amqp-5.0.6.tar.gz New: ---- amqp-5.0.8.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-amqp.spec ++++++ --- /var/tmp/diff_new_pack.tGai9G/_old 2021-12-21 18:40:18.873856764 +0100 +++ /var/tmp/diff_new_pack.tGai9G/_new 2021-12-21 18:40:18.881856771 +0100 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-amqp -Version: 5.0.6 +Version: 5.0.8 Release: 0 Summary: Low-level AMQP client for Python (fork of amqplib) License: LGPL-2.1-or-later ++++++ amqp-5.0.6.tar.gz -> amqp-5.0.8.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/Changelog new/amqp-5.0.8/Changelog --- old/amqp-5.0.6/Changelog 2021-04-01 06:40:10.000000000 +0200 +++ new/amqp-5.0.8/Changelog 2021-12-19 06:01:33.000000000 +0100 @@ -5,6 +5,30 @@ The previous amqplib changelog is here: http://code.google.com/p/py-amqplib/source/browse/CHANGES + +.. _version-5.0.8: + +5.0.8 +===== +:release-date: 2021-12-19 11:15 A.M. UTC+6:00 +:release-by: Asif Saif Uddin + +- Reduce memory usage of Connection (#377) +- Add additional error handling around code where an OSError + may be raised on failed connections. Fixes (#378) + + +.. _version-5.0.7: + +5.0.7 +===== +:release-date: 2021-12-13 15:45 P.M. UTC+6:00 +:release-by: Asif Saif Uddin + +- Remove dependency to case +- Bugfix: not closing socket after server disconnect + + .. _version-5.0.6: 5.0.6 @@ -167,7 +191,7 @@ :release-by: Asif Saif Uddin - Fix buffer overflow in frame_writer after frame_max is increased. `frame_writer` -allocates a `bytearray` on intialization with a length based on the `connection.frame_max` +allocates a `bytearray` on initialization with a length based on the `connection.frame_max` value. If `connection.frame_max` is changed to a larger value, this causes an error like `pack_into requires a buffer of at least 408736 bytes`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/PKG-INFO new/amqp-5.0.8/PKG-INFO --- old/amqp-5.0.6/PKG-INFO 2021-04-01 08:11:48.080170400 +0200 +++ new/amqp-5.0.8/PKG-INFO 2021-12-19 06:06:23.980194600 +0100 @@ -1,223 +1,12 @@ Metadata-Version: 2.1 Name: amqp -Version: 5.0.6 +Version: 5.0.8 Summary: Low-level AMQP client for Python (fork of amqplib). Home-page: http://github.com/celery/py-amqp Author: Barry Pederson Author-email: pya...@celeryproject.org Maintainer: Asif Saif Uddin, Matus Valo License: BSD -Description: ===================================================================== - Python AMQP 0.9.1 client library - ===================================================================== - - |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| - - :Version: 5.0.6 - :Web: https://amqp.readthedocs.io/ - :Download: https://pypi.org/project/amqp/ - :Source: http://github.com/celery/py-amqp/ - :Keywords: amqp, rabbitmq - - About - ===== - - This is a fork of amqplib_ which was originally written by Barry Pederson. - It is maintained by the Celery_ project, and used by `kombu`_ as a pure python - alternative when `librabbitmq`_ is not available. - - This library should be API compatible with `librabbitmq`_. - - .. _amqplib: https://pypi.org/project/amqplib/ - .. _Celery: http://celeryproject.org/ - .. _kombu: https://kombu.readthedocs.io/ - .. _librabbitmq: https://pypi.org/project/librabbitmq/ - - Differences from `amqplib`_ - =========================== - - - Supports draining events from multiple channels (``Connection.drain_events``) - - Support for timeouts - - Channels are restored after channel error, instead of having to close the - connection. - - Support for heartbeats - - - ``Connection.heartbeat_tick(rate=2)`` must called at regular intervals - (half of the heartbeat value if rate is 2). - - Or some other scheme by using ``Connection.send_heartbeat``. - - Supports RabbitMQ extensions: - - Consumer Cancel Notifications - - by default a cancel results in ``ChannelError`` being raised - - but not if a ``on_cancel`` callback is passed to ``basic_consume``. - - Publisher confirms - - ``Channel.confirm_select()`` enables publisher confirms. - - ``Channel.events['basic_ack'].append(my_callback)`` adds a callback - to be called when a message is confirmed. This callback is then - called with the signature ``(delivery_tag, multiple)``. - - Exchange-to-exchange bindings: ``exchange_bind`` / ``exchange_unbind``. - - ``Channel.confirm_select()`` enables publisher confirms. - - ``Channel.events['basic_ack'].append(my_callback)`` adds a callback - to be called when a message is confirmed. This callback is then - called with the signature ``(delivery_tag, multiple)``. - - Authentication Failure Notifications - Instead of just closing the connection abruptly on invalid - credentials, py-amqp will raise an ``AccessRefused`` error - when connected to rabbitmq-server 3.2.0 or greater. - - Support for ``basic_return`` - - Uses AMQP 0-9-1 instead of 0-8. - - ``Channel.access_request`` and ``ticket`` arguments to methods - **removed**. - - Supports the ``arguments`` argument to ``basic_consume``. - - ``internal`` argument to ``exchange_declare`` removed. - - ``auto_delete`` argument to ``exchange_declare`` deprecated - - ``insist`` argument to ``Connection`` removed. - - ``Channel.alerts`` has been removed. - - Support for ``Channel.basic_recover_async``. - - ``Channel.basic_recover`` deprecated. - - Exceptions renamed to have idiomatic names: - - ``AMQPException`` -> ``AMQPError`` - - ``AMQPConnectionException`` -> ConnectionError`` - - ``AMQPChannelException`` -> ChannelError`` - - ``Connection.known_hosts`` removed. - - ``Connection`` no longer supports redirects. - - ``exchange`` argument to ``queue_bind`` can now be empty - to use the "default exchange". - - Adds ``Connection.is_alive`` that tries to detect - whether the connection can still be used. - - Adds ``Connection.connection_errors`` and ``.channel_errors``, - a list of recoverable errors. - - Exposes the underlying socket as ``Connection.sock``. - - Adds ``Channel.no_ack_consumers`` to keep track of consumer tags - that set the no_ack flag. - - Slightly better at error recovery - - Quick overview - ============== - - Simple producer publishing messages to ``test`` queue using default exchange: - - .. code:: python - - import amqp - - with amqp.Connection('broker.example.com') as c: - ch = c.channel() - ch.basic_publish(amqp.Message('Hello World'), routing_key='test') - - Producer publishing to ``test_exchange`` exchange with publisher confirms enabled and using virtual_host ``test_vhost``: - - .. code:: python - - import amqp - - with amqp.Connection( - 'broker.example.com', exchange='test_exchange', - confirm_publish=True, virtual_host='test_vhost' - ) as c: - ch = c.channel() - ch.basic_publish(amqp.Message('Hello World'), routing_key='test') - - Consumer with acknowledgments enabled: - - .. code:: python - - import amqp - - with amqp.Connection('broker.example.com') as c: - ch = c.channel() - def on_message(message): - print('Received message (delivery tag: {}): {}'.format(message.delivery_tag, message.body)) - ch.basic_ack(message.delivery_tag) - ch.basic_consume(queue='test', callback=on_message) - while True: - c.drain_events() - - - Consumer with acknowledgments disabled: - - .. code:: python - - import amqp - - with amqp.Connection('broker.example.com') as c: - ch = c.channel() - def on_message(message): - print('Received message (delivery tag: {}): {}'.format(message.delivery_tag, message.body)) - ch.basic_consume(queue='test', callback=on_message, no_ack=True) - while True: - c.drain_events() - - Speedups - ======== - - This library has **experimental** support of speedups. Speedups are implemented using Cython. To enable speedups, ``CELERY_ENABLE_SPEEDUPS`` environment variable must be set during building/installation. - Currently speedups can be installed: - - 1. using source package (using ``--no-binary`` switch): - - .. code:: shell - - CELERY_ENABLE_SPEEDUPS=true pip install --no-binary :all: amqp - - - 2. building directly source code: - - .. code:: shell - - CELERY_ENABLE_SPEEDUPS=true python setup.py install - - Further - ======= - - - Differences between AMQP 0.8 and 0.9.1 - - http://www.rabbitmq.com/amqp-0-8-to-0-9-1.html - - - AMQP 0.9.1 Quick Reference - - http://www.rabbitmq.com/amqp-0-9-1-quickref.html - - - RabbitMQ Extensions - - http://www.rabbitmq.com/extensions.html - - - For more information about AMQP, visit - - http://www.amqp.org - - - For other Python client libraries see: - - http://www.rabbitmq.com/devtools.html#python-dev - - .. |build-status| image:: https://api.travis-ci.com/celery/py-amqp.png?branch=master - :alt: Build status - :target: https://travis-ci.com/celery/py-amqp - - .. |coverage| image:: https://codecov.io/github/celery/py-amqp/coverage.svg?branch=master - :target: https://codecov.io/github/celery/py-amqp?branch=master - - .. |license| image:: https://img.shields.io/pypi/l/amqp.svg - :alt: BSD License - :target: https://opensource.org/licenses/BSD-3-Clause - - .. |wheel| image:: https://img.shields.io/pypi/wheel/amqp.svg - :alt: Python AMQP can be installed via wheel - :target: https://pypi.org/project/amqp/ - - .. |pyversion| image:: https://img.shields.io/pypi/pyversions/amqp.svg - :alt: Supported Python versions. - :target: https://pypi.org/project/amqp/ - - .. |pyimp| image:: https://img.shields.io/pypi/implementation/amqp.svg - :alt: Support Python implementations. - :target: https://pypi.org/project/amqp/ - - py-amqp as part of the Tidelift Subscription - ============================================ - - The maintainers of py-amqp and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-amqp?utm_source=pypi-amqp&utm_medium=referral&utm_campaign=readme&utm_term=repo) - - Keywords: amqp rabbitmq cloudamqp messaging Platform: any Classifier: Development Status :: 5 - Production/Stable @@ -227,6 +16,8 @@ Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: License :: OSI Approved :: BSD License @@ -234,3 +25,217 @@ Classifier: Operating System :: OS Independent Requires-Python: >=3.6 Description-Content-Type: text/x-rst +License-File: LICENSE + +===================================================================== + Python AMQP 0.9.1 client library +===================================================================== + +|build-status| |coverage| |license| |wheel| |pyversion| |pyimp| + +:Version: 5.0.8 +:Web: https://amqp.readthedocs.io/ +:Download: https://pypi.org/project/amqp/ +:Source: http://github.com/celery/py-amqp/ +:Keywords: amqp, rabbitmq + +About +===== + +This is a fork of amqplib_ which was originally written by Barry Pederson. +It is maintained by the Celery_ project, and used by `kombu`_ as a pure python +alternative when `librabbitmq`_ is not available. + +This library should be API compatible with `librabbitmq`_. + +.. _amqplib: https://pypi.org/project/amqplib/ +.. _Celery: http://celeryproject.org/ +.. _kombu: https://kombu.readthedocs.io/ +.. _librabbitmq: https://pypi.org/project/librabbitmq/ + +Differences from `amqplib`_ +=========================== + +- Supports draining events from multiple channels (``Connection.drain_events``) +- Support for timeouts +- Channels are restored after channel error, instead of having to close the + connection. +- Support for heartbeats + + - ``Connection.heartbeat_tick(rate=2)`` must called at regular intervals + (half of the heartbeat value if rate is 2). + - Or some other scheme by using ``Connection.send_heartbeat``. +- Supports RabbitMQ extensions: + - Consumer Cancel Notifications + - by default a cancel results in ``ChannelError`` being raised + - but not if a ``on_cancel`` callback is passed to ``basic_consume``. + - Publisher confirms + - ``Channel.confirm_select()`` enables publisher confirms. + - ``Channel.events['basic_ack'].append(my_callback)`` adds a callback + to be called when a message is confirmed. This callback is then + called with the signature ``(delivery_tag, multiple)``. + - Exchange-to-exchange bindings: ``exchange_bind`` / ``exchange_unbind``. + - ``Channel.confirm_select()`` enables publisher confirms. + - ``Channel.events['basic_ack'].append(my_callback)`` adds a callback + to be called when a message is confirmed. This callback is then + called with the signature ``(delivery_tag, multiple)``. + - Authentication Failure Notifications + Instead of just closing the connection abruptly on invalid + credentials, py-amqp will raise an ``AccessRefused`` error + when connected to rabbitmq-server 3.2.0 or greater. +- Support for ``basic_return`` +- Uses AMQP 0-9-1 instead of 0-8. + - ``Channel.access_request`` and ``ticket`` arguments to methods + **removed**. + - Supports the ``arguments`` argument to ``basic_consume``. + - ``internal`` argument to ``exchange_declare`` removed. + - ``auto_delete`` argument to ``exchange_declare`` deprecated + - ``insist`` argument to ``Connection`` removed. + - ``Channel.alerts`` has been removed. + - Support for ``Channel.basic_recover_async``. + - ``Channel.basic_recover`` deprecated. +- Exceptions renamed to have idiomatic names: + - ``AMQPException`` -> ``AMQPError`` + - ``AMQPConnectionException`` -> ConnectionError`` + - ``AMQPChannelException`` -> ChannelError`` + - ``Connection.known_hosts`` removed. + - ``Connection`` no longer supports redirects. + - ``exchange`` argument to ``queue_bind`` can now be empty + to use the "default exchange". +- Adds ``Connection.is_alive`` that tries to detect + whether the connection can still be used. +- Adds ``Connection.connection_errors`` and ``.channel_errors``, + a list of recoverable errors. +- Exposes the underlying socket as ``Connection.sock``. +- Adds ``Channel.no_ack_consumers`` to keep track of consumer tags + that set the no_ack flag. +- Slightly better at error recovery + +Quick overview +============== + +Simple producer publishing messages to ``test`` queue using default exchange: + +.. code:: python + + import amqp + + with amqp.Connection('broker.example.com') as c: + ch = c.channel() + ch.basic_publish(amqp.Message('Hello World'), routing_key='test') + +Producer publishing to ``test_exchange`` exchange with publisher confirms enabled and using virtual_host ``test_vhost``: + +.. code:: python + + import amqp + + with amqp.Connection( + 'broker.example.com', exchange='test_exchange', + confirm_publish=True, virtual_host='test_vhost' + ) as c: + ch = c.channel() + ch.basic_publish(amqp.Message('Hello World'), routing_key='test') + +Consumer with acknowledgments enabled: + +.. code:: python + + import amqp + + with amqp.Connection('broker.example.com') as c: + ch = c.channel() + def on_message(message): + print('Received message (delivery tag: {}): {}'.format(message.delivery_tag, message.body)) + ch.basic_ack(message.delivery_tag) + ch.basic_consume(queue='test', callback=on_message) + while True: + c.drain_events() + + +Consumer with acknowledgments disabled: + +.. code:: python + + import amqp + + with amqp.Connection('broker.example.com') as c: + ch = c.channel() + def on_message(message): + print('Received message (delivery tag: {}): {}'.format(message.delivery_tag, message.body)) + ch.basic_consume(queue='test', callback=on_message, no_ack=True) + while True: + c.drain_events() + +Speedups +======== + +This library has **experimental** support of speedups. Speedups are implemented using Cython. To enable speedups, ``CELERY_ENABLE_SPEEDUPS`` environment variable must be set during building/installation. +Currently speedups can be installed: + +1. using source package (using ``--no-binary`` switch): + +.. code:: shell + + CELERY_ENABLE_SPEEDUPS=true pip install --no-binary :all: amqp + + +2. building directly source code: + +.. code:: shell + + CELERY_ENABLE_SPEEDUPS=true python setup.py install + +Further +======= + +- Differences between AMQP 0.8 and 0.9.1 + + http://www.rabbitmq.com/amqp-0-8-to-0-9-1.html + +- AMQP 0.9.1 Quick Reference + + http://www.rabbitmq.com/amqp-0-9-1-quickref.html + +- RabbitMQ Extensions + + http://www.rabbitmq.com/extensions.html + +- For more information about AMQP, visit + + http://www.amqp.org + +- For other Python client libraries see: + + http://www.rabbitmq.com/devtools.html#python-dev + +.. |build-status| image:: https://api.travis-ci.com/celery/py-amqp.png?branch=master + :alt: Build status + :target: https://travis-ci.com/celery/py-amqp + +.. |coverage| image:: https://codecov.io/github/celery/py-amqp/coverage.svg?branch=master + :target: https://codecov.io/github/celery/py-amqp?branch=master + +.. |license| image:: https://img.shields.io/pypi/l/amqp.svg + :alt: BSD License + :target: https://opensource.org/licenses/BSD-3-Clause + +.. |wheel| image:: https://img.shields.io/pypi/wheel/amqp.svg + :alt: Python AMQP can be installed via wheel + :target: https://pypi.org/project/amqp/ + +.. |pyversion| image:: https://img.shields.io/pypi/pyversions/amqp.svg + :alt: Supported Python versions. + :target: https://pypi.org/project/amqp/ + +.. |pyimp| image:: https://img.shields.io/pypi/implementation/amqp.svg + :alt: Support Python implementations. + :target: https://pypi.org/project/amqp/ + +py-amqp as part of the Tidelift Subscription +============================================ + +The maintainers of py-amqp and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-amqp?utm_source=pypi-amqp&utm_medium=referral&utm_campaign=readme&utm_term=repo) + + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/README.rst new/amqp-5.0.8/README.rst --- old/amqp-5.0.6/README.rst 2021-04-01 08:10:12.000000000 +0200 +++ new/amqp-5.0.8/README.rst 2021-12-19 06:03:38.000000000 +0100 @@ -4,7 +4,7 @@ |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| -:Version: 5.0.6 +:Version: 5.0.8 :Web: https://amqp.readthedocs.io/ :Download: https://pypi.org/project/amqp/ :Source: http://github.com/celery/py-amqp/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/amqp/__init__.py new/amqp-5.0.8/amqp/__init__.py --- old/amqp-5.0.6/amqp/__init__.py 2021-04-01 06:41:46.000000000 +0200 +++ new/amqp-5.0.8/amqp/__init__.py 2021-12-19 06:02:34.000000000 +0100 @@ -4,7 +4,7 @@ import re from collections import namedtuple -__version__ = '5.0.6' +__version__ = '5.0.8' __author__ = 'Barry Pederson' __maintainer__ = 'Asif Saif Uddin, Matus Valo' __contact__ = 'pya...@celeryproject.org' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/amqp/abstract_channel.py new/amqp-5.0.8/amqp/abstract_channel.py --- old/amqp-5.0.6/amqp/abstract_channel.py 2021-01-28 17:38:45.000000000 +0100 +++ new/amqp-5.0.8/amqp/abstract_channel.py 2021-12-12 06:39:32.000000000 +0100 @@ -68,7 +68,7 @@ def close(self): """Close this Channel or Connection.""" - raise NotImplementedError('Must be overriden in subclass') + raise NotImplementedError('Must be overridden in subclass') def wait(self, method, callback=None, timeout=None, returns_tuple=False): p = ensure_promise(callback) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/amqp/channel.py new/amqp-5.0.8/amqp/channel.py --- old/amqp-5.0.6/amqp/channel.py 2021-04-01 06:06:58.000000000 +0200 +++ new/amqp-5.0.8/amqp/channel.py 2021-12-17 04:55:58.000000000 +0100 @@ -150,7 +150,11 @@ connection, self.connection = self.connection, None if connection: connection.channels.pop(channel_id, None) - connection._avail_channel_ids.append(channel_id) + try: + connection._used_channel_ids.remove(channel_id) + except ValueError: + # channel id already removed + pass self.callbacks.clear() self.cancel_callbacks.clear() self.events.clear() @@ -1380,7 +1384,7 @@ False, the delivery tag refers to a single message. If the multiple field is True, and the delivery tag is zero, tells the server to acknowledge all - outstanding mesages. + outstanding messages. RULE: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/amqp/connection.py new/amqp-5.0.8/amqp/connection.py --- old/amqp-5.0.6/amqp/connection.py 2021-01-28 17:38:49.000000000 +0100 +++ new/amqp-5.0.8/amqp/connection.py 2021-12-17 04:55:58.000000000 +0100 @@ -104,7 +104,7 @@ When "confirm_publish" is set to True, the channel is put to confirm mode. In this mode, each published message is - confirmed using Publisher confirms RabbitMQ extention. + confirmed using Publisher confirms RabbitMQ extension. """ Channel = Channel @@ -267,7 +267,7 @@ self.on_unblocked = on_unblocked self.on_open = ensure_promise(on_open) - self._avail_channel_ids = array('H', range(self.channel_max, 0, -1)) + self._used_channel_ids = array('H') # Properties set in the Start method self.version_major = 0 @@ -466,38 +466,36 @@ return self._transport and self._transport.connected def collect(self): - try: - if self._transport: - self._transport.close() + if self._transport: + self._transport.close() - if self.channels: - # Copy all the channels except self since the channels - # dictionary changes during the collection process. - channels = [ - ch for ch in self.channels.values() - if ch is not self - ] - - for ch in channels: - ch.collect() - except OSError: - pass # connection already closed on the other end - finally: - self._transport = self.connection = self.channels = None + if self.channels: + # Copy all the channels except self since the channels + # dictionary changes during the collection process. + channels = [ + ch for ch in self.channels.values() + if ch is not self + ] + + for ch in channels: + ch.collect() + self._transport = self.connection = self.channels = None def _get_free_channel_id(self): - try: - return self._avail_channel_ids.pop() - except IndexError: - raise ResourceError( - 'No free channel ids, current={}, channel_max={}'.format( - len(self.channels), self.channel_max), spec.Channel.Open) + for channel_id in range(1, self.channel_max): + if channel_id not in self._used_channel_ids: + return channel_id + + raise ResourceError( + 'No free channel ids, current={}, channel_max={}'.format( + len(self.channels), self.channel_max), spec.Channel.Open) def _claim_channel_id(self, channel_id): - try: - return self._avail_channel_ids.remove(channel_id) - except ValueError: + if channel_id in self._used_channel_ids: raise ConnectionError(f'Channel {channel_id!r} already open') + else: + self._used_channel_ids.append(channel_id) + return channel_id def channel(self, channel_id=None, callback=None): """Create new channel. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/amqp/transport.py new/amqp-5.0.8/amqp/transport.py --- old/amqp-5.0.6/amqp/transport.py 2021-02-25 13:35:44.000000000 +0100 +++ new/amqp-5.0.8/amqp/transport.py 2021-12-17 04:55:58.000000000 +0100 @@ -256,7 +256,7 @@ def _read(self, n, initial=False): """Read exactly n bytes from the peer.""" - raise NotImplementedError('Must be overriden in subclass') + raise NotImplementedError('Must be overridden in subclass') def _setup_transport(self): """Do any additional initialization of the class.""" @@ -268,16 +268,27 @@ def _write(self, s): """Completely write a string to the peer.""" - raise NotImplementedError('Must be overriden in subclass') + raise NotImplementedError('Must be overridden in subclass') def close(self): if self.sock is not None: - self._shutdown_transport() + try: + self._shutdown_transport() + except OSError: + pass + # Call shutdown first to make sure that pending messages # reach the AMQP broker if the program exits after # calling this method. - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() + try: + self.sock.shutdown(socket.SHUT_RDWR) + except OSError: + pass + + try: + self.sock.close() + except OSError: + pass self.sock = None self.connected = False @@ -525,8 +536,8 @@ context.load_verify_locations(ca_certs) if ciphers is not None: context.set_ciphers(ciphers) - # Set SNI headers if supported. - # Must set context.check_hostname before setting context.verify_mode + # Set SNI headers if supported. + # Must set context.check_hostname before setting context.verify_mode # to avoid setting context.verify_mode=ssl.CERT_NONE while # context.check_hostname is still True (the default value in context # if client-side) which results in the following exception: @@ -539,7 +550,7 @@ except AttributeError: pass # ask forgiveness not permission - # See note above re: ordering for context.check_hostname and + # See note above re: ordering for context.check_hostname and # context.verify_mode assignments. if cert_reqs is not None: context.verify_mode = cert_reqs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/amqp.egg-info/PKG-INFO new/amqp-5.0.8/amqp.egg-info/PKG-INFO --- old/amqp-5.0.6/amqp.egg-info/PKG-INFO 2021-04-01 08:11:47.000000000 +0200 +++ new/amqp-5.0.8/amqp.egg-info/PKG-INFO 2021-12-19 06:06:23.000000000 +0100 @@ -1,223 +1,12 @@ Metadata-Version: 2.1 Name: amqp -Version: 5.0.6 +Version: 5.0.8 Summary: Low-level AMQP client for Python (fork of amqplib). Home-page: http://github.com/celery/py-amqp Author: Barry Pederson Author-email: pya...@celeryproject.org Maintainer: Asif Saif Uddin, Matus Valo License: BSD -Description: ===================================================================== - Python AMQP 0.9.1 client library - ===================================================================== - - |build-status| |coverage| |license| |wheel| |pyversion| |pyimp| - - :Version: 5.0.6 - :Web: https://amqp.readthedocs.io/ - :Download: https://pypi.org/project/amqp/ - :Source: http://github.com/celery/py-amqp/ - :Keywords: amqp, rabbitmq - - About - ===== - - This is a fork of amqplib_ which was originally written by Barry Pederson. - It is maintained by the Celery_ project, and used by `kombu`_ as a pure python - alternative when `librabbitmq`_ is not available. - - This library should be API compatible with `librabbitmq`_. - - .. _amqplib: https://pypi.org/project/amqplib/ - .. _Celery: http://celeryproject.org/ - .. _kombu: https://kombu.readthedocs.io/ - .. _librabbitmq: https://pypi.org/project/librabbitmq/ - - Differences from `amqplib`_ - =========================== - - - Supports draining events from multiple channels (``Connection.drain_events``) - - Support for timeouts - - Channels are restored after channel error, instead of having to close the - connection. - - Support for heartbeats - - - ``Connection.heartbeat_tick(rate=2)`` must called at regular intervals - (half of the heartbeat value if rate is 2). - - Or some other scheme by using ``Connection.send_heartbeat``. - - Supports RabbitMQ extensions: - - Consumer Cancel Notifications - - by default a cancel results in ``ChannelError`` being raised - - but not if a ``on_cancel`` callback is passed to ``basic_consume``. - - Publisher confirms - - ``Channel.confirm_select()`` enables publisher confirms. - - ``Channel.events['basic_ack'].append(my_callback)`` adds a callback - to be called when a message is confirmed. This callback is then - called with the signature ``(delivery_tag, multiple)``. - - Exchange-to-exchange bindings: ``exchange_bind`` / ``exchange_unbind``. - - ``Channel.confirm_select()`` enables publisher confirms. - - ``Channel.events['basic_ack'].append(my_callback)`` adds a callback - to be called when a message is confirmed. This callback is then - called with the signature ``(delivery_tag, multiple)``. - - Authentication Failure Notifications - Instead of just closing the connection abruptly on invalid - credentials, py-amqp will raise an ``AccessRefused`` error - when connected to rabbitmq-server 3.2.0 or greater. - - Support for ``basic_return`` - - Uses AMQP 0-9-1 instead of 0-8. - - ``Channel.access_request`` and ``ticket`` arguments to methods - **removed**. - - Supports the ``arguments`` argument to ``basic_consume``. - - ``internal`` argument to ``exchange_declare`` removed. - - ``auto_delete`` argument to ``exchange_declare`` deprecated - - ``insist`` argument to ``Connection`` removed. - - ``Channel.alerts`` has been removed. - - Support for ``Channel.basic_recover_async``. - - ``Channel.basic_recover`` deprecated. - - Exceptions renamed to have idiomatic names: - - ``AMQPException`` -> ``AMQPError`` - - ``AMQPConnectionException`` -> ConnectionError`` - - ``AMQPChannelException`` -> ChannelError`` - - ``Connection.known_hosts`` removed. - - ``Connection`` no longer supports redirects. - - ``exchange`` argument to ``queue_bind`` can now be empty - to use the "default exchange". - - Adds ``Connection.is_alive`` that tries to detect - whether the connection can still be used. - - Adds ``Connection.connection_errors`` and ``.channel_errors``, - a list of recoverable errors. - - Exposes the underlying socket as ``Connection.sock``. - - Adds ``Channel.no_ack_consumers`` to keep track of consumer tags - that set the no_ack flag. - - Slightly better at error recovery - - Quick overview - ============== - - Simple producer publishing messages to ``test`` queue using default exchange: - - .. code:: python - - import amqp - - with amqp.Connection('broker.example.com') as c: - ch = c.channel() - ch.basic_publish(amqp.Message('Hello World'), routing_key='test') - - Producer publishing to ``test_exchange`` exchange with publisher confirms enabled and using virtual_host ``test_vhost``: - - .. code:: python - - import amqp - - with amqp.Connection( - 'broker.example.com', exchange='test_exchange', - confirm_publish=True, virtual_host='test_vhost' - ) as c: - ch = c.channel() - ch.basic_publish(amqp.Message('Hello World'), routing_key='test') - - Consumer with acknowledgments enabled: - - .. code:: python - - import amqp - - with amqp.Connection('broker.example.com') as c: - ch = c.channel() - def on_message(message): - print('Received message (delivery tag: {}): {}'.format(message.delivery_tag, message.body)) - ch.basic_ack(message.delivery_tag) - ch.basic_consume(queue='test', callback=on_message) - while True: - c.drain_events() - - - Consumer with acknowledgments disabled: - - .. code:: python - - import amqp - - with amqp.Connection('broker.example.com') as c: - ch = c.channel() - def on_message(message): - print('Received message (delivery tag: {}): {}'.format(message.delivery_tag, message.body)) - ch.basic_consume(queue='test', callback=on_message, no_ack=True) - while True: - c.drain_events() - - Speedups - ======== - - This library has **experimental** support of speedups. Speedups are implemented using Cython. To enable speedups, ``CELERY_ENABLE_SPEEDUPS`` environment variable must be set during building/installation. - Currently speedups can be installed: - - 1. using source package (using ``--no-binary`` switch): - - .. code:: shell - - CELERY_ENABLE_SPEEDUPS=true pip install --no-binary :all: amqp - - - 2. building directly source code: - - .. code:: shell - - CELERY_ENABLE_SPEEDUPS=true python setup.py install - - Further - ======= - - - Differences between AMQP 0.8 and 0.9.1 - - http://www.rabbitmq.com/amqp-0-8-to-0-9-1.html - - - AMQP 0.9.1 Quick Reference - - http://www.rabbitmq.com/amqp-0-9-1-quickref.html - - - RabbitMQ Extensions - - http://www.rabbitmq.com/extensions.html - - - For more information about AMQP, visit - - http://www.amqp.org - - - For other Python client libraries see: - - http://www.rabbitmq.com/devtools.html#python-dev - - .. |build-status| image:: https://api.travis-ci.com/celery/py-amqp.png?branch=master - :alt: Build status - :target: https://travis-ci.com/celery/py-amqp - - .. |coverage| image:: https://codecov.io/github/celery/py-amqp/coverage.svg?branch=master - :target: https://codecov.io/github/celery/py-amqp?branch=master - - .. |license| image:: https://img.shields.io/pypi/l/amqp.svg - :alt: BSD License - :target: https://opensource.org/licenses/BSD-3-Clause - - .. |wheel| image:: https://img.shields.io/pypi/wheel/amqp.svg - :alt: Python AMQP can be installed via wheel - :target: https://pypi.org/project/amqp/ - - .. |pyversion| image:: https://img.shields.io/pypi/pyversions/amqp.svg - :alt: Supported Python versions. - :target: https://pypi.org/project/amqp/ - - .. |pyimp| image:: https://img.shields.io/pypi/implementation/amqp.svg - :alt: Support Python implementations. - :target: https://pypi.org/project/amqp/ - - py-amqp as part of the Tidelift Subscription - ============================================ - - The maintainers of py-amqp and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-amqp?utm_source=pypi-amqp&utm_medium=referral&utm_campaign=readme&utm_term=repo) - - Keywords: amqp rabbitmq cloudamqp messaging Platform: any Classifier: Development Status :: 5 - Production/Stable @@ -227,6 +16,8 @@ Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: License :: OSI Approved :: BSD License @@ -234,3 +25,217 @@ Classifier: Operating System :: OS Independent Requires-Python: >=3.6 Description-Content-Type: text/x-rst +License-File: LICENSE + +===================================================================== + Python AMQP 0.9.1 client library +===================================================================== + +|build-status| |coverage| |license| |wheel| |pyversion| |pyimp| + +:Version: 5.0.8 +:Web: https://amqp.readthedocs.io/ +:Download: https://pypi.org/project/amqp/ +:Source: http://github.com/celery/py-amqp/ +:Keywords: amqp, rabbitmq + +About +===== + +This is a fork of amqplib_ which was originally written by Barry Pederson. +It is maintained by the Celery_ project, and used by `kombu`_ as a pure python +alternative when `librabbitmq`_ is not available. + +This library should be API compatible with `librabbitmq`_. + +.. _amqplib: https://pypi.org/project/amqplib/ +.. _Celery: http://celeryproject.org/ +.. _kombu: https://kombu.readthedocs.io/ +.. _librabbitmq: https://pypi.org/project/librabbitmq/ + +Differences from `amqplib`_ +=========================== + +- Supports draining events from multiple channels (``Connection.drain_events``) +- Support for timeouts +- Channels are restored after channel error, instead of having to close the + connection. +- Support for heartbeats + + - ``Connection.heartbeat_tick(rate=2)`` must called at regular intervals + (half of the heartbeat value if rate is 2). + - Or some other scheme by using ``Connection.send_heartbeat``. +- Supports RabbitMQ extensions: + - Consumer Cancel Notifications + - by default a cancel results in ``ChannelError`` being raised + - but not if a ``on_cancel`` callback is passed to ``basic_consume``. + - Publisher confirms + - ``Channel.confirm_select()`` enables publisher confirms. + - ``Channel.events['basic_ack'].append(my_callback)`` adds a callback + to be called when a message is confirmed. This callback is then + called with the signature ``(delivery_tag, multiple)``. + - Exchange-to-exchange bindings: ``exchange_bind`` / ``exchange_unbind``. + - ``Channel.confirm_select()`` enables publisher confirms. + - ``Channel.events['basic_ack'].append(my_callback)`` adds a callback + to be called when a message is confirmed. This callback is then + called with the signature ``(delivery_tag, multiple)``. + - Authentication Failure Notifications + Instead of just closing the connection abruptly on invalid + credentials, py-amqp will raise an ``AccessRefused`` error + when connected to rabbitmq-server 3.2.0 or greater. +- Support for ``basic_return`` +- Uses AMQP 0-9-1 instead of 0-8. + - ``Channel.access_request`` and ``ticket`` arguments to methods + **removed**. + - Supports the ``arguments`` argument to ``basic_consume``. + - ``internal`` argument to ``exchange_declare`` removed. + - ``auto_delete`` argument to ``exchange_declare`` deprecated + - ``insist`` argument to ``Connection`` removed. + - ``Channel.alerts`` has been removed. + - Support for ``Channel.basic_recover_async``. + - ``Channel.basic_recover`` deprecated. +- Exceptions renamed to have idiomatic names: + - ``AMQPException`` -> ``AMQPError`` + - ``AMQPConnectionException`` -> ConnectionError`` + - ``AMQPChannelException`` -> ChannelError`` + - ``Connection.known_hosts`` removed. + - ``Connection`` no longer supports redirects. + - ``exchange`` argument to ``queue_bind`` can now be empty + to use the "default exchange". +- Adds ``Connection.is_alive`` that tries to detect + whether the connection can still be used. +- Adds ``Connection.connection_errors`` and ``.channel_errors``, + a list of recoverable errors. +- Exposes the underlying socket as ``Connection.sock``. +- Adds ``Channel.no_ack_consumers`` to keep track of consumer tags + that set the no_ack flag. +- Slightly better at error recovery + +Quick overview +============== + +Simple producer publishing messages to ``test`` queue using default exchange: + +.. code:: python + + import amqp + + with amqp.Connection('broker.example.com') as c: + ch = c.channel() + ch.basic_publish(amqp.Message('Hello World'), routing_key='test') + +Producer publishing to ``test_exchange`` exchange with publisher confirms enabled and using virtual_host ``test_vhost``: + +.. code:: python + + import amqp + + with amqp.Connection( + 'broker.example.com', exchange='test_exchange', + confirm_publish=True, virtual_host='test_vhost' + ) as c: + ch = c.channel() + ch.basic_publish(amqp.Message('Hello World'), routing_key='test') + +Consumer with acknowledgments enabled: + +.. code:: python + + import amqp + + with amqp.Connection('broker.example.com') as c: + ch = c.channel() + def on_message(message): + print('Received message (delivery tag: {}): {}'.format(message.delivery_tag, message.body)) + ch.basic_ack(message.delivery_tag) + ch.basic_consume(queue='test', callback=on_message) + while True: + c.drain_events() + + +Consumer with acknowledgments disabled: + +.. code:: python + + import amqp + + with amqp.Connection('broker.example.com') as c: + ch = c.channel() + def on_message(message): + print('Received message (delivery tag: {}): {}'.format(message.delivery_tag, message.body)) + ch.basic_consume(queue='test', callback=on_message, no_ack=True) + while True: + c.drain_events() + +Speedups +======== + +This library has **experimental** support of speedups. Speedups are implemented using Cython. To enable speedups, ``CELERY_ENABLE_SPEEDUPS`` environment variable must be set during building/installation. +Currently speedups can be installed: + +1. using source package (using ``--no-binary`` switch): + +.. code:: shell + + CELERY_ENABLE_SPEEDUPS=true pip install --no-binary :all: amqp + + +2. building directly source code: + +.. code:: shell + + CELERY_ENABLE_SPEEDUPS=true python setup.py install + +Further +======= + +- Differences between AMQP 0.8 and 0.9.1 + + http://www.rabbitmq.com/amqp-0-8-to-0-9-1.html + +- AMQP 0.9.1 Quick Reference + + http://www.rabbitmq.com/amqp-0-9-1-quickref.html + +- RabbitMQ Extensions + + http://www.rabbitmq.com/extensions.html + +- For more information about AMQP, visit + + http://www.amqp.org + +- For other Python client libraries see: + + http://www.rabbitmq.com/devtools.html#python-dev + +.. |build-status| image:: https://api.travis-ci.com/celery/py-amqp.png?branch=master + :alt: Build status + :target: https://travis-ci.com/celery/py-amqp + +.. |coverage| image:: https://codecov.io/github/celery/py-amqp/coverage.svg?branch=master + :target: https://codecov.io/github/celery/py-amqp?branch=master + +.. |license| image:: https://img.shields.io/pypi/l/amqp.svg + :alt: BSD License + :target: https://opensource.org/licenses/BSD-3-Clause + +.. |wheel| image:: https://img.shields.io/pypi/wheel/amqp.svg + :alt: Python AMQP can be installed via wheel + :target: https://pypi.org/project/amqp/ + +.. |pyversion| image:: https://img.shields.io/pypi/pyversions/amqp.svg + :alt: Supported Python versions. + :target: https://pypi.org/project/amqp/ + +.. |pyimp| image:: https://img.shields.io/pypi/implementation/amqp.svg + :alt: Support Python implementations. + :target: https://pypi.org/project/amqp/ + +py-amqp as part of the Tidelift Subscription +============================================ + +The maintainers of py-amqp and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/pypi-amqp?utm_source=pypi-amqp&utm_medium=referral&utm_campaign=readme&utm_term=repo) + + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/amqp.egg-info/SOURCES.txt new/amqp-5.0.8/amqp.egg-info/SOURCES.txt --- old/amqp-5.0.6/amqp.egg-info/SOURCES.txt 2021-04-01 08:11:47.000000000 +0200 +++ new/amqp-5.0.8/amqp.egg-info/SOURCES.txt 2021-12-19 06:06:23.000000000 +0100 @@ -56,11 +56,13 @@ requirements/test-ci.txt requirements/test.txt t/__init__.py +t/mocks.py t/integration/__init__.py t/integration/conftest.py t/integration/test_integration.py t/integration/test_rmq.py t/unit/__init__.py +t/unit/conftest.py t/unit/test_abstract_channel.py t/unit/test_basic_message.py t/unit/test_channel.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/docs/includes/introduction.txt new/amqp-5.0.8/docs/includes/introduction.txt --- old/amqp-5.0.6/docs/includes/introduction.txt 2021-04-01 06:42:21.000000000 +0200 +++ new/amqp-5.0.8/docs/includes/introduction.txt 2021-12-19 06:03:07.000000000 +0100 @@ -1,4 +1,4 @@ -:Version: 5.0.6 +:Version: 5.0.8 :Web: https://amqp.readthedocs.io/ :Download: https://pypi.org/project/amqp/ :Source: http://github.com/celery/py-amqp/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/requirements/pkgutils.txt new/amqp-5.0.8/requirements/pkgutils.txt --- old/amqp-5.0.6/requirements/pkgutils.txt 2021-01-28 17:38:43.000000000 +0100 +++ new/amqp-5.0.8/requirements/pkgutils.txt 2021-12-19 05:49:08.000000000 +0100 @@ -1,6 +1,6 @@ setuptools>=20.6.7 wheel>=0.29.0 -flake8==3.8.3 +flake8>=3.8.3 tox>=2.3.1 sphinx2rst>=1.0 bumpversion diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/requirements/test-ci.txt new/amqp-5.0.8/requirements/test-ci.txt --- old/amqp-5.0.6/requirements/test-ci.txt 2021-04-01 06:06:52.000000000 +0200 +++ new/amqp-5.0.8/requirements/test-ci.txt 2021-12-12 06:39:40.000000000 +0100 @@ -1,4 +1,3 @@ pytest-cov codecov -pytest-travis-fold pytest-xdist diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/requirements/test.txt new/amqp-5.0.8/requirements/test.txt --- old/amqp-5.0.6/requirements/test.txt 2020-06-01 07:25:14.000000000 +0200 +++ new/amqp-5.0.8/requirements/test.txt 2021-12-19 05:48:27.000000000 +0100 @@ -1,4 +1,3 @@ -case>=1.3.1 -pytest>=3.0,<=5.3.5 +pytest>=6.2.5,<=7.0.0 pytest-sugar>=0.9.1 pytest-rerunfailures>=6.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/setup.py new/amqp-5.0.8/setup.py --- old/amqp-5.0.6/setup.py 2021-04-01 08:02:15.000000000 +0200 +++ new/amqp-5.0.8/setup.py 2021-12-19 05:50:47.000000000 +0100 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import re import sys @@ -20,6 +20,8 @@ Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy License :: OSI Approved :: BSD License diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/t/integration/test_integration.py new/amqp-5.0.8/t/integration/test_integration.py --- old/amqp-5.0.6/t/integration/test_integration.py 2021-01-28 17:38:45.000000000 +0100 +++ new/amqp-5.0.8/t/integration/test_integration.py 2021-11-18 09:18:39.000000000 +0100 @@ -114,7 +114,7 @@ class DataComparator: # Comparator used for asserting serialized data. It can be used - # in cases when direct comparision of bytestream cannot be used + # in cases when direct comparison of bytestream cannot be used # (mainly cases of Table type where order of items can vary) def __init__(self, argsig, items): self.argsig = argsig @@ -367,7 +367,7 @@ @patch('amqp.Connection._on_blocked') def test_connecion_ignore_methods_during_close(self, on_blocked_mock): # Test checking that py-amqp will discard any received methods - # except Close and Close-OK after sending Connecion.Close method + # except Close and Close-OK after sending Connection.Close method # to server. frame_writer_cls_mock = Mock() frame_writer_mock = frame_writer_cls_mock() @@ -601,7 +601,7 @@ callback_mock.assert_called_once() def test_basic_publish(self): - # Test verifing publishing message. + # Test verifying publishing message. frame_writer_cls_mock = Mock() conn = Connection(frame_writer=frame_writer_cls_mock) with patch.object(conn, 'Transport') as transport_mock: @@ -621,7 +621,7 @@ ) def test_consume_no_consumer_tag(self): - # Test verifing starting consuming without specified consumer_tag + # Test verifying starting consuming without specified consumer_tag callback_mock = Mock() frame_writer_cls_mock = Mock() conn = Connection(frame_writer=frame_writer_cls_mock) @@ -652,7 +652,7 @@ assert ret == 'amq.ctag-PCmzXGkhCw_v0Zq7jXyvkg' def test_consume_with_consumer_tag(self): - # Test verifing starting consuming with specified consumer_tag + # Test verifying starting consuming with specified consumer_tag callback_mock = Mock() frame_writer_cls_mock = Mock() conn = Connection(frame_writer=frame_writer_cls_mock) @@ -745,7 +745,7 @@ assert excinfo.value.method_sig == spec.Exchange.Declare # Client is sending to broker: # 1. Exchange Declare - # 2. Connection.CloseOk as reply to received Connecton.Close + # 2. Connection.CloseOk as reply to received Connection.Close frame_writer_calls = [ call( 1, 1, spec.Queue.Declare, @@ -1024,7 +1024,7 @@ assert excinfo.value.method_sig == spec.Exchange.Declare # Client is sending to broker: # 1. Exchange Declare - # 2. Connection.CloseOk as reply to received Connecton.Close + # 2. Connection.CloseOk as reply to received Connection.Close frame_writer_calls = [ call( 1, 1, spec.Exchange.Declare, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/t/mocks.py new/amqp-5.0.8/t/mocks.py --- old/amqp-5.0.6/t/mocks.py 1970-01-01 01:00:00.000000000 +0100 +++ new/amqp-5.0.8/t/mocks.py 2021-11-18 09:18:39.000000000 +0100 @@ -0,0 +1,24 @@ +from unittest.mock import Mock + +class _ContextMock(Mock): + """Dummy class implementing __enter__ and __exit__ + as the :keyword:`with` statement requires these to be implemented + in the class, not just the instance.""" + + def __enter__(self): + return self + + def __exit__(self, *exc_info): + pass + + +def ContextMock(*args, **kwargs): + """Mock that mocks :keyword:`with` statement contexts.""" + obj = _ContextMock(*args, **kwargs) + obj.attach_mock(_ContextMock(), '__enter__') + obj.attach_mock(_ContextMock(), '__exit__') + obj.__enter__.return_value = obj + # if __exit__ return a value the exception is ignored, + # so it must return None here. + obj.__exit__.return_value = None + return obj diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/t/unit/conftest.py new/amqp-5.0.8/t/unit/conftest.py --- old/amqp-5.0.6/t/unit/conftest.py 1970-01-01 01:00:00.000000000 +0100 +++ new/amqp-5.0.8/t/unit/conftest.py 2021-11-18 09:18:39.000000000 +0100 @@ -0,0 +1,54 @@ +from unittest.mock import MagicMock +import pytest + +sentinel = object() + +class _patching: + + def __init__(self, monkeypatch, request): + self.monkeypatch = monkeypatch + self.request = request + + def __getattr__(self, name): + return getattr(self.monkeypatch, name) + + def __call__(self, path, value=sentinel, name=None, + new=MagicMock, **kwargs): + value = self._value_or_mock(value, new, name, path, **kwargs) + self.monkeypatch.setattr(path, value) + return value + + def _value_or_mock(self, value, new, name, path, **kwargs): + if value is sentinel: + value = new(name=name or path.rpartition('.')[2]) + for k, v in kwargs.items(): + setattr(value, k, v) + return value + + def setattr(self, target, name=sentinel, value=sentinel, **kwargs): + # alias to __call__ with the interface of pytest.monkeypatch.setattr + if value is sentinel: + value, name = name, None + return self(target, value, name=name) + + def setitem(self, dic, name, value=sentinel, new=MagicMock, **kwargs): + # same as pytest.monkeypatch.setattr but default value is MagicMock + value = self._value_or_mock(value, new, name, dic, **kwargs) + self.monkeypatch.setitem(dic, name, value) + return value + + +@pytest.fixture +def patching(monkeypatch, request): + """Monkeypath.setattr shortcut. + Example: + .. code-block:: python + def test_foo(patching): + # execv value here will be mock.MagicMock by default. + execv = patching('os.execv') + patching('sys.platform', 'darwin') # set concrete value + patching.setenv('DJANGO_SETTINGS_MODULE', 'x.settings') + # val will be of type mock.MagicMock by default + val = patching.setitem('path.to.dict', 'KEY') + """ + return _patching(monkeypatch, request) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/t/unit/test_channel.py new/amqp-5.0.8/t/unit/test_channel.py --- old/amqp-5.0.6/t/unit/test_channel.py 2021-01-28 17:38:47.000000000 +0100 +++ new/amqp-5.0.8/t/unit/test_channel.py 2021-11-18 09:18:39.000000000 +0100 @@ -3,7 +3,6 @@ from unittest.mock import ANY, MagicMock, Mock, patch import pytest -from case import ContextMock from vine import promise from amqp import spec @@ -13,6 +12,7 @@ RecoverableConnectionError) from amqp.serialization import dumps +from t.mocks import ContextMock class test_Channel: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/t/unit/test_connection.py new/amqp-5.0.8/t/unit/test_connection.py --- old/amqp-5.0.6/t/unit/test_connection.py 2021-01-28 17:38:47.000000000 +0100 +++ new/amqp-5.0.8/t/unit/test_connection.py 2021-12-17 04:55:58.000000000 +0100 @@ -1,10 +1,10 @@ import re import socket import warnings +from array import array from unittest.mock import Mock, call, patch import pytest -from case import ContextMock from amqp import Connection, spec from amqp.connection import SSLError @@ -13,6 +13,8 @@ from amqp.sasl import AMQPLAIN, EXTERNAL, GSSAPI, PLAIN, SASL from amqp.transport import TCPTransport +from t.mocks import ContextMock + class test_Connection: @@ -322,10 +324,17 @@ channel.collect.assert_called_with() assert self.conn._transport is None - def test_collect__channel_raises_socket_error(self): - self.conn.channels = self.conn.channels = {1: Mock(name='c1')} - self.conn.channels[1].collect.side_effect = socket.error() + def test_collect__transport_socket_raises_os_error(self): + self.conn.transport = TCPTransport('localhost:5672') + sock = self.conn.transport.sock = Mock(name='sock') + channel = Mock(name='c1') + self.conn.channels = {1: channel} + sock.shutdown.side_effect = OSError self.conn.collect() + channel.collect.assert_called_with() + sock.close.assert_called_with() + assert self.conn._transport is None + assert self.conn.channels is None def test_collect_no_transport(self): self.conn = Connection() @@ -339,8 +348,11 @@ self.conn.collect() self.conn.collect() + def test_get_free_channel_id(self): + assert self.conn._get_free_channel_id() == 1 + def test_get_free_channel_id__raises_IndexError(self): - self.conn._avail_channel_ids = [] + self.conn._used_channel_ids = array('H', range(1, self.conn.channel_max)) with pytest.raises(ResourceError): self.conn._get_free_channel_id() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-5.0.6/t/unit/test_transport.py new/amqp-5.0.8/t/unit/test_transport.py --- old/amqp-5.0.6/t/unit/test_transport.py 2021-02-25 13:35:44.000000000 +0100 +++ new/amqp-5.0.8/t/unit/test_transport.py 2021-12-17 04:55:58.000000000 +0100 @@ -282,6 +282,13 @@ self.t.close() assert self.t.sock is None and self.t.connected is False + def test_close_os_error(self): + sock = self.t.sock = Mock() + sock.shutdown.side_effect = OSError + self.t.close() + sock.close.assert_called_with() + assert self.t.sock is None and self.t.connected is False + def test_read_frame__timeout(self): self.t._read = Mock() self.t._read.side_effect = socket.timeout() @@ -580,6 +587,16 @@ self.t.connect() assert self.t.connected and self.t.sock is sock_obj + def test_close__close_error(self): + # sock.close() can raise an error if the fd is invalid + # make sure the socket is properly deallocated + sock = self.t.sock = Mock() + sock.unwrap.return_value = sock + sock.close.side_effect = OSError + self.t.close() + sock.close.assert_called_with() + assert self.t.sock is None and self.t.connected is False + class test_SSLTransport: class Transport(transport.SSLTransport): @@ -719,7 +736,7 @@ ) assert context.verify_mode == sentinel.CERT_REQS - # testing context creation inside _wrap_socket_sni() with parameter + # testing context creation inside _wrap_socket_sni() with parameter # cert_reqs == ssl.CERT_NONE. Previously raised ValueError because # code path attempted to set context.verify_mode=ssl.CERT_NONE before # setting context.check_hostname = False which raised a ValueError @@ -740,7 +757,7 @@ ) mock_load_default_certs.assert_not_called() mock_wrap_socket.assert_called_once() - + with patch('ssl.SSLContext.wrap_socket') as mock_wrap_socket: with patch('ssl.SSLContext.load_default_certs') as mock_load_default_certs: sock = Mock() @@ -828,6 +845,14 @@ self.t._shutdown_transport() assert self.t.sock is sock.unwrap() + def test_close__unwrap_error(self): + # sock.unwrap() can raise an error if the was a connection failure + # make sure the socket is properly closed and deallocated + sock = self.t.sock = Mock() + sock.unwrap.side_effect = OSError + self.t.close() + assert self.t.sock is None + def test_read_EOF(self): self.t.sock = Mock(name='SSLSocket') self.t.connected = True