Hello community, here is the log from the commit of package python-amqp for openSUSE:Factory checked in at 2014-01-15 16:26:33 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-amqp (Old) and /work/SRC/openSUSE:Factory/.python-amqp.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-amqp" Changes: -------- --- /work/SRC/openSUSE:Factory/python-amqp/python-amqp.changes 2013-12-02 09:53:05.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python-amqp.new/python-amqp.changes 2014-01-15 16:26:34.000000000 +0100 @@ -1,0 +2,8 @@ +Tue Jan 14 10:56:30 UTC 2014 - dmuel...@suse.com + +- update to 1.4.0: + - Heartbeat implementation improved (Issue #6). + - NoneType is now supported in tables and arrays. + - SSLTransport: Now handles ``ENOENT``. + +------------------------------------------------------------------- Old: ---- amqp-1.3.3.tar.gz New: ---- amqp-1.4.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-amqp.spec ++++++ --- /var/tmp/diff_new_pack.seb3u1/_old 2014-01-15 16:26:34.000000000 +0100 +++ /var/tmp/diff_new_pack.seb3u1/_new 2014-01-15 16:26:34.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-amqp # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: python-amqp -Version: 1.3.3 +Version: 1.4.0 Release: 0 Summary: Low-level AMQP client for Python (fork of amqplib) License: LGPL-2.1 ++++++ amqp-1.3.3.tar.gz -> amqp-1.4.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/Changelog new/amqp-1.4.0/Changelog --- old/amqp-1.3.3/Changelog 2013-11-11 16:25:08.000000000 +0100 +++ new/amqp-1.4.0/Changelog 2014-01-13 15:50:56.000000000 +0100 @@ -5,6 +5,36 @@ The previous amqplib changelog is here: http://code.google.com/p/py-amqplib/source/browse/CHANGES +.. _version-1.4.0: + +1.4.0 +:release-date: 2014-01-13 3:00 P.M UTC + +- Heartbeat implementation improved (Issue #6). + + The new heartbeat behavior is the same approach as taken by the + RabbitMQ java library. + + This also means that clients should preferably call the ``heartbeat_tick`` + method more frequently (like every second) instead of using the old + ``rate`` argument (which is now ignored). + + - Heartbeat interval is negotiated with the server. + - Some delay is allowed if the heartbeat is late. + - Monotonic time is used to keep track of the heartbeat + instead of relying on the caller to call the checking function + at the right time. + + Contributed by Dustin J. Mitchell. + +- NoneType is now supported in tables and arrays. + + Contributed by Dominik Fässler. + +- SSLTransport: Now handles ``ENOENT``. + + Fix contributed by Adrien Guinet. + .. _version-1.3.3: 1.3.3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/PKG-INFO new/amqp-1.4.0/PKG-INFO --- old/amqp-1.3.3/PKG-INFO 2013-11-11 16:25:52.000000000 +0100 +++ new/amqp-1.4.0/PKG-INFO 2014-01-13 16:01:08.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: amqp -Version: 1.3.3 +Version: 1.4.0 Summary: Low-level AMQP client for Python (fork of amqplib) Home-page: http://github.com/celery/py-amqp Author: Ask Solem @@ -10,7 +10,7 @@ Python AMQP 0.9.1 client library ===================================================================== - :Version: 1.3.3 + :Version: 1.4.0 :Web: http://amqp.readthedocs.org/ :Download: http://pypi.python.org/pypi/amqp/ :Source: http://github.com/celery/py-amqp/ @@ -107,6 +107,9 @@ http://www.rabbitmq.com/devtools.html#python-dev + .. image:: https://d2weczhvl823v0.cloudfront.net/celery/celery/trend.png + :alt: Bitdeli badge + :target: https://bitdeli.com/free Platform: any Classifier: Development Status :: 5 - Production/Stable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/README.rst new/amqp-1.4.0/README.rst --- old/amqp-1.3.3/README.rst 2013-11-11 16:24:04.000000000 +0100 +++ new/amqp-1.4.0/README.rst 2014-01-13 15:51:21.000000000 +0100 @@ -2,7 +2,7 @@ Python AMQP 0.9.1 client library ===================================================================== -:Version: 1.3.3 +:Version: 1.4.0 :Web: http://amqp.readthedocs.org/ :Download: http://pypi.python.org/pypi/amqp/ :Source: http://github.com/celery/py-amqp/ @@ -99,3 +99,6 @@ http://www.rabbitmq.com/devtools.html#python-dev +.. image:: https://d2weczhvl823v0.cloudfront.net/celery/celery/trend.png + :alt: Bitdeli badge + :target: https://bitdeli.com/free diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/amqp/__init__.py new/amqp-1.4.0/amqp/__init__.py --- old/amqp-1.3.3/amqp/__init__.py 2013-11-11 16:24:00.000000000 +0100 +++ new/amqp-1.4.0/amqp/__init__.py 2014-01-13 15:51:11.000000000 +0100 @@ -16,7 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 from __future__ import absolute_import -VERSION = (1, 3, 3) +VERSION = (1, 4, 0) __version__ = '.'.join(map(str, VERSION[0:3])) + ''.join(VERSION[3:]) __author__ = 'Barry Pederson' __maintainer__ = 'Ask Solem' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/amqp/abstract_channel.py new/amqp-1.4.0/amqp/abstract_channel.py --- old/amqp-1.3.3/amqp/abstract_channel.py 2013-11-10 01:53:13.000000000 +0100 +++ new/amqp-1.4.0/amqp/abstract_channel.py 2014-01-13 15:26:01.000000000 +0100 @@ -19,12 +19,6 @@ from .exceptions import AMQPNotImplementedError, RecoverableConnectionError from .serialization import AMQPWriter -try: - bytes -except NameError: - # Python 2.5 and lower - bytes = str - __all__ = ['AbstractChannel'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/amqp/connection.py new/amqp-1.4.0/amqp/connection.py --- old/amqp-1.3.3/amqp/connection.py 2013-11-10 01:53:13.000000000 +0100 +++ new/amqp-1.4.0/amqp/connection.py 2014-01-13 15:34:16.000000000 +0100 @@ -34,7 +34,7 @@ ConnectionForced, ConnectionError, error_for_code, RecoverableConnectionError, RecoverableChannelError, ) -from .five import items, range, values +from .five import items, range, values, monotonic from .method_framing import MethodReader, MethodWriter from .serialization import AMQPWriter from .transport import create_transport @@ -80,9 +80,26 @@ """ Channel = Channel + #: Final heartbeat interval value (in float seconds) after negotiation + heartbeat = None + + #: Original heartbeat interval value proposed by client. + client_heartbeat = None + + #: Original heartbeat interval proposed by server. + server_heartbeat = None + + #: Time of last heartbeat sent (in monotonic time, if available). + last_heartbeat_sent = 0 + + #: Time of last heartbeat received (in monotonic time, if available). + last_heartbeat_received = 0 + + #: Number of bytes sent to socket at the last heartbeat check. prev_sent = None + + #: Number of bytes received from socket at the last heartbeat check. prev_recv = None - missed_heartbeats = 0 def __init__(self, host='localhost', userid='guest', password='guest', login_method='AMQPLAIN', login_response=None, @@ -125,7 +142,7 @@ # Properties set in the Tune method self.channel_max = channel_max self.frame_max = frame_max - self.heartbeat = heartbeat + self.client_heartbeat = heartbeat self.confirm_publish = confirm_publish @@ -843,7 +860,14 @@ self.channel_max = args.read_short() or self.channel_max self.frame_max = args.read_long() or self.frame_max self.method_writer.frame_max = self.frame_max - heartbeat = args.read_short() # noqa + self.server_heartbeat = args.read_short() + + # negotiate the heartbeat interval to the smaller of the + # specified values + if self.server_heartbeat == 0 or self.client_heartbeat == 0: + self.heartbeat = max(self.server_heartbeat, self.client_heartbeat) + else: + self.heartbeat = min(self.server_heartbeat, self.client_heartbeat) self._x_tune_ok(self.channel_max, self.frame_max, self.heartbeat) @@ -851,28 +875,34 @@ self.transport.write_frame(8, 0, bytes()) def heartbeat_tick(self, rate=2): - """Verify that hartbeats are sent and received. - - :keyword rate: Rate is how often the tick is called - compared to the actual heartbeat value. E.g. if - the heartbeat is set to 3 seconds, and the tick - is called every 3 / 2 seconds, then the rate is 2. + """Send heartbeat packets, if necessary, and fail if none have been + received recently. This should be called frequently, on the order of + once per second. + :keyword rate: Ignored """ + if not self.heartbeat: + return + + # treat actual data exchange in either direction as a heartbeat sent_now = self.method_writer.bytes_sent recv_now = self.method_reader.bytes_recv + if self.prev_sent is None or self.prev_sent != sent_now: + self.last_heartbeat_sent = monotonic() + if self.prev_recv is None or self.prev_recv != recv_now: + self.last_heartbeat_received = monotonic() + self.prev_sent, self.prev_recv = sent_now, recv_now - if self.prev_sent is not None and self.prev_sent == sent_now: + # send a heartbeat if it's time to do so + if monotonic() > self.last_heartbeat_sent + self.heartbeat: self.send_heartbeat() + self.last_heartbeat_sent = monotonic() - if self.prev_recv is not None and self.prev_recv == recv_now: - self.missed_heartbeats += 1 - else: - self.missed_heartbeats = 0 - - self.prev_sent, self.prev_recv = sent_now, recv_now - - if self.missed_heartbeats >= rate: + # if we've missed two intervals' heartbeats, fail; this gives the + # server enough time to send heartbeats a little late + if (self.last_heartbeat_received and + self.last_heartbeat_received + 2 * + self.heartbeat < monotonic()): raise ConnectionForced('Too many heartbeats missed') def _x_tune_ok(self, channel_max, frame_max, heartbeat): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/amqp/five.py new/amqp-1.4.0/amqp/five.py --- old/amqp-1.3.3/amqp/five.py 2013-11-10 01:53:13.000000000 +0100 +++ new/amqp-1.4.0/amqp/five.py 2014-01-13 15:34:29.000000000 +0100 @@ -131,3 +131,58 @@ return Type(Class.__name__, Class.__bases__, attrs) return _clone_with_metaclass + +############## time.monotonic ################################################ + +if sys.version_info < (3, 3): + + import platform + SYSTEM = platform.system() + + if SYSTEM == 'Darwin': + import ctypes + from ctypes.util import find_library + libSystem = ctypes.CDLL('libSystem.dylib') + CoreServices = ctypes.CDLL(find_library('CoreServices'), + use_errno=True) + mach_absolute_time = libSystem.mach_absolute_time + mach_absolute_time.restype = ctypes.c_uint64 + absolute_to_nanoseconds = CoreServices.AbsoluteToNanoseconds + absolute_to_nanoseconds.restype = ctypes.c_uint64 + absolute_to_nanoseconds.argtypes = [ctypes.c_uint64] + + def _monotonic(): + return absolute_to_nanoseconds(mach_absolute_time()) * 1e-9 + + elif SYSTEM == 'Linux': + # from stackoverflow: + # questions/1205722/how-do-i-get-monotonic-time-durations-in-python + import ctypes + import os + + CLOCK_MONOTONIC = 1 # see <linux/time.h> + + class timespec(ctypes.Structure): + _fields_ = [ + ('tv_sec', ctypes.c_long), + ('tv_nsec', ctypes.c_long), + ] + + librt = ctypes.CDLL('librt.so.1', use_errno=True) + clock_gettime = librt.clock_gettime + clock_gettime.argtypes = [ + ctypes.c_int, ctypes.POINTER(timespec), + ] + + def _monotonic(): # noqa + t = timespec() + if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(t)) != 0: + errno_ = ctypes.get_errno() + raise OSError(errno_, os.strerror(errno_)) + return t.tv_sec + t.tv_nsec * 1e-9 + else: + from time import time as _monotonic +try: + from time import monotonic +except ImportError: + monotonic = _monotonic # noqa diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/amqp/method_framing.py new/amqp-1.4.0/amqp/method_framing.py --- old/amqp-1.3.3/amqp/method_framing.py 2013-11-10 01:53:13.000000000 +0100 +++ new/amqp-1.4.0/amqp/method_framing.py 2014-01-13 15:26:07.000000000 +0100 @@ -19,12 +19,6 @@ from collections import defaultdict, deque from struct import pack, unpack -try: - bytes -except NameError: - # Python 2.5 and lower - bytes = str - from .basic_message import Message from .exceptions import AMQPError, UnexpectedFrame from .five import range, string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/amqp/serialization.py new/amqp-1.4.0/amqp/serialization.py --- old/amqp-1.3.3/amqp/serialization.py 2013-11-10 01:53:13.000000000 +0100 +++ new/amqp-1.4.0/amqp/serialization.py 2014-01-13 15:34:38.000000000 +0100 @@ -25,6 +25,7 @@ from datetime import datetime from decimal import Decimal +from io import BytesIO from struct import pack, unpack from time import mktime @@ -39,19 +40,6 @@ else: byte = chr -try: - from io import BytesIO -except ImportError: # Py2.5 - try: - from cStringIO import StringIO as BytesIO # noqa - except ImportError: - from StringIO import StringIO as BytesIO # noqa - -try: - bytes -except NameError: - # Python 2.5 and lower - bytes = str ILLEGAL_TABLE_TYPE_WITH_KEY = """\ Table type {0!r} for key {1!r} not handled by amqp. [value: {2!r}] @@ -174,6 +162,8 @@ val = self.read_bit() elif ftype == 100: val = self.read_float() + elif ftype == 86: # 'V' + val = None else: raise FrameSyntaxError( 'Unknown value in table: {0!r} ({1!r})'.format( @@ -357,6 +347,8 @@ elif isinstance(v, (list, tuple)): self.write(b'A') self.write_array(v) + elif v is None: + self.write(b'V') else: err = (ILLEGAL_TABLE_TYPE_WITH_KEY.format(type(v), k, v) if k else ILLEGAL_TABLE_TYPE.format(type(v), v)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/amqp/transport.py new/amqp-1.4.0/amqp/transport.py --- old/amqp-1.3.3/amqp/transport.py 2013-11-11 16:23:01.000000000 +0100 +++ new/amqp-1.4.0/amqp/transport.py 2014-01-13 15:34:57.000000000 +0100 @@ -1,9 +1,3 @@ -""" -Read/Write AMQP frames over network transports. - -2009-01-14 Barry Pederson <b...@barryp.org> - -""" # Copyright (C) 2009 Barry Pederson <b...@barryp.org> # # This library is free software; you can redistribute it and/or @@ -24,6 +18,7 @@ import errno import re import socket +import ssl # Jython does not have this attribute try: @@ -31,27 +26,12 @@ except ImportError: # pragma: no cover from socket import IPPROTO_TCP as SOL_TCP # noqa -# -# See if Python 2.6+ SSL support is available -# -try: - import ssl - HAVE_PY26_SSL = True -except: - HAVE_PY26_SSL = False - -try: - bytes -except: - # Python 2.5 and lower - bytes = str - from struct import pack, unpack from .exceptions import UnexpectedFrame from .utils import get_errno, set_cloexec -_UNAVAIL = errno.EAGAIN, errno.EINTR +_UNAVAIL = errno.EAGAIN, errno.EINTR, errno.ENOENT AMQP_PORT = 5672 @@ -200,22 +180,17 @@ super(SSLTransport, self).__init__(host, connect_timeout) def _setup_transport(self): - """Wrap the socket in an SSL object, either the - new Python 2.6 version, or the older Python 2.5 and - lower version.""" - if HAVE_PY26_SSL: - if hasattr(self, 'sslopts'): - self.sock = ssl.wrap_socket(self.sock, **self.sslopts) - else: - self.sock = ssl.wrap_socket(self.sock) - self.sock.do_handshake() + """Wrap the socket in an SSL object.""" + if hasattr(self, 'sslopts'): + self.sock = ssl.wrap_socket(self.sock, **self.sslopts) else: - self.sock = socket.ssl(self.sock) + self.sock = ssl.wrap_socket(self.sock) + self.sock.do_handshake() self._quick_recv = self.sock.read def _shutdown_transport(self): """Unwrap a Python 2.6 SSL socket, so we can call shutdown()""" - if HAVE_PY26_SSL and self.sock is not None: + if self.sock is not None: try: unwrap = self.sock.unwrap except AttributeError: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/amqp/utils.py new/amqp-1.4.0/amqp/utils.py --- old/amqp-1.3.3/amqp/utils.py 2013-11-10 01:53:13.000000000 +0100 +++ new/amqp-1.4.0/amqp/utils.py 2014-01-13 14:55:09.000000000 +0100 @@ -11,7 +11,8 @@ class promise(object): if not hasattr(sys, 'pypy_version_info'): __slots__ = tuple( - 'fun args kwargs value ready failed on_success on_error'.split() + 'fun args kwargs value ready failed ' + ' on_success on_error calls'.split() ) def __init__(self, fun, args=(), kwargs=(), @@ -24,6 +25,7 @@ self.on_success = on_success self.on_error = on_error self.value = None + self.calls = 0 def __repr__(self): return '<$: {0.fun.__name__}(*{0.args!r}, **{0.kwargs!r})'.format( @@ -43,6 +45,7 @@ self.on_success(self.value) finally: self.ready = True + self.calls += 1 def then(self, callback=None, on_error=None): self.on_success = callback diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/amqp.egg-info/PKG-INFO new/amqp-1.4.0/amqp.egg-info/PKG-INFO --- old/amqp-1.3.3/amqp.egg-info/PKG-INFO 2013-11-11 16:25:49.000000000 +0100 +++ new/amqp-1.4.0/amqp.egg-info/PKG-INFO 2014-01-13 16:01:03.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: amqp -Version: 1.3.3 +Version: 1.4.0 Summary: Low-level AMQP client for Python (fork of amqplib) Home-page: http://github.com/celery/py-amqp Author: Ask Solem @@ -10,7 +10,7 @@ Python AMQP 0.9.1 client library ===================================================================== - :Version: 1.3.3 + :Version: 1.4.0 :Web: http://amqp.readthedocs.org/ :Download: http://pypi.python.org/pypi/amqp/ :Source: http://github.com/celery/py-amqp/ @@ -107,6 +107,9 @@ http://www.rabbitmq.com/devtools.html#python-dev + .. image:: https://d2weczhvl823v0.cloudfront.net/celery/celery/trend.png + :alt: Bitdeli badge + :target: https://bitdeli.com/free Platform: any Classifier: Development Status :: 5 - Production/Stable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/demo/amqp_clock.py new/amqp-1.4.0/demo/amqp_clock.py --- old/amqp-1.3.3/demo/amqp_clock.py 2012-12-18 17:41:48.000000000 +0100 +++ new/amqp-1.4.0/demo/amqp_clock.py 2014-01-13 15:36:30.000000000 +0100 @@ -27,18 +27,23 @@ def main(): parser = OptionParser() - parser.add_option('--host', dest='host', - help='AMQP server to connect to (default: %default)', - default='localhost') - parser.add_option('-u', '--userid', dest='userid', + parser.add_option( + '--host', dest='host', + help='AMQP server to connect to (default: %default)', + default='localhost', + ) + parser.add_option( + '-u', '--userid', dest='userid', help='AMQP userid to authenticate as (default: %default)', default='guest', ) - parser.add_option('-p', '--password', dest='password', + parser.add_option( + '-p', '--password', dest='password', help='AMQP password to authenticate with (default: %default)', default='guest', ) - parser.add_option('--ssl', dest='ssl', action='store_true', + parser.add_option( + '--ssl', dest='ssl', action='store_true', help='Enable SSL with AMQP server (default: not enabled)', default=False, ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/demo/demo_receive.py new/amqp-1.4.0/demo/demo_receive.py --- old/amqp-1.3.3/demo/demo_receive.py 2012-12-18 17:41:48.000000000 +0100 +++ new/amqp-1.4.0/demo/demo_receive.py 2014-01-13 15:36:06.000000000 +0100 @@ -16,14 +16,14 @@ def callback(channel, msg): for key, val in msg.properties.items(): - print ('%s: %s' % (key, str(val))) + print('%s: %s' % (key, str(val))) for key, val in msg.delivery_info.items(): - print ('> %s: %s' % (key, str(val))) + print('> %s: %s' % (key, str(val))) - print ('') - print (msg.body) - print ('-------') - print msg.delivery_tag + print('') + print(msg.body) + print('-------') + print(msg.delivery_tag) channel.basic_ack(msg.delivery_tag) # @@ -35,19 +35,23 @@ def main(): parser = OptionParser() - parser.add_option('--host', dest='host', + parser.add_option( + '--host', dest='host', help='AMQP server to connect to (default: %default)', default='localhost', ) - parser.add_option('-u', '--userid', dest='userid', + parser.add_option( + '-u', '--userid', dest='userid', help='userid to authenticate as (default: %default)', default='guest', ) - parser.add_option('-p', '--password', dest='password', + parser.add_option( + '-p', '--password', dest='password', help='password to authenticate with (default: %default)', default='guest', ) - parser.add_option('--ssl', dest='ssl', action='store_true', + parser.add_option( + '--ssl', dest='ssl', action='store_true', help='Enable SSL (default: not enabled)', default=False, ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/demo/demo_send.py new/amqp-1.4.0/demo/demo_send.py --- old/amqp-1.3.3/demo/demo_send.py 2012-12-18 17:41:48.000000000 +0100 +++ new/amqp-1.4.0/demo/demo_send.py 2014-01-13 15:35:20.000000000 +0100 @@ -19,19 +19,23 @@ parser = OptionParser( usage='usage: %prog [options] message\nexample: %prog hello world', ) - parser.add_option('--host', dest='host', + parser.add_option( + '--host', dest='host', help='AMQP server to connect to (default: %default)', default='localhost', ) - parser.add_option('-u', '--userid', dest='userid', + parser.add_option( + '-u', '--userid', dest='userid', help='userid to authenticate as (default: %default)', default='guest', ) - parser.add_option('-p', '--password', dest='password', + parser.add_option( + '-p', '--password', dest='password', help='password to authenticate with (default: %default)', default='guest', ) - parser.add_option('--ssl', dest='ssl', action='store_true', + parser.add_option( + '--ssl', dest='ssl', action='store_true', help='Enable SSL (default: not enabled)', default=False, ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/docs/_ext/applyxrefs.py new/amqp-1.4.0/docs/_ext/applyxrefs.py --- old/amqp-1.3.3/docs/_ext/applyxrefs.py 2012-12-18 17:41:48.000000000 +0100 +++ new/amqp-1.4.0/docs/_ext/applyxrefs.py 2014-01-13 15:40:23.000000000 +0100 @@ -6,8 +6,8 @@ testing = False DONT_TOUCH = ( - './index.txt', - ) + './index.txt', +) def target_name(fn): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/docs/_ext/literals_to_xrefs.py new/amqp-1.4.0/docs/_ext/literals_to_xrefs.py --- old/amqp-1.3.3/docs/_ext/literals_to_xrefs.py 2012-12-18 17:41:48.000000000 +0100 +++ new/amqp-1.4.0/docs/_ext/literals_to_xrefs.py 2014-01-13 15:41:47.000000000 +0100 @@ -95,8 +95,8 @@ replace_type in ("class", "func", "meth"): default = default[:-2] replace_value = raw_input( - colorize("Text <target> [", fg="yellow") + default + \ - colorize("]: ", fg="yellow")).strip() + colorize("Text <target> [", fg="yellow") + default + + colorize("]: ", fg="yellow")).strip() if not replace_value: replace_value = default new.append(":%s:`%s`" % (replace_type, replace_value)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/docs/changelog.rst new/amqp-1.4.0/docs/changelog.rst --- old/amqp-1.3.3/docs/changelog.rst 2013-11-11 16:25:08.000000000 +0100 +++ new/amqp-1.4.0/docs/changelog.rst 2014-01-13 15:50:56.000000000 +0100 @@ -5,6 +5,36 @@ The previous amqplib changelog is here: http://code.google.com/p/py-amqplib/source/browse/CHANGES +.. _version-1.4.0: + +1.4.0 +:release-date: 2014-01-13 3:00 P.M UTC + +- Heartbeat implementation improved (Issue #6). + + The new heartbeat behavior is the same approach as taken by the + RabbitMQ java library. + + This also means that clients should preferably call the ``heartbeat_tick`` + method more frequently (like every second) instead of using the old + ``rate`` argument (which is now ignored). + + - Heartbeat interval is negotiated with the server. + - Some delay is allowed if the heartbeat is late. + - Monotonic time is used to keep track of the heartbeat + instead of relying on the caller to call the checking function + at the right time. + + Contributed by Dustin J. Mitchell. + +- NoneType is now supported in tables and arrays. + + Contributed by Dominik Fässler. + +- SSLTransport: Now handles ``ENOENT``. + + Fix contributed by Adrien Guinet. + .. _version-1.3.3: 1.3.3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/docs/conf.py new/amqp-1.4.0/docs/conf.py --- old/amqp-1.3.3/docs/conf.py 2012-12-18 17:41:48.000000000 +0100 +++ new/amqp-1.4.0/docs/conf.py 2014-01-13 15:40:14.000000000 +0100 @@ -70,8 +70,8 @@ html_use_index = True latex_documents = [ - ('index', 'py-amqp.tex', ur'py-amqp Documentation', - ur'Ask Solem & Contributors', 'manual'), + ('index', 'py-amqp.tex', ur'py-amqp Documentation', + ur'Ask Solem & Contributors', 'manual'), ] html_theme = "celery" @@ -89,7 +89,7 @@ issuetracker_project = "celery/py-amqp" issuetracker_issue_pattern = r'[Ii]ssue #(\d+)' -# -- Options for Epub output --------------------------------------------------- +# -- Options for Epub output ------------------------------------------------ # Bibliographic Dublin Core info. epub_title = 'py-amqp Manual, Version 1.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/extra/generate_skeleton_0_8.py new/amqp-1.4.0/extra/generate_skeleton_0_8.py --- old/amqp-1.3.3/extra/generate_skeleton_0_8.py 2012-12-18 17:41:48.000000000 +0100 +++ new/amqp-1.4.0/extra/generate_skeleton_0_8.py 2014-01-13 15:39:36.000000000 +0100 @@ -204,9 +204,10 @@ if 'content' in amqp_method.attrib: params.append('msg') - out.write(' def %s(%s):\n' % - (_fixup_method_name(class_element, amqp_method), - ', '.join(params + fieldnames))) + out.write(' def %s(%s):\n' % ( + _fixup_method_name(class_element, amqp_method), + ', '.join(params + fieldnames)), + ) s = generate_docstr(amqp_method, ' ', ' """') if s: @@ -231,7 +232,7 @@ if 'synchronous' in amqp_method.attrib: responses = [x.attrib['name'] - for x in amqp_method.findall('response')] + for x in amqp_method.findall('response')] out.write(' return self.wait(allowed_methods=[\n') for r in responses: resp = method_name_map[(class_element.attrib['name'], r)] @@ -274,7 +275,7 @@ # for amqp_class in spec.findall('class'): if (amqp_class.attrib['handler'] == class_element.attrib['name']) and \ - (amqp_class.attrib['name'] != class_element.attrib['name']): + (amqp_class.attrib['name'] != class_element.attrib['name']): out.write(' #############\n') out.write(' #\n') out.write(' # %s\n' % amqp_class.attrib['name'].capitalize()) @@ -315,8 +316,8 @@ ( amqp_class.attrib['index'], amqp_method.attrib['index'], - amqp_class.attrib['handler'].capitalize() + '.' + - _fixup_method_name(amqp_class, amqp_method), + (amqp_class.attrib['handler'].capitalize() + '.' + + _fixup_method_name(amqp_class, amqp_method)), ) #### Actually generate output @@ -335,7 +336,7 @@ # for chassis in amqp_method.findall('chassis'): # print ' ', chassis.attrib chassis = [x.attrib['name'] - for x in amqp_method.findall('chassis')] + for x in amqp_method.findall('chassis')] if 'client' in chassis: out.write(" (%s, %s): (%s, %s._%s),\n" % ( amqp_class.attrib['index'], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/funtests/test_channel.py new/amqp-1.4.0/funtests/test_channel.py --- old/amqp-1.3.3/funtests/test_channel.py 2013-11-10 01:53:13.000000000 +0100 +++ new/amqp-1.4.0/funtests/test_channel.py 2014-01-13 15:33:10.000000000 +0100 @@ -22,15 +22,8 @@ import sys import unittest -try: - bytes -except NameError: - # Python 2.5 and lower - bytes = str - import settings - from amqp import ChannelError, Connection, Message, FrameSyntaxError @@ -163,14 +156,19 @@ self.assertTrue(isinstance(msg2.body, bytes)) self.assertEqual(msg2.body, u'hello w\xf6rld'.encode('latin_1')) - def test_exception(self): - """ - Check that Channel exceptions are actually raised as Python - exceptions. + def test_queue_delete_empty(self): + self.assertFalse( + self.ch.queue_delete('bogus_queue_that_does_not_exist') + ) - """ + def test_survives_channel_error(self): with self.assertRaises(ChannelError): - self.ch.queue_delete('bogus_queue_that_does_not_exist') + self.ch.queue_declare('krjqheewq_bogus', passive=True) + self.ch.queue_declare('funtest_survive') + self.ch.queue_declare('funtest_survive', passive=True) + self.assertEqual( + 0, self.ch.queue_delete('funtest_survive'), + ) def test_invalid_header(self): """ @@ -181,7 +179,7 @@ """ qname, _, _ = self.ch.queue_declare() - msg = Message(application_headers={'test': None}) + msg = Message(application_headers={'test': object()}) self.assertRaises( FrameSyntaxError, self.ch.basic_publish, msg, routing_key=qname, @@ -248,10 +246,10 @@ content_type='text/plain', application_headers={'foo': 7, 'bar': 'baz'}) - self.ch.basic_publish(msg, 'unittest.fanout') - self.ch.basic_publish(msg, 'unittest.fanout', mandatory=True) - self.ch.basic_publish(msg, 'unittest.fanout', mandatory=True) - self.ch.basic_publish(msg, 'unittest.fanout', mandatory=True) + self.ch.basic_publish(msg, 'funtest.fanout') + self.ch.basic_publish(msg, 'funtest.fanout', mandatory=True) + self.ch.basic_publish(msg, 'funtest.fanout', mandatory=True) + self.ch.basic_publish(msg, 'funtest.fanout', mandatory=True) self.ch.close() # @@ -264,38 +262,37 @@ Network configuration is as follows (-> is forwards to : source_exchange -> dest_exchange -> queue The test checks that once the message is publish to the - destination exchange(unittest.topic_dest) it is delivered to the queue. + destination exchange(funtest.topic_dest) it is delivered to the queue. """ test_routing_key = 'unit_test__key' - dest_exchange = 'unittest.topic_dest_bind' - source_exchange = 'unittest.topic_source_bind' + dest_exchange = 'funtest.topic_dest_bind' + source_exchange = 'funtest.topic_source_bind' self.ch.exchange_declare(dest_exchange, 'topic', auto_delete=True) self.ch.exchange_declare(source_exchange, 'topic', auto_delete=True) qname, _, _ = self.ch.queue_declare() - self.ch.exchange_bind(destination = dest_exchange, - source = source_exchange, - routing_key = test_routing_key) + self.ch.exchange_bind(destination=dest_exchange, + source=source_exchange, + routing_key=test_routing_key) self.ch.queue_bind(qname, dest_exchange, routing_key=test_routing_key) - msg = Message('unittest message', + msg = Message('funtest message', content_type='text/plain', application_headers={'foo': 7, 'bar': 'baz'}) - self.ch.basic_publish(msg, source_exchange, - routing_key = test_routing_key) + routing_key=test_routing_key) msg2 = self.ch.basic_get(qname, no_ack=True) self.assertEqual(msg, msg2) def test_exchange_unbind(self): - dest_exchange = 'unittest.topic_dest_unbind' - source_exchange = 'unittest.topic_source_unbind' + dest_exchange = 'funtest.topic_dest_unbind' + source_exchange = 'funtest.topic_source_unbind' test_routing_key = 'unit_test__key' self.ch.exchange_declare(dest_exchange, @@ -311,6 +308,7 @@ source=source_exchange, routing_key=test_routing_key) + def main(): suite = unittest.TestLoader().loadTestsFromTestCase(TestChannel) unittest.TextTestRunner(**settings.test_args).run(suite) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/funtests/test_serialization.py new/amqp-1.4.0/funtests/test_serialization.py --- old/amqp-1.3.3/funtests/test_serialization.py 2013-11-10 01:53:13.000000000 +0100 +++ new/amqp-1.4.0/funtests/test_serialization.py 2014-01-13 15:33:25.000000000 +0100 @@ -26,12 +26,6 @@ import sys import unittest -try: - bytes -except NameError: - # Python 2.5 and lower - bytes = str - import settings from amqp.serialization import ( @@ -316,7 +310,7 @@ Check that an un-serializable table entry raises a ValueError """ - val = {'test': None} + val = {'test': object()} w = AMQPWriter() self.assertRaises(FrameSyntaxError, w.write_table, val) @@ -327,6 +321,7 @@ 'baz': 'this is some random string I typed', 'ubaz': u'And something in unicode', 'dday_aniv': datetime(1994, 6, 6), + 'nothing': None, 'more': { 'abc': -123, 'def': 'hello world', @@ -351,26 +346,26 @@ # Array # def test_array_from_list(self): - val = [1, 'foo'] + val = [1, 'foo', None] w = AMQPWriter() w.write_array(val) s = w.getvalue() self.assertEqualBinary( - s, '\x00\x00\x00\x0DI\x00\x00\x00\x01S\x00\x00\x00\x03foo', + s, '\x00\x00\x00\x0EI\x00\x00\x00\x01S\x00\x00\x00\x03fooV', ) r = AMQPReader(s) self.assertEqual(r.read_array(), val) def test_array_from_tuple(self): - val = (1, 'foo') + val = (1, 'foo', None) w = AMQPWriter() w.write_array(val) s = w.getvalue() self.assertEqualBinary( - s, '\x00\x00\x00\x0DI\x00\x00\x00\x01S\x00\x00\x00\x03foo', + s, '\x00\x00\x00\x0EI\x00\x00\x00\x01S\x00\x00\x00\x03fooV', ) r = AMQPReader(s) @@ -387,48 +382,6 @@ } w = AMQPWriter() - w.write_table(val) - s = w.getvalue() - - r = AMQPReader(s) - self.assertEqual(r.read_table(), val) - - # - # Array - # - def test_array_from_list(self): - val = [1, 'foo'] - w = AMQPWriter() - w.write_array(val) - s = w.getvalue() - - self.assertEqualBinary(s, '\x00\x00\x00\x0DI\x00\x00\x00\x01S\x00\x00\x00\x03foo') - - r = AMQPReader(s) - self.assertEqual(r.read_array(), val) - - def test_array_from_tuple(self): - val = (1, 'foo') - w = AMQPWriter() - w.write_array(val) - s = w.getvalue() - - self.assertEqualBinary(s, '\x00\x00\x00\x0DI\x00\x00\x00\x01S\x00\x00\x00\x03foo') - - r = AMQPReader(s) - self.assertEqual(r.read_array(), list(val)) - - def test_table_with_array(self): - val = { - 'foo': 7, - 'bar': Decimal('123345.1234'), - 'baz': 'this is some random string I typed', - 'blist': [1,2,3], - 'nlist': [1, [2,3,4]], - 'ndictl': {'nfoo': 8, 'nblist': [5,6,7] } - } - - w = AMQPWriter() w.write_table(val) s = w.getvalue() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/amqp-1.3.3/setup.py new/amqp-1.4.0/setup.py --- old/amqp-1.3.3/setup.py 2013-11-10 01:53:13.000000000 +0100 +++ new/amqp-1.4.0/setup.py 2014-01-13 15:42:15.000000000 +0100 @@ -15,8 +15,8 @@ import sys import codecs -if sys.version_info < (2, 5): - raise Exception('amqp requires Python 2.5 or higher.') +if sys.version_info < (2, 6): + raise Exception('amqp requires Python 2.6 or higher.') NAME = 'amqp' entrypoints = {} @@ -35,7 +35,8 @@ Programming Language :: Python :: 3.1 Programming Language :: Python :: 3.2 Programming Language :: Python :: 3.3 - License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) + License :: OSI Approved :: GNU Library or \ +Lesser General Public License (LGPL) Intended Audience :: Developers License :: OSI Approved :: BSD License Operating System :: OS Independent -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org