From a79a0a50318ddb96b83762d1fb924af4ab9eb46b Mon Sep 17 00:00:00 2001 From: Dan Rowles Date: Mon, 5 Jan 2015 14:34:24 +0000 Subject: [PATCH 01/51] If an on_close_if handler in a BufferedChannel decides to close the channel, don't try to send any more _zpc_more messages, as they can no longer be sent. --- tests/test_buffered_channel.py | 58 ++++++++++++++++++++++++++++++++++ zerorpc/channel.py | 5 ++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/tests/test_buffered_channel.py b/tests/test_buffered_channel.py index f55993c..3c8855e 100644 --- a/tests/test_buffered_channel.py +++ b/tests/test_buffered_channel.py @@ -444,3 +444,61 @@ def _do_with_assert_raises(): client.close() server_bufchan.close() server.close() + + +def test_on_close_if(): + """ + Test that the on_close_if method does not cause exceptions when the client + is slow to recv() data. + """ + endpoint = random_ipc_endpoint() + server_events = zerorpc.Events(zmq.ROUTER) + server_events.bind(endpoint) + server = zerorpc.ChannelMultiplexer(server_events) + + client_events = zerorpc.Events(zmq.DEALER) + client_events.connect(endpoint) + client = zerorpc.ChannelMultiplexer(client_events, ignore_broadcast=True) + + client_channel = client.channel() + client_hbchan = zerorpc.HeartBeatOnChannel(client_channel, freq=2) + client_bufchan = zerorpc.BufferedChannel(client_hbchan, inqueue_size=10) + + event = server.recv() + server_channel = server.channel(event) + server_hbchan = zerorpc.HeartBeatOnChannel(server_channel, freq=2) + server_bufchan = zerorpc.BufferedChannel(server_hbchan, inqueue_size=10) + + seen = [] + + def is_stream_done(event): + return event.name == 'done' + + def client_do(): + while True: + event = client_bufchan.recv() + if event.name == 'done': + return + seen.append(event.args) + gevent.sleep(0.1) + + def server_do(): + for i in range(0, 10): + server_bufchan.emit('blah', (i)) + server_bufchan.emit('done', ('bye')) + + client_bufchan.on_close_if = is_stream_done + + coro_pool = gevent.pool.Pool() + g1 = coro_pool.spawn(client_do) + g2 = coro_pool.spawn(server_do) + + g1.get() # Re-raise any exceptions... + g2.get() + + assert seen == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + client_bufchan.close() + server_bufchan.close() + client.close() + server.close() diff --git a/zerorpc/channel.py b/zerorpc/channel.py index 5da8991..1974370 100644 --- a/zerorpc/channel.py +++ b/zerorpc/channel.py @@ -254,7 +254,10 @@ def _request_data(self): self._channel.emit('_zpc_more', (open_slots,)) def recv(self, timeout=None): - if self._verbose: + # self._channel can be set to None by an 'on_close_if' callback if it + # sees a suitable message from the remote end... + # + if self._verbose and self._channel: if self._input_queue_reserved < self._input_queue_size / 2: self._request_data() else: From a83c120fc9821def288bf878e7567df5ed18c299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Fri, 11 Sep 2015 18:38:55 -0700 Subject: [PATCH 02/51] Python 2.6 compat: get the PyZmq Frame Buffer A pyzmq frame in python2.6 and 2.7 are not similar. They both offer the attribute buffer which is: - a read-only buffer in 2.6 - a memoryview in 2.7 Apparently the read-only buffer doesn't implement the buffer interface while the memoryview does, which is needed for msgpack. Both accept to be sliced though which returns: - an 'str' in 2.6 - a memoryview in 2.7 Sadly, until very recently, taking a slice of a memoryview of dimension raises an exception: https://bugs.python.org/issue15944. Although it looks like recent version of pyzqm>14.2 are not affected. Anyway, the easiest is access the buffer differently depending of the python version. Fixes 0rpc/zerorpc-python#125. Additionally fixes the unit tests for 2.6 and add it back to travis. --- .travis.yml | 1 + tests/test_buffered_channel.py | 9 ++++----- zerorpc/events.py | 11 ++++++++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index a4f2163..dec8728 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: python python: + - 2.6 - 2.7 env: matrix: diff --git a/tests/test_buffered_channel.py b/tests/test_buffered_channel.py index adb27d6..23b7c70 100644 --- a/tests/test_buffered_channel.py +++ b/tests/test_buffered_channel.py @@ -166,7 +166,7 @@ def server_fn(): client_bufchan.close() client.close() if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, server_coro.get()) + assert_raises(zerorpc.LostRemote, server_coro.get) else: with assert_raises(zerorpc.LostRemote): server_coro.get() @@ -393,7 +393,7 @@ def test_congestion_control_server_pushing(): client_events.connect(endpoint) client = zerorpc.ChannelMultiplexer(client_events, ignore_broadcast=True) - read_cnt = 0 + read_cnt = type('Dummy', (object,), { "value": 0 }) def client_do(): client_channel = client.channel() @@ -403,8 +403,7 @@ def client_do(): event = client_bufchan.recv() assert event.name == 'coucou' assert event.args == x - global read_cnt - read_cnt += 1 + read_cnt.value += 1 client_bufchan.close() coro_pool = gevent.pool.Pool() @@ -434,7 +433,7 @@ def _do_with_assert_raises(): with assert_raises(zerorpc.TimeoutExpired): for x in xrange(2, 200): server_bufchan.emit('coucou', x, timeout=0) # will fail when x == 100 - for x in xrange(read_cnt, 200): + for x in xrange(read_cnt.value, 200): server_bufchan.emit('coucou', x) # block until receiver is ready server_bufchan.close() diff --git a/zerorpc/events.py b/zerorpc/events.py index ae82fb1..f009505 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -30,6 +30,7 @@ import gevent.local import gevent.lock import logging +import sys import gevent_zmq as zmq from .exceptions import TimeoutExpired @@ -37,6 +38,14 @@ from .channel_base import ChannelBase +if sys.version_info < (2, 7): + def get_pyzmq_frame_buffer(frame): + return frame.buffer[:] +else: + def get_pyzmq_frame_buffer(frame): + return frame.buffer + + class SequentialSender(object): def __init__(self, socket): @@ -329,7 +338,7 @@ def recv(self, timeout=None): else: identity = None blob = parts[0] - event = Event.unpack(blob) + event = Event.unpack(get_pyzmq_frame_buffer(blob)) event.identity = identity if self._debug: logging.debug('<-- %s', event) From 75df686a2c0d94fd164bb796708a866d2b43ddd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Fri, 11 Sep 2015 19:04:26 -0700 Subject: [PATCH 03/51] Switch to travis' new infrastructure. + update pyzmq matrix --- .travis.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index dec8728..84bace9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ python: - 2.7 env: matrix: + - PYZMQ='pyzmq>=14' - PYZMQ='pyzmq>=14.3' - PYZMQ='pyzmq>=14.2,<14.3' - PYZMQ='pyzmq>=14.1,<14.2' @@ -11,12 +12,15 @@ env: - PYZMQ='pyzmq<14' matrix: fast_finish: true -script: +script: - flake8 --ignore=E501,E128 zerorpc bin - - ZPC_TEST_TIME_FACTOR=0.1 nosetests -before_install: - - sudo apt-get update - - sudo apt-get install python-dev libevent-dev + - ZPC_TEST_TIME_FACTOR=0.2 nosetests -v +sudo: false +addons: + apt: + packages: + - python-dev + - libevent-dev install: - pip install flake8 - "pip install nose gevent msgpack-python $PYZMQ" From 6a583808c08590f5fd0e21bf5aa5b66d54df5708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Fri, 11 Sep 2015 22:42:26 -0700 Subject: [PATCH 04/51] bump version to v0.5.2 --- zerorpc/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zerorpc/version.py b/zerorpc/version.py index 3208b41..00742c9 100644 --- a/zerorpc/version.py +++ b/zerorpc/version.py @@ -23,7 +23,7 @@ # SOFTWARE. __title__ = 'zerorpc' -__version__ = '0.5.1' +__version__ = '0.5.2' __author__ = 'François-Xavier Bourlet .' __license__ = 'MIT' __copyright__ = 'Copyright 2015 François-Xavier Bourlet .' From da8815cbd8209961783c41b15ce44e9bddf0d267 Mon Sep 17 00:00:00 2001 From: Bartosz Date: Thu, 17 Sep 2015 14:13:18 +0200 Subject: [PATCH 05/51] Fix loggers names. --- zerorpc/channel.py | 9 ++++----- zerorpc/events.py | 15 +++++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/zerorpc/channel.py b/zerorpc/channel.py index 7a43f7a..59ecb15 100644 --- a/zerorpc/channel.py +++ b/zerorpc/channel.py @@ -32,9 +32,8 @@ from .exceptions import TimeoutExpired from .channel_base import ChannelBase -from logging import getLogger -logger = getLogger(__name__) +logger = logging.getLogger(__name__) class ChannelMultiplexer(ChannelBase): @@ -123,7 +122,7 @@ def __init__(self, multiplexer, from_event=None): self._channel_id = from_event.header['message_id'] self._zmqid = from_event.identity self._multiplexer._active_channels[self._channel_id] = self - logging.debug('<-- new channel %s', self._channel_id) + logger.debug('<-- new channel %s', self._channel_id) self._queue.put(from_event) @property @@ -137,7 +136,7 @@ def emit_is_supported(self): def close(self): if self._channel_id is not None: del self._multiplexer._active_channels[self._channel_id] - logging.debug('-x- closed channel %s', self._channel_id) + logger.debug('-x- closed channel %s', self._channel_id) self._channel_id = None def new_event(self, name, args, xheader=None): @@ -145,7 +144,7 @@ def new_event(self, name, args, xheader=None): if self._channel_id is None: self._channel_id = event.header['message_id'] self._multiplexer._active_channels[self._channel_id] = self - logging.debug('--> new channel %s', self._channel_id) + logger.debug('--> new channel %s', self._channel_id) else: event.header['response_to'] = self._channel_id event.identity = self._zmqid diff --git a/zerorpc/events.py b/zerorpc/events.py index f009505..8bc9723 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -46,6 +46,9 @@ def get_pyzmq_frame_buffer(frame): return frame.buffer +logger = logging.getLogger(__name__) + + class SequentialSender(object): def __init__(self, socket): @@ -281,9 +284,9 @@ def debug(self, v): if v != self._debug: self._debug = v if self._debug: - logging.debug('debug enabled') + logger.debug('debug enabled') else: - logging.debug('debug disabled') + logger.debug('debug disabled') def _resolve_endpoint(self, endpoint, resolve=True): if resolve: @@ -299,14 +302,14 @@ def connect(self, endpoint, resolve=True): r = [] for endpoint_ in self._resolve_endpoint(endpoint, resolve): r.append(self._socket.connect(endpoint_)) - logging.debug('connected to %s (status=%s)', endpoint_, r[-1]) + logger.debug('connected to %s (status=%s)', endpoint_, r[-1]) return r def bind(self, endpoint, resolve=True): r = [] for endpoint_ in self._resolve_endpoint(endpoint, resolve): r.append(self._socket.bind(endpoint_)) - logging.debug('bound to %s (status=%s)', endpoint_, r[-1]) + logger.debug('bound to %s (status=%s)', endpoint_, r[-1]) return r def new_event(self, name, args, xheader=None): @@ -317,7 +320,7 @@ def new_event(self, name, args, xheader=None): def emit_event(self, event, timeout=None): if self._debug: - logging.debug('--> %s', event) + logger.debug('--> %s', event) if event.identity: parts = list(event.identity or list()) parts.extend(['', event.pack()]) @@ -341,7 +344,7 @@ def recv(self, timeout=None): event = Event.unpack(get_pyzmq_frame_buffer(blob)) event.identity = identity if self._debug: - logging.debug('<-- %s', event) + logger.debug('<-- %s', event) return event def setsockopt(self, *args): From 6ca6fdf598905ca67f2678973034dae435a28594 Mon Sep 17 00:00:00 2001 From: Wang Yanqing Date: Sat, 26 Sep 2015 22:55:04 +0800 Subject: [PATCH 06/51] Update msgpack protocol to msgpack 2.0(msgpack-python>=0.4.0) Add use_bin_type to msgpack Packer and set utf-8 encoding for msgpack Unpacker. --- setup.py | 2 +- zerorpc/events.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 1a22102..80846d5 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ requirements = [ 'gevent>=1.0', - 'msgpack-python', + 'msgpack-python>=0.4.0', 'pyzmq>=13.1.0' ] if sys.version_info < (2, 7): diff --git a/zerorpc/events.py b/zerorpc/events.py index f009505..44a2fdb 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -189,11 +189,11 @@ def identity(self, v): self._identity = v def pack(self): - return msgpack.Packer().pack((self._header, self._name, self._args)) + return msgpack.Packer(use_bin_type=True).pack((self._header, self._name, self._args)) @staticmethod def unpack(blob): - unpacker = msgpack.Unpacker() + unpacker = msgpack.Unpacker(encoding='utf-8') unpacker.feed(blob) unpacked_msg = unpacker.unpack() From ab69b94e6a865a5f31291dc59719c69e85ec1348 Mon Sep 17 00:00:00 2001 From: Wang Yanqing Date: Sat, 26 Sep 2015 23:25:28 +0800 Subject: [PATCH 07/51] add unittest for msgpack string type --- tests/test_events.py | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/test_events.py b/tests/test_events.py index e3d1616..224a41c 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -169,3 +169,59 @@ def test_events_push_pull(): print event assert event.name == 'myevent' assert list(event.args) == [x] + + +def test_msgpack(): + context = zerorpc.Context() + event = zerorpc.Event('myevent', ('a',), context=context) + print event + assert type(event.name) == str + for key in event.header.keys(): + assert type(key) == str + assert type(event.header['message_id']) == str + assert type(event.args[0]) == str + + packed = event.pack() + event = event.unpack(packed) + print event + assert type(event.name) == str + for key in event.header.keys(): + assert type(key) == str + assert type(event.header['message_id']) == str + assert type(event.args[0]) == str + + event = zerorpc.Event('myevent', (u'a',), context=context) + print event + assert type(event.name) == str + for key in event.header.keys(): + assert type(key) == str + assert type(event.header['message_id']) == str + assert type(event.args[0]) == unicode + + packed = event.pack() + event = event.unpack(packed) + print event + assert type(event.name) == str + for key in event.header.keys(): + assert type(key) == str + assert type(event.header['message_id']) == str + assert type(event.args[0]) == unicode + + event = zerorpc.Event('myevent', (u'a', 'b'), context=context) + print event + assert type(event.name) == str + for key in event.header.keys(): + assert type(key) == str + assert type(event.header['message_id']) == str + assert type(event.args[0]) == unicode + assert type(event.args[1]) == str + + packed = event.pack() + event = event.unpack(packed) + print event + assert type(event.name) == str + for key in event.header.keys(): + assert type(key) == str + assert type(event.header['message_id']) == str + assert type(event.args[0]) == unicode + assert type(event.args[1]) == str From 7fffc42321aa2c25f922d58b55c0fb8463fe0ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowak?= Date: Wed, 24 Feb 2016 17:41:42 +0100 Subject: [PATCH 08/51] Added TypeError to events.Events __del__ On interpreter shutdown you may hit TypeError("'NoneType' object is not callable",) --- zerorpc/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zerorpc/events.py b/zerorpc/events.py index 615426a..9c95709 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -261,7 +261,7 @@ def __del__(self): try: if not self._socket.closed: self.close() - except AttributeError: + except (AttributeError, TypeError): pass def close(self): From e36bcccee65813f6291045ae0b764665c178853a Mon Sep 17 00:00:00 2001 From: Wang Yanqing Date: Thu, 3 Mar 2016 14:57:41 +0800 Subject: [PATCH 09/51] Add disconnct option for zrpc socket --- zerorpc/events.py | 7 +++++++ zerorpc/socket.py | 3 +++ 2 files changed, 10 insertions(+) diff --git a/zerorpc/events.py b/zerorpc/events.py index 44a2fdb..7c289e3 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -309,6 +309,13 @@ def bind(self, endpoint, resolve=True): logging.debug('bound to %s (status=%s)', endpoint_, r[-1]) return r + def disconnect(self, endpoint, resolve=True): + r = [] + for endpoint_ in self._resolve_endpoint(endpoint, resolve): + r.append(self._socket.disconnect(endpoint_)) + logging.debug('disconnected from %s (status=%s)', endpoint_, r[-1]) + return r + def new_event(self, name, args, xheader=None): event = Event(name, args, context=self._context) if xheader: diff --git a/zerorpc/socket.py b/zerorpc/socket.py index 51f99c2..35cb7e4 100644 --- a/zerorpc/socket.py +++ b/zerorpc/socket.py @@ -42,6 +42,9 @@ def connect(self, endpoint, resolve=True): def bind(self, endpoint, resolve=True): return self._events.bind(endpoint, resolve) + def disconnect(self, endpoint, resolve=True): + return self._events.disconnect(endpoint, resolve) + @property def debug(self): return self._events.debug From 0e98746bd01b8aedf8f12af5e0f898dc9124bb83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 20 Mar 2016 19:33:03 -0700 Subject: [PATCH 10/51] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 1210822..e1cd19f 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ zerorpc ======= -.. image:: https://secure.travis-ci.org/0rpc/zerorpc-python.png +.. image:: https://secure.travis-ci.org/0rpc/zerorpc-python.png?branch=master :target: http://travis-ci.org/0rpc/zerorpc-python Mailing list: zerorpc@googlegroups.com (https://groups.google.com/d/forum/zerorpc) From a032789794bb25cacab6c696f9e230dd47ddfb45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 20 Mar 2016 16:29:00 -0700 Subject: [PATCH 11/51] Flake8 configuration in tox.ini Flake8 will read the config from tox.ini by itself. --- tox.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tox.ini b/tox.ini index 6f68c02..b56bac5 100644 --- a/tox.ini +++ b/tox.ini @@ -8,3 +8,8 @@ deps = commands = flake8 --ignore=E501,E128 zerorpc bin nosetests + +[flake8] +ignore = E501,E128 +filename = *.py,zerorpc +exclude = tests,.git,dist,doc,*.egg-info,__pycache__,setup.py From b02121218b948433924ab624ae2feb2c07db8100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 20 Mar 2016 16:29:23 -0700 Subject: [PATCH 12/51] Few tags for pypi. --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index 80846d5..8192082 100644 --- a/setup.py +++ b/setup.py @@ -62,5 +62,8 @@ 'Natural Language :: English', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.4', ), ) From 916f84dcdaa8c3d01b724813cdfe09e6020f2bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 20 Mar 2016 20:54:05 -0700 Subject: [PATCH 13/51] Keepy flake8 happy. --- bin/zerorpc | 2 +- zerorpc/cli.py | 2 +- zerorpc/core.py | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bin/zerorpc b/bin/zerorpc index f0e1172..c9d31d3 100755 --- a/bin/zerorpc +++ b/bin/zerorpc @@ -27,7 +27,7 @@ import os import sys sys.path.append(os.path.dirname(os.path.dirname(sys.argv[0]))) -from zerorpc import cli +from zerorpc import cli # NOQA if __name__ == "__main__": exit(cli.main()) diff --git a/zerorpc/cli.py b/zerorpc/cli.py index 1766b08..691e861 100644 --- a/zerorpc/cli.py +++ b/zerorpc/cli.py @@ -222,7 +222,7 @@ def zerorpc_inspect(client, method=None, long_doc=True, include_argspec=True): if not isinstance(remote_methods, dict): (longest_name_len, detailled_methods) = zerorpc_inspect_python_argspecs( - remote_methods, method, long_doc, include_argspec) + remote_methods, method, long_doc, include_argspec) (longest_name_len, detailled_methods) = zerorpc_inspect_generic( remote_methods, method, long_doc, include_argspec) diff --git a/zerorpc/core.py b/zerorpc/core.py index 0bd820c..31921d8 100644 --- a/zerorpc/core.py +++ b/zerorpc/core.py @@ -73,9 +73,8 @@ def _filter_methods(cls, self, methods): server_methods = set(k for k in dir(cls) if not k.startswith('_')) return dict((k, getattr(methods, k)) for k in dir(methods) - if callable(getattr(methods, k)) - and not k.startswith('_') - and k not in server_methods + if callable(getattr(methods, k)) and + not k.startswith('_') and k not in server_methods ) @staticmethod From bd9e6b05a16e414717bb0593391e458fd52d1f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 20 Mar 2016 22:08:01 -0700 Subject: [PATCH 14/51] Update README.rst --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index e1cd19f..d2b2965 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,8 @@ zerorpc ======= -.. image:: https://secure.travis-ci.org/0rpc/zerorpc-python.png?branch=master - :target: http://travis-ci.org/0rpc/zerorpc-python +.. image:: https://travis-ci.org/0rpc/zerorpc-python.svg?branch=master + :target: https://travis-ci.org/0rpc/zerorpc-python Mailing list: zerorpc@googlegroups.com (https://groups.google.com/d/forum/zerorpc) From 468659b72de6e95a60fc1dbf14472ffd8e4ca43f Mon Sep 17 00:00:00 2001 From: Nick Allen Date: Tue, 31 May 2016 16:48:26 -0400 Subject: [PATCH 15/51] Fix reference to root logger instead of namespaced logger --- zerorpc/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zerorpc/events.py b/zerorpc/events.py index 5612ff9..9ab9e67 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -316,7 +316,7 @@ def disconnect(self, endpoint, resolve=True): r = [] for endpoint_ in self._resolve_endpoint(endpoint, resolve): r.append(self._socket.disconnect(endpoint_)) - logging.debug('disconnected from %s (status=%s)', endpoint_, r[-1]) + logger.debug('disconnected from %s (status=%s)', endpoint_, r[-1]) return r def new_event(self, name, args, xheader=None): From 6d375b9213ff5cfebdea2be774ab180c1450adcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 28 Feb 2016 20:55:49 -0800 Subject: [PATCH 16/51] Python3 dependencies --- .travis.yml | 1 + setup.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 84bace9..fc548af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: python python: - 2.6 - 2.7 + - 3.4 env: matrix: - PYZMQ='pyzmq>=14' diff --git a/setup.py b/setup.py index 8192082..b68b42e 100644 --- a/setup.py +++ b/setup.py @@ -35,13 +35,19 @@ requirements = [ - 'gevent>=1.0', 'msgpack-python>=0.4.0', - 'pyzmq>=13.1.0' + 'pyzmq>=13.1.0', + 'future', ] + if sys.version_info < (2, 7): requirements.append('argparse') +if sys.version_info < (3, 0): + requirements.append('gevent>=1.0') +else: + requirements.append('gevent>=1.1rc5') + setup( name='zerorpc', From 72e268dd8c5564e445aa59145b8adfdf3d9f31e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Mon, 29 Feb 2016 00:43:56 -0800 Subject: [PATCH 17/51] Conversion to >=Python3.4 Code is now using the python 3 syntax , but thanks to "future" and "builtins", it is compatible with 2.6 and 2.7. Hopefully everything was done carefully enough to not impair performances on python 2. Note: Code is not functional and tests are not passing yet. A throughout review of str, bytes and unicode strings is still necessary. --- tests/test_buffered_channel.py | 56 ++++++++++--------- tests/test_channel.py | 16 ++++-- tests/test_client.py | 3 +- tests/test_client_async.py | 8 ++- tests/test_client_heartbeat.py | 33 ++++++----- tests/test_events.py | 64 ++++++++++++---------- tests/test_heartbeat.py | 44 ++++++++------- tests/test_middleware.py | 58 +++++++++++--------- tests/test_middleware_before_after_exec.py | 7 ++- tests/test_middleware_client.py | 7 ++- tests/test_pubpush.py | 26 +++++---- tests/test_reqstream.py | 14 +++-- tests/test_server.py | 36 ++++++------ tests/test_zmq.py | 16 +++--- tests/testutils.py | 7 ++- tests/zmqbug.py | 16 +++--- zerorpc/channel.py | 2 +- zerorpc/cli.py | 22 +++++--- zerorpc/context.py | 7 ++- zerorpc/core.py | 15 +++-- zerorpc/events.py | 8 ++- zerorpc/gevent_zmq.py | 6 +- zerorpc/patterns.py | 4 +- 23 files changed, 273 insertions(+), 202 deletions(-) diff --git a/tests/test_buffered_channel.py b/tests/test_buffered_channel.py index 47c6578..76d0fe3 100644 --- a/tests/test_buffered_channel.py +++ b/tests/test_buffered_channel.py @@ -23,13 +23,17 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import +from builtins import range + from nose.tools import assert_raises import gevent import sys from zerorpc import zmq import zerorpc -from testutils import teardown, random_ipc_endpoint, TIME_FACTOR +from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR def test_close_server_bufchan(): @@ -54,14 +58,14 @@ def test_close_server_bufchan(): server_bufchan.recv() gevent.sleep(TIME_FACTOR * 3) - print 'CLOSE SERVER SOCKET!!!' + print('CLOSE SERVER SOCKET!!!') server_bufchan.close() if sys.version_info < (2, 7): assert_raises(zerorpc.LostRemote, client_bufchan.recv) else: with assert_raises(zerorpc.LostRemote): client_bufchan.recv() - print 'CLIENT LOST SERVER :)' + print('CLIENT LOST SERVER :)') client_bufchan.close() server.close() client.close() @@ -89,14 +93,14 @@ def test_close_client_bufchan(): server_bufchan.recv() gevent.sleep(TIME_FACTOR * 3) - print 'CLOSE CLIENT SOCKET!!!' + print('CLOSE CLIENT SOCKET!!!') client_bufchan.close() if sys.version_info < (2, 7): assert_raises(zerorpc.LostRemote, client_bufchan.recv) else: with assert_raises(zerorpc.LostRemote): client_bufchan.recv() - print 'SERVER LOST CLIENT :)' + print('SERVER LOST CLIENT :)') server_bufchan.close() server.close() client.close() @@ -122,14 +126,14 @@ def test_heartbeat_can_open_channel_server_close(): server_bufchan = zerorpc.BufferedChannel(server_hbchan) gevent.sleep(TIME_FACTOR * 3) - print 'CLOSE SERVER SOCKET!!!' + print('CLOSE SERVER SOCKET!!!') server_bufchan.close() if sys.version_info < (2, 7): assert_raises(zerorpc.LostRemote, client_bufchan.recv) else: with assert_raises(zerorpc.LostRemote): client_bufchan.recv() - print 'CLIENT LOST SERVER :)' + print('CLIENT LOST SERVER :)') client_bufchan.close() server.close() client.close() @@ -162,7 +166,7 @@ def server_fn(): server_coro = gevent.spawn(server_fn) gevent.sleep(TIME_FACTOR * 3) - print 'CLOSE CLIENT SOCKET!!!' + print('CLOSE CLIENT SOCKET!!!') client_bufchan.close() client.close() if sys.version_info < (2, 7): @@ -170,7 +174,7 @@ def server_fn(): else: with assert_raises(zerorpc.LostRemote): server_coro.get() - print 'SERVER LOST CLIENT :)' + print('SERVER LOST CLIENT :)') server.close() @@ -189,7 +193,7 @@ def client_do(): client_channel = client.channel() client_hbchan = zerorpc.HeartBeatOnChannel(client_channel, freq=TIME_FACTOR * 2) client_bufchan = zerorpc.BufferedChannel(client_hbchan) - for x in xrange(20): + for x in range(20): client_bufchan.emit('add', (x, x * x)) event = client_bufchan.recv() assert event.name == 'OK' @@ -205,7 +209,7 @@ def server_do(): server_hbchan = zerorpc.HeartBeatOnChannel(server_channel, freq=TIME_FACTOR * 2) server_bufchan = zerorpc.BufferedChannel(server_hbchan) - for x in xrange(20): + for x in range(20): event = server_bufchan.recv() assert event.name == 'add' server_bufchan.emit('OK', (sum(event.args),)) @@ -229,11 +233,11 @@ def test_do_some_req_rep_lost_server(): client = zerorpc.ChannelMultiplexer(client_events, ignore_broadcast=True) def client_do(): - print 'running' + print('running') client_channel = client.channel() client_hbchan = zerorpc.HeartBeatOnChannel(client_channel, freq=TIME_FACTOR * 2) client_bufchan = zerorpc.BufferedChannel(client_hbchan) - for x in xrange(10): + for x in range(10): client_bufchan.emit('add', (x, x * x)) event = client_bufchan.recv() assert event.name == 'OK' @@ -254,7 +258,7 @@ def server_do(): server_channel = server.channel(event) server_hbchan = zerorpc.HeartBeatOnChannel(server_channel, freq=TIME_FACTOR * 2) server_bufchan = zerorpc.BufferedChannel(server_hbchan) - for x in xrange(10): + for x in range(10): event = server_bufchan.recv() assert event.name == 'add' server_bufchan.emit('OK', (sum(event.args),)) @@ -282,7 +286,7 @@ def client_do(): client_hbchan = zerorpc.HeartBeatOnChannel(client_channel, freq=TIME_FACTOR * 2) client_bufchan = zerorpc.BufferedChannel(client_hbchan) - for x in xrange(10): + for x in range(10): client_bufchan.emit('add', (x, x * x)) event = client_bufchan.recv() assert event.name == 'OK' @@ -298,7 +302,7 @@ def server_do(): server_hbchan = zerorpc.HeartBeatOnChannel(server_channel, freq=TIME_FACTOR * 2) server_bufchan = zerorpc.BufferedChannel(server_hbchan) - for x in xrange(10): + for x in range(10): event = server_bufchan.recv() assert event.name == 'add' server_bufchan.emit('OK', (sum(event.args),)) @@ -334,7 +338,7 @@ def client_do(): if sys.version_info < (2, 7): def _do_with_assert_raises(): - for x in xrange(10): + for x in range(10): client_bufchan.emit('sleep', (x,)) event = client_bufchan.recv(timeout=TIME_FACTOR * 3) assert event.name == 'OK' @@ -342,7 +346,7 @@ def _do_with_assert_raises(): assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: with assert_raises(zerorpc.TimeoutExpired): - for x in xrange(10): + for x in range(10): client_bufchan.emit('sleep', (x,)) event = client_bufchan.recv(timeout=TIME_FACTOR * 3) assert event.name == 'OK' @@ -360,7 +364,7 @@ def server_do(): if sys.version_info < (2, 7): def _do_with_assert_raises(): - for x in xrange(20): + for x in range(20): event = server_bufchan.recv() assert event.name == 'sleep' gevent.sleep(TIME_FACTOR * event.args[0]) @@ -368,7 +372,7 @@ def _do_with_assert_raises(): assert_raises(zerorpc.LostRemote, _do_with_assert_raises) else: with assert_raises(zerorpc.LostRemote): - for x in xrange(20): + for x in range(20): event = server_bufchan.recv() assert event.name == 'sleep' gevent.sleep(TIME_FACTOR * event.args[0]) @@ -399,7 +403,7 @@ def client_do(): client_channel = client.channel() client_hbchan = zerorpc.HeartBeatOnChannel(client_channel, freq=TIME_FACTOR * 2) client_bufchan = zerorpc.BufferedChannel(client_hbchan, inqueue_size=100) - for x in xrange(200): + for x in range(200): event = client_bufchan.recv() assert event.name == 'coucou' assert event.args == x @@ -416,24 +420,24 @@ def server_do(): server_bufchan = zerorpc.BufferedChannel(server_hbchan, inqueue_size=100) if sys.version_info < (2, 7): def _do_with_assert_raises(): - for x in xrange(200): + for x in range(200): server_bufchan.emit('coucou', x, timeout=0) # will fail when x == 1 assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: with assert_raises(zerorpc.TimeoutExpired): - for x in xrange(200): + for x in range(200): server_bufchan.emit('coucou', x, timeout=0) # will fail when x == 1 server_bufchan.emit('coucou', 1) # block until receiver is ready if sys.version_info < (2, 7): def _do_with_assert_raises(): - for x in xrange(2, 200): + for x in range(2, 200): server_bufchan.emit('coucou', x, timeout=0) # will fail when x == 100 assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: with assert_raises(zerorpc.TimeoutExpired): - for x in xrange(2, 200): + for x in range(2, 200): server_bufchan.emit('coucou', x, timeout=0) # will fail when x == 100 - for x in xrange(read_cnt.value, 200): + for x in range(read_cnt.value, 200): server_bufchan.emit('coucou', x) # block until receiver is ready server_bufchan.close() diff --git a/tests/test_channel.py b/tests/test_channel.py index 18d2d8d..6a85036 100644 --- a/tests/test_channel.py +++ b/tests/test_channel.py @@ -23,9 +23,13 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import +from builtins import range + from zerorpc import zmq import zerorpc -from testutils import teardown, random_ipc_endpoint +from .testutils import teardown, random_ipc_endpoint def test_events_channel_client_side(): @@ -42,7 +46,7 @@ def test_events_channel_client_side(): client_channel.emit('someevent', (42,)) event = server.recv() - print event + print(event) assert list(event.args) == [42] assert event.identity is not None @@ -68,16 +72,16 @@ def test_events_channel_client_side_server_send_many(): client_channel.emit('giveme', (10,)) event = server.recv() - print event + print(event) assert list(event.args) == [10] assert event.identity is not None - for x in xrange(10): + for x in range(10): reply_event = server.new_event('someanswer', (x,), xheader=dict(response_to=event.header['message_id'])) reply_event.identity = event.identity server.emit_event(reply_event) - for x in xrange(10): + for x in range(10): event = client_channel.recv() assert list(event.args) == [x] @@ -96,7 +100,7 @@ def test_events_channel_both_side(): client_channel.emit('openthat', (42,)) event = server.recv() - print event + print(event) assert list(event.args) == [42] assert event.name == 'openthat' diff --git a/tests/test_client.py b/tests/test_client.py index 7a954ba..6a692b3 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,10 +23,11 @@ # SOFTWARE. +from __future__ import absolute_import import gevent import zerorpc -from testutils import teardown, random_ipc_endpoint +from .testutils import teardown, random_ipc_endpoint def test_client_connect(): endpoint = random_ipc_endpoint() diff --git a/tests/test_client_async.py b/tests/test_client_async.py index 93645fe..3acbd3b 100644 --- a/tests/test_client_async.py +++ b/tests/test_client_async.py @@ -23,13 +23,15 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import from nose.tools import assert_raises import gevent import sys from zerorpc import zmq import zerorpc -from testutils import teardown, random_ipc_endpoint, TIME_FACTOR +from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR def test_client_server_client_timeout_with_async(): @@ -55,11 +57,11 @@ def add(self, a, b): if sys.version_info < (2, 7): def _do_with_assert_raises(): - print async_result.get() + print(async_result.get()) assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: with assert_raises(zerorpc.TimeoutExpired): - print async_result.get() + print(async_result.get()) client.close() srv.close() diff --git a/tests/test_client_heartbeat.py b/tests/test_client_heartbeat.py index 1d2936a..6b552a4 100644 --- a/tests/test_client_heartbeat.py +++ b/tests/test_client_heartbeat.py @@ -23,10 +23,15 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import +from builtins import next +from builtins import range + import gevent import zerorpc -from testutils import teardown, random_ipc_endpoint, TIME_FACTOR +from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR def test_client_server_hearbeat(): @@ -48,7 +53,7 @@ def slow(self): client.connect(endpoint) assert client.lolita() == 42 - print 'GOT ANSWER' + print('GOT ANSWER') def test_client_server_activate_heartbeat(): @@ -69,7 +74,7 @@ def lolita(self): client.connect(endpoint) assert client.lolita() == 42 - print 'GOT ANSWER' + print('GOT ANSWER') def test_client_server_passive_hearbeat(): @@ -93,7 +98,7 @@ def slow(self): client.connect(endpoint) assert client.slow() == 2 - print 'GOT ANSWER' + print('GOT ANSWER') def test_client_hb_doesnt_linger_on_streaming(): @@ -103,7 +108,7 @@ class MySrv(zerorpc.Server): @zerorpc.stream def iter(self): - return xrange(42) + return range(42) srv = MySrv(heartbeat=TIME_FACTOR * 1, context=zerorpc.Context()) srv.bind(endpoint) @@ -112,8 +117,8 @@ def iter(self): client1 = zerorpc.Client(endpoint, heartbeat=TIME_FACTOR * 1, context=zerorpc.Context()) def test_client(): - assert list(client1.iter()) == list(xrange(42)) - print 'sleep 3s' + assert list(client1.iter()) == list(range(42)) + print('sleep 3s') gevent.sleep(TIME_FACTOR * 3) gevent.spawn(test_client).join() @@ -158,10 +163,10 @@ def iter(self): client1 = zerorpc.Client(endpoint, heartbeat=TIME_FACTOR * 1, context=zerorpc.Context()) def test_client(): - print 'grab iter' + print('grab iter') i = client1.iter() - print 'sleep 3s' + print('sleep 3s') gevent.sleep(TIME_FACTOR * 3) gevent.spawn(test_client).join() @@ -174,7 +179,7 @@ class MySrv(zerorpc.Server): @zerorpc.stream def iter(self): - return xrange(500) + return range(500) srv = MySrv(heartbeat=TIME_FACTOR * 1, context=zerorpc.Context()) srv.bind(endpoint) @@ -183,13 +188,13 @@ def iter(self): client1 = zerorpc.Client(endpoint, heartbeat=TIME_FACTOR * 1, context=zerorpc.Context()) def test_client(): - print 'grab iter' + print('grab iter') i = client1.iter() - print 'consume some' - assert list(next(i) for x in xrange(142)) == list(xrange(142)) + print('consume some') + assert list(next(i) for x in range(142)) == list(range(142)) - print 'sleep 3s' + print('sleep 3s') gevent.sleep(TIME_FACTOR * 3) gevent.spawn(test_client).join() diff --git a/tests/test_events.py b/tests/test_events.py index 224a41c..91a116b 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -23,11 +23,17 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import +from builtins import str +from builtins import range +from builtins import object + from zerorpc import zmq import zerorpc -from testutils import teardown, random_ipc_endpoint +from .testutils import teardown, random_ipc_endpoint -class MokupContext(): +class MokupContext(object): _next_id = 0 def new_msgid(self): @@ -44,32 +50,32 @@ def test_context(): def test_event(): context = MokupContext() event = zerorpc.Event('mylittleevent', (None,), context=context) - print event + print(event) assert event.name == 'mylittleevent' assert event.header['message_id'] == 0 assert event.args == (None,) event = zerorpc.Event('mylittleevent2', ('42',), context=context) - print event + print(event) assert event.name == 'mylittleevent2' assert event.header['message_id'] == 1 assert event.args == ('42',) event = zerorpc.Event('mylittleevent3', ('a', 42), context=context) - print event + print(event) assert event.name == 'mylittleevent3' assert event.header['message_id'] == 2 assert event.args == ('a', 42) event = zerorpc.Event('mylittleevent4', ('b', 21), context=context) - print event + print(event) assert event.name == 'mylittleevent4' assert event.header['message_id'] == 3 assert event.args == ('b', 21) packed = event.pack() unpacked = zerorpc.Event.unpack(packed) - print unpacked + print(unpacked) assert unpacked.name == 'mylittleevent4' assert unpacked.header['message_id'] == 3 @@ -77,13 +83,13 @@ def test_event(): event = zerorpc.Event('mylittleevent5', ('c', 24, True), header={'lol': 'rofl'}, context=None) - print event + print(event) assert event.name == 'mylittleevent5' assert event.header['lol'] == 'rofl' assert event.args == ('c', 24, True) event = zerorpc.Event('mod', (42,), context=context) - print event + print(event) assert event.name == 'mod' assert event.header['message_id'] == 4 assert event.args == (42,) @@ -102,7 +108,7 @@ def test_events_req_rep(): client.emit('myevent', ('arg1',)) event = server.recv() - print event + print(event) assert event.name == 'myevent' assert list(event.args) == ['arg1'] @@ -115,16 +121,16 @@ def test_events_req_rep2(): client = zerorpc.Events(zmq.REQ) client.connect(endpoint) - for i in xrange(10): + for i in range(10): client.emit('myevent' + str(i), (i,)) event = server.recv() - print event + print(event) assert event.name == 'myevent' + str(i) assert list(event.args) == [i] server.emit('answser' + str(i * 2), (i * 2,)) event = client.recv() - print event + print(event) assert event.name == 'answser' + str(i * 2) assert list(event.args) == [i * 2] @@ -137,10 +143,10 @@ def test_events_dealer_router(): client = zerorpc.Events(zmq.DEALER) client.connect(endpoint) - for i in xrange(6): + for i in range(6): client.emit('myevent' + str(i), (i,)) event = server.recv() - print event + print(event) assert event.name == 'myevent' + str(i) assert list(event.args) == [i] @@ -148,7 +154,7 @@ def test_events_dealer_router(): reply_event.identity = event.identity server.emit_event(reply_event) event = client.recv() - print event + print(event) assert event.name == 'answser' + str(i * 2) assert list(event.args) == [i * 2] @@ -161,12 +167,12 @@ def test_events_push_pull(): client = zerorpc.Events(zmq.PUSH) client.connect(endpoint) - for x in xrange(10): + for x in range(10): client.emit('myevent', (x,)) - for x in xrange(10): + for x in range(10): event = server.recv() - print event + print(event) assert event.name == 'myevent' assert list(event.args) == [x] @@ -174,7 +180,7 @@ def test_events_push_pull(): def test_msgpack(): context = zerorpc.Context() event = zerorpc.Event('myevent', ('a',), context=context) - print event + print(event) assert type(event.name) == str for key in event.header.keys(): assert type(key) == str @@ -183,7 +189,7 @@ def test_msgpack(): packed = event.pack() event = event.unpack(packed) - print event + print(event) assert type(event.name) == str for key in event.header.keys(): assert type(key) == str @@ -191,37 +197,37 @@ def test_msgpack(): assert type(event.args[0]) == str event = zerorpc.Event('myevent', (u'a',), context=context) - print event + print(event) assert type(event.name) == str for key in event.header.keys(): assert type(key) == str assert type(event.header['message_id']) == str - assert type(event.args[0]) == unicode + assert type(event.args[0]) == str packed = event.pack() event = event.unpack(packed) - print event + print(event) assert type(event.name) == str for key in event.header.keys(): assert type(key) == str assert type(event.header['message_id']) == str - assert type(event.args[0]) == unicode + assert type(event.args[0]) == str event = zerorpc.Event('myevent', (u'a', 'b'), context=context) - print event + print(event) assert type(event.name) == str for key in event.header.keys(): assert type(key) == str assert type(event.header['message_id']) == str - assert type(event.args[0]) == unicode + assert type(event.args[0]) == str assert type(event.args[1]) == str packed = event.pack() event = event.unpack(packed) - print event + print(event) assert type(event.name) == str for key in event.header.keys(): assert type(key) == str assert type(event.header['message_id']) == str - assert type(event.args[0]) == unicode + assert type(event.args[0]) == str assert type(event.args[1]) == str diff --git a/tests/test_heartbeat.py b/tests/test_heartbeat.py index 0eee2b5..75b1d29 100644 --- a/tests/test_heartbeat.py +++ b/tests/test_heartbeat.py @@ -23,13 +23,17 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import +from builtins import range + from nose.tools import assert_raises import gevent import sys from zerorpc import zmq import zerorpc -from testutils import teardown, random_ipc_endpoint, TIME_FACTOR +from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR def test_close_server_hbchan(): @@ -52,14 +56,14 @@ def test_close_server_hbchan(): server_hbchan.recv() gevent.sleep(TIME_FACTOR * 3) - print 'CLOSE SERVER SOCKET!!!' + print('CLOSE SERVER SOCKET!!!') server_hbchan.close() if sys.version_info < (2, 7): assert_raises(zerorpc.LostRemote, client_hbchan.recv) else: with assert_raises(zerorpc.LostRemote): client_hbchan.recv() - print 'CLIENT LOST SERVER :)' + print('CLIENT LOST SERVER :)') client_hbchan.close() server.close() client.close() @@ -85,14 +89,14 @@ def test_close_client_hbchan(): server_hbchan.recv() gevent.sleep(TIME_FACTOR * 3) - print 'CLOSE CLIENT SOCKET!!!' + print('CLOSE CLIENT SOCKET!!!') client_hbchan.close() if sys.version_info < (2, 7): assert_raises(zerorpc.LostRemote, server_hbchan.recv) else: with assert_raises(zerorpc.LostRemote): server_hbchan.recv() - print 'SERVER LOST CLIENT :)' + print('SERVER LOST CLIENT :)') server_hbchan.close() server.close() client.close() @@ -116,14 +120,14 @@ def test_heartbeat_can_open_channel_server_close(): server_hbchan = zerorpc.HeartBeatOnChannel(server_channel, freq=TIME_FACTOR * 2) gevent.sleep(TIME_FACTOR * 3) - print 'CLOSE SERVER SOCKET!!!' + print('CLOSE SERVER SOCKET!!!') server_hbchan.close() if sys.version_info < (2, 7): assert_raises(zerorpc.LostRemote, client_hbchan.recv) else: with assert_raises(zerorpc.LostRemote): client_hbchan.recv() - print 'CLIENT LOST SERVER :)' + print('CLIENT LOST SERVER :)') client_hbchan.close() server.close() client.close() @@ -147,7 +151,7 @@ def test_heartbeat_can_open_channel_client_close(): server_hbchan = zerorpc.HeartBeatOnChannel(server_channel, freq=TIME_FACTOR * 2) gevent.sleep(TIME_FACTOR * 3) - print 'CLOSE CLIENT SOCKET!!!' + print('CLOSE CLIENT SOCKET!!!') client_hbchan.close() client.close() if sys.version_info < (2, 7): @@ -155,7 +159,7 @@ def test_heartbeat_can_open_channel_client_close(): else: with assert_raises(zerorpc.LostRemote): server_hbchan.recv() - print 'SERVER LOST CLIENT :)' + print('SERVER LOST CLIENT :)') server_hbchan.close() server.close() @@ -178,7 +182,7 @@ def test_do_some_req_rep(): server_hbchan = zerorpc.HeartBeatOnChannel(server_channel, freq=TIME_FACTOR * 4) def client_do(): - for x in xrange(20): + for x in range(20): client_hbchan.emit('add', (x, x * x)) event = client_hbchan.recv() assert event.name == 'OK' @@ -188,7 +192,7 @@ def client_do(): client_task = gevent.spawn(client_do) def server_do(): - for x in xrange(20): + for x in range(20): event = server_hbchan.recv() assert event.name == 'add' server_hbchan.emit('OK', (sum(event.args),)) @@ -213,10 +217,10 @@ def test_do_some_req_rep_lost_server(): client = zerorpc.ChannelMultiplexer(client_events, ignore_broadcast=True) def client_do(): - print 'running' + print('running') client_channel = client.channel() client_hbchan = zerorpc.HeartBeatOnChannel(client_channel, freq=TIME_FACTOR * 2) - for x in xrange(10): + for x in range(10): client_hbchan.emit('add', (x, x * x)) event = client_hbchan.recv() assert event.name == 'OK' @@ -235,7 +239,7 @@ def server_do(): event = server.recv() server_channel = server.channel(event) server_hbchan = zerorpc.HeartBeatOnChannel(server_channel, freq=TIME_FACTOR * 2) - for x in xrange(10): + for x in range(10): event = server_hbchan.recv() assert event.name == 'add' server_hbchan.emit('OK', (sum(event.args),)) @@ -263,7 +267,7 @@ def client_do(): client_channel = client.channel() client_hbchan = zerorpc.HeartBeatOnChannel(client_channel, freq=TIME_FACTOR * 2) - for x in xrange(10): + for x in range(10): client_hbchan.emit('add', (x, x * x)) event = client_hbchan.recv() assert event.name == 'OK' @@ -277,7 +281,7 @@ def server_do(): server_channel = server.channel(event) server_hbchan = zerorpc.HeartBeatOnChannel(server_channel, freq=TIME_FACTOR * 2) - for x in xrange(10): + for x in range(10): event = server_hbchan.recv() assert event.name == 'add' server_hbchan.emit('OK', (sum(event.args),)) @@ -313,7 +317,7 @@ def client_do(): if sys.version_info < (2, 7): def _do_with_assert_raises(): - for x in xrange(10): + for x in range(10): client_hbchan.emit('sleep', (x,)) event = client_hbchan.recv(timeout=TIME_FACTOR * 3) assert event.name == 'OK' @@ -321,7 +325,7 @@ def _do_with_assert_raises(): assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: with assert_raises(zerorpc.TimeoutExpired): - for x in xrange(10): + for x in range(10): client_hbchan.emit('sleep', (x,)) event = client_hbchan.recv(timeout=TIME_FACTOR * 3) assert event.name == 'OK' @@ -337,7 +341,7 @@ def server_do(): if sys.version_info < (2, 7): def _do_with_assert_raises(): - for x in xrange(20): + for x in range(20): event = server_hbchan.recv() assert event.name == 'sleep' gevent.sleep(TIME_FACTOR * event.args[0]) @@ -345,7 +349,7 @@ def _do_with_assert_raises(): assert_raises(zerorpc.LostRemote, _do_with_assert_raises) else: with assert_raises(zerorpc.LostRemote): - for x in xrange(20): + for x in range(20): event = server_hbchan.recv() assert event.name == 'sleep' gevent.sleep(TIME_FACTOR * event.args[0]) diff --git a/tests/test_middleware.py b/tests/test_middleware.py index c97270a..5592713 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -23,6 +23,10 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import +from builtins import str + from nose.tools import assert_raises import gevent import gevent.local @@ -32,7 +36,7 @@ from zerorpc import zmq import zerorpc -from testutils import teardown, random_ipc_endpoint, TIME_FACTOR +from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR def test_resolve_endpoint(): @@ -47,16 +51,16 @@ def resolve(endpoint): cnt = c.register_middleware({ 'resolve_endpoint': resolve }) - print 'registered_count:', cnt + print('registered_count:', cnt) assert cnt == 1 - print 'resolve titi:', c.hook_resolve_endpoint('titi') + print('resolve titi:', c.hook_resolve_endpoint('titi')) assert c.hook_resolve_endpoint('titi') == test_endpoint - print 'resolve toto:', c.hook_resolve_endpoint('toto') + print('resolve toto:', c.hook_resolve_endpoint('toto')) assert c.hook_resolve_endpoint('toto') == 'toto' - class Resolver(): + class Resolver(object): def resolve_endpoint(self, endpoint): if endpoint == 'toto': @@ -64,18 +68,18 @@ def resolve_endpoint(self, endpoint): return endpoint cnt = c.register_middleware(Resolver()) - print 'registered_count:', cnt + print('registered_count:', cnt) assert cnt == 1 - print 'resolve titi:', c.hook_resolve_endpoint('titi') + print('resolve titi:', c.hook_resolve_endpoint('titi')) assert c.hook_resolve_endpoint('titi') == test_endpoint - print 'resolve toto:', c.hook_resolve_endpoint('toto') + print('resolve toto:', c.hook_resolve_endpoint('toto')) assert c.hook_resolve_endpoint('toto') == test_endpoint c2 = zerorpc.Context() - print 'resolve titi:', c2.hook_resolve_endpoint('titi') + print('resolve titi:', c2.hook_resolve_endpoint('titi')) assert c2.hook_resolve_endpoint('titi') == 'titi' - print 'resolve toto:', c2.hook_resolve_endpoint('toto') + print('resolve toto:', c2.hook_resolve_endpoint('toto')) assert c2.hook_resolve_endpoint('toto') == 'toto' @@ -83,7 +87,7 @@ def test_resolve_endpoint_events(): test_endpoint = random_ipc_endpoint() c = zerorpc.Context() - class Resolver(): + class Resolver(object): def resolve_endpoint(self, endpoint): if endpoint == 'some_service': return test_endpoint @@ -91,7 +95,7 @@ def resolve_endpoint(self, endpoint): class Srv(zerorpc.Server): def hello(self): - print 'heee' + print('heee') return 'world' srv = Srv(heartbeat=TIME_FACTOR * 1, context=c) @@ -114,7 +118,7 @@ def hello(self): srv.close() -class Tracer: +class Tracer(object): '''Used by test_task_context_* tests''' def __init__(self, identity): self._identity = identity @@ -127,7 +131,7 @@ def trace_id(self): def load_task_context(self, event_header): self._locals.trace_id = event_header.get('trace_id', None) - print self._identity, 'load_task_context', self.trace_id + print(self._identity, 'load_task_context', self.trace_id) self._log.append(('load', self.trace_id)) def get_task_context(self): @@ -136,10 +140,10 @@ def get_task_context(self): self._locals.trace_id = '<{0}>'.format(hashlib.md5( str(random.random())[3:] ).hexdigest()[0:6].upper()) - print self._identity, 'get_task_context! [make a new one]', self.trace_id + print(self._identity, 'get_task_context! [make a new one]', self.trace_id) self._log.append(('new', self.trace_id)) else: - print self._identity, 'get_task_context! [reuse]', self.trace_id + print(self._identity, 'get_task_context! [reuse]', self.trace_id) self._log.append(('reuse', self.trace_id)) return { 'trace_id': self.trace_id } @@ -154,7 +158,7 @@ def test_task_context(): cli_tracer = Tracer('[client]') cli_ctx.register_middleware(cli_tracer) - class Srv: + class Srv(object): def echo(self, msg): return msg @@ -201,7 +205,7 @@ def test_task_context_relay(): cli_tracer = Tracer('[client]') cli_ctx.register_middleware(cli_tracer) - class Srv: + class Srv(object): def echo(self, msg): return msg @@ -212,7 +216,7 @@ def echo(self, msg): c_relay = zerorpc.Client(context=srv_relay_ctx) c_relay.connect(endpoint1) - class SrvRelay: + class SrvRelay(object): def echo(self, msg): return c_relay.echo('relay' + msg) + 'relayed' @@ -257,7 +261,7 @@ def test_task_context_relay_fork(): cli_tracer = Tracer('[client]') cli_ctx.register_middleware(cli_tracer) - class Srv: + class Srv(object): def echo(self, msg): return msg @@ -268,15 +272,15 @@ def echo(self, msg): c_relay = zerorpc.Client(context=srv_relay_ctx) c_relay.connect(endpoint1) - class SrvRelay: + class SrvRelay(object): def echo(self, msg): def dothework(msg): return c_relay.echo(msg) + 'relayed' g = gevent.spawn(zerorpc.fork_task_context(dothework, srv_relay_ctx), 'relay' + msg) - print 'relaying in separate task:', g + print('relaying in separate task:', g) r = g.get() - print 'back to main task' + print('back to main task') return r srv_relay = zerorpc.Server(SrvRelay(), context=srv_relay_ctx) @@ -321,7 +325,7 @@ def test_task_context_pushpull(): trigger = gevent.event.Event() - class Puller: + class Puller(object): def echo(self, msg): trigger.set() @@ -359,7 +363,7 @@ def test_task_context_pubsub(): trigger = gevent.event.Event() - class Subscriber: + class Subscriber(object): def echo(self, msg): trigger.set() @@ -381,9 +385,9 @@ def echo(self, msg): subscriber.stop() subscriber_task.join() - print publisher_tracer._log + print(publisher_tracer._log) assert ('new', publisher_tracer.trace_id) in publisher_tracer._log - print subscriber_tracer._log + print(subscriber_tracer._log) assert ('load', publisher_tracer.trace_id) in subscriber_tracer._log diff --git a/tests/test_middleware_before_after_exec.py b/tests/test_middleware_before_after_exec.py index 07821bc..5dafeb0 100644 --- a/tests/test_middleware_before_after_exec.py +++ b/tests/test_middleware_before_after_exec.py @@ -22,10 +22,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from __future__ import absolute_import +from builtins import range + import gevent import zerorpc -from testutils import random_ipc_endpoint, TIME_FACTOR +from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR class EchoModule(object): @@ -42,7 +45,7 @@ def echo(self, msg): @zerorpc.stream def echoes(self, msg): self.last_msg = 'echo: ' + msg - for i in xrange(0, 3): + for i in range(0, 3): yield self.last_msg class ServerBeforeExecMiddleware(object): diff --git a/tests/test_middleware_client.py b/tests/test_middleware_client.py index c65eae9..943985e 100644 --- a/tests/test_middleware_client.py +++ b/tests/test_middleware_client.py @@ -22,10 +22,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from __future__ import absolute_import +from builtins import range + import gevent import zerorpc -from testutils import random_ipc_endpoint, TIME_FACTOR +from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR class EchoModule(object): @@ -42,7 +45,7 @@ def echo(self, msg): @zerorpc.stream def echoes(self, msg): self.last_msg = "echo: " + msg - for i in xrange(0, 3): + for i in range(0, 3): yield self.last_msg def crash(self, msg): diff --git a/tests/test_pubpush.py b/tests/test_pubpush.py index ac93711..a99f9b4 100644 --- a/tests/test_pubpush.py +++ b/tests/test_pubpush.py @@ -23,11 +23,15 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import +from builtins import range + import gevent import gevent.event import zerorpc -from testutils import teardown, random_ipc_endpoint +from .testutils import teardown, random_ipc_endpoint def test_pushpull_inheritance(): @@ -39,7 +43,7 @@ def test_pushpull_inheritance(): class Puller(zerorpc.Puller): def lolita(self, a, b): - print 'lolita', a, b + print('lolita', a, b) assert a + b == 3 trigger.set() @@ -50,7 +54,7 @@ def lolita(self, a, b): trigger.clear() pusher.lolita(1, 2) trigger.wait() - print 'done' + print('done') def test_pubsub_inheritance(): @@ -62,7 +66,7 @@ def test_pubsub_inheritance(): class Subscriber(zerorpc.Subscriber): def lolita(self, a, b): - print 'lolita', a, b + print('lolita', a, b) assert a + b == 3 trigger.set() @@ -73,10 +77,10 @@ def lolita(self, a, b): trigger.clear() # We need this retry logic to wait that the subscriber.run coroutine starts # reading (the published messages will go to /dev/null until then). - for attempt in xrange(0, 10): + for attempt in range(0, 10): publisher.lolita(1, 2) if trigger.wait(0.2): - print 'done' + print('done') return raise RuntimeError("The subscriber didn't receive any published message") @@ -87,7 +91,7 @@ def test_pushpull_composite(): class Puller(object): def lolita(self, a, b): - print 'lolita', a, b + print('lolita', a, b) assert a + b == 3 trigger.set() @@ -102,7 +106,7 @@ def lolita(self, a, b): trigger.clear() pusher.lolita(1, 2) trigger.wait() - print 'done' + print('done') def test_pubsub_composite(): @@ -111,7 +115,7 @@ def test_pubsub_composite(): class Subscriber(object): def lolita(self, a, b): - print 'lolita', a, b + print('lolita', a, b) assert a + b == 3 trigger.set() @@ -126,10 +130,10 @@ def lolita(self, a, b): trigger.clear() # We need this retry logic to wait that the subscriber.run coroutine starts # reading (the published messages will go to /dev/null until then). - for attempt in xrange(0, 10): + for attempt in range(0, 10): publisher.lolita(1, 2) if trigger.wait(0.2): - print 'done' + print('done') return raise RuntimeError("The subscriber didn't receive any published message") diff --git a/tests/test_reqstream.py b/tests/test_reqstream.py index 276d5dd..927019d 100644 --- a/tests/test_reqstream.py +++ b/tests/test_reqstream.py @@ -23,10 +23,14 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import +from builtins import range + import gevent import zerorpc -from testutils import teardown, random_ipc_endpoint, TIME_FACTOR +from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR def test_rcp_streaming(): @@ -36,11 +40,11 @@ class MySrv(zerorpc.Server): @zerorpc.rep def range(self, max): - return range(max) + return list(range(max)) @zerorpc.stream def xrange(self, max): - return xrange(max) + return range(max) srv = MySrv(heartbeat=TIME_FACTOR * 4) srv.bind(endpoint) @@ -55,8 +59,8 @@ def xrange(self, max): r = client.xrange(10) assert getattr(r, 'next', None) is not None l = [] - print 'wait 4s for fun' + print('wait 4s for fun') gevent.sleep(TIME_FACTOR * 4) for x in r: l.append(x) - assert l == range(10) + assert l == list(range(10)) diff --git a/tests/test_server.py b/tests/test_server.py index 548b1e4..200b462 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -23,13 +23,17 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import +from builtins import range + from nose.tools import assert_raises import gevent import sys from zerorpc import zmq import zerorpc -from testutils import teardown, random_ipc_endpoint, TIME_FACTOR +from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR def test_server_manual(): @@ -83,10 +87,10 @@ def add(self, a, b): client = zerorpc.Client() client.connect(endpoint) - print client.lolita() + print(client.lolita()) assert client.lolita() == 42 - print client.add(1, 4) + print(client.add(1, 4)) assert client.add(1, 4) == 5 @@ -113,7 +117,7 @@ def add(self, a, b): assert_raises(zerorpc.TimeoutExpired, client.add, 1, 4) else: with assert_raises(zerorpc.TimeoutExpired): - print client.add(1, 4) + print(client.add(1, 4)) client.close() srv.close() @@ -135,12 +139,12 @@ def raise_something(self, a): if sys.version_info < (2, 7): def _do_with_assert_raises(): - print client.raise_something(42) + print(client.raise_something(42)) assert_raises(zerorpc.RemoteError, _do_with_assert_raises) else: with assert_raises(zerorpc.RemoteError): - print client.raise_something(42) - assert client.raise_something(range(5)) == 4 + print(client.raise_something(42)) + assert client.raise_something(list(range(5))) == 4 client.close() srv.close() @@ -162,17 +166,17 @@ def raise_error(self): if sys.version_info < (2, 7): def _do_with_assert_raises(): - print client.raise_error() + print(client.raise_error()) assert_raises(zerorpc.RemoteError, _do_with_assert_raises) else: with assert_raises(zerorpc.RemoteError): - print client.raise_error() + print(client.raise_error()) try: client.raise_error() except zerorpc.RemoteError as e: - print 'got that:', e - print 'name', e.name - print 'msg', e.msg + print('got that:', e) + print('name', e.name) + print('msg', e.msg) assert e.name == 'RuntimeError' assert e.msg == 'oops!' @@ -197,20 +201,20 @@ class MySrv(zerorpc.Server): rpccall = client.channel() rpccall.emit('donotexist', tuple()) event = rpccall.recv() - print event + print(event) assert event.name == 'ERR' (name, msg, tb) = event.args - print 'detailed error', name, msg, tb + print('detailed error', name, msg, tb) assert name == 'NameError' assert msg == 'donotexist' rpccall = client.channel() rpccall.emit('donotexist', tuple(), xheader=dict(v=1)) event = rpccall.recv() - print event + print(event) assert event.name == 'ERR' (msg,) = event.args - print 'msg only', msg + print('msg only', msg) assert msg == "NameError('donotexist',)" client_events.close() diff --git a/tests/test_zmq.py b/tests/test_zmq.py index 723c941..e3f24d2 100644 --- a/tests/test_zmq.py +++ b/tests/test_zmq.py @@ -23,10 +23,12 @@ # SOFTWARE. +from __future__ import print_function +from __future__ import absolute_import import gevent from zerorpc import zmq -from testutils import random_ipc_endpoint +from .testutils import teardown, random_ipc_endpoint def test1(): @@ -36,10 +38,10 @@ def server(): s = c.socket(zmq.REP) s.bind(endpoint) while True: - print 'srv recving...' + print('srv recving...') r = s.recv() - print 'srv', r - print 'srv sending...' + print('srv', r) + print('srv sending...') s.send('world') s.close() @@ -50,11 +52,11 @@ def client(): s = c.socket(zmq.REQ) s.connect(endpoint) - print 'cli sending...' + print('cli sending...') s.send('hello') - print 'cli recving...' + print('cli recving...') r = s.recv() - print 'cli', r + print('cli', r) s.close() c.term() diff --git a/tests/testutils.py b/tests/testutils.py index 5b73bc5..eb731ce 100644 --- a/tests/testutils.py +++ b/tests/testutils.py @@ -22,6 +22,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from __future__ import print_function +from builtins import str + import functools import nose.exc import random @@ -38,7 +41,7 @@ def random_ipc_endpoint(): def teardown(): global _tmpfiles for tmpfile in _tmpfiles: - print 'unlink', tmpfile + print('unlink', tmpfile) try: os.unlink(tmpfile) except Exception: @@ -55,6 +58,6 @@ def wrap(): try: TIME_FACTOR = float(os.environ.get('ZPC_TEST_TIME_FACTOR')) - print 'ZPC_TEST_TIME_FACTOR:', TIME_FACTOR + print('ZPC_TEST_TIME_FACTOR:', TIME_FACTOR) except TypeError: TIME_FACTOR = 1.0 diff --git a/tests/zmqbug.py b/tests/zmqbug.py index 3544aab..1d102a2 100644 --- a/tests/zmqbug.py +++ b/tests/zmqbug.py @@ -25,6 +25,8 @@ # Based on https://github.com/traviscline/gevent-zeromq/blob/master/gevent_zeromq/core.py +from __future__ import print_function + import zmq import gevent.event @@ -79,7 +81,7 @@ def send(self, data, flags=0, copy=True, track=False): while True: try: return super(ZMQSocket, self).send(data, flags, copy, track) - except zmq.ZMQError, e: + except zmq.ZMQError as e: if e.errno != zmq.EAGAIN: raise self._writable.clear() @@ -92,14 +94,14 @@ def recv(self, flags=0, copy=True, track=False): while True: try: return super(ZMQSocket, self).recv(flags, copy, track) - except zmq.ZMQError, e: + except zmq.ZMQError as e: if e.errno != zmq.EAGAIN: raise self._readable.clear() while not self._readable.wait(timeout=10): events = self.getsockopt(zmq.EVENTS) if bool(events & zmq.POLLIN): - print "here we go, nobody told me about new messages!" + print("here we go, nobody told me about new messages!") global STOP_EVERYTHING STOP_EVERYTHING = True raise gevent.GreenletExit() @@ -111,7 +113,7 @@ def server(): socket = ZMQSocket(zmq_context, zmq.REP) socket.bind('ipc://zmqbug') - class Cnt: + class Cnt(object): responded = 0 cnt = Cnt() @@ -125,7 +127,7 @@ def responder(): gevent.spawn(responder) while not STOP_EVERYTHING: - print "cnt.responded=", cnt.responded + print("cnt.responded=", cnt.responded) gevent.sleep(0.5) @@ -133,7 +135,7 @@ def client(): socket = ZMQSocket(zmq_context, zmq.DEALER) socket.connect('ipc://zmqbug') - class Cnt: + class Cnt(object): recv = 0 send = 0 @@ -156,7 +158,7 @@ def sendmsg(): gevent.spawn(sendmsg) while not STOP_EVERYTHING: - print "cnt.recv=", cnt.recv, "cnt.send=", cnt.send + print("cnt.recv=", cnt.recv, "cnt.send=", cnt.send) gevent.sleep(0.5) gevent.spawn(server) diff --git a/zerorpc/channel.py b/zerorpc/channel.py index 8c96a5b..e1e6853 100644 --- a/zerorpc/channel.py +++ b/zerorpc/channel.py @@ -246,7 +246,7 @@ def recv(self, timeout=None): # sees a suitable message from the remote end... # if self._verbose and self._channel: - if self._input_queue_reserved < self._input_queue_size / 2: + if self._input_queue_reserved < self._input_queue_size // 2: self._request_data() else: self._verbose = True diff --git a/zerorpc/cli.py b/zerorpc/cli.py index 691e861..2985c91 100644 --- a/zerorpc/cli.py +++ b/zerorpc/cli.py @@ -24,12 +24,16 @@ # SOFTWARE. +from __future__ import print_function +from builtins import map + import argparse import json import sys import inspect import os import logging +import collections from pprint import pprint import zerorpc @@ -86,7 +90,7 @@ def setup_links(args, socket): if args.bind: for endpoint in args.bind: - print 'binding to "{0}"'.format(endpoint) + print('binding to "{0}"'.format(endpoint)) socket.bind(endpoint) addresses = [] if args.address: @@ -94,7 +98,7 @@ def setup_links(args, socket): if args.connect: addresses.extend(args.connect) for endpoint in addresses: - print 'connecting to "{0}"'.format(endpoint) + print('connecting to "{0}"'.format(endpoint)) socket.connect(endpoint) @@ -116,7 +120,7 @@ def run_server(args): if args.debug: server.debug = True setup_links(args, server) - print 'serving "{0}"'.format(server_obj_path) + print('serving "{0}"'.format(server_obj_path)) return server.run() @@ -239,29 +243,29 @@ def run_client(args): if not args.command: (longest_name_len, detailled_methods, service) = zerorpc_inspect(client, long_doc=False, include_argspec=args.inspect) - print '[{0}]'.format(service) + print('[{0}]'.format(service)) if args.inspect: for (name, doc) in detailled_methods: - print name + print(name) else: for (name, doc) in detailled_methods: - print '{0} {1}'.format(name.ljust(longest_name_len), doc) + print('{0} {1}'.format(name.ljust(longest_name_len), doc)) return if args.inspect: (longest_name_len, detailled_methods, service) = zerorpc_inspect(client, method=args.command) if detailled_methods: (name, doc) = detailled_methods[0] - print '[{0}]\n{1}\n\n{2}\n'.format(service, name, doc) + print('[{0}]\n{1}\n\n{2}\n'.format(service, name, doc)) else: - print '[{0}]\nNo documentation for "{1}".'.format(service, args.command) + print('[{0}]\nNo documentation for "{1}".'.format(service, args.command)) return if args.json: call_args = [json.loads(x) for x in args.params] else: call_args = args.params results = client(args.command, *call_args) - if getattr(results, 'next', None) is None: + if not isinstance(results, collections.Iterator): if args.print_json: json.dump(results, sys.stdout) else: diff --git a/zerorpc/context.py b/zerorpc/context.py index 327f1ff..9600d62 100644 --- a/zerorpc/context.py +++ b/zerorpc/context.py @@ -23,10 +23,13 @@ # SOFTWARE. +from __future__ import absolute_import +from builtins import str + import uuid import random -import gevent_zmq as zmq +from . import gevent_zmq as zmq class Context(zmq.Context): @@ -114,7 +117,7 @@ def new_msgid(self): def register_middleware(self, middleware_instance): registered_count = 0 self._middlewares.append(middleware_instance) - for hook in self._hooks.keys(): + for hook in self._hooks: functor = getattr(middleware_instance, hook, None) if functor is None: try: diff --git a/zerorpc/core.py b/zerorpc/core.py index 31921d8..72e394e 100644 --- a/zerorpc/core.py +++ b/zerorpc/core.py @@ -23,6 +23,11 @@ # SOFTWARE. +from __future__ import absolute_import +from builtins import str +from builtins import zip +from future.utils import iteritems + import sys import traceback import gevent.pool @@ -31,14 +36,14 @@ import gevent.local import gevent.lock -import gevent_zmq as zmq +from . import gevent_zmq as zmq from .exceptions import TimeoutExpired, RemoteError, LostRemote from .channel import ChannelMultiplexer, BufferedChannel from .socket import SocketBase from .heartbeat import HeartBeatOnChannel from .context import Context from .decorators import DecoratorBase, rep -import patterns +from . import patterns from logging import getLogger logger = getLogger(__name__) @@ -62,7 +67,7 @@ def __init__(self, channel, methods=None, name=None, context=None, self._inject_builtins() self._heartbeat_freq = heartbeat - for (k, functor) in self._methods.items(): + for (k, functor) in iteritems(self._methods): if not isinstance(functor, DecoratorBase): self._methods[k] = rep(functor) @@ -97,11 +102,11 @@ def _format_args_spec(self, args_spec, r=None): return r def _zerorpc_inspect(self): - methods = dict((m, f) for m, f in self._methods.items() + methods = dict((m, f) for m, f in iteritems(self._methods) if not m.startswith('_')) detailled_methods = dict((m, dict(args=self._format_args_spec(f._zerorpc_args()), - doc=f._zerorpc_doc())) for (m, f) in methods.items()) + doc=f._zerorpc_doc())) for (m, f) in iteritems(methods)) return {'name': self._name, 'methods': detailled_methods} diff --git a/zerorpc/events.py b/zerorpc/events.py index 5612ff9..07f3266 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -23,6 +23,10 @@ # SOFTWARE. +from __future__ import absolute_import +from builtins import str +from builtins import range + import msgpack import gevent.pool import gevent.queue @@ -32,7 +36,7 @@ import logging import sys -import gevent_zmq as zmq +from . import gevent_zmq as zmq from .exceptions import TimeoutExpired from .context import Context from .channel_base import ChannelBase @@ -56,7 +60,7 @@ def __init__(self, socket): def _send(self, parts): e = None - for i in xrange(len(parts) - 1): + for i in range(len(parts) - 1): try: self._socket.send(parts[i], copy=False, flags=zmq.SNDMORE) except (gevent.GreenletExit, gevent.Timeout) as e: diff --git a/zerorpc/gevent_zmq.py b/zerorpc/gevent_zmq.py index b4c89e3..badd8ea 100644 --- a/zerorpc/gevent_zmq.py +++ b/zerorpc/gevent_zmq.py @@ -100,7 +100,7 @@ def connect(self, *args, **kwargs): while True: try: return super(Socket, self).connect(*args, **kwargs) - except _zmq.ZMQError, e: + except _zmq.ZMQError as e: if e.errno not in (_zmq.EAGAIN, errno.EINTR): raise @@ -122,7 +122,7 @@ def send(self, data, flags=0, copy=True, track=False): # send and recv on the socket. self._on_state_changed() return msg - except _zmq.ZMQError, e: + except _zmq.ZMQError as e: if e.errno not in (_zmq.EAGAIN, errno.EINTR): raise self._writable.clear() @@ -162,7 +162,7 @@ def recv(self, flags=0, copy=True, track=False): # send and recv on the socket. self._on_state_changed() return msg - except _zmq.ZMQError, e: + except _zmq.ZMQError as e: if e.errno not in (_zmq.EAGAIN, errno.EINTR): raise self._readable.clear() diff --git a/zerorpc/patterns.py b/zerorpc/patterns.py index bf6ede5..8d6ee0a 100644 --- a/zerorpc/patterns.py +++ b/zerorpc/patterns.py @@ -23,7 +23,7 @@ # SOFTWARE. -class ReqRep: +class ReqRep(object): def process_call(self, context, channel, req_event, functor): context.hook_server_before_exec(req_event) @@ -49,7 +49,7 @@ def process_answer(self, context, channel, req_event, rep_event, channel.close() -class ReqStream: +class ReqStream(object): def process_call(self, context, channel, req_event, functor): context.hook_server_before_exec(req_event) From f044578b23d403334802134ed8e96a765a3a4f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 20 Mar 2016 19:22:58 -0700 Subject: [PATCH 18/51] Proper handling of bytes vs str (unicode). Something to be careful about as zerorpc is now writtent in python3: - str() must be an unicode string (using builtins.str ensure that on python 2). - bytes() must be a string of bytes (we must use builtins.bytes to get the same behavior on pythong 2). - b"some bytes" is a string of bytes. - u"some unicode" is a string of unicodes. And notably "a string" is a byte string on python 2, but an unicode string on python 3. This means zerorpc between a service and a client using different version of python requires proper testing. --- tests/test_channel.py | 4 +- tests/test_events.py | 86 ++++++++++++++++++++-------------------- tests/test_middleware.py | 3 +- tests/test_reqstream.py | 3 +- tests/test_server.py | 2 +- tests/test_zmq.py | 4 +- zerorpc/channel.py | 8 ++-- zerorpc/context.py | 6 +-- zerorpc/core.py | 6 +-- zerorpc/events.py | 10 +++-- zerorpc/heartbeat.py | 2 +- 11 files changed, 69 insertions(+), 65 deletions(-) diff --git a/tests/test_channel.py b/tests/test_channel.py index 6a85036..98b44c1 100644 --- a/tests/test_channel.py +++ b/tests/test_channel.py @@ -51,7 +51,7 @@ def test_events_channel_client_side(): assert event.identity is not None reply_event = server.new_event('someanswer', (21,), - xheader=dict(response_to=event.header['message_id'])) + xheader={b'response_to': event.header[b'message_id']}) reply_event.identity = event.identity server.emit_event(reply_event) event = client_channel.recv() @@ -78,7 +78,7 @@ def test_events_channel_client_side_server_send_many(): for x in range(10): reply_event = server.new_event('someanswer', (x,), - xheader=dict(response_to=event.header['message_id'])) + xheader={b'response_to': event.header[b'message_id']}) reply_event.identity = event.identity server.emit_event(reply_event) for x in range(10): diff --git a/tests/test_events.py b/tests/test_events.py index 91a116b..9fb4569 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -23,11 +23,9 @@ # SOFTWARE. -from __future__ import print_function -from __future__ import absolute_import -from builtins import str -from builtins import range -from builtins import object +from __future__ import print_function, absolute_import +from builtins import str, bytes +from builtins import range, object from zerorpc import zmq import zerorpc @@ -52,25 +50,25 @@ def test_event(): event = zerorpc.Event('mylittleevent', (None,), context=context) print(event) assert event.name == 'mylittleevent' - assert event.header['message_id'] == 0 + assert event.header[b'message_id'] == 0 assert event.args == (None,) event = zerorpc.Event('mylittleevent2', ('42',), context=context) print(event) assert event.name == 'mylittleevent2' - assert event.header['message_id'] == 1 + assert event.header[b'message_id'] == 1 assert event.args == ('42',) event = zerorpc.Event('mylittleevent3', ('a', 42), context=context) print(event) assert event.name == 'mylittleevent3' - assert event.header['message_id'] == 2 + assert event.header[b'message_id'] == 2 assert event.args == ('a', 42) event = zerorpc.Event('mylittleevent4', ('b', 21), context=context) print(event) assert event.name == 'mylittleevent4' - assert event.header['message_id'] == 3 + assert event.header[b'message_id'] == 3 assert event.args == ('b', 21) packed = event.pack() @@ -78,23 +76,23 @@ def test_event(): print(unpacked) assert unpacked.name == 'mylittleevent4' - assert unpacked.header['message_id'] == 3 + assert unpacked.header[b'message_id'] == 3 assert list(unpacked.args) == ['b', 21] event = zerorpc.Event('mylittleevent5', ('c', 24, True), - header={'lol': 'rofl'}, context=None) + header={b'lol': 'rofl'}, context=None) print(event) assert event.name == 'mylittleevent5' - assert event.header['lol'] == 'rofl' + assert event.header[b'lol'] == 'rofl' assert event.args == ('c', 24, True) event = zerorpc.Event('mod', (42,), context=context) print(event) assert event.name == 'mod' - assert event.header['message_id'] == 4 + assert event.header[b'message_id'] == 4 assert event.args == (42,) - event.header.update({'stream': True}) - assert event.header['stream'] is True + event.header.update({b'stream': True}) + assert event.header[b'stream'] is True def test_events_req_rep(): @@ -179,55 +177,55 @@ def test_events_push_pull(): def test_msgpack(): context = zerorpc.Context() - event = zerorpc.Event('myevent', ('a',), context=context) + event = zerorpc.Event(u'myevent', (u'a',), context=context) print(event) - assert type(event.name) == str + assert isinstance(event.name, str) for key in event.header.keys(): - assert type(key) == str - assert type(event.header['message_id']) == str - assert type(event.args[0]) == str + assert isinstance(key, bytes) + assert isinstance(event.header[b'message_id'], bytes) + assert isinstance(event.args[0], str) packed = event.pack() event = event.unpack(packed) print(event) - assert type(event.name) == str + assert isinstance(event.name, str) for key in event.header.keys(): - assert type(key) == str - assert type(event.header['message_id']) == str - assert type(event.args[0]) == str + assert isinstance(key, bytes) + assert isinstance(event.header[b'message_id'], bytes) + assert isinstance(event.args[0], str) - event = zerorpc.Event('myevent', (u'a',), context=context) + event = zerorpc.Event(b'myevent', (u'a',), context=context) print(event) - assert type(event.name) == str + assert isinstance(event.name, bytes) for key in event.header.keys(): - assert type(key) == str - assert type(event.header['message_id']) == str - assert type(event.args[0]) == str + assert isinstance(key, bytes) + assert isinstance(event.header[b'message_id'], bytes) + assert isinstance(event.args[0], str) packed = event.pack() event = event.unpack(packed) print(event) - assert type(event.name) == str + assert isinstance(event.name, bytes) for key in event.header.keys(): - assert type(key) == str - assert type(event.header['message_id']) == str - assert type(event.args[0]) == str + assert isinstance(key, bytes) + assert isinstance(event.header[b'message_id'], bytes) + assert isinstance(event.args[0], str) - event = zerorpc.Event('myevent', (u'a', 'b'), context=context) + event = zerorpc.Event(u'myevent', (u'a', u'b'), context=context) print(event) - assert type(event.name) == str + assert isinstance(event.name, str) for key in event.header.keys(): - assert type(key) == str - assert type(event.header['message_id']) == str - assert type(event.args[0]) == str - assert type(event.args[1]) == str + assert isinstance(key, bytes) + assert isinstance(event.header[b'message_id'], bytes) + assert isinstance(event.args[0], str) + assert isinstance(event.args[1], str) packed = event.pack() event = event.unpack(packed) print(event) - assert type(event.name) == str + assert isinstance(event.name, str) for key in event.header.keys(): - assert type(key) == str - assert type(event.header['message_id']) == str - assert type(event.args[0]) == str - assert type(event.args[1]) == str + assert isinstance(key, bytes) + assert isinstance(event.header[b'message_id'], bytes) + assert isinstance(event.args[0], str) + assert isinstance(event.args[1], str) diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 5592713..754f8cb 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -26,6 +26,7 @@ from __future__ import print_function from __future__ import absolute_import from builtins import str +from future.utils import tobytes from nose.tools import assert_raises import gevent @@ -138,7 +139,7 @@ def get_task_context(self): if self.trace_id is None: # just an ugly code to generate a beautiful little hash. self._locals.trace_id = '<{0}>'.format(hashlib.md5( - str(random.random())[3:] + tobytes(str(random.random())[3:]) ).hexdigest()[0:6].upper()) print(self._identity, 'get_task_context! [make a new one]', self.trace_id) self._log.append(('new', self.trace_id)) diff --git a/tests/test_reqstream.py b/tests/test_reqstream.py index 927019d..5d48b4d 100644 --- a/tests/test_reqstream.py +++ b/tests/test_reqstream.py @@ -28,6 +28,7 @@ from builtins import range import gevent +import collections import zerorpc from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR @@ -57,7 +58,7 @@ def xrange(self, max): assert list(r) == list(range(10)) r = client.xrange(10) - assert getattr(r, 'next', None) is not None + assert isinstance(r, collections.Iterator) l = [] print('wait 4s for fun') gevent.sleep(TIME_FACTOR * 4) diff --git a/tests/test_server.py b/tests/test_server.py index 200b462..b9997b4 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -209,7 +209,7 @@ class MySrv(zerorpc.Server): assert msg == 'donotexist' rpccall = client.channel() - rpccall.emit('donotexist', tuple(), xheader=dict(v=1)) + rpccall.emit('donotexist', tuple(), xheader={b'v': 1}) event = rpccall.recv() print(event) assert event.name == 'ERR' diff --git a/tests/test_zmq.py b/tests/test_zmq.py index e3f24d2..b584cf6 100644 --- a/tests/test_zmq.py +++ b/tests/test_zmq.py @@ -42,7 +42,7 @@ def server(): r = s.recv() print('srv', r) print('srv sending...') - s.send('world') + s.send(b'world') s.close() c.term() @@ -53,7 +53,7 @@ def client(): s.connect(endpoint) print('cli sending...') - s.send('hello') + s.send(b'hello') print('cli recving...') r = s.recv() print('cli', r) diff --git a/zerorpc/channel.py b/zerorpc/channel.py index e1e6853..8e3a395 100644 --- a/zerorpc/channel.py +++ b/zerorpc/channel.py @@ -79,7 +79,7 @@ def _channel_dispatcher(self): except Exception: logger.exception('zerorpc.ChannelMultiplexer ignoring error on recv') continue - channel_id = event.header.get('response_to', None) + channel_id = event.header.get(b'response_to', None) queue = None if channel_id is not None: @@ -119,7 +119,7 @@ def __init__(self, multiplexer, from_event=None): self._zmqid = None self._queue = gevent.queue.Queue(maxsize=1) if from_event is not None: - self._channel_id = from_event.header['message_id'] + self._channel_id = from_event.header[b'message_id'] self._zmqid = from_event.identity self._multiplexer._active_channels[self._channel_id] = self logger.debug('<-- new channel %s', self._channel_id) @@ -142,11 +142,11 @@ def close(self): def new_event(self, name, args, xheader=None): event = self._multiplexer.new_event(name, args, xheader) if self._channel_id is None: - self._channel_id = event.header['message_id'] + self._channel_id = event.header[b'message_id'] self._multiplexer._active_channels[self._channel_id] = self logger.debug('--> new channel %s', self._channel_id) else: - event.header['response_to'] = self._channel_id + event.header[b'response_to'] = self._channel_id event.identity = self._zmqid return event diff --git a/zerorpc/context.py b/zerorpc/context.py index 9600d62..debce26 100644 --- a/zerorpc/context.py +++ b/zerorpc/context.py @@ -24,7 +24,7 @@ from __future__ import absolute_import -from builtins import str +from future.utils import tobytes import uuid import random @@ -103,7 +103,7 @@ def get_instance(): return Context._instance def _reset_msgid(self): - self._msg_id_base = str(uuid.uuid4())[8:] + self._msg_id_base = tobytes(uuid.uuid4().hex)[8:] self._msg_id_counter = random.randrange(0, 2 ** 32) self._msg_id_counter_stop = random.randrange(self._msg_id_counter, 2 ** 32) @@ -112,7 +112,7 @@ def new_msgid(self): self._reset_msgid() else: self._msg_id_counter = (self._msg_id_counter + 1) - return '{0:08x}{1}'.format(self._msg_id_counter, self._msg_id_base) + return tobytes('{0:08x}'.format(self._msg_id_counter)) + self._msg_id_base def register_middleware(self, middleware_instance): registered_count = 0 diff --git a/zerorpc/core.py b/zerorpc/core.py index 72e394e..41e435c 100644 --- a/zerorpc/core.py +++ b/zerorpc/core.py @@ -138,7 +138,7 @@ def _print_traceback(self, protocol_v1, exc_infos): return (name, human_msg, human_traceback) def _async_task(self, initial_event): - protocol_v1 = initial_event.header.get('v', 1) < 2 + protocol_v1 = initial_event.header.get(b'v', 1) < 2 channel = self._multiplexer.channel(initial_event) hbchan = HeartBeatOnChannel(channel, freq=self._heartbeat_freq, passive=protocol_v1) @@ -201,7 +201,7 @@ def close(self): def _handle_remote_error(self, event): exception = self._context.hook_client_handle_remote_error(event) if not exception: - if event.header.get('v', 1) >= 2: + if event.header.get(b'v', 1) >= 2: (name, msg, traceback) = event.args exception = RemoteError(name, msg, traceback) else: @@ -370,7 +370,7 @@ class Subscriber(Puller): def __init__(self, methods=None, context=None): super(Subscriber, self).__init__(methods=methods, context=context, zmq_socket=zmq.SUB) - self._events.setsockopt(zmq.SUBSCRIBE, '') + self._events.setsockopt(zmq.SUBSCRIBE, b'') def fork_task_context(functor, context=None): diff --git a/zerorpc/events.py b/zerorpc/events.py index 07f3266..7bfa6bf 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -49,6 +49,10 @@ def get_pyzmq_frame_buffer(frame): def get_pyzmq_frame_buffer(frame): return frame.buffer +# gevent <= 1.1.0.rc5 is missing the Python3 __next__ method. +if sys.version_info >= (3, 0) and gevent.version_info <= (1, 1, 0, 'rc', '5'): + setattr(gevent.queue.Channel, '__next__', gevent.queue.Channel.next) + logger = logging.getLogger(__name__) @@ -166,7 +170,7 @@ def __init__(self, name, args, context, header=None): self._name = name self._args = args if header is None: - self._header = {'message_id': context.new_msgid(), 'v': 3} + self._header = {b'message_id': context.new_msgid(), b'v': 3} else: self._header = header self._identity = None @@ -334,9 +338,9 @@ def emit_event(self, event, timeout=None): logger.debug('--> %s', event) if event.identity: parts = list(event.identity or list()) - parts.extend(['', event.pack()]) + parts.extend([b'', event.pack()]) elif self._zmq_socket_type in (zmq.DEALER, zmq.ROUTER): - parts = ('', event.pack()) + parts = (b'', event.pack()) else: parts = (event.pack(),) self._send(parts, timeout) diff --git a/zerorpc/heartbeat.py b/zerorpc/heartbeat.py index 5ac9206..776358d 100644 --- a/zerorpc/heartbeat.py +++ b/zerorpc/heartbeat.py @@ -91,7 +91,7 @@ def _recver(self): while True: event = self._channel.recv() if self._compat_v2 is None: - self._compat_v2 = event.header.get('v', 0) < 3 + self._compat_v2 = event.header.get(b'v', 0) < 3 if event.name == '_zpc_hb': self._remote_last_hb = time.time() self._start_heartbeat() From 294e7c7e980ba8340c08c0fe56f9802291a5a652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 20 Mar 2016 19:44:43 -0700 Subject: [PATCH 19/51] Add python 3.5 to travis. Also reduce the test matrix on PYZMQ. --- .travis.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index fc548af..79ce4f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,14 +3,12 @@ python: - 2.6 - 2.7 - 3.4 + - 3.5 env: matrix: - - PYZMQ='pyzmq>=14' - - PYZMQ='pyzmq>=14.3' - - PYZMQ='pyzmq>=14.2,<14.3' - - PYZMQ='pyzmq>=14.1,<14.2' - - PYZMQ='pyzmq>=14.0,<14.1' - - PYZMQ='pyzmq<14' + - PYZMQ='pyzmq>=15' + - PYZMQ='pyzmq>=14,<15' + - PYZMQ='pyzmq>=13,<14' matrix: fast_finish: true script: From 1c55df981a81df0e8f8f05c034ba8b4f701302dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 20 Mar 2016 21:27:18 -0700 Subject: [PATCH 20/51] Fix travis config to install dependencies properly. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 79ce4f4..9073da8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,5 +22,5 @@ addons: - libevent-dev install: - pip install flake8 - - "pip install nose gevent msgpack-python $PYZMQ" - - pip install . --no-deps + - "pip install nose $PYZMQ" + - pip install . From d67b81daf8d82b147c9ae9ed8633b868508c17ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Fri, 27 May 2016 19:32:01 -0700 Subject: [PATCH 21/51] Tox config updated. --- tox.ini | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index b56bac5..22e50ab 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,15 @@ [tox] -envlist = py26,py27,py31,py32 +envlist = py26,py27,py34,py35 [testenv] deps = flake8 nose commands = - flake8 --ignore=E501,E128 zerorpc bin - nosetests + flake8 zerorpc bin + nosetests -v +setenv = + ZPC_TEST_TIME_FACTOR=0.2 [flake8] ignore = E501,E128 From c475621c9ec3e7230a99e1a2fae2fb645c1fca6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Fri, 27 May 2016 19:56:51 -0700 Subject: [PATCH 22/51] New default time factor is 0.2 --- .travis.yml | 2 +- tests/testutils.py | 4 ++-- tox.ini | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9073da8..3399b99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ matrix: fast_finish: true script: - flake8 --ignore=E501,E128 zerorpc bin - - ZPC_TEST_TIME_FACTOR=0.2 nosetests -v + - nosetests -v sudo: false addons: apt: diff --git a/tests/testutils.py b/tests/testutils.py index eb731ce..2a0110c 100644 --- a/tests/testutils.py +++ b/tests/testutils.py @@ -58,6 +58,6 @@ def wrap(): try: TIME_FACTOR = float(os.environ.get('ZPC_TEST_TIME_FACTOR')) - print('ZPC_TEST_TIME_FACTOR:', TIME_FACTOR) except TypeError: - TIME_FACTOR = 1.0 + TIME_FACTOR = 0.2 +print('ZPC_TEST_TIME_FACTOR:', TIME_FACTOR) diff --git a/tox.ini b/tox.ini index 22e50ab..3490b2c 100644 --- a/tox.ini +++ b/tox.ini @@ -8,8 +8,7 @@ deps = commands = flake8 zerorpc bin nosetests -v -setenv = - ZPC_TEST_TIME_FACTOR=0.2 +passenv = ZPC_TEST_TIME_FACTOR [flake8] ignore = E501,E128 From a5530875abd77f81d2c3694ec4d309c7cb9f6ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Fri, 27 May 2016 19:58:01 -0700 Subject: [PATCH 23/51] Ignore GreenletExit exceptions in Events.close(). During a gc pass, children greenlets might have exited already. --- zerorpc/events.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zerorpc/events.py b/zerorpc/events.py index 7bfa6bf..3437748 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -275,11 +275,11 @@ def __del__(self): def close(self): try: self._send.close() - except AttributeError: + except (AttributeError, TypeError, gevent.GreenletExit): pass try: self._recv.close() - except AttributeError: + except (AttributeError, TypeError, gevent.GreenletExit): pass self._socket.close() From 6c9c7364d29f062c6791c140ccce363e6f1a4248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Fri, 3 Jun 2016 21:44:15 -0700 Subject: [PATCH 24/51] Finally correctly handling msgpack bin vs string. A long time ago msgpack had a single RAW type for bytes string. It was the application responsibility to use any compatible string encoding across languages/runtimes. At some point msgpack was updated with a distinction between BIN type and STRING type. The STRING type is the RAW type renamed, and should only contain and UTF-8 encoded string. The BIN type is to contain any byte strings encoded at the application's responsibility. Because STRING is the RAW type renamed, when reading a msgpack message written an older version of msgpack, it is impossible to know if the string was supposed to be encoded in UTF-8 or not. So msgpack-python for backward compatibility, reads both RAW and BIN by as bytes strings by default. On the write side bytes strings and unicode strings encoded to UTF-8 are sent as STRING (and it will appear as UTF-8 string on nodejs for example). And btw Python2 strings are somewhat loosely defined ASCII strings (which is a subset of UTF-8) so everything was all fine, in/out of zerorpc-python was UTF-8 strings. But one day, somebody wanted zerorpc-python to handle the distinction between unicode strings and bytes strings. This was the day commit 6ca6fdf598905ca67f2678973034dae435a28594 was born. This broke the compatibility with zerorpc-node because suddenly, zerorpc-python on python2 (remember, strings on python2 are bytes strings) was sending BIN (bytes strings) instead of STRING (utf-8 strings) that zerorpc-node expects. On the other hand, zerorpc-python on python3 was sending STRING as it should, because in python3, strings are unicode by default and msgpack-python will encode them as UTF-8 strings with the type STRING. In an attempt of making zerorpc-python working across python2 & python3, I did the wrong thing and used Python2 as reference instead of using Python3, which further broke compatibility with zerorpc-node. This commit restores compatibility with zerorpc-node and across python3/python3. Fixes #142. Updates #108. Note also this new repo 0rpc/zerorpc-crosstests to run basic zerorpc tests across languages. I hope it will prevent this kind of bugs to be published ever again. --- tests/test_channel.py | 4 +-- tests/test_events.py | 74 ++++++++++++------------------------------- tests/test_server.py | 2 +- tests/test_zmq.py | 2 +- zerorpc/channel.py | 12 +++---- zerorpc/core.py | 23 ++++++++++++-- zerorpc/events.py | 10 ++++-- zerorpc/heartbeat.py | 12 +++---- zerorpc/patterns.py | 22 ++++++------- 9 files changed, 76 insertions(+), 85 deletions(-) diff --git a/tests/test_channel.py b/tests/test_channel.py index 98b44c1..1d59b1e 100644 --- a/tests/test_channel.py +++ b/tests/test_channel.py @@ -51,7 +51,7 @@ def test_events_channel_client_side(): assert event.identity is not None reply_event = server.new_event('someanswer', (21,), - xheader={b'response_to': event.header[b'message_id']}) + xheader={'response_to': event.header['message_id']}) reply_event.identity = event.identity server.emit_event(reply_event) event = client_channel.recv() @@ -78,7 +78,7 @@ def test_events_channel_client_side_server_send_many(): for x in range(10): reply_event = server.new_event('someanswer', (x,), - xheader={b'response_to': event.header[b'message_id']}) + xheader={'response_to': event.header['message_id']}) reply_event.identity = event.identity server.emit_event(reply_event) for x in range(10): diff --git a/tests/test_events.py b/tests/test_events.py index 9fb4569..7acf98e 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -50,49 +50,49 @@ def test_event(): event = zerorpc.Event('mylittleevent', (None,), context=context) print(event) assert event.name == 'mylittleevent' - assert event.header[b'message_id'] == 0 + assert event.header['message_id'] == 0 assert event.args == (None,) event = zerorpc.Event('mylittleevent2', ('42',), context=context) print(event) assert event.name == 'mylittleevent2' - assert event.header[b'message_id'] == 1 + assert event.header['message_id'] == 1 assert event.args == ('42',) event = zerorpc.Event('mylittleevent3', ('a', 42), context=context) print(event) assert event.name == 'mylittleevent3' - assert event.header[b'message_id'] == 2 + assert event.header['message_id'] == 2 assert event.args == ('a', 42) - event = zerorpc.Event('mylittleevent4', ('b', 21), context=context) + event = zerorpc.Event('mylittleevent4', ('', 21), context=context) print(event) assert event.name == 'mylittleevent4' - assert event.header[b'message_id'] == 3 - assert event.args == ('b', 21) + assert event.header['message_id'] == 3 + assert event.args == ('', 21) packed = event.pack() unpacked = zerorpc.Event.unpack(packed) print(unpacked) assert unpacked.name == 'mylittleevent4' - assert unpacked.header[b'message_id'] == 3 - assert list(unpacked.args) == ['b', 21] + assert unpacked.header['message_id'] == 3 + assert list(unpacked.args) == ['', 21] event = zerorpc.Event('mylittleevent5', ('c', 24, True), - header={b'lol': 'rofl'}, context=None) + header={'lol': 'rofl'}, context=None) print(event) assert event.name == 'mylittleevent5' - assert event.header[b'lol'] == 'rofl' + assert event.header['lol'] == 'rofl' assert event.args == ('c', 24, True) event = zerorpc.Event('mod', (42,), context=context) print(event) assert event.name == 'mod' - assert event.header[b'message_id'] == 4 + assert event.header['message_id'] == 4 assert event.args == (42,) - event.header.update({b'stream': True}) - assert event.header[b'stream'] is True + event.header.update({'stream': True}) + assert event.header['stream'] is True def test_events_req_rep(): @@ -179,10 +179,13 @@ def test_msgpack(): context = zerorpc.Context() event = zerorpc.Event(u'myevent', (u'a',), context=context) print(event) + # note here that str is an unicode string in all Python version (thanks to + # the builtin str import). assert isinstance(event.name, str) for key in event.header.keys(): - assert isinstance(key, bytes) - assert isinstance(event.header[b'message_id'], bytes) + assert isinstance(key, str) + assert isinstance(event.header[u'message_id'], bytes) + assert isinstance(event.header[u'v'], int) assert isinstance(event.args[0], str) packed = event.pack() @@ -190,42 +193,7 @@ def test_msgpack(): print(event) assert isinstance(event.name, str) for key in event.header.keys(): - assert isinstance(key, bytes) - assert isinstance(event.header[b'message_id'], bytes) + assert isinstance(key, str) + assert isinstance(event.header[u'message_id'], bytes) + assert isinstance(event.header[u'v'], int) assert isinstance(event.args[0], str) - - event = zerorpc.Event(b'myevent', (u'a',), context=context) - print(event) - assert isinstance(event.name, bytes) - for key in event.header.keys(): - assert isinstance(key, bytes) - assert isinstance(event.header[b'message_id'], bytes) - assert isinstance(event.args[0], str) - - packed = event.pack() - event = event.unpack(packed) - print(event) - assert isinstance(event.name, bytes) - for key in event.header.keys(): - assert isinstance(key, bytes) - assert isinstance(event.header[b'message_id'], bytes) - assert isinstance(event.args[0], str) - - event = zerorpc.Event(u'myevent', (u'a', u'b'), context=context) - print(event) - assert isinstance(event.name, str) - for key in event.header.keys(): - assert isinstance(key, bytes) - assert isinstance(event.header[b'message_id'], bytes) - assert isinstance(event.args[0], str) - assert isinstance(event.args[1], str) - - packed = event.pack() - event = event.unpack(packed) - print(event) - assert isinstance(event.name, str) - for key in event.header.keys(): - assert isinstance(key, bytes) - assert isinstance(event.header[b'message_id'], bytes) - assert isinstance(event.args[0], str) - assert isinstance(event.args[1], str) diff --git a/tests/test_server.py b/tests/test_server.py index b9997b4..2a266ce 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -209,7 +209,7 @@ class MySrv(zerorpc.Server): assert msg == 'donotexist' rpccall = client.channel() - rpccall.emit('donotexist', tuple(), xheader={b'v': 1}) + rpccall.emit('donotexist', tuple(), xheader={'v': 1}) event = rpccall.recv() print(event) assert event.name == 'ERR' diff --git a/tests/test_zmq.py b/tests/test_zmq.py index b584cf6..1e7b4dd 100644 --- a/tests/test_zmq.py +++ b/tests/test_zmq.py @@ -38,7 +38,7 @@ def server(): s = c.socket(zmq.REP) s.bind(endpoint) while True: - print('srv recving...') + print(b'srv recving...') r = s.recv() print('srv', r) print('srv sending...') diff --git a/zerorpc/channel.py b/zerorpc/channel.py index 8e3a395..ad21c27 100644 --- a/zerorpc/channel.py +++ b/zerorpc/channel.py @@ -79,7 +79,7 @@ def _channel_dispatcher(self): except Exception: logger.exception('zerorpc.ChannelMultiplexer ignoring error on recv') continue - channel_id = event.header.get(b'response_to', None) + channel_id = event.header.get(u'response_to', None) queue = None if channel_id is not None: @@ -119,7 +119,7 @@ def __init__(self, multiplexer, from_event=None): self._zmqid = None self._queue = gevent.queue.Queue(maxsize=1) if from_event is not None: - self._channel_id = from_event.header[b'message_id'] + self._channel_id = from_event.header[u'message_id'] self._zmqid = from_event.identity self._multiplexer._active_channels[self._channel_id] = self logger.debug('<-- new channel %s', self._channel_id) @@ -142,11 +142,11 @@ def close(self): def new_event(self, name, args, xheader=None): event = self._multiplexer.new_event(name, args, xheader) if self._channel_id is None: - self._channel_id = event.header[b'message_id'] + self._channel_id = event.header[u'message_id'] self._multiplexer._active_channels[self._channel_id] = self logger.debug('--> new channel %s', self._channel_id) else: - event.header[b'response_to'] = self._channel_id + event.header[u'response_to'] = self._channel_id event.identity = self._zmqid return event @@ -205,7 +205,7 @@ def close(self): def _recver(self): while True: event = self._channel.recv() - if event.name == '_zpc_more': + if event.name == u'_zpc_more': try: self._remote_queue_open_slots += int(event.args[0]) except Exception: @@ -239,7 +239,7 @@ def emit_event(self, event, timeout=None): def _request_data(self): open_slots = self._input_queue_size - self._input_queue_reserved self._input_queue_reserved += open_slots - self._channel.emit('_zpc_more', (open_slots,)) + self._channel.emit(u'_zpc_more', (open_slots,)) def recv(self, timeout=None): # self._channel can be set to None by an 'on_close_if' callback if it diff --git a/zerorpc/core.py b/zerorpc/core.py index 41e435c..9fa63e3 100644 --- a/zerorpc/core.py +++ b/zerorpc/core.py @@ -138,7 +138,7 @@ def _print_traceback(self, protocol_v1, exc_infos): return (name, human_msg, human_traceback) def _async_task(self, initial_event): - protocol_v1 = initial_event.header.get(b'v', 1) < 2 + protocol_v1 = initial_event.header.get(u'v', 1) < 2 channel = self._multiplexer.channel(initial_event) hbchan = HeartBeatOnChannel(channel, freq=self._heartbeat_freq, passive=protocol_v1) @@ -157,7 +157,7 @@ def _async_task(self, initial_event): except Exception: exc_infos = list(sys.exc_info()) human_exc_infos = self._print_traceback(protocol_v1, exc_infos) - reply_event = bufchan.new_event('ERR', human_exc_infos, + reply_event = bufchan.new_event(u'ERR', human_exc_infos, self._context.hook_get_task_context()) self._context.hook_server_inspect_exception(event, reply_event, exc_infos) bufchan.emit_event(reply_event) @@ -201,7 +201,7 @@ def close(self): def _handle_remote_error(self, event): exception = self._context.hook_client_handle_remote_error(event) if not exception: - if event.header.get(b'v', 1) >= 2: + if event.header.get(u'v', 1) >= 2: (name, msg, traceback) = event.args exception = RemoteError(name, msg, traceback) else: @@ -238,6 +238,23 @@ def raise_error(ex): reply_event, self._handle_remote_error) def __call__(self, method, *args, **kargs): + # here `method` is either a string of bytes or an unicode string in + # Python2 and Python3. Python2: str aka a byte string containing ASCII + # (unless the user explicitly provide an unicode string). Python3: str + # aka an unicode string (unless the user explicitly provide a byte + # string). + # zerorpc protocol requires an utf-8 encoded string at the msgpack + # level. msgpack will encode any unicode string object to UTF-8 and tag + # it `string`, while a bytes string will be tagged `bin`. + # + # So when we get a bytes string, we assume it to be an UTF-8 string + # (ASCII is contained in UTF-8) that we decode to an unicode string. + # Right after, msgpack-python will re-encode it as UTF-8. Yes this is + # terribly inefficient with Python2 because most of the time `method` + # will already be an UTF-8 encoded bytes string. + if isinstance(method, bytes): + method = method.decode('utf-8') + timeout = kargs.get('timeout', self._timeout) channel = self._multiplexer.channel() hbchan = HeartBeatOnChannel(channel, freq=self._heartbeat_freq, diff --git a/zerorpc/events.py b/zerorpc/events.py index 3437748..cd75bfe 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -166,11 +166,15 @@ class Event(object): __slots__ = ['_name', '_args', '_header', '_identity'] + # protocol details: + # - `name` and `header` keys must be unicode strings. + # - `message_id` and 'response_to' values are opaque bytes string. + # - `v' value is an integer. def __init__(self, name, args, context, header=None): self._name = name self._args = args if header is None: - self._header = {b'message_id': context.new_msgid(), b'v': 3} + self._header = {u'message_id': context.new_msgid(), u'v': 3} else: self._header = header self._identity = None @@ -200,7 +204,9 @@ def identity(self, v): self._identity = v def pack(self): - return msgpack.Packer(use_bin_type=True).pack((self._header, self._name, self._args)) + payload = (self._header, self._name, self._args) + r = msgpack.Packer(use_bin_type=True).pack(payload) + return r @staticmethod def unpack(blob): diff --git a/zerorpc/heartbeat.py b/zerorpc/heartbeat.py index 776358d..f0f317e 100644 --- a/zerorpc/heartbeat.py +++ b/zerorpc/heartbeat.py @@ -81,7 +81,7 @@ def _heartbeat(self): gevent.kill(self._parent_coroutine, self._lost_remote_exception()) break - self._channel.emit('_zpc_hb', (0,)) # 0 -> compat with protocol v2 + self._channel.emit(u'_zpc_hb', (0,)) # 0 -> compat with protocol v2 def _start_heartbeat(self): if self._heartbeat_task is None and self._heartbeat_freq is not None and not self._closed: @@ -91,12 +91,12 @@ def _recver(self): while True: event = self._channel.recv() if self._compat_v2 is None: - self._compat_v2 = event.header.get(b'v', 0) < 3 - if event.name == '_zpc_hb': + self._compat_v2 = event.header.get(u'v', 0) < 3 + if event.name == u'_zpc_hb': self._remote_last_hb = time.time() self._start_heartbeat() if self._compat_v2: - event.name = '_zpc_more' + event.name = u'_zpc_more' self._input_queue.put(event) else: self._input_queue.put(event) @@ -106,8 +106,8 @@ def _lost_remote_exception(self): self._heartbeat_freq * 2)) def new_event(self, name, args, header=None): - if self._compat_v2 and name == '_zpc_more': - name = '_zpc_hb' + if self._compat_v2 and name == u'_zpc_more': + name = u'_zpc_hb' return self._channel.new_event(name, args, header) def emit_event(self, event, timeout=None): diff --git a/zerorpc/patterns.py b/zerorpc/patterns.py index 8d6ee0a..3623e17 100644 --- a/zerorpc/patterns.py +++ b/zerorpc/patterns.py @@ -28,18 +28,18 @@ class ReqRep(object): def process_call(self, context, channel, req_event, functor): context.hook_server_before_exec(req_event) result = functor(*req_event.args) - rep_event = channel.new_event('OK', (result,), + rep_event = channel.new_event(u'OK', (result,), context.hook_get_task_context()) context.hook_server_after_exec(req_event, rep_event) channel.emit_event(rep_event) def accept_answer(self, event): - return event.name in ('OK', 'ERR') + return event.name in (u'OK', u'ERR') def process_answer(self, context, channel, req_event, rep_event, handle_remote_error): try: - if rep_event.name == 'ERR': + if rep_event.name == u'ERR': exception = handle_remote_error(rep_event) context.hook_client_after_request(req_event, rep_event, exception) raise exception @@ -55,33 +55,33 @@ def process_call(self, context, channel, req_event, functor): context.hook_server_before_exec(req_event) xheader = context.hook_get_task_context() for result in iter(functor(*req_event.args)): - channel.emit('STREAM', result, xheader) - done_event = channel.new_event('STREAM_DONE', None, xheader) + channel.emit(u'STREAM', result, xheader) + done_event = channel.new_event(u'STREAM_DONE', None, xheader) # NOTE: "We" made the choice to call the hook once the stream is done, - # the other choice was to call it at each iteration. I don't think that - # one choice is better than the other, so I'm fine with changing this + # the other choice was to call it at each iteration. I donu't think that + # one choice is better than the other, so Iu'm fine with changing this # or adding the server_after_iteration and client_after_iteration hooks. context.hook_server_after_exec(req_event, done_event) channel.emit_event(done_event) def accept_answer(self, event): - return event.name in ('STREAM', 'STREAM_DONE') + return event.name in (u'STREAM', u'STREAM_DONE') def process_answer(self, context, channel, req_event, rep_event, handle_remote_error): def is_stream_done(rep_event): - return rep_event.name == 'STREAM_DONE' + return rep_event.name == u'STREAM_DONE' channel.on_close_if = is_stream_done def iterator(req_event, rep_event): try: - while rep_event.name == 'STREAM': + while rep_event.name == u'STREAM': # Like in process_call, we made the choice to call the # after_exec hook only when the stream is done. yield rep_event.args rep_event = channel.recv() - if rep_event.name == 'ERR': + if rep_event.name == u'ERR': exception = handle_remote_error(rep_event) context.hook_client_after_request(req_event, rep_event, exception) raise exception From eb2b4006a78dea1e56ca2b9e13850e5572b19297 Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Wed, 31 Aug 2016 17:41:18 +0200 Subject: [PATCH 25/51] fixes encoding problem --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b68b42e..ff335a4 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ # SOFTWARE. # execfile() doesn't exist in Python 3, this way we are compatible with both. -exec(compile(open('zerorpc/version.py').read(), 'zerorpc/version.py', 'exec')) +exec(compile(open('zerorpc/version.py', encoding='utf8').read(), 'zerorpc/version.py', 'exec')) import sys From 45c0015b39e50882db4b123f700a373883052cd8 Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Wed, 31 Aug 2016 19:06:36 +0200 Subject: [PATCH 26/51] make open() with encoding work under Python2 --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index ff335a4..352a96c 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from io import open + # execfile() doesn't exist in Python 3, this way we are compatible with both. exec(compile(open('zerorpc/version.py', encoding='utf8').read(), 'zerorpc/version.py', 'exec')) From 47c031dc9a39c59f3c11b99e486403c08a6395ad Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Thu, 1 Sep 2016 10:46:48 +0200 Subject: [PATCH 27/51] trying yet another execfile alternative --- setup.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 352a96c..887892b 100644 --- a/setup.py +++ b/setup.py @@ -22,10 +22,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from io import open +from past.builtins import execfile -# execfile() doesn't exist in Python 3, this way we are compatible with both. -exec(compile(open('zerorpc/version.py', encoding='utf8').read(), 'zerorpc/version.py', 'exec')) +execfile('zerorpc/version.py') import sys From b34abce59eab1f30cf7759d43622a52eb02e9208 Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Thu, 1 Sep 2016 10:58:27 +0200 Subject: [PATCH 28/51] adding a special case for Python3 --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 887892b..6644e96 100644 --- a/setup.py +++ b/setup.py @@ -22,12 +22,12 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from past.builtins import execfile - -execfile('zerorpc/version.py') - import sys +if sys.version_info < (3, 0): + execfile('zerorpc/version.py') +else: + exec(compile(open('zerorpc/version.py', encoding='utf8').read(), 'zerorpc/version.py', 'exec')) try: from setuptools import setup From 12cb7633dc00c9f91b66ca379a5240ce8b677867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 4 Sep 2016 07:46:40 -0700 Subject: [PATCH 29/51] Explicit imports to please flake8 Let's be honest, its also cleaner. --- zerorpc/decorators.py | 2 +- zerorpc/gevent_zmq.py | 3 +++ zerorpc/heartbeat.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/zerorpc/decorators.py b/zerorpc/decorators.py index 60cf1f8..8ef39dc 100644 --- a/zerorpc/decorators.py +++ b/zerorpc/decorators.py @@ -24,7 +24,7 @@ import inspect -from .patterns import * # noqa +from .patterns import ReqRep, ReqStream class DecoratorBase(object): diff --git a/zerorpc/gevent_zmq.py b/zerorpc/gevent_zmq.py index badd8ea..9430695 100644 --- a/zerorpc/gevent_zmq.py +++ b/zerorpc/gevent_zmq.py @@ -27,6 +27,9 @@ # We want to act like zmq from zmq import * # noqa +# Explicit import to please flake8 +from zmq import ZMQError + # A way to access original zmq import zmq as _zmq diff --git a/zerorpc/heartbeat.py b/zerorpc/heartbeat.py index f0f317e..23b974d 100644 --- a/zerorpc/heartbeat.py +++ b/zerorpc/heartbeat.py @@ -30,7 +30,7 @@ import gevent.local import gevent.lock -from .exceptions import * # noqa +from .exceptions import LostRemote, TimeoutExpired from .channel_base import ChannelBase From beb8606c263c1e855601f59cd808f769c748bf88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 4 Sep 2016 08:05:33 -0700 Subject: [PATCH 30/51] Do not run flake8 on travis for python2.6. flake8 doesn't support python2.6 anymore. --- .travis.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3399b99..4a59b0a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +sudo: false language: python python: - 2.6 @@ -11,16 +12,19 @@ env: - PYZMQ='pyzmq>=13,<14' matrix: fast_finish: true -script: - - flake8 --ignore=E501,E128 zerorpc bin - - nosetests -v -sudo: false addons: apt: packages: - python-dev - libevent-dev install: - - pip install flake8 + - if [ $TRAVIS_PYTHON_VERSION != '2.6' ]; then + pip install flake8; + fi - "pip install nose $PYZMQ" - pip install . +script: + - if [ $TRAVIS_PYTHON_VERSION != '2.6' ]; then + flake8 --ignore=E501,E128 zerorpc bin; + fi + - nosetests -v From e0c6107ad39c3ccafe7fd5d929214eb7895762db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Sun, 4 Sep 2016 08:52:31 -0700 Subject: [PATCH 31/51] Bump version to 0.6.0. --- zerorpc/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zerorpc/version.py b/zerorpc/version.py index 00742c9..4a455ec 100644 --- a/zerorpc/version.py +++ b/zerorpc/version.py @@ -23,7 +23,7 @@ # SOFTWARE. __title__ = 'zerorpc' -__version__ = '0.5.2' +__version__ = '0.6.0' __author__ = 'François-Xavier Bourlet .' __license__ = 'MIT' __copyright__ = 'Copyright 2015 François-Xavier Bourlet .' From 05319212da3bcce812368773e8c85b05883b2c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Tue, 20 Sep 2016 11:17:57 -0700 Subject: [PATCH 32/51] Update README.rst --- README.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.rst b/README.rst index d2b2965..93b43ef 100644 --- a/README.rst +++ b/README.rst @@ -16,6 +16,14 @@ with a convenient script, "zerorpc", allowing to: * expose Python modules without modifying a single line of code, * call those modules remotely through the command line. +Installation +------------ + +On most systems, its a matter of:: + + $ pip install zerorpc + +Depending of the support from Gevent and PyZMQ on your system, you might need to install `libev` (for gevent) and `libzmq` (for pyzmq) with the development files. Create a server with a one-liner -------------------------------- From 08b87639ac5148f85a885d8e88b04d35214613db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Mon, 30 Jan 2017 17:11:03 -0800 Subject: [PATCH 33/51] gevent 1.1.* for python 2.6 --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6644e96..b88b308 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,9 @@ if sys.version_info < (2, 7): requirements.append('argparse') -if sys.version_info < (3, 0): +if sys.version_info < (2, 7): + requirements.append('gevent==1.1.*') +elif sys.version_info < (3, 0): requirements.append('gevent>=1.0') else: requirements.append('gevent>=1.1rc5') From eb8da609bb504a684d891f99e00298e482144e51 Mon Sep 17 00:00:00 2001 From: Samuel Killin Date: Thu, 16 Mar 2017 07:38:14 +1100 Subject: [PATCH 34/51] Expose pool_size on CLI --- zerorpc/cli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zerorpc/cli.py b/zerorpc/cli.py index 2985c91..c0211d2 100644 --- a/zerorpc/cli.py +++ b/zerorpc/cli.py @@ -61,6 +61,8 @@ parser.add_argument('--heartbeat', default=5, metavar='seconds', type=int, help='heartbeat frequency. You should always use \ the same frequency as the server. (default: 5s)') +parser.add_argument('--pool-size', default=None, metavar='count', type=int, + help='size of worker pool. --server only.') parser.add_argument('-j', '--json', default=False, action='store_true', help='arguments are in JSON format and will be be parsed \ before being sent to the remote') @@ -116,7 +118,7 @@ def run_server(args): if callable(server_obj): server_obj = server_obj() - server = zerorpc.Server(server_obj, heartbeat=args.heartbeat) + server = zerorpc.Server(server_obj, heartbeat=args.heartbeat, pool_size=args.pool_size) if args.debug: server.debug = True setup_links(args, server) From fbba28b9f44068accc96f25c4c99240595c631bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Thu, 13 Apr 2017 20:35:28 -0700 Subject: [PATCH 35/51] Bump version to 0.6.1. --- zerorpc/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zerorpc/version.py b/zerorpc/version.py index 4a455ec..99b5366 100644 --- a/zerorpc/version.py +++ b/zerorpc/version.py @@ -23,7 +23,7 @@ # SOFTWARE. __title__ = 'zerorpc' -__version__ = '0.6.0' +__version__ = '0.6.1' __author__ = 'François-Xavier Bourlet .' __license__ = 'MIT' __copyright__ = 'Copyright 2015 François-Xavier Bourlet .' From a4f954766679ad7554325f06a2fdf20563a1768d Mon Sep 17 00:00:00 2001 From: gtt116 Date: Thu, 1 Jun 2017 21:35:19 +0800 Subject: [PATCH 36/51] Fix setup.py in python2.6 and setuptools 0.6 In python2.6, the setuptools version is '0.6' which do not support wild-card in version. The result is pip install failed. This patch fix it. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b88b308..a54f792 100644 --- a/setup.py +++ b/setup.py @@ -45,7 +45,7 @@ requirements.append('argparse') if sys.version_info < (2, 7): - requirements.append('gevent==1.1.*') + requirements.append('gevent>=1.1.0,<1.2.0') elif sys.version_info < (3, 0): requirements.append('gevent>=1.0') else: From dbdbbc8114d3a73c6295233f9e8ba62e31250113 Mon Sep 17 00:00:00 2001 From: Alex Long Date: Mon, 28 Aug 2017 11:52:21 -0400 Subject: [PATCH 37/51] If functor's __name__ is not available then just stringify it --- zerorpc/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zerorpc/decorators.py b/zerorpc/decorators.py index 8ef39dc..43dfa64 100644 --- a/zerorpc/decorators.py +++ b/zerorpc/decorators.py @@ -33,7 +33,7 @@ class DecoratorBase(object): def __init__(self, functor): self._functor = functor self.__doc__ = functor.__doc__ - self.__name__ = functor.__name__ + self.__name__ = getattr(functor, "__name__", str(functor)) def __get__(self, instance, type_instance=None): if instance is None: From 660891e4575d35950874d05913567521bb87ee42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Fri, 2 Feb 2018 13:03:37 -0800 Subject: [PATCH 38/51] msgpack-python was renamed to msgpack As of version 0.5 msgpack-python was renamed mgspack Fixes #185 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a54f792..8206147 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ requirements = [ - 'msgpack-python>=0.4.0', + 'msgpack>=0.5.2', 'pyzmq>=13.1.0', 'future', ] From 516b9b8d5b192a1347405f5839bb5a5460f3ecdb Mon Sep 17 00:00:00 2001 From: David Antliff Date: Wed, 12 Dec 2018 16:44:35 +1300 Subject: [PATCH 39/51] MsgPack is deprecating Unpacker(encoding='utf-8') - use 'raw=True' as recommended by MsgPack docs. --- zerorpc/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zerorpc/events.py b/zerorpc/events.py index 6939165..f87d0b5 100644 --- a/zerorpc/events.py +++ b/zerorpc/events.py @@ -210,7 +210,7 @@ def pack(self): @staticmethod def unpack(blob): - unpacker = msgpack.Unpacker(encoding='utf-8') + unpacker = msgpack.Unpacker(raw=False) unpacker.feed(blob) unpacked_msg = unpacker.unpack() From 5cf189d55547fc106d25a2ee1c9f06ac679044a2 Mon Sep 17 00:00:00 2001 From: Shiplu Mokaddim Date: Thu, 13 Jun 2019 14:42:49 +0200 Subject: [PATCH 40/51] Put non-output to sys.stderr --- zerorpc/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zerorpc/cli.py b/zerorpc/cli.py index c0211d2..2907c25 100644 --- a/zerorpc/cli.py +++ b/zerorpc/cli.py @@ -92,7 +92,7 @@ def setup_links(args, socket): if args.bind: for endpoint in args.bind: - print('binding to "{0}"'.format(endpoint)) + print('binding to "{0}"'.format(endpoint), file=sys.stderr) socket.bind(endpoint) addresses = [] if args.address: @@ -100,7 +100,7 @@ def setup_links(args, socket): if args.connect: addresses.extend(args.connect) for endpoint in addresses: - print('connecting to "{0}"'.format(endpoint)) + print('connecting to "{0}"'.format(endpoint), file=sys.stderr) socket.connect(endpoint) @@ -122,7 +122,7 @@ def run_server(args): if args.debug: server.debug = True setup_links(args, server) - print('serving "{0}"'.format(server_obj_path)) + print('serving "{0}"'.format(server_obj_path), file=sys.stderr) return server.run() From eedfb85b0e8b30627e40364bed32dff004e6077f Mon Sep 17 00:00:00 2001 From: himanshu4code <52200766+himanshu4code@users.noreply.github.com> Date: Tue, 25 Jun 2019 15:59:35 +0530 Subject: [PATCH 41/51] updated gevent version for python 3.6 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8206147..730b19f 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ elif sys.version_info < (3, 0): requirements.append('gevent>=1.0') else: - requirements.append('gevent>=1.1rc5') + requirements.append('gevent>=1.1') setup( From d28a744330744234a11e222d88fb427aeb1ad32c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Wed, 26 Jun 2019 02:00:13 -0700 Subject: [PATCH 42/51] Bump version to 0.6.2. --- zerorpc/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zerorpc/version.py b/zerorpc/version.py index 99b5366..32b8c89 100644 --- a/zerorpc/version.py +++ b/zerorpc/version.py @@ -23,7 +23,7 @@ # SOFTWARE. __title__ = 'zerorpc' -__version__ = '0.6.1' +__version__ = '0.6.2' __author__ = 'François-Xavier Bourlet .' __license__ = 'MIT' __copyright__ = 'Copyright 2015 François-Xavier Bourlet .' From 57451b80ef74c119a30e1a947f61b189f07dfcd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Bourlet?= Date: Wed, 26 Jun 2019 02:00:19 -0700 Subject: [PATCH 43/51] Bump version to 0.6.3. Fix README.rst. Export long_description in setup.py. This is to upload to pypi with twine. --- README.rst | 4 ++-- setup.py | 4 ++++ zerorpc/version.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 93b43ef..3538015 100644 --- a/README.rst +++ b/README.rst @@ -36,7 +36,7 @@ we will expose the Python "time" module:: .. note:: The bind address uses the zeromq address format. You are not limited to TCP transport: you could as well specify ipc:///tmp/time to use - host-local sockets, for instance. "tcp://*:1234" is a short-hand to + host-local sockets, for instance. "tcp://\*:1234" is a short-hand to "tcp://0.0.0.0:1234" and means "listen on TCP port 1234, accepting connections on all IP addresses". @@ -137,7 +137,7 @@ the "--bind" option:: $ zerorpc --server --bind tcp://*:1234 --bind ipc:///tmp/time time -You can then connect to it using either "zerorpc tcp://*:1234" or +You can then connect to it using either "zerorpc tcp://\*:1234" or "zerorpc ipc:///tmp/time". Wait, there is more! You can even mix "--bind" and "--connect". That means diff --git a/setup.py b/setup.py index 730b19f..610e68b 100644 --- a/setup.py +++ b/setup.py @@ -51,11 +51,15 @@ else: requirements.append('gevent>=1.1') +with open("README.rst", "r") as fh: + long_description = fh.read() setup( name='zerorpc', version=__version__, description='zerorpc is a flexible RPC based on zeromq.', + long_description=long_description, + long_description_content_type='text/x-rst', author=__author__, url='https://github.com/0rpc/zerorpc-python', packages=['zerorpc'], diff --git a/zerorpc/version.py b/zerorpc/version.py index 32b8c89..4324a5a 100644 --- a/zerorpc/version.py +++ b/zerorpc/version.py @@ -23,7 +23,7 @@ # SOFTWARE. __title__ = 'zerorpc' -__version__ = '0.6.2' +__version__ = '0.6.3' __author__ = 'François-Xavier Bourlet .' __license__ = 'MIT' __copyright__ = 'Copyright 2015 François-Xavier Bourlet .' From 20f71e0f4e67546cc304d7616545a064f5d6caac Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Tue, 11 Feb 2020 21:42:39 +1100 Subject: [PATCH 44/51] Fix simple typo: sream -> stream Closes #228 --- doc/protocol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/protocol.md b/doc/protocol.md index a5ee1ff..37a6417 100644 --- a/doc/protocol.md +++ b/doc/protocol.md @@ -231,7 +231,7 @@ FIXME we should rather standardize about the basic introspection calls. At the protocol level, streaming is straightforward. When a server wants to stream some data, instead of sending a "OK" message, it sends a "STREAM" message. The client will know that it needs to keep waiting for more. -At the end of the sream, a "STREAM_DONE" message is expected. +At the end of the stream, a "STREAM_DONE" message is expected. Formal definitions follow. From 23c2e28a801ab82a8dbc33a30bcc4cc6f01a3638 Mon Sep 17 00:00:00 2001 From: Shiplu Mokaddim Date: Wed, 20 May 2020 13:53:51 +0200 Subject: [PATCH 45/51] Using trusty as distro for python 2.6 build Travis changed the default distro to Xenial which doesn't have python 2.6 environment. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4a59b0a..267e190 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +dist: trusty sudo: false language: python python: From 6237243ff24c1f1046115ac209f601ae698fcb66 Mon Sep 17 00:00:00 2001 From: Shiplu Mokaddim Date: Sun, 24 May 2020 09:35:55 +0200 Subject: [PATCH 46/51] add pip freeze in travis.yml To see the installed package versions --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 267e190..c01068d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,7 @@ install: fi - "pip install nose $PYZMQ" - pip install . + - pip freeze script: - if [ $TRAVIS_PYTHON_VERSION != '2.6' ]; then flake8 --ignore=E501,E128 zerorpc bin; From c43ac74a207ecf5e8e3b38621d15a6f2ec735581 Mon Sep 17 00:00:00 2001 From: Cedric Hombourger Date: Wed, 5 Jan 2022 21:23:52 +0100 Subject: [PATCH 47/51] try collections.abc instead of collections for Python >= 3.4 Kill a depreciation warning by importing "collections.abc" and fallback to "collections" on failure in order to maintain support for older versions of Python. Fixes: #231 Signed-off-by: Cedric Hombourger --- tests/test_reqstream.py | 10 ++++++++-- zerorpc/cli.py | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/test_reqstream.py b/tests/test_reqstream.py index 5d48b4d..71e1511 100644 --- a/tests/test_reqstream.py +++ b/tests/test_reqstream.py @@ -28,11 +28,17 @@ from builtins import range import gevent -import collections import zerorpc from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR +try: + # Try collections.abc for 3.4+ + from collections.abc import Iterator +except ImportError: + # Fallback to collections for Python 2 + from collections import Iterator + def test_rcp_streaming(): endpoint = random_ipc_endpoint() @@ -58,7 +64,7 @@ def xrange(self, max): assert list(r) == list(range(10)) r = client.xrange(10) - assert isinstance(r, collections.Iterator) + assert isinstance(r, Iterator) l = [] print('wait 4s for fun') gevent.sleep(TIME_FACTOR * 4) diff --git a/zerorpc/cli.py b/zerorpc/cli.py index 2907c25..3fd6350 100644 --- a/zerorpc/cli.py +++ b/zerorpc/cli.py @@ -33,11 +33,17 @@ import inspect import os import logging -import collections from pprint import pprint import zerorpc +try: + # Try collections.abc for 3.4+ + from collections.abc import Iterator +except ImportError: + # Fallback to collections for Python 2 + from collections import Iterator + parser = argparse.ArgumentParser( description='Make a zerorpc call to a remote service.' @@ -267,7 +273,7 @@ def run_client(args): else: call_args = args.params results = client(args.command, *call_args) - if not isinstance(results, collections.Iterator): + if not isinstance(results, Iterator): if args.print_json: json.dump(results, sys.stdout) else: From d6346f5687d235acdd2f4eec10acc7cfeb8ba572 Mon Sep 17 00:00:00 2001 From: Cedric Hombourger Date: Wed, 5 Jan 2022 21:05:09 +0100 Subject: [PATCH 48/51] core: handle both "async" and "async_" in remote calls Python 3.7 made "async" a reserved keyword: this causes a syntax error when passing "async" as a named parameter in remote procedure calls. Make ClientBase.__call__() understand both "async" and "async_" so we don't break our binary interface with older clients. Fixes: #239 Signed-off-by: Cedric Hombourger --- tests/test_client_async.py | 6 +++--- zerorpc/core.py | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/test_client_async.py b/tests/test_client_async.py index 3acbd3b..6ce4def 100644 --- a/tests/test_client_async.py +++ b/tests/test_client_async.py @@ -53,7 +53,7 @@ def add(self, a, b): client = zerorpc.Client(timeout=TIME_FACTOR * 2) client.connect(endpoint) - async_result = client.add(1, 4, async=True) + async_result = client.add(1, 4, async_=True) if sys.version_info < (2, 7): def _do_with_assert_raises(): @@ -84,8 +84,8 @@ def add(self, a, b): client = zerorpc.Client() client.connect(endpoint) - async_result = client.lolita(async=True) + async_result = client.lolita(async_=True) assert async_result.get() == 42 - async_result = client.add(1, 4, async=True) + async_result = client.add(1, 4, async_=True) assert async_result.get() == 5 diff --git a/zerorpc/core.py b/zerorpc/core.py index 9fa63e3..9dbf5cc 100644 --- a/zerorpc/core.py +++ b/zerorpc/core.py @@ -266,7 +266,10 @@ def __call__(self, method, *args, **kargs): self._context.hook_client_before_request(request_event) bufchan.emit_event(request_event) - if kargs.get('async', False) is False: + # In python 3.7, "async" is a reserved keyword, clients should now use + # "async_": support both for the time being + if (kargs.get('async', False) is False and + kargs.get('async_', False) is False): return self._process_response(request_event, bufchan, timeout) async_result = gevent.event.AsyncResult() From f662983af608db2da39773718ae9ac13ae266e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20K=C5=82oczko?= Date: Thu, 6 Jan 2022 02:40:22 +0000 Subject: [PATCH 49/51] Move from deprecated nose to pytest (solves #243) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomasz Kłoczko --- .travis.yml | 2 +- setup.py | 4 ++-- tests/test_buffered_channel.py | 42 +++++++++++++++++----------------- tests/test_client_async.py | 6 ++--- tests/test_heartbeat.py | 34 +++++++++++++-------------- tests/test_middleware.py | 6 ++--- tests/test_server.py | 14 ++++++------ tests/testutils.py | 4 ++-- tox.ini | 4 ++-- 9 files changed, 58 insertions(+), 58 deletions(-) diff --git a/.travis.yml b/.travis.yml index c01068d..67c2d20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,4 +29,4 @@ script: - if [ $TRAVIS_PYTHON_VERSION != '2.6' ]; then flake8 --ignore=E501,E128 zerorpc bin; fi - - nosetests -v + - pytest -v diff --git a/setup.py b/setup.py index 610e68b..b07ebcb 100644 --- a/setup.py +++ b/setup.py @@ -64,8 +64,8 @@ url='https://github.com/0rpc/zerorpc-python', packages=['zerorpc'], install_requires=requirements, - tests_require=['nose'], - test_suite='nose.collector', + tests_require=['pytest'], + test_suite='pytest.collector', zip_safe=False, entry_points={'console_scripts': ['zerorpc = zerorpc.cli:main']}, license='MIT', diff --git a/tests/test_buffered_channel.py b/tests/test_buffered_channel.py index 76d0fe3..20b8173 100644 --- a/tests/test_buffered_channel.py +++ b/tests/test_buffered_channel.py @@ -27,7 +27,7 @@ from __future__ import absolute_import from builtins import range -from nose.tools import assert_raises +import pytest import gevent import sys @@ -61,9 +61,9 @@ def test_close_server_bufchan(): print('CLOSE SERVER SOCKET!!!') server_bufchan.close() if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, client_bufchan.recv) + pytest.raises(zerorpc.LostRemote, client_bufchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): client_bufchan.recv() print('CLIENT LOST SERVER :)') client_bufchan.close() @@ -96,9 +96,9 @@ def test_close_client_bufchan(): print('CLOSE CLIENT SOCKET!!!') client_bufchan.close() if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, client_bufchan.recv) + pytest.raises(zerorpc.LostRemote, client_bufchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): client_bufchan.recv() print('SERVER LOST CLIENT :)') server_bufchan.close() @@ -129,9 +129,9 @@ def test_heartbeat_can_open_channel_server_close(): print('CLOSE SERVER SOCKET!!!') server_bufchan.close() if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, client_bufchan.recv) + pytest.raises(zerorpc.LostRemote, client_bufchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): client_bufchan.recv() print('CLIENT LOST SERVER :)') client_bufchan.close() @@ -170,9 +170,9 @@ def server_fn(): client_bufchan.close() client.close() if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, server_coro.get) + pytest.raises(zerorpc.LostRemote, server_coro.get) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): server_coro.get() print('SERVER LOST CLIENT :)') server.close() @@ -244,9 +244,9 @@ def client_do(): assert list(event.args) == [x + x * x] client_bufchan.emit('add', (x, x * x)) if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, client_bufchan.recv) + pytest.raises(zerorpc.LostRemote, client_bufchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): client_bufchan.recv() client_bufchan.close() @@ -308,9 +308,9 @@ def server_do(): server_bufchan.emit('OK', (sum(event.args),)) if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, server_bufchan.recv) + pytest.raises(zerorpc.LostRemote, server_bufchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): server_bufchan.recv() server_bufchan.close() @@ -343,9 +343,9 @@ def _do_with_assert_raises(): event = client_bufchan.recv(timeout=TIME_FACTOR * 3) assert event.name == 'OK' assert list(event.args) == [x] - assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) + pytest.raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: - with assert_raises(zerorpc.TimeoutExpired): + with pytest.raises(zerorpc.TimeoutExpired): for x in range(10): client_bufchan.emit('sleep', (x,)) event = client_bufchan.recv(timeout=TIME_FACTOR * 3) @@ -369,9 +369,9 @@ def _do_with_assert_raises(): assert event.name == 'sleep' gevent.sleep(TIME_FACTOR * event.args[0]) server_bufchan.emit('OK', event.args) - assert_raises(zerorpc.LostRemote, _do_with_assert_raises) + pytest.raises(zerorpc.LostRemote, _do_with_assert_raises) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): for x in range(20): event = server_bufchan.recv() assert event.name == 'sleep' @@ -422,9 +422,9 @@ def server_do(): def _do_with_assert_raises(): for x in range(200): server_bufchan.emit('coucou', x, timeout=0) # will fail when x == 1 - assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) + pytest.raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: - with assert_raises(zerorpc.TimeoutExpired): + with pytest.raises(zerorpc.TimeoutExpired): for x in range(200): server_bufchan.emit('coucou', x, timeout=0) # will fail when x == 1 server_bufchan.emit('coucou', 1) # block until receiver is ready @@ -432,9 +432,9 @@ def _do_with_assert_raises(): def _do_with_assert_raises(): for x in range(2, 200): server_bufchan.emit('coucou', x, timeout=0) # will fail when x == 100 - assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) + pytest.raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: - with assert_raises(zerorpc.TimeoutExpired): + with pytest.raises(zerorpc.TimeoutExpired): for x in range(2, 200): server_bufchan.emit('coucou', x, timeout=0) # will fail when x == 100 for x in range(read_cnt.value, 200): diff --git a/tests/test_client_async.py b/tests/test_client_async.py index 3acbd3b..7d39364 100644 --- a/tests/test_client_async.py +++ b/tests/test_client_async.py @@ -25,7 +25,7 @@ from __future__ import print_function from __future__ import absolute_import -from nose.tools import assert_raises +import pytest import gevent import sys @@ -58,9 +58,9 @@ def add(self, a, b): if sys.version_info < (2, 7): def _do_with_assert_raises(): print(async_result.get()) - assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) + pytest.raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: - with assert_raises(zerorpc.TimeoutExpired): + with pytest.raises(zerorpc.TimeoutExpired): print(async_result.get()) client.close() srv.close() diff --git a/tests/test_heartbeat.py b/tests/test_heartbeat.py index 75b1d29..14c66fd 100644 --- a/tests/test_heartbeat.py +++ b/tests/test_heartbeat.py @@ -27,7 +27,7 @@ from __future__ import absolute_import from builtins import range -from nose.tools import assert_raises +import pytest import gevent import sys @@ -59,9 +59,9 @@ def test_close_server_hbchan(): print('CLOSE SERVER SOCKET!!!') server_hbchan.close() if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, client_hbchan.recv) + pytest.raises(zerorpc.LostRemote, client_hbchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): client_hbchan.recv() print('CLIENT LOST SERVER :)') client_hbchan.close() @@ -92,9 +92,9 @@ def test_close_client_hbchan(): print('CLOSE CLIENT SOCKET!!!') client_hbchan.close() if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, server_hbchan.recv) + pytest.raises(zerorpc.LostRemote, server_hbchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): server_hbchan.recv() print('SERVER LOST CLIENT :)') server_hbchan.close() @@ -123,9 +123,9 @@ def test_heartbeat_can_open_channel_server_close(): print('CLOSE SERVER SOCKET!!!') server_hbchan.close() if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, client_hbchan.recv) + pytest.raises(zerorpc.LostRemote, client_hbchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): client_hbchan.recv() print('CLIENT LOST SERVER :)') client_hbchan.close() @@ -155,9 +155,9 @@ def test_heartbeat_can_open_channel_client_close(): client_hbchan.close() client.close() if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, server_hbchan.recv) + pytest.raises(zerorpc.LostRemote, server_hbchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): server_hbchan.recv() print('SERVER LOST CLIENT :)') server_hbchan.close() @@ -227,9 +227,9 @@ def client_do(): assert list(event.args) == [x + x * x] client_hbchan.emit('add', (x, x * x)) if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, client_hbchan.recv) + pytest.raises(zerorpc.LostRemote, client_hbchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): client_hbchan.recv() client_hbchan.close() @@ -287,9 +287,9 @@ def server_do(): server_hbchan.emit('OK', (sum(event.args),)) if sys.version_info < (2, 7): - assert_raises(zerorpc.LostRemote, server_hbchan.recv) + pytest.raises(zerorpc.LostRemote, server_hbchan.recv) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): server_hbchan.recv() server_hbchan.close() @@ -322,9 +322,9 @@ def _do_with_assert_raises(): event = client_hbchan.recv(timeout=TIME_FACTOR * 3) assert event.name == 'OK' assert list(event.args) == [x] - assert_raises(zerorpc.TimeoutExpired, _do_with_assert_raises) + pytest.raises(zerorpc.TimeoutExpired, _do_with_assert_raises) else: - with assert_raises(zerorpc.TimeoutExpired): + with pytest.raises(zerorpc.TimeoutExpired): for x in range(10): client_hbchan.emit('sleep', (x,)) event = client_hbchan.recv(timeout=TIME_FACTOR * 3) @@ -346,9 +346,9 @@ def _do_with_assert_raises(): assert event.name == 'sleep' gevent.sleep(TIME_FACTOR * event.args[0]) server_hbchan.emit('OK', event.args) - assert_raises(zerorpc.LostRemote, _do_with_assert_raises) + pytest.raises(zerorpc.LostRemote, _do_with_assert_raises) else: - with assert_raises(zerorpc.LostRemote): + with pytest.raises(zerorpc.LostRemote): for x in range(20): event = server_hbchan.recv() assert event.name == 'sleep' diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 754f8cb..3163a3a 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -28,7 +28,7 @@ from builtins import str from future.utils import tobytes -from nose.tools import assert_raises +import pytest import gevent import gevent.local import random @@ -101,9 +101,9 @@ def hello(self): srv = Srv(heartbeat=TIME_FACTOR * 1, context=c) if sys.version_info < (2, 7): - assert_raises(zmq.ZMQError, srv.bind, 'some_service') + pytest.raises(zmq.ZMQError, srv.bind, 'some_service') else: - with assert_raises(zmq.ZMQError): + with pytest.raises(zmq.ZMQError): srv.bind('some_service') cnt = c.register_middleware(Resolver()) diff --git a/tests/test_server.py b/tests/test_server.py index 2a266ce..86997a9 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -27,7 +27,7 @@ from __future__ import absolute_import from builtins import range -from nose.tools import assert_raises +import pytest import gevent import sys @@ -114,9 +114,9 @@ def add(self, a, b): client.connect(endpoint) if sys.version_info < (2, 7): - assert_raises(zerorpc.TimeoutExpired, client.add, 1, 4) + pytest.raises(zerorpc.TimeoutExpired, client.add, 1, 4) else: - with assert_raises(zerorpc.TimeoutExpired): + with pytest.raises(zerorpc.TimeoutExpired): print(client.add(1, 4)) client.close() srv.close() @@ -140,9 +140,9 @@ def raise_something(self, a): if sys.version_info < (2, 7): def _do_with_assert_raises(): print(client.raise_something(42)) - assert_raises(zerorpc.RemoteError, _do_with_assert_raises) + pytest.raises(zerorpc.RemoteError, _do_with_assert_raises) else: - with assert_raises(zerorpc.RemoteError): + with pytest.raises(zerorpc.RemoteError): print(client.raise_something(42)) assert client.raise_something(list(range(5))) == 4 client.close() @@ -167,9 +167,9 @@ def raise_error(self): if sys.version_info < (2, 7): def _do_with_assert_raises(): print(client.raise_error()) - assert_raises(zerorpc.RemoteError, _do_with_assert_raises) + pytest.raises(zerorpc.RemoteError, _do_with_assert_raises) else: - with assert_raises(zerorpc.RemoteError): + with pytest.raises(zerorpc.RemoteError): print(client.raise_error()) try: client.raise_error() diff --git a/tests/testutils.py b/tests/testutils.py index 2a0110c..85b6a96 100644 --- a/tests/testutils.py +++ b/tests/testutils.py @@ -26,7 +26,7 @@ from builtins import str import functools -import nose.exc +import pytest import random import os @@ -52,7 +52,7 @@ def skip(reason): def _skip(test): @functools.wraps(test) def wrap(): - raise nose.exc.SkipTest(reason) + raise pytest.SkipTest(reason) return wrap return _skip diff --git a/tox.ini b/tox.ini index 3490b2c..96bace8 100644 --- a/tox.ini +++ b/tox.ini @@ -4,10 +4,10 @@ envlist = py26,py27,py34,py35 [testenv] deps = flake8 - nose + pytest commands = flake8 zerorpc bin - nosetests -v + pytest -v passenv = ZPC_TEST_TIME_FACTOR [flake8] From dd6843c114e9bfd6e81abf68f6a2eb3c598d1c2f Mon Sep 17 00:00:00 2001 From: Cedric Hombourger Date: Thu, 19 May 2022 22:54:27 +0200 Subject: [PATCH 50/51] gevent_zmq: import enums from pyzmq >= 23.0.0 With pyzmq 23.0.0, constants were changed to enums and moved to the constants module. Attempt to import all globals from it into our zmq wrapper. Closes: #251 Signed-off-by: Cedric Hombourger --- zerorpc/gevent_zmq.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/zerorpc/gevent_zmq.py b/zerorpc/gevent_zmq.py index 9430695..54420ae 100644 --- a/zerorpc/gevent_zmq.py +++ b/zerorpc/gevent_zmq.py @@ -27,6 +27,13 @@ # We want to act like zmq from zmq import * # noqa +try: + # Try to import enums for pyzmq >= 23.0.0 + from zmq.constants import * # noqa +except ImportError: + pass + + # Explicit import to please flake8 from zmq import ZMQError From be578354c09c43412d052c53de14745868bd0c4f Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Wed, 20 Jul 2022 18:20:11 +1000 Subject: [PATCH 51/51] docs: Fix a few typos There are small typos in: - doc/protocol.md - zerorpc/core.py Fixes: - Should read `transferred` rather than `transfered`. - Should read `occurred` rather than `occured`. Signed-off-by: Tim Gates --- doc/protocol.md | 2 +- zerorpc/core.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/protocol.md b/doc/protocol.md index 37a6417..cfc83d2 100644 --- a/doc/protocol.md +++ b/doc/protocol.md @@ -207,7 +207,7 @@ exception is raised), we use the ERR event. - Name of the error (it should be the exception class name, or another meaningful keyword). - Human representation of the error (preferably in english). - - If possible a pretty printed traceback of the call stack when the error occured. + - If possible a pretty printed traceback of the call stack when the error occurred. > A future version of the protocol will probably add a structured version of the > traceback, allowing machine-to-machine stack walking and better cross-language diff --git a/zerorpc/core.py b/zerorpc/core.py index 9dbf5cc..ec2e008 100644 --- a/zerorpc/core.py +++ b/zerorpc/core.py @@ -406,7 +406,7 @@ def fork_task_context(functor, context=None): - task1 is created to handle this event this task will be linked to the initial event context. zerorpc.Server does that for you. - task1 make use of some zerorpc.Client instances, the initial - event context is transfered on every call. + event context is transferred on every call. - task1 spawn a new task2. - task2 make use of some zerorpc.Client instances, it's a fresh @@ -415,7 +415,7 @@ def fork_task_context(functor, context=None): - task1 spawn a new fork_task_context(task3). - task3 make use of some zerorpc.Client instances, the initial - event context is transfered on every call. + event context is transferred on every call. A real use case is a distributed tracer. Each time a new event is created, a trace_id is injected in it or copied from the current task