From c43ac74a207ecf5e8e3b38621d15a6f2ec735581 Mon Sep 17 00:00:00 2001 From: Cedric Hombourger Date: Wed, 5 Jan 2022 21:23:52 +0100 Subject: [PATCH 1/5] 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 2/5] 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 3/5] 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 4/5] 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 5/5] 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