Hello community,

here is the log from the commit of package python-amqp for openSUSE:Factory 
checked in at 2020-06-11 14:44:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-amqp (Old)
 and      /work/SRC/openSUSE:Factory/.python-amqp.new.3606 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-amqp"

Thu Jun 11 14:44:37 2020 rev:32 rq:812617 version:2.6.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-amqp/python-amqp.changes  2019-11-04 
17:04:37.920147389 +0100
+++ /work/SRC/openSUSE:Factory/.python-amqp.new.3606/python-amqp.changes        
2020-06-11 14:44:59.245432392 +0200
@@ -1,0 +2,14 @@
+Mon Jun  8 13:29:28 UTC 2020 - Dirk Mueller <dmuel...@suse.com>
+
+- update to 2.6.0:
+  - Implement speedups in cython (#311)
+  - Updated some tests & code improvements
+  - Separate logger for Connection.heartbeat_tick method
+  - Cython generic content (#315)
+  - Improve documentation a_global parameter of basic_qos() method.
+  - Fix saving partial read buffer on windows during socket timeout. (#321)
+  - Fix deserialization of long string field values that are not utf-8.
+  - Added simple cythonization of abstract_channel.py
+  - Speedups of serialization.py are more restrictive
+
+-------------------------------------------------------------------

Old:
----
  amqp-2.5.2.tar.gz

New:
----
  amqp-2.6.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-amqp.spec ++++++
--- /var/tmp/diff_new_pack.ydMPfL/_old  2020-06-11 14:44:59.705433732 +0200
+++ /var/tmp/diff_new_pack.ydMPfL/_new  2020-06-11 14:44:59.709433744 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-amqp
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-amqp
-Version:        2.5.2
+Version:        2.6.0
 Release:        0
 Summary:        Low-level AMQP client for Python (fork of amqplib)
 License:        LGPL-2.1-or-later

++++++ amqp-2.5.2.tar.gz -> amqp-2.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/Changelog new/amqp-2.6.0/Changelog
--- old/amqp-2.5.2/Changelog    2019-09-30 14:52:24.000000000 +0200
+++ new/amqp-2.6.0/Changelog    2020-06-01 07:45:06.000000000 +0200
@@ -5,6 +5,23 @@
 The previous amqplib changelog is here:
 http://code.google.com/p/py-amqplib/source/browse/CHANGES
 
+.. _version-2.6.0:
+
+2.6.0
+=====
+:release-date: 20-06-01 12.00 P.M UTC+6:00
+:release-by: Asif Saif Uddin
+
+- Implement speedups in cython (#311) 
+- Updated some tests & code improvements
+- Separate logger for Connection.heartbeat_tick method 
+- Cython generic content (#315)
+- Improve documentation a_global parameter of basic_qos() method.
+- Fix saving partial read buffer on windows during socket timeout. (#321)
+- Fix deserialization of long string field values that are not utf-8.
+- Added simple cythonization of abstract_channel.py
+- Speedups of serialization.py are more restrictive
+
 .. _version-2.5.2:
 
 2.5.2
@@ -12,10 +29,8 @@
 :release-date: 2019-09-30 19.00 P.M UTC+6:00
 :release-by: Asif Saif Uddin
 
-- Ignore all methods except Close and Close-OK when channel/connection is 
closing
-- Fix faulty ssl sni intiation parameters (#283) 
-- Undeprecate auto_delete flag for exchanges. (#287) 
-- Improved tests and testing environments
+- Fixed a channel issue against a connection already closed 
+- Updated some tests & code improvements
 
 
 .. _version-2.5.1:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/PKG-INFO new/amqp-2.6.0/PKG-INFO
--- old/amqp-2.5.2/PKG-INFO     2019-09-30 15:03:23.000000000 +0200
+++ new/amqp-2.6.0/PKG-INFO     2020-06-01 08:15:08.735072100 +0200
@@ -1,143 +1,13 @@
 Metadata-Version: 1.2
 Name: amqp
-Version: 2.5.2
+Version: 2.6.0
 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, Omer Katz
+Maintainer: Asif Saif Uddin, Matus Valo
 License: BSD
-Description: 
=====================================================================
-         Python AMQP 0.9.1 client library
-        =====================================================================
-        
-        |build-status| |coverage| |license| |wheel| |pyversion| |pyimp|
-        
-        :Version: 2.5.2
-        :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
-        
-        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://secure.travis-ci.org/celery/py-amqp.png?branch=master
-            :alt: Build status
-            :target: https://travis-ci.org/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/
-        
-        
+Description: UNKNOWN
 Keywords: amqp rabbitmq cloudamqp messaging
 Platform: any
 Classifier: Development Status :: 5 - Production/Stable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/README.rst new/amqp-2.6.0/README.rst
--- old/amqp-2.5.2/README.rst   2019-09-30 14:58:55.000000000 +0200
+++ new/amqp-2.6.0/README.rst   2020-06-01 07:47:59.000000000 +0200
@@ -4,7 +4,7 @@
 
 |build-status| |coverage| |license| |wheel| |pyversion| |pyimp|
 
-:Version: 2.5.2
+:Version: 2.6.0
 :Web: https://amqp.readthedocs.io/
 :Download: https://pypi.org/project/amqp/
 :Source: http://github.com/celery/py-amqp/
@@ -82,6 +82,79 @@
   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-block::
+CELERY_ENABLE_SPEEDUPS=true pip install --no-binary :all: amqp
+
+
+2. building directly source code:
+
+.. code-block::
+CELERY_ENABLE_SPEEDUPS=true python setup.py install
+
 Further
 =======
 
@@ -127,4 +200,9 @@
 .. |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-2.5.2/amqp/__init__.py 
new/amqp-2.6.0/amqp/__init__.py
--- old/amqp-2.5.2/amqp/__init__.py     2019-09-30 14:58:17.000000000 +0200
+++ new/amqp-2.6.0/amqp/__init__.py     2020-06-01 07:46:47.000000000 +0200
@@ -6,9 +6,9 @@
 
 from collections import namedtuple
 
-__version__ = '2.5.2'
+__version__ = '2.6.0'
 __author__ = 'Barry Pederson'
-__maintainer__ = 'Asif Saif Uddin, Omer Katz'
+__maintainer__ = 'Asif Saif Uddin, Matus Valo'
 __contact__ = 'pya...@celeryproject.org'
 __homepage__ = 'http://github.com/celery/py-amqp'
 __docformat__ = 'restructuredtext'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/amqp/basic_message.py 
new/amqp-2.6.0/amqp/basic_message.py
--- old/amqp-2.5.2/amqp/basic_message.py        2019-07-12 07:25:19.000000000 
+0200
+++ new/amqp-2.6.0/amqp/basic_message.py        2020-06-01 07:25:14.000000000 
+0200
@@ -55,7 +55,7 @@
         message_id: shortstr
             The application message identifier
 
-        timestamp: datetime.datetime
+        timestamp: unsigned long
             The message timestamp
 
         type: shortstr
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/amqp/channel.py 
new/amqp-2.6.0/amqp/channel.py
--- old/amqp-2.5.2/amqp/channel.py      2019-08-14 17:32:29.000000000 +0200
+++ new/amqp-2.6.0/amqp/channel.py      2020-06-01 07:25:14.000000000 +0200
@@ -1842,11 +1842,16 @@
 
             a_global: boolean
 
-                apply to entire connection
+                Defines a scope of QoS. Semantics of this parameter differs
+                between AMQP 0-9-1 standard and RabbitMQ broker:
 
-                By default the QoS settings apply to the current
-                channel only.  If this field is set, they are applied
-                to the entire connection.
+                MEANING IN AMQP 0-9-1:
+                    False:  shared across all consumers on the channel
+                    True:   shared across all consumers on the connection
+                MEANING IN RABBITMQ:
+                    False:  applied separately to each new consumer
+                            on the channel
+                    True:   shared across all consumers on the channel
         """
         return self.send_method(
             spec.Basic.Qos, argsig, (prefetch_size, prefetch_count, a_global),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/amqp/connection.py 
new/amqp-2.6.0/amqp/connection.py
--- old/amqp-2.5.2/amqp/connection.py   2019-09-30 14:34:47.000000000 +0200
+++ new/amqp-2.6.0/amqp/connection.py   2020-06-01 07:25:14.000000000 +0200
@@ -42,6 +42,9 @@
 __all__ = ['Connection']
 
 AMQP_LOGGER = logging.getLogger('amqp')
+AMQP_HEARTBEAT_LOGGER = logging.getLogger(
+    'amqp.connection.Connection.heartbeat_tick'
+)
 
 #: Default map for :attr:`Connection.library_properties`
 LIBRARY_PROPERTIES = {
@@ -705,8 +708,8 @@
         Keyword Arguments:
             rate (int): Previously used, but ignored now.
         """
-        AMQP_LOGGER.debug('heartbeat_tick : for connection %s',
-                          self._connection_id)
+        AMQP_HEARTBEAT_LOGGER.debug('heartbeat_tick : for connection %s',
+                                    self._connection_id)
         if not self.heartbeat:
             return
 
@@ -719,7 +722,7 @@
             self.last_heartbeat_received = monotonic()
 
         now = monotonic()
-        AMQP_LOGGER.debug(
+        AMQP_HEARTBEAT_LOGGER.debug(
             'heartbeat_tick : Prev sent/recv: %s/%s, '
             'now - %s/%s, monotonic - %s, '
             'last_heartbeat_sent - %s, heartbeat int. - %s '
@@ -735,7 +738,7 @@
 
         # send a heartbeat if it's time to do so
         if now > self.last_heartbeat_sent + self.heartbeat:
-            AMQP_LOGGER.debug(
+            AMQP_HEARTBEAT_LOGGER.debug(
                 'heartbeat_tick: sending heartbeat for connection %s',
                 self._connection_id)
             self.send_heartbeat()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/amqp/serialization.py 
new/amqp-2.6.0/amqp/serialization.py
--- old/amqp-2.5.2/amqp/serialization.py        2019-07-12 07:25:19.000000000 
+0200
+++ new/amqp-2.6.0/amqp/serialization.py        2020-06-01 07:25:14.000000000 
+0200
@@ -34,7 +34,7 @@
 """
 
 
-def _read_item(buf, offset=0, unpack_from=unpack_from, ftype_t=ftype_t):
+def _read_item(buf, offset):
     ftype = ftype_t(buf[offset]) if ftype_t else buf[offset]
     offset += 1
 
@@ -42,7 +42,11 @@
     if ftype == 'S':
         slen, = unpack_from('>I', buf, offset)
         offset += 4
-        val = pstr_t(buf[offset:offset + slen])
+        try:
+            val = pstr_t(buf[offset:offset + slen])
+        except UnicodeDecodeError:
+            val = buf[offset:offset + slen]
+
         offset += slen
     # 's': short string
     elif ftype == 's':
@@ -144,9 +148,7 @@
     return val, offset
 
 
-def loads(format, buf, offset=0,
-          ord=ord, unpack_from=unpack_from,
-          _read_item=_read_item, pstr_t=pstr_t):
+def loads(format, buf, offset):
     """Deserialize amqp format.
 
     bit = b
@@ -245,7 +247,7 @@
     return values, offset
 
 
-def _flushbits(bits, write, pack=pack):
+def _flushbits(bits, write):
     if bits:
         write(pack('B' * len(bits), *bits))
         bits[:] = []
@@ -325,7 +327,7 @@
     return out.getvalue()
 
 
-def _write_table(d, write, bits, pack=pack):
+def _write_table(d, write, bits):
     out = BytesIO()
     twrite = out.write
     for k, v in items(d):
@@ -343,7 +345,7 @@
     write(table_data)
 
 
-def _write_array(l, write, bits, pack=pack):
+def _write_array(l, write, bits):
     out = BytesIO()
     awrite = out.write
     for v in l:
@@ -357,11 +359,7 @@
     write(array_data)
 
 
-def _write_item(v, write, bits, pack=pack,
-                string_t=string_t, bytes=bytes, string=string, bool=bool,
-                float=float, int_types=int_types, Decimal=Decimal,
-                datetime=datetime, dict=dict, list=list, tuple=tuple,
-                None_t=None):
+def _write_item(v, write, bits):
     if isinstance(v, (string_t, bytes)):
         if isinstance(v, string):
             v = v.encode('utf-8', 'surrogatepass')
@@ -393,14 +391,13 @@
     elif isinstance(v, (list, tuple)):
         write(b'A')
         _write_array(v, write, bits)
-    elif v is None_t:
+    elif v is None:
         write(b'V')
     else:
         raise ValueError()
 
 
-def decode_properties_basic(buf, offset=0,
-                            unpack_from=unpack_from, pstr_t=pstr_t):
+def decode_properties_basic(buf, offset):
     """Decode basic properties."""
     properties = {}
 
@@ -507,8 +504,7 @@
             return self.properties[name]
         raise AttributeError(name)
 
-    def _load_properties(self, class_id, buf, offset=0,
-                         classes=PROPERTY_CLASSES, unpack_from=unpack_from):
+    def _load_properties(self, class_id, buf, offset):
         """Load AMQP properties.
 
         Given the raw bytes containing the property-flags and property-list
@@ -516,7 +512,7 @@
         stored in this object as an attribute named 'properties'.
         """
         # Read 16-bit shorts until we get one with a low bit set to zero
-        props, offset = classes[class_id](buf, offset)
+        props, offset = PROPERTY_CLASSES[class_id](buf, offset)
         self.properties = props
         return offset
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/amqp/transport.py 
new/amqp-2.6.0/amqp/transport.py
--- old/amqp-2.5.2/amqp/transport.py    2019-08-14 17:32:29.000000000 +0200
+++ new/amqp-2.6.0/amqp/transport.py    2020-06-01 07:25:14.000000000 +0200
@@ -2,6 +2,7 @@
 # Copyright (C) 2009 Barry Pederson <b...@barryp.org>
 from __future__ import absolute_import, unicode_literals
 
+import os
 import errno
 import re
 import socket
@@ -256,7 +257,15 @@
             # so we know the size can be at most 2 * SIGNED_INT_MAX
             if size > SIGNED_INT_MAX:
                 part1 = read(SIGNED_INT_MAX)
-                part2 = read(size - SIGNED_INT_MAX)
+
+                try:
+                    part2 = read(size - SIGNED_INT_MAX)
+                except (socket.timeout, socket.error, SSLError):
+                    # In case this read times out, we need to make sure to not
+                    # lose part1 when we retry the read
+                    read_frame_buffer += part1
+                    raise
+
                 payload = b''.join([part1, part2])
             else:
                 payload = read(size)
@@ -266,10 +275,22 @@
             self._read_buffer = read_frame_buffer + self._read_buffer
             raise
         except (OSError, IOError, SSLError, socket.error) as exc:
-            # Don't disconnect for ssl read time outs
-            # http://bugs.python.org/issue10272
+            if (
+                isinstance(exc, socket.error) and os.name == 'nt'
+                and get_errno(exc) == errno.EWOULDBLOCK  # noqa
+            ):
+                # On windows we can get a read timeout with a winsock error
+                # code instead of a proper socket.timeout() error, see
+                # https://github.com/celery/py-amqp/issues/320
+                self._read_buffer = read_frame_buffer + self._read_buffer
+                raise socket.timeout()
+
             if isinstance(exc, SSLError) and 'timed out' in str(exc):
+                # Don't disconnect for ssl read time outs
+                # http://bugs.python.org/issue10272
+                self._read_buffer = read_frame_buffer + self._read_buffer
                 raise socket.timeout()
+
             if get_errno(exc) not in _UNAVAIL:
                 self.connected = False
             raise
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/amqp.egg-info/PKG-INFO 
new/amqp-2.6.0/amqp.egg-info/PKG-INFO
--- old/amqp-2.5.2/amqp.egg-info/PKG-INFO       2019-09-30 15:03:23.000000000 
+0200
+++ new/amqp-2.6.0/amqp.egg-info/PKG-INFO       2020-06-01 08:15:08.000000000 
+0200
@@ -1,143 +1,13 @@
 Metadata-Version: 1.2
 Name: amqp
-Version: 2.5.2
+Version: 2.6.0
 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, Omer Katz
+Maintainer: Asif Saif Uddin, Matus Valo
 License: BSD
-Description: 
=====================================================================
-         Python AMQP 0.9.1 client library
-        =====================================================================
-        
-        |build-status| |coverage| |license| |wheel| |pyversion| |pyimp|
-        
-        :Version: 2.5.2
-        :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
-        
-        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://secure.travis-ci.org/celery/py-amqp.png?branch=master
-            :alt: Build status
-            :target: https://travis-ci.org/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/
-        
-        
+Description: UNKNOWN
 Keywords: amqp rabbitmq cloudamqp messaging
 Platform: any
 Classifier: Development Status :: 5 - Production/Stable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/docs/includes/introduction.txt 
new/amqp-2.6.0/docs/includes/introduction.txt
--- old/amqp-2.5.2/docs/includes/introduction.txt       2019-09-30 
14:58:33.000000000 +0200
+++ new/amqp-2.6.0/docs/includes/introduction.txt       2020-06-01 
07:49:30.000000000 +0200
@@ -1,4 +1,4 @@
-:Version: 2.5.2
+:Version: 2.6.0
 :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-2.5.2/requirements/test.txt 
new/amqp-2.6.0/requirements/test.txt
--- old/amqp-2.5.2/requirements/test.txt        2019-07-12 07:25:19.000000000 
+0200
+++ new/amqp-2.6.0/requirements/test.txt        2020-06-01 07:25:14.000000000 
+0200
@@ -1,4 +1,4 @@
 case>=1.3.1
-pytest>=3.0
+pytest>=3.0,<=5.3.5
 pytest-sugar>=0.9.1
 pytest-rerunfailures>=6.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/setup.py new/amqp-2.6.0/setup.py
--- old/amqp-2.5.2/setup.py     2019-08-14 17:48:25.000000000 +0200
+++ new/amqp-2.6.0/setup.py     2020-06-01 08:15:02.000000000 +0200
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
+import codecs
 import io
 import os
 import re
@@ -81,11 +82,11 @@
 
 # -*- Long Description -*-
 
-if os.path.exists('README.rst'):
-    with io.open('README.rst', encoding='utf-8') as fp:
-        long_description = fp.read()
-else:
-    long_description = 'See https://pypi.org/project/amqp/'
+def long_description():
+    try:
+        return codecs.open('README.rst', 'r', 'utf-8').read()
+    except IOError:
+        return 'Long description error: Missing README.rst file'
 
 # -*- %%% -*-
 
@@ -103,10 +104,34 @@
         sys.exit(pytest.main(pytest_args))
 
 
+if os.environ.get("CELERY_ENABLE_SPEEDUPS"):
+    setup_requires=['Cython']
+    ext_modules = [
+        setuptools.Extension(
+            'amqp.serialization',
+            ["amqp/serialization.py"],
+        ),
+        setuptools.Extension(
+            'amqp.basic_message',
+            ["amqp/basic_message.py"],
+        ),
+        setuptools.Extension(
+            'amqp.method_framing',
+            ["amqp/method_framing.py"],
+        ),
+        setuptools.Extension(
+            'amqp.abstract_channel',
+            ["amqp/abstract_channel.py"],
+        ),
+    ]
+else:
+    setup_requires = []
+    ext_modules = []
+
+
 setuptools.setup(
     name=NAME,
     packages=setuptools.find_packages(exclude=['ez_setup', 't', 't.*']),
-    long_description=long_description,
     version=meta['version'],
     description=meta['doc'],
     keywords='amqp rabbitmq cloudamqp messaging',
@@ -119,7 +144,9 @@
     classifiers=classifiers,
     python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
     install_requires=reqs('default.txt'),
+    setup_requires=setup_requires,
     tests_require=reqs('test.txt'),
     cmdclass={'test': pytest},
     zip_safe=False,
+    ext_modules = ext_modules,
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/t/integration/test_integration.py 
new/amqp-2.6.0/t/integration/test_integration.py
--- old/amqp-2.5.2/t/integration/test_integration.py    2019-07-12 
07:25:19.000000000 +0200
+++ new/amqp-2.6.0/t/integration/test_integration.py    2020-06-01 
07:25:14.000000000 +0200
@@ -123,7 +123,7 @@
         self.items = items
 
     def __eq__(self, other):
-        values, offset = loads(self.argsig, other)
+        values, offset = loads(self.argsig, other, 0)
         return tuple(values) == tuple(self.items)
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/t/integration/test_rmq.py 
new/amqp-2.6.0/t/integration/test_rmq.py
--- old/amqp-2.5.2/t/integration/test_rmq.py    2019-07-12 07:25:19.000000000 
+0200
+++ new/amqp-2.6.0/t/integration/test_rmq.py    2020-06-01 07:25:14.000000000 
+0200
@@ -1,6 +1,7 @@
 from __future__ import absolute_import, unicode_literals
 
 import os
+import ssl
 
 import pytest
 
@@ -8,14 +9,41 @@
 from case import ANY, Mock
 
 
-@pytest.fixture
+def get_connection(
+        hostname, port, vhost, use_tls=False, keyfile=None, certfile=None):
+    host = '%s:%s' % (hostname, port)
+    if use_tls:
+        return amqp.Connection(host=host, vhost=vhost, ssl={
+            'keyfile': keyfile,
+            'certfile': certfile
+        }
+        )
+    else:
+        return amqp.Connection(host=host, vhost=vhost)
+
+
+@pytest.fixture(params=['plain', 'tls'])
 def connection(request):
-    host = '%s:%s' % (
-        os.environ.get('RABBITMQ_HOST', 'localhost'),
-        os.environ.get('RABBITMQ_5672_TCP', '5672')
-    )
-    vhost = getattr(request.config, "slaveinput", {}).get("slaveid", None)
-    return amqp.Connection(host=host, vhost=vhost)
+    # this fixture yields plain connections to broker and TLS encrypted
+    if request.param == 'plain':
+        return get_connection(
+            hostname=os.environ.get('RABBITMQ_HOST', 'localhost'),
+            port=os.environ.get('RABBITMQ_5672_TCP', '5672'),
+            vhost=getattr(
+                request.config, "slaveinput", {}
+            ).get("slaveid", None),
+        )
+    elif request.param == 'tls':
+        return get_connection(
+            hostname=os.environ.get('RABBITMQ_HOST', 'localhost'),
+            port=os.environ.get('RABBITMQ_5671_TCP', '5671'),
+            vhost=getattr(
+                request.config, "slaveinput", {}
+            ).get("slaveid", None),
+            use_tls=True,
+            keyfile='t/certs/client_key.pem',
+            certfile='t/certs/client_certificate.pem'
+        )
 
 
 @pytest.mark.env('rabbitmq')
@@ -26,6 +54,23 @@
 
 
 @pytest.mark.env('rabbitmq')
+@pytest.mark.flaky(reruns=5, reruns_delay=2)
+def test_tls_connect_fails():
+    # testing that wrong client key/certificate yields SSLError
+    # when encrypted connection is used
+    connection = get_connection(
+        hostname=os.environ.get('RABBITMQ_HOST', 'localhost'),
+        port=os.environ.get('RABBITMQ_5671_TCP', '5671'),
+        vhost='/',
+        use_tls=True,
+        keyfile='t/certs/client_key_broken.pem',
+        certfile='t/certs/client_certificate_broken.pem'
+    )
+    with pytest.raises(ssl.SSLError):
+        connection.connect()
+
+
+@pytest.mark.env('rabbitmq')
 class test_rabbitmq_operations():
 
     @pytest.fixture(autouse=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/t/unit/test_serialization.py 
new/amqp-2.6.0/t/unit/test_serialization.py
--- old/amqp-2.5.2/t/unit/test_serialization.py 2019-07-12 07:25:19.000000000 
+0200
+++ new/amqp-2.6.0/t/unit/test_serialization.py 2020-06-01 07:25:14.000000000 
+0200
@@ -3,6 +3,7 @@
 from datetime import datetime
 from decimal import Decimal
 from math import ceil
+import pickle
 
 import pytest
 
@@ -25,6 +26,7 @@
 
     @pytest.mark.parametrize('descr,frame,expected,cast', [
         ('S', b's8thequick', 'thequick', None),
+        ('S', b'S\x00\x00\x00\x03\xc0\xc0\x00', b'\xc0\xc0\x00', None),
         ('x', b'x\x00\x00\x00\x09thequick\xffIGNORED', b'thequick\xff', None),
         ('b', b'b' + pack('>B', True), True, None),
         ('B', b'B' + pack('>b', 123), 123, None),
@@ -36,12 +38,12 @@
         ('f', b'f' + pack('>f', 33.3), 34.0, ceil),
     ])
     def test_read_item(self, descr, frame, expected, cast):
-        actual = _read_item(frame)[0]
+        actual = _read_item(frame, 0)[0]
         actual = cast(actual) if cast else actual
         assert actual == expected
 
     def test_read_item_V(self):
-        assert _read_item(b'V')[0] is None
+        assert _read_item(b'V', 0)[0] is None
 
     def test_roundtrip(self):
         format = b'bobBlLbsbSTx'
@@ -51,7 +53,7 @@
             datetime(2015, 3, 13, 10, 23),
             b'thequick\xff'
         ])
-        y = loads(format, x)
+        y = loads(format, x, 0)
         assert [
             True, 32, False, 3415, 4513134, 13241923419,
             True, 'thequickbrownfox', False, 'jumpsoverthelazydog',
@@ -63,18 +65,18 @@
         x = dumps(format, [
             {'a': -2147483649, 'b': 2147483648},  # celery/celery#3121
         ])
-        y = loads(format, x)
+        y = loads(format, x, 0)
         assert y[0] == [{
             'a': -2147483649, 'b': 2147483648,  # celery/celery#3121
         }]
 
     def test_loads_unknown_type(self):
         with pytest.raises(FrameSyntaxError):
-            loads('y', 'asdsad')
+            loads('y', 'asdsad', 0)
 
     def test_float(self):
-        assert (int(loads(b'fb', dumps(b'fb', [32.31, False]))[0][0] * 100) ==
-                3231)
+        data = int(loads(b'fb', dumps(b'fb', [32.31, False]), 0)[0][0] * 100)
+        assert(data == 3231)
 
     def test_table(self):
         table = {
@@ -85,7 +87,19 @@
                 1, True, 'bar'
             ]
         }
-        assert loads(b'F', dumps(b'F', [table]))[0][0] == table
+        assert loads(b'F', dumps(b'F', [table]), 0)[0][0] == table
+
+    def test_table__unknown_type(self):
+        table = {
+            'foo': object(),
+            'bar': 'baz',
+            'nil': None,
+            'array': [
+                1, True, 'bar'
+            ]
+        }
+        with pytest.raises(FrameSyntaxError):
+            dumps(b'F', [table])
 
     def test_array(self):
         array = [
@@ -99,7 +113,7 @@
         expected = list(array)
         expected[6] = _ANY()
 
-        assert expected == loads('A', dumps('A', [array]))[0][0]
+        assert expected == loads('A', dumps('A', [array]), 0)[0][0]
 
     def test_array_unknown_type(self):
         with pytest.raises(FrameSyntaxError):
@@ -109,14 +123,14 @@
         expected = [50, "quick", "fox", True,
                     False, False, True, True, {"prop1": True}]
         buf = dumps('BssbbbbbF', expected)
-        actual, _ = loads('BssbbbbbF', buf)
+        actual, _ = loads('BssbbbbbF', buf, 0)
         assert actual == expected
 
     def test_sixteen_bitflags(self):
         expected = [True, False] * 8
         format = 'b' * len(expected)
         buf = dumps(format, expected)
-        actual, _ = loads(format, buf)
+        actual, _ = loads(format, buf, 0)
         assert actual == expected
 
 
@@ -128,12 +142,13 @@
 
     def test_getattr(self):
         self.g.properties['foo'] = 30
-        with pytest.raises(AttributeError):
-            self.g.__setstate__
         assert self.g.foo == 30
         with pytest.raises(AttributeError):
             self.g.bar
 
+    def test_pickle(self):
+        pickle.loads(pickle.dumps(self.g))
+
     def test_load_properties(self):
         m = Message()
         m.properties = {
@@ -157,7 +172,7 @@
         }
         s = m._serialize_properties()
         m2 = Message()
-        m2._load_properties(m2.CLASS_ID, s)
+        m2._load_properties(m2.CLASS_ID, s, 0)
         assert m2.properties == m.properties
 
     def test_load_properties__some_missing(self):
@@ -176,7 +191,7 @@
         }
         s = m._serialize_properties()
         m2 = Message()
-        m2._load_properties(m2.CLASS_ID, s)
+        m2._load_properties(m2.CLASS_ID, s, 0)
 
     def test_inbound_header(self):
         m = Message()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/amqp-2.5.2/t/unit/test_transport.py 
new/amqp-2.6.0/t/unit/test_transport.py
--- old/amqp-2.5.2/t/unit/test_transport.py     2019-08-14 17:32:29.000000000 
+0200
+++ new/amqp-2.6.0/t/unit/test_transport.py     2020-06-01 07:25:14.000000000 
+0200
@@ -3,6 +3,7 @@
 import errno
 import socket
 import struct
+import os
 
 import pytest
 
@@ -715,3 +716,39 @@
         with pytest.raises(IOError,
                            match=r'.*Server unexpectedly closed connection.*'):
             self.t._read(64)
+
+    def test_read_frame__windowstimeout(self, monkeypatch):
+        """Make sure BlockingIOError on Windows properly saves off partial 
reads.
+
+        See https://github.com/celery/py-amqp/issues/320
+        """
+
+        self.t._quick_recv = Mock()
+
+        self.t._quick_recv.side_effect = [
+            pack('>BHI', 1, 1, 16),
+            socket.error(
+                10035,
+                "A non-blocking socket operation could "
+                "not be completed immediately"
+            ),
+            b'thequickbrownfox',
+            b'\xce'
+        ]
+
+        monkeypatch.setattr(os, 'name', 'nt')
+        monkeypatch.setattr(errno, 'EWOULDBLOCK', 10035)
+
+        assert len(self.t._read_buffer) == 0
+
+        with pytest.raises(socket.timeout):
+            self.t.read_frame()
+
+        assert len(self.t._read_buffer) == 7
+
+        frame_type, channel, payload = self.t.read_frame()
+
+        assert len(self.t._read_buffer) == 0
+        assert frame_type == 1
+        assert channel == 1
+        assert payload == b'thequickbrownfox'


Reply via email to