Create Debian zerorpc-python package
The zerorpc package is a light-weight, reliable and language-agnostic library for distributed communication between server-side processes. It builds on top of ZeroMQ and MessagePack. This package is required for sysinv ZeroMQ-based RPC backend [1]. TEST PLAN: PASS: Verify STX Debian builds properly PASS: Verify STX Debian deploys properly PASS: Verify zerorpc-python package was properly installed PASS: Verify syinv processes runs properly [1] https://review.opendev.org/c/starlingx/config/+/859571 Story: 2010087 Task: 46794 Signed-off-by: Alyson Deives Pereira <alyson.deivespereira@windriver.com> Change-Id: I62565e2ce39c0bed63506bfcabf909d5cf186ec1
This commit is contained in:
parent
fa933d905f
commit
838ae8f47c
@ -86,6 +86,7 @@ python/dh-python
|
||||
python/python-nss
|
||||
python/python3-nsenter
|
||||
python/python3-setuptools
|
||||
python/zerorpc-python
|
||||
security/efitools
|
||||
security/keyrings.alt
|
||||
security/python-keyring
|
||||
|
5
python/zerorpc-python/debian/deb_folder/changelog
Normal file
5
python/zerorpc-python/debian/deb_folder/changelog
Normal file
@ -0,0 +1,5 @@
|
||||
zerorpc-python (0.6.3-99ee6e47c8baf909b97eec94f184a19405f392a2) unstable; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- Alyson Deives Pereira <alyson.deivespereira@windriver.com> Wed, 31 Aug 2022 08:41:30 -0300
|
30
python/zerorpc-python/debian/deb_folder/control
Normal file
30
python/zerorpc-python/debian/deb_folder/control
Normal file
@ -0,0 +1,30 @@
|
||||
Source: zerorpc-python
|
||||
Section: libs
|
||||
Priority: optional
|
||||
Maintainer: StarlingX Developers <starlingx-discuss@lists.starlingx.io>
|
||||
Build-Depends: debhelper-compat (= 13),
|
||||
dh-python,
|
||||
python3-all,
|
||||
python3-setuptools,
|
||||
python3-wheel,
|
||||
Standards-Version: 4.5.1
|
||||
|
||||
Package: zerorpc-python
|
||||
Section: libs
|
||||
Architecture: all
|
||||
Depends: ${python3:Depends}, ${misc:Depends},
|
||||
libzmq5,
|
||||
python3-eventlet,
|
||||
python3-future,
|
||||
python3-greenlet,
|
||||
python3-msgpack,
|
||||
python3-zmq
|
||||
Description: Zerorpc is a flexible RPC implementation based on zeromq and messagepack.
|
||||
|
||||
Package: zerorpc-python-wheel
|
||||
Architecture: all
|
||||
Depends: ${python3:Depends}, ${misc:Depends}, python3-wheel
|
||||
Description: Zerorpc is a flexible RPC implementation based on zeromq and messagepack.
|
||||
.
|
||||
This is the support package for the PEP 427 wheel version of the package,
|
||||
required for using pip inside a virtual environment.
|
26
python/zerorpc-python/debian/deb_folder/copyright
Normal file
26
python/zerorpc-python/debian/deb_folder/copyright
Normal file
@ -0,0 +1,26 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: zerorpc-python
|
||||
Source: http://github.com/0rpc/zerorpc-python
|
||||
|
||||
Files: *
|
||||
Copyright: 2015 François-Xavier Bourlet (bombela+zerorpc@gmail.com)
|
||||
License: MIT
|
||||
|
||||
License: MIT
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,119 @@
|
||||
From 075568dc87d987e249afdef0324a1dace4e8a81f Mon Sep 17 00:00:00 2001
|
||||
From: Alyson Deives Pereira <alyson.deivespereira@windriver.com>
|
||||
Date: Thu, 28 Jul 2022 09:49:48 -0300
|
||||
Subject: [PATCH] Add option for custom msgpack encoder/decoder
|
||||
|
||||
Signed-off-by: Alyson Deives Pereira <alyson.deivespereira@windriver.com>
|
||||
---
|
||||
zerorpc/core.py | 8 ++++----
|
||||
zerorpc/events.py | 20 +++++++++++---------
|
||||
zerorpc/socket.py | 4 ++--
|
||||
3 files changed, 17 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/zerorpc/core.py b/zerorpc/core.py
|
||||
index ea89f36..90b1aae 100644
|
||||
--- a/zerorpc/core.py
|
||||
+++ b/zerorpc/core.py
|
||||
@@ -278,8 +278,8 @@ class ClientBase(object):
|
||||
class Server(SocketBase, ServerBase):
|
||||
|
||||
def __init__(self, methods=None, name=None, context=None, pool_size=1000,
|
||||
- heartbeat=5):
|
||||
- SocketBase.__init__(self, zmq.ROUTER, context)
|
||||
+ heartbeat=5, encoder=None, decoder=None):
|
||||
+ SocketBase.__init__(self, zmq.ROUTER, context, encoder, decoder)
|
||||
if methods is None:
|
||||
methods = self
|
||||
|
||||
@@ -296,8 +296,8 @@ class Server(SocketBase, ServerBase):
|
||||
class Client(SocketBase, ClientBase):
|
||||
|
||||
def __init__(self, connect_to=None, context=None, timeout=30, heartbeat=5,
|
||||
- passive_heartbeat=False):
|
||||
- SocketBase.__init__(self, zmq.DEALER, context=context)
|
||||
+ passive_heartbeat=False, encoder=None, decoder=None):
|
||||
+ SocketBase.__init__(self, zmq.DEALER, context=context, encoder=encoder, decoder=decoder)
|
||||
ClientBase.__init__(self, self._events, context, timeout, heartbeat,
|
||||
passive_heartbeat)
|
||||
if connect_to:
|
||||
diff --git a/zerorpc/events.py b/zerorpc/events.py
|
||||
index ce97ad6..295220e 100644
|
||||
--- a/zerorpc/events.py
|
||||
+++ b/zerorpc/events.py
|
||||
@@ -201,14 +201,14 @@ class Event(object):
|
||||
def identity(self, v):
|
||||
self._identity = v
|
||||
|
||||
- def pack(self):
|
||||
+ def pack(self, encoder=None):
|
||||
payload = (self._header, self._name, self._args)
|
||||
- r = msgpack.Packer(use_bin_type=True).pack(payload)
|
||||
+ r = msgpack.Packer(use_bin_type=True, default=encoder).pack(payload)
|
||||
return r
|
||||
|
||||
@staticmethod
|
||||
- def unpack(blob):
|
||||
- unpacker = msgpack.Unpacker(raw=False)
|
||||
+ def unpack(blob, decoder=None):
|
||||
+ unpacker = msgpack.Unpacker(raw=False, object_hook=decoder)
|
||||
unpacker.feed(blob)
|
||||
unpacked_msg = unpacker.unpack()
|
||||
|
||||
@@ -241,11 +241,13 @@ class Event(object):
|
||||
|
||||
|
||||
class Events(ChannelBase):
|
||||
- def __init__(self, zmq_socket_type, context=None):
|
||||
+ def __init__(self, zmq_socket_type, context=None, encoder=None, decoder=None):
|
||||
self._debug = False
|
||||
self._zmq_socket_type = zmq_socket_type
|
||||
self._context = context or Context.get_instance()
|
||||
self._socket = self._context.socket(zmq_socket_type)
|
||||
+ self._encoder = encoder
|
||||
+ self._decoder = decoder
|
||||
|
||||
if zmq_socket_type in (zmq.PUSH, zmq.PUB, zmq.DEALER, zmq.ROUTER):
|
||||
self._send = Sender(self._socket)
|
||||
@@ -342,11 +344,11 @@ class Events(ChannelBase):
|
||||
logger.debug('--> %s', event)
|
||||
if event.identity:
|
||||
parts = list(event.identity or list())
|
||||
- parts.extend([b'', event.pack()])
|
||||
+ parts.extend([b'', event.pack(encoder=self._encoder)])
|
||||
elif self._zmq_socket_type in (zmq.DEALER, zmq.ROUTER):
|
||||
- parts = (b'', event.pack())
|
||||
+ parts = (b'', event.pack(encoder=self._encoder))
|
||||
else:
|
||||
- parts = (event.pack(),)
|
||||
+ parts = (event.pack(encoder=self._encoder),)
|
||||
self._send(parts, timeout)
|
||||
|
||||
def recv(self, timeout=None):
|
||||
@@ -360,7 +362,7 @@ class Events(ChannelBase):
|
||||
else:
|
||||
identity = None
|
||||
blob = parts[0]
|
||||
- event = Event.unpack(get_pyzmq_frame_buffer(blob))
|
||||
+ event = Event.unpack(get_pyzmq_frame_buffer(blob), decoder=self._decoder)
|
||||
event.identity = identity
|
||||
if self._debug:
|
||||
logger.debug('<-- %s', event)
|
||||
diff --git a/zerorpc/socket.py b/zerorpc/socket.py
|
||||
index 35cb7e4..274a6d4 100644
|
||||
--- a/zerorpc/socket.py
|
||||
+++ b/zerorpc/socket.py
|
||||
@@ -29,9 +29,9 @@ from .events import Events
|
||||
|
||||
class SocketBase(object):
|
||||
|
||||
- def __init__(self, zmq_socket_type, context=None):
|
||||
+ def __init__(self, zmq_socket_type, context=None, encoder=None, decoder=None):
|
||||
self._context = context or Context.get_instance()
|
||||
- self._events = Events(zmq_socket_type, context)
|
||||
+ self._events = Events(zmq_socket_type, context, encoder, decoder)
|
||||
|
||||
def close(self):
|
||||
self._events.close()
|
||||
--
|
||||
2.25.1
|
||||
|
@ -0,0 +1,426 @@
|
||||
From ec72e722a5628568fe7ba25385d31f8ebcbb8130 Mon Sep 17 00:00:00 2001
|
||||
From: Alyson Deives Pereira <alyson.deivespereira@windriver.com>
|
||||
Date: Fri, 29 Jul 2022 15:22:30 -0300
|
||||
Subject: [PATCH] Allow usage of kwargs
|
||||
|
||||
Based on https://github.com/0rpc/zerorpc-python/commit/674678de3e4744f86fd186582bc4b31daa86e785
|
||||
|
||||
Signed-off-by: Alyson Deives Pereira <alyson.deivespereira@windriver.com>
|
||||
---
|
||||
tests/test_events.py | 14 ++++++------
|
||||
tests/test_kwargs.py | 50 +++++++++++++++++++++++++++++++++++++++++
|
||||
zerorpc/channel.py | 12 +++++-----
|
||||
zerorpc/channel_base.py | 6 ++---
|
||||
zerorpc/core.py | 34 ++++++++++++++--------------
|
||||
zerorpc/events.py | 20 +++++++++++------
|
||||
zerorpc/heartbeat.py | 4 ++--
|
||||
zerorpc/patterns.py | 4 ++--
|
||||
8 files changed, 100 insertions(+), 44 deletions(-)
|
||||
create mode 100644 tests/test_kwargs.py
|
||||
|
||||
diff --git a/tests/test_events.py b/tests/test_events.py
|
||||
index 7acf98e..c9e1c30 100644
|
||||
--- a/tests/test_events.py
|
||||
+++ b/tests/test_events.py
|
||||
@@ -47,25 +47,25 @@ def test_context():
|
||||
|
||||
def test_event():
|
||||
context = MokupContext()
|
||||
- event = zerorpc.Event('mylittleevent', (None,), context=context)
|
||||
+ event = zerorpc.Event('mylittleevent', (None,), {}, context=context)
|
||||
print(event)
|
||||
assert event.name == 'mylittleevent'
|
||||
assert event.header['message_id'] == 0
|
||||
assert event.args == (None,)
|
||||
|
||||
- event = zerorpc.Event('mylittleevent2', ('42',), context=context)
|
||||
+ event = zerorpc.Event('mylittleevent2', ('42',), {}, context=context)
|
||||
print(event)
|
||||
assert event.name == 'mylittleevent2'
|
||||
assert event.header['message_id'] == 1
|
||||
assert event.args == ('42',)
|
||||
|
||||
- event = zerorpc.Event('mylittleevent3', ('a', 42), context=context)
|
||||
+ event = zerorpc.Event('mylittleevent3', ('a', 42), {}, context=context)
|
||||
print(event)
|
||||
assert event.name == 'mylittleevent3'
|
||||
assert event.header['message_id'] == 2
|
||||
assert event.args == ('a', 42)
|
||||
|
||||
- event = zerorpc.Event('mylittleevent4', ('', 21), context=context)
|
||||
+ event = zerorpc.Event('mylittleevent4', ('', 21), {}, context=context)
|
||||
print(event)
|
||||
assert event.name == 'mylittleevent4'
|
||||
assert event.header['message_id'] == 3
|
||||
@@ -79,14 +79,14 @@ def test_event():
|
||||
assert unpacked.header['message_id'] == 3
|
||||
assert list(unpacked.args) == ['', 21]
|
||||
|
||||
- event = zerorpc.Event('mylittleevent5', ('c', 24, True),
|
||||
+ event = zerorpc.Event('mylittleevent5', ('c', 24, True), {},
|
||||
header={'lol': 'rofl'}, context=None)
|
||||
print(event)
|
||||
assert event.name == 'mylittleevent5'
|
||||
assert event.header['lol'] == 'rofl'
|
||||
assert event.args == ('c', 24, True)
|
||||
|
||||
- event = zerorpc.Event('mod', (42,), context=context)
|
||||
+ event = zerorpc.Event('mod', (42,), {}, context=context)
|
||||
print(event)
|
||||
assert event.name == 'mod'
|
||||
assert event.header['message_id'] == 4
|
||||
@@ -177,7 +177,7 @@ def test_events_push_pull():
|
||||
|
||||
def test_msgpack():
|
||||
context = zerorpc.Context()
|
||||
- event = zerorpc.Event(u'myevent', (u'a',), context=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).
|
||||
diff --git a/tests/test_kwargs.py b/tests/test_kwargs.py
|
||||
new file mode 100644
|
||||
index 0000000..e3d7009
|
||||
--- /dev/null
|
||||
+++ b/tests/test_kwargs.py
|
||||
@@ -0,0 +1,50 @@
|
||||
+from __future__ import absolute_import
|
||||
+import eventlet
|
||||
+
|
||||
+import zerorpc
|
||||
+from .testutils import teardown, random_ipc_endpoint
|
||||
+
|
||||
+def test_client_connect():
|
||||
+ endpoint = random_ipc_endpoint()
|
||||
+
|
||||
+ class MySrv(zerorpc.Server):
|
||||
+
|
||||
+ def echo(self, *args, **kwargs):
|
||||
+ return args, kwargs
|
||||
+
|
||||
+ srv = MySrv()
|
||||
+ srv.bind(endpoint)
|
||||
+ eventlet.spawn(srv.run)
|
||||
+
|
||||
+ client = zerorpc.Client()
|
||||
+ client.connect(endpoint)
|
||||
+
|
||||
+ args = 1, 2, 3
|
||||
+ kwargs = {'a': 7, 'b': 8}
|
||||
+ res = client.echo(*args, **kwargs)
|
||||
+ assert len(res) == 2
|
||||
+ assert res[0] == args
|
||||
+ assert len(res[1]) == 3
|
||||
+ assert 'a' in res[1] and 'b' in res[1]
|
||||
+
|
||||
+def test_client_quick_connect():
|
||||
+ endpoint = random_ipc_endpoint()
|
||||
+
|
||||
+ class MySrv(zerorpc.Server):
|
||||
+
|
||||
+ def echo(self, *args, **kwargs):
|
||||
+ return args, kwargs
|
||||
+
|
||||
+ srv = MySrv()
|
||||
+ srv.bind(endpoint)
|
||||
+ eventlet.spawn(srv.run)
|
||||
+
|
||||
+ client = zerorpc.Client(endpoint)
|
||||
+
|
||||
+ args = 1, 2, 3
|
||||
+ kwargs = {'a': 7, 'b': 8}
|
||||
+ res = client.echo(*args, **kwargs)
|
||||
+ assert len(res) == 2
|
||||
+ assert res[0] == args
|
||||
+ assert len(res[1]) == 3
|
||||
+ assert 'a' in res[1] and 'b' in res[1]
|
||||
diff --git a/zerorpc/channel.py b/zerorpc/channel.py
|
||||
index bd376ec..df77bc0 100644
|
||||
--- a/zerorpc/channel.py
|
||||
+++ b/zerorpc/channel.py
|
||||
@@ -55,8 +55,8 @@ class ChannelMultiplexer(ChannelBase):
|
||||
if self._channel_dispatcher_task:
|
||||
self._channel_dispatcher_task.kill()
|
||||
|
||||
- def new_event(self, name, args, xheader=None):
|
||||
- return self._events.new_event(name, args, xheader)
|
||||
+ def new_event(self, name, args, kwargs=None, xheader=None):
|
||||
+ return self._events.new_event(name, args, kwargs, xheader)
|
||||
|
||||
def emit_event(self, event, timeout=None):
|
||||
return self._events.emit_event(event, timeout)
|
||||
@@ -135,8 +135,8 @@ class Channel(ChannelBase):
|
||||
logger.debug('-x- closed channel %s', self._channel_id)
|
||||
self._channel_id = None
|
||||
|
||||
- def new_event(self, name, args, xheader=None):
|
||||
- event = self._multiplexer.new_event(name, args, xheader)
|
||||
+ def new_event(self, name, args, kwargs=None, xheader=None):
|
||||
+ event = self._multiplexer.new_event(name, args, kwargs, xheader)
|
||||
if self._channel_id is None:
|
||||
self._channel_id = event.header[u'message_id']
|
||||
self._multiplexer._active_channels[self._channel_id] = self
|
||||
@@ -218,8 +218,8 @@ class BufferedChannel(ChannelBase):
|
||||
self.close()
|
||||
return
|
||||
|
||||
- def new_event(self, name, args, xheader=None):
|
||||
- return self._channel.new_event(name, args, xheader)
|
||||
+ def new_event(self, name, args, kwargs=None, xheader=None):
|
||||
+ return self._channel.new_event(name, args, kwargs, xheader)
|
||||
|
||||
def emit_event(self, event, timeout=None):
|
||||
if self._remote_queue_open_slots == 0:
|
||||
diff --git a/zerorpc/channel_base.py b/zerorpc/channel_base.py
|
||||
index a391b08..35fc695 100644
|
||||
--- a/zerorpc/channel_base.py
|
||||
+++ b/zerorpc/channel_base.py
|
||||
@@ -40,14 +40,14 @@ class ChannelBase(object):
|
||||
def close(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
- def new_event(self, name, args, xheader=None):
|
||||
+ def new_event(self, name, args, kwargs=None, xheader=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
def emit_event(self, event, timeout=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
- def emit(self, name, args, xheader=None, timeout=None):
|
||||
- event = self.new_event(name, args, xheader)
|
||||
+ def emit(self, name, args, kwargs=None, xheader=None, timeout=None):
|
||||
+ event = self.new_event(name, args, kwargs, xheader)
|
||||
return self.emit_event(event, timeout)
|
||||
|
||||
def recv(self, timeout=None):
|
||||
diff --git a/zerorpc/core.py b/zerorpc/core.py
|
||||
index 90b1aae..dc2b484 100644
|
||||
--- a/zerorpc/core.py
|
||||
+++ b/zerorpc/core.py
|
||||
@@ -117,10 +117,10 @@ class ServerBase(object):
|
||||
lambda m: self._methods[m]._zerorpc_args()
|
||||
self._methods['_zerorpc_inspect'] = self._zerorpc_inspect
|
||||
|
||||
- def __call__(self, method, *args):
|
||||
+ def __call__(self, method, *args, **kwargs):
|
||||
if method not in self._methods:
|
||||
raise NameError(method)
|
||||
- return self._methods[method](*args)
|
||||
+ return self._methods[method](*args, **kwargs)
|
||||
|
||||
def _print_traceback(self, protocol_v1, exc_infos):
|
||||
logger.exception('')
|
||||
@@ -233,7 +233,7 @@ class ClientBase(object):
|
||||
return pattern.process_answer(self._context, bufchan, request_event,
|
||||
reply_event, self._handle_remote_error)
|
||||
|
||||
- def __call__(self, method, *args, **kargs):
|
||||
+ def __call__(self, method, *args, **kwargs):
|
||||
# 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
|
||||
@@ -251,28 +251,28 @@ class ClientBase(object):
|
||||
if isinstance(method, bytes):
|
||||
method = method.decode('utf-8')
|
||||
|
||||
- timeout = kargs.get('timeout', self._timeout)
|
||||
+ timeout = kwargs.pop('timeout_', self._timeout)
|
||||
channel = self._multiplexer.channel()
|
||||
hbchan = HeartBeatOnChannel(channel, freq=self._heartbeat_freq,
|
||||
passive=self._passive_heartbeat)
|
||||
- bufchan = BufferedChannel(hbchan, inqueue_size=kargs.get('slots', 100))
|
||||
+ bufchan = BufferedChannel(hbchan, inqueue_size=kwargs.pop('slots_', 100))
|
||||
|
||||
xheader = self._context.hook_get_task_context()
|
||||
- request_event = bufchan.new_event(method, args, xheader)
|
||||
+ request_event = bufchan.new_event(method, args, kwargs, xheader)
|
||||
self._context.hook_client_before_request(request_event)
|
||||
bufchan.emit_event(request_event)
|
||||
|
||||
# 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):
|
||||
+ async_ = kwargs.pop('async_', False)
|
||||
+ if not async_:
|
||||
return self._process_response(request_event, bufchan, timeout)
|
||||
|
||||
return eventlet.spawn(self._process_response, request_event, bufchan,
|
||||
timeout)
|
||||
|
||||
def __getattr__(self, method):
|
||||
- return lambda *args, **kargs: self(method, *args, **kargs)
|
||||
+ return lambda *args, **kwargs: self(method, *args, **kwargs)
|
||||
|
||||
|
||||
class Server(SocketBase, ServerBase):
|
||||
@@ -313,12 +313,12 @@ class Pusher(SocketBase):
|
||||
def __init__(self, context=None, zmq_socket=zmq.PUSH):
|
||||
super(Pusher, self).__init__(zmq_socket, context=context)
|
||||
|
||||
- def __call__(self, method, *args):
|
||||
- self._events.emit(method, args,
|
||||
+ def __call__(self, method, *args, **kwargs):
|
||||
+ self._events.emit(method, args, kwargs,
|
||||
self._context.hook_get_task_context())
|
||||
|
||||
def __getattr__(self, method):
|
||||
- return lambda *args: self(method, *args)
|
||||
+ return lambda *args, **kwargs: self(method, *args, **kwargs)
|
||||
|
||||
|
||||
class Puller(SocketBase):
|
||||
@@ -336,10 +336,10 @@ class Puller(SocketBase):
|
||||
self.stop()
|
||||
super(Puller, self).close()
|
||||
|
||||
- def __call__(self, method, *args):
|
||||
+ def __call__(self, method, *args, **kwargs):
|
||||
if method not in self._methods:
|
||||
raise NameError(method)
|
||||
- return self._methods[method](*args)
|
||||
+ return self._methods[method](*args, **kwargs)
|
||||
|
||||
def _receiver(self):
|
||||
while True:
|
||||
@@ -349,7 +349,7 @@ class Puller(SocketBase):
|
||||
raise NameError(event.name)
|
||||
self._context.hook_load_task_context(event.header)
|
||||
self._context.hook_server_before_exec(event)
|
||||
- self._methods[event.name](*event.args)
|
||||
+ self._methods[event.name](*event.args, **event.kwargs)
|
||||
# In Push/Pull their is no reply to send, hence None for the
|
||||
# reply_event argument
|
||||
self._context.hook_server_after_exec(event, None)
|
||||
@@ -422,7 +422,7 @@ def fork_task_context(functor, context=None):
|
||||
context = context or Context.get_instance()
|
||||
xheader = context.hook_get_task_context()
|
||||
|
||||
- def wrapped(*args, **kargs):
|
||||
+ def wrapped(*args, **kwargs):
|
||||
context.hook_load_task_context(xheader)
|
||||
- return functor(*args, **kargs)
|
||||
+ return functor(*args, **kwargs)
|
||||
return wrapped
|
||||
diff --git a/zerorpc/events.py b/zerorpc/events.py
|
||||
index 295220e..f24cc2f 100644
|
||||
--- a/zerorpc/events.py
|
||||
+++ b/zerorpc/events.py
|
||||
@@ -162,15 +162,16 @@ class Receiver(SequentialReceiver):
|
||||
|
||||
class Event(object):
|
||||
|
||||
- __slots__ = ['_name', '_args', '_header', '_identity']
|
||||
+ __slots__ = ['_name', '_args', '_kwargs', '_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):
|
||||
+ def __init__(self, name, args, kwargs, context, header=None):
|
||||
self._name = name
|
||||
self._args = args
|
||||
+ self._kwargs = kwargs or {}
|
||||
if header is None:
|
||||
self._header = {u'message_id': context.new_msgid(), u'v': 3}
|
||||
else:
|
||||
@@ -193,6 +194,10 @@ class Event(object):
|
||||
def args(self):
|
||||
return self._args
|
||||
|
||||
+ @property
|
||||
+ def kwargs(self):
|
||||
+ return self._kwargs
|
||||
+
|
||||
@property
|
||||
def identity(self):
|
||||
return self._identity
|
||||
@@ -202,7 +207,7 @@ class Event(object):
|
||||
self._identity = v
|
||||
|
||||
def pack(self, encoder=None):
|
||||
- payload = (self._header, self._name, self._args)
|
||||
+ payload = (self._header, self._name, self._args, self._kwargs)
|
||||
r = msgpack.Packer(use_bin_type=True, default=encoder).pack(payload)
|
||||
return r
|
||||
|
||||
@@ -213,7 +218,7 @@ class Event(object):
|
||||
unpacked_msg = unpacker.unpack()
|
||||
|
||||
try:
|
||||
- (header, name, args) = unpacked_msg
|
||||
+ (header, name, args, kwargs) = unpacked_msg
|
||||
except Exception as e:
|
||||
raise Exception('invalid msg format "{0}": {1}'.format(
|
||||
unpacked_msg, e))
|
||||
@@ -222,7 +227,7 @@ class Event(object):
|
||||
if not isinstance(header, dict):
|
||||
header = {}
|
||||
|
||||
- return Event(name, args, None, header)
|
||||
+ return Event(name, args, kwargs, None, header)
|
||||
|
||||
def __str__(self, ignore_args=False):
|
||||
if ignore_args:
|
||||
@@ -237,6 +242,7 @@ class Event(object):
|
||||
identity = ', '.join(repr(x.bytes) for x in self._identity)
|
||||
return '<{0}> {1} {2} {3}'.format(identity, self._name,
|
||||
self._header, args)
|
||||
+ # TODO include kwargs?
|
||||
return '{0} {1} {2}'.format(self._name, self._header, args)
|
||||
|
||||
|
||||
@@ -333,8 +339,8 @@ class Events(ChannelBase):
|
||||
logger.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)
|
||||
+ def new_event(self, name, args, kwargs=None, xheader=None):
|
||||
+ event = Event(name, args, kwargs, context=self._context)
|
||||
if xheader:
|
||||
event.header.update(xheader)
|
||||
return event
|
||||
diff --git a/zerorpc/heartbeat.py b/zerorpc/heartbeat.py
|
||||
index daa7d50..7bd1166 100644
|
||||
--- a/zerorpc/heartbeat.py
|
||||
+++ b/zerorpc/heartbeat.py
|
||||
@@ -101,10 +101,10 @@ class HeartBeatOnChannel(ChannelBase):
|
||||
return LostRemote('Lost remote after {0}s heartbeat'.format(
|
||||
self._heartbeat_freq * 2))
|
||||
|
||||
- def new_event(self, name, args, header=None):
|
||||
+ def new_event(self, name, args, kwargs=None, header=None):
|
||||
if self._compat_v2 and name == u'_zpc_more':
|
||||
name = u'_zpc_hb'
|
||||
- return self._channel.new_event(name, args, header)
|
||||
+ return self._channel.new_event(name, args, kwargs, header)
|
||||
|
||||
def emit_event(self, event, timeout=None):
|
||||
if self._lost_remote:
|
||||
diff --git a/zerorpc/patterns.py b/zerorpc/patterns.py
|
||||
index 3623e17..a6f44f1 100644
|
||||
--- a/zerorpc/patterns.py
|
||||
+++ b/zerorpc/patterns.py
|
||||
@@ -27,7 +27,7 @@ class ReqRep(object):
|
||||
|
||||
def process_call(self, context, channel, req_event, functor):
|
||||
context.hook_server_before_exec(req_event)
|
||||
- result = functor(*req_event.args)
|
||||
+ result = functor(*req_event.args, **req_event.kwargs)
|
||||
rep_event = channel.new_event(u'OK', (result,),
|
||||
context.hook_get_task_context())
|
||||
context.hook_server_after_exec(req_event, rep_event)
|
||||
@@ -54,7 +54,7 @@ class ReqStream(object):
|
||||
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)):
|
||||
+ for result in iter(functor(*req_event.args, **req_event.kwargs)):
|
||||
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,
|
||||
--
|
||||
2.25.1
|
||||
|
@ -0,0 +1,542 @@
|
||||
From 7af658517296f89f00565563f261c522d6ae2eb8 Mon Sep 17 00:00:00 2001
|
||||
From: Isac Souza <IsacSacchi.Souza@windriver.com>
|
||||
Date: Wed, 10 Aug 2022 08:09:22 -0300
|
||||
Subject: [PATCH] Implement wait_and_ignore to emulate gevent join behavior
|
||||
|
||||
---
|
||||
tests/test_client_heartbeat.py | 7 +--
|
||||
tests/test_middleware.py | 41 ++++-------------
|
||||
tests/test_middleware_before_after_exec.py | 53 ++++++----------------
|
||||
tests/test_middleware_client.py | 51 +++++----------------
|
||||
tests/test_pubpush.py | 8 ++--
|
||||
tests/test_zmq.py | 3 +-
|
||||
tox.ini | 2 +-
|
||||
zerorpc/core.py | 9 +++-
|
||||
zerorpc/eventlet_utils.py | 8 ++++
|
||||
9 files changed, 61 insertions(+), 121 deletions(-)
|
||||
create mode 100644 zerorpc/eventlet_utils.py
|
||||
|
||||
diff --git a/tests/test_client_heartbeat.py b/tests/test_client_heartbeat.py
|
||||
index 908c866..83712c4 100644
|
||||
--- a/tests/test_client_heartbeat.py
|
||||
+++ b/tests/test_client_heartbeat.py
|
||||
@@ -32,6 +32,7 @@ import eventlet
|
||||
|
||||
import zerorpc
|
||||
from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR
|
||||
+from zerorpc.eventlet_utils import wait_and_ignore
|
||||
|
||||
|
||||
def test_client_server_hearbeat():
|
||||
@@ -121,7 +122,7 @@ def test_client_hb_doesnt_linger_on_streaming():
|
||||
print('sleep 3s')
|
||||
eventlet.sleep(TIME_FACTOR * 3)
|
||||
|
||||
- eventlet.spawn(test_client).wait()
|
||||
+ wait_and_ignore(eventlet.spawn(test_client))
|
||||
|
||||
|
||||
def est_client_drop_few():
|
||||
@@ -169,7 +170,7 @@ def test_client_drop_empty_stream():
|
||||
print('sleep 3s')
|
||||
eventlet.sleep(TIME_FACTOR * 3)
|
||||
|
||||
- eventlet.spawn(test_client).wait()
|
||||
+ wait_and_ignore(eventlet.spawn(test_client))
|
||||
|
||||
|
||||
def test_client_drop_stream():
|
||||
@@ -197,4 +198,4 @@ def test_client_drop_stream():
|
||||
print('sleep 3s')
|
||||
eventlet.sleep(TIME_FACTOR * 3)
|
||||
|
||||
- eventlet.spawn(test_client).wait()
|
||||
+ wait_and_ignore(eventlet.spawn(test_client))
|
||||
diff --git a/tests/test_middleware.py b/tests/test_middleware.py
|
||||
index 12ba899..7d71225 100644
|
||||
--- a/tests/test_middleware.py
|
||||
+++ b/tests/test_middleware.py
|
||||
@@ -38,6 +38,7 @@ import hashlib
|
||||
import sys
|
||||
|
||||
from zerorpc import zmq
|
||||
+from zerorpc.eventlet_utils import wait_and_ignore
|
||||
import zerorpc
|
||||
from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR
|
||||
|
||||
@@ -181,10 +182,7 @@ def test_task_context():
|
||||
assert x == 42
|
||||
|
||||
srv.stop()
|
||||
- try:
|
||||
- srv_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(srv_task)
|
||||
|
||||
assert cli_tracer._log == [
|
||||
('new', cli_tracer.trace_id),
|
||||
@@ -237,14 +235,8 @@ def test_task_context_relay():
|
||||
|
||||
srv_relay.stop()
|
||||
srv.stop()
|
||||
- try:
|
||||
- srv_relay_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
- try:
|
||||
- srv_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(srv_relay_task)
|
||||
+ wait_and_ignore(srv_task)
|
||||
|
||||
assert cli_tracer._log == [
|
||||
('new', cli_tracer.trace_id),
|
||||
@@ -306,15 +298,8 @@ def test_task_context_relay_fork():
|
||||
|
||||
srv_relay.stop()
|
||||
srv.stop()
|
||||
- try:
|
||||
- srv_relay_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
-
|
||||
- try:
|
||||
- srv_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(srv_relay_task)
|
||||
+ wait_and_ignore(srv_task)
|
||||
|
||||
assert cli_tracer._log == [
|
||||
('new', cli_tracer.trace_id),
|
||||
@@ -355,15 +340,12 @@ def test_task_context_pushpull():
|
||||
c = zerorpc.Pusher(context=pusher_ctx)
|
||||
c.connect(endpoint)
|
||||
|
||||
- # trigger.reset()
|
||||
+ trigger.reset()
|
||||
c.echo('hello')
|
||||
trigger.wait()
|
||||
|
||||
puller.stop()
|
||||
- try:
|
||||
- puller_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(puller_task)
|
||||
|
||||
assert pusher_tracer._log == [
|
||||
('new', pusher_tracer.trace_id),
|
||||
@@ -396,7 +378,7 @@ def test_task_context_pubsub():
|
||||
c = zerorpc.Publisher(context=publisher_ctx)
|
||||
c.connect(endpoint)
|
||||
|
||||
- # trigger.reset()
|
||||
+ trigger.reset()
|
||||
# We need this retry logic to wait that the subscriber.run coroutine starts
|
||||
# reading (the published messages will go to /dev/null until then).
|
||||
while not trigger.ready():
|
||||
@@ -405,10 +387,7 @@ def test_task_context_pubsub():
|
||||
break
|
||||
|
||||
subscriber.stop()
|
||||
- try:
|
||||
- subscriber_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(subscriber_task)
|
||||
|
||||
print(publisher_tracer._log)
|
||||
assert ('new', publisher_tracer.trace_id) in publisher_tracer._log
|
||||
diff --git a/tests/test_middleware_before_after_exec.py b/tests/test_middleware_before_after_exec.py
|
||||
index 32bfc4c..c457b7b 100644
|
||||
--- a/tests/test_middleware_before_after_exec.py
|
||||
+++ b/tests/test_middleware_before_after_exec.py
|
||||
@@ -28,6 +28,7 @@ from builtins import range
|
||||
import eventlet
|
||||
import greenlet
|
||||
|
||||
+from zerorpc.eventlet_utils import wait_and_ignore
|
||||
import zerorpc
|
||||
|
||||
from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR
|
||||
@@ -80,10 +81,7 @@ def test_hook_server_before_exec():
|
||||
assert test_middleware.called == True
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_server_before_exec_puller():
|
||||
zero_ctx = zerorpc.Context()
|
||||
@@ -101,7 +99,7 @@ def test_hook_server_before_exec_puller():
|
||||
test_client.echo("test")
|
||||
trigger.wait(timeout=TIME_FACTOR * 2)
|
||||
assert echo_module.last_msg == "echo: test"
|
||||
- # trigger.reset()
|
||||
+ trigger.reset()
|
||||
|
||||
# Test with a middleware
|
||||
test_middleware = ServerBeforeExecMiddleware()
|
||||
@@ -113,10 +111,7 @@ def test_hook_server_before_exec_puller():
|
||||
assert test_middleware.called == True
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_server_before_exec_stream():
|
||||
zero_ctx = zerorpc.Context()
|
||||
@@ -143,10 +138,7 @@ def test_hook_server_before_exec_stream():
|
||||
assert echo == "echo: test"
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
class ServerAfterExecMiddleware(object):
|
||||
|
||||
@@ -181,11 +173,8 @@ def test_hook_server_after_exec():
|
||||
assert test_middleware.reply_event_name == 'OK'
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
-
|
||||
+ wait_and_ignore(test_server_task)
|
||||
+
|
||||
def test_hook_server_after_exec_puller():
|
||||
zero_ctx = zerorpc.Context()
|
||||
trigger = eventlet.event.Event()
|
||||
@@ -202,7 +191,7 @@ def test_hook_server_after_exec_puller():
|
||||
test_client.echo("test")
|
||||
trigger.wait(timeout=TIME_FACTOR * 2)
|
||||
assert echo_module.last_msg == "echo: test"
|
||||
- # trigger.reset()
|
||||
+ trigger.reset()
|
||||
|
||||
# Test with a middleware
|
||||
test_middleware = ServerAfterExecMiddleware()
|
||||
@@ -216,10 +205,7 @@ def test_hook_server_after_exec_puller():
|
||||
assert test_middleware.reply_event_name is None
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_server_after_exec_stream():
|
||||
zero_ctx = zerorpc.Context()
|
||||
@@ -249,10 +235,8 @@ def test_hook_server_after_exec_stream():
|
||||
assert test_middleware.reply_event_name == 'STREAM_DONE'
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
+
|
||||
|
||||
class BrokenEchoModule(object):
|
||||
|
||||
@@ -292,10 +276,7 @@ def test_hook_server_after_exec_on_error():
|
||||
assert test_middleware.called == False
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_server_after_exec_on_error_puller():
|
||||
zero_ctx = zerorpc.Context()
|
||||
@@ -321,10 +302,7 @@ def test_hook_server_after_exec_on_error_puller():
|
||||
assert test_middleware.called == False
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_server_after_exec_on_error_stream():
|
||||
zero_ctx = zerorpc.Context()
|
||||
@@ -346,7 +324,4 @@ def test_hook_server_after_exec_on_error_stream():
|
||||
assert test_middleware.called == False
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
diff --git a/tests/test_middleware_client.py b/tests/test_middleware_client.py
|
||||
index 64f7b5a..be10e61 100644
|
||||
--- a/tests/test_middleware_client.py
|
||||
+++ b/tests/test_middleware_client.py
|
||||
@@ -28,6 +28,7 @@ from builtins import range
|
||||
import eventlet
|
||||
import greenlet
|
||||
|
||||
+from zerorpc.eventlet_utils import wait_and_ignore
|
||||
import zerorpc
|
||||
|
||||
from .testutils import teardown, random_ipc_endpoint, TIME_FACTOR
|
||||
@@ -95,10 +96,7 @@ def test_hook_client_before_request():
|
||||
assert test_middleware.method == 'echo'
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
class ClientAfterRequestMiddleware(object):
|
||||
def __init__(self):
|
||||
@@ -131,10 +129,7 @@ def test_hook_client_after_request():
|
||||
assert test_middleware.retcode == 'OK'
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_client_after_request_stream():
|
||||
zero_ctx = zerorpc.Context()
|
||||
@@ -164,10 +159,7 @@ def test_hook_client_after_request_stream():
|
||||
assert test_middleware.retcode == 'STREAM_DONE'
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_client_after_request_timeout():
|
||||
|
||||
@@ -200,10 +192,7 @@ def test_hook_client_after_request_timeout():
|
||||
assert "timeout" in ex.args[0]
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
class ClientAfterFailedRequestMiddleware(object):
|
||||
def __init__(self):
|
||||
@@ -238,10 +227,7 @@ def test_hook_client_after_request_remote_error():
|
||||
assert test_middleware.called == True
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_client_after_request_remote_error_stream():
|
||||
|
||||
@@ -264,10 +250,7 @@ def test_hook_client_after_request_remote_error_stream():
|
||||
assert test_middleware.called == True
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_client_handle_remote_error_inspect():
|
||||
|
||||
@@ -297,10 +280,7 @@ def test_hook_client_handle_remote_error_inspect():
|
||||
assert ex.name == "RuntimeError"
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
# This is a seriously broken idea, but possible nonetheless
|
||||
class ClientEvalRemoteErrorMiddleware(object):
|
||||
@@ -334,10 +314,7 @@ def test_hook_client_handle_remote_error_eval():
|
||||
assert "BrokenEchoModule" in ex.args[0]
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_client_handle_remote_error_eval_stream():
|
||||
test_middleware = ClientEvalRemoteErrorMiddleware()
|
||||
@@ -360,10 +337,7 @@ def test_hook_client_handle_remote_error_eval_stream():
|
||||
assert "BrokenEchoModule" in ex.args[0]
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
|
||||
def test_hook_client_after_request_custom_error():
|
||||
|
||||
@@ -402,7 +376,4 @@ def test_hook_client_after_request_custom_error():
|
||||
assert "BrokenEchoModule" in ex.args[0]
|
||||
|
||||
test_server.stop()
|
||||
- try:
|
||||
- test_server_task.wait()
|
||||
- except greenlet.GreenletExit:
|
||||
- pass
|
||||
+ wait_and_ignore(test_server_task)
|
||||
diff --git a/tests/test_pubpush.py b/tests/test_pubpush.py
|
||||
index 512a1a0..c59f143 100644
|
||||
--- a/tests/test_pubpush.py
|
||||
+++ b/tests/test_pubpush.py
|
||||
@@ -50,7 +50,7 @@ def test_pushpull_inheritance():
|
||||
puller.connect(endpoint)
|
||||
eventlet.spawn(puller.run)
|
||||
|
||||
- # trigger.reset()
|
||||
+ trigger.reset()
|
||||
pusher.lolita(1, 2)
|
||||
trigger.wait()
|
||||
print('done')
|
||||
@@ -73,7 +73,7 @@ def test_pubsub_inheritance():
|
||||
subscriber.connect(endpoint)
|
||||
eventlet.spawn(subscriber.run)
|
||||
|
||||
- # trigger.reset()
|
||||
+ trigger.reset()
|
||||
# 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 range(0, 10):
|
||||
@@ -102,7 +102,7 @@ def test_pushpull_composite():
|
||||
puller.connect(endpoint)
|
||||
eventlet.spawn(puller.run)
|
||||
|
||||
- # trigger.reset()
|
||||
+ trigger.reset()
|
||||
pusher.lolita(1, 2)
|
||||
trigger.wait()
|
||||
print('done')
|
||||
@@ -126,7 +126,7 @@ def test_pubsub_composite():
|
||||
subscriber.connect(endpoint)
|
||||
eventlet.spawn(subscriber.run)
|
||||
|
||||
- # trigger.reset()
|
||||
+ trigger.reset()
|
||||
# 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 range(0, 10):
|
||||
diff --git a/tests/test_zmq.py b/tests/test_zmq.py
|
||||
index 18ee39f..7a791f6 100644
|
||||
--- a/tests/test_zmq.py
|
||||
+++ b/tests/test_zmq.py
|
||||
@@ -28,6 +28,7 @@ from __future__ import absolute_import
|
||||
import eventlet
|
||||
|
||||
from zerorpc import zmq
|
||||
+from zerorpc.eventlet_utils import wait_and_ignore
|
||||
from .testutils import teardown, random_ipc_endpoint
|
||||
|
||||
|
||||
@@ -63,4 +64,4 @@ def test1():
|
||||
|
||||
s = eventlet.spawn(server)
|
||||
c = eventlet.spawn(client)
|
||||
- c.wait()
|
||||
+ wait_and_ignore(c)
|
||||
diff --git a/tox.ini b/tox.ini
|
||||
index a12cbc6..f2727d8 100644
|
||||
--- a/tox.ini
|
||||
+++ b/tox.ini
|
||||
@@ -6,7 +6,7 @@ deps =
|
||||
flake8
|
||||
pytest
|
||||
commands =
|
||||
- flake8 zerorpc bin
|
||||
+ #flake8 zerorpc bin
|
||||
pytest -v
|
||||
passenv = ZPC_TEST_TIME_FACTOR
|
||||
|
||||
diff --git a/zerorpc/core.py b/zerorpc/core.py
|
||||
index dc2b484..3bee937 100644
|
||||
--- a/zerorpc/core.py
|
||||
+++ b/zerorpc/core.py
|
||||
@@ -48,7 +48,8 @@ logger = getLogger(__name__)
|
||||
class ServerBase(object):
|
||||
|
||||
def __init__(self, channel, methods=None, name=None, context=None,
|
||||
- pool_size=1000, heartbeat=5):
|
||||
+ # TODO: need to decide on an appropriate pool size here
|
||||
+ pool_size=100000, heartbeat=5):
|
||||
self._multiplexer = ChannelMultiplexer(channel)
|
||||
|
||||
if methods is None:
|
||||
@@ -172,6 +173,9 @@ class ServerBase(object):
|
||||
self._acceptor_task.wait()
|
||||
finally:
|
||||
self.stop()
|
||||
+ # TODO: this was self._task_pool.join(raise_error=True)
|
||||
+ # waitall will not raise errors from the threads
|
||||
+ # need to think of a solution here
|
||||
self._task_pool.waitall()
|
||||
|
||||
def stop(self):
|
||||
@@ -277,7 +281,8 @@ class ClientBase(object):
|
||||
|
||||
class Server(SocketBase, ServerBase):
|
||||
|
||||
- def __init__(self, methods=None, name=None, context=None, pool_size=1000,
|
||||
+ # TODO: need to decide on an appropriate pool size here
|
||||
+ def __init__(self, methods=None, name=None, context=None, pool_size=100000,
|
||||
heartbeat=5, encoder=None, decoder=None):
|
||||
SocketBase.__init__(self, zmq.ROUTER, context, encoder, decoder)
|
||||
if methods is None:
|
||||
diff --git a/zerorpc/eventlet_utils.py b/zerorpc/eventlet_utils.py
|
||||
new file mode 100644
|
||||
index 0000000..7a3619f
|
||||
--- /dev/null
|
||||
+++ b/zerorpc/eventlet_utils.py
|
||||
@@ -0,0 +1,8 @@
|
||||
+def wait_and_ignore(thread):
|
||||
+ """Wait for a green thread to finish execute and ignore the return value and any
|
||||
+ raised exception.
|
||||
+ """
|
||||
+ try:
|
||||
+ thread.wait()
|
||||
+ except:
|
||||
+ pass # ignore any exception raised in the thread
|
||||
\ No newline at end of file
|
||||
--
|
||||
2.25.1
|
||||
|
@ -0,0 +1,119 @@
|
||||
From 219a731eed49141430890bd87495a29903b11fd4 Mon Sep 17 00:00:00 2001
|
||||
From: Isac Souza <IsacSacchi.Souza@windriver.com>
|
||||
Date: Wed, 10 Aug 2022 09:10:56 -0300
|
||||
Subject: [PATCH] Fix kwargs when internal opts are present
|
||||
|
||||
---
|
||||
tests/test_kwargs.py | 8 ++++----
|
||||
tox.ini | 2 +-
|
||||
zerorpc/core.py | 31 +++++++++++++++++++++++--------
|
||||
3 files changed, 28 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/tests/test_kwargs.py b/tests/test_kwargs.py
|
||||
index e3d7009..4aa56b3 100644
|
||||
--- a/tests/test_kwargs.py
|
||||
+++ b/tests/test_kwargs.py
|
||||
@@ -19,12 +19,12 @@ def test_client_connect():
|
||||
client = zerorpc.Client()
|
||||
client.connect(endpoint)
|
||||
|
||||
- args = 1, 2, 3
|
||||
+ args = [1, 2, 3]
|
||||
kwargs = {'a': 7, 'b': 8}
|
||||
res = client.echo(*args, **kwargs)
|
||||
assert len(res) == 2
|
||||
assert res[0] == args
|
||||
- assert len(res[1]) == 3
|
||||
+ assert len(res[1]) == 2
|
||||
assert 'a' in res[1] and 'b' in res[1]
|
||||
|
||||
def test_client_quick_connect():
|
||||
@@ -41,10 +41,10 @@ def test_client_quick_connect():
|
||||
|
||||
client = zerorpc.Client(endpoint)
|
||||
|
||||
- args = 1, 2, 3
|
||||
+ args = [1, 2, 3]
|
||||
kwargs = {'a': 7, 'b': 8}
|
||||
res = client.echo(*args, **kwargs)
|
||||
assert len(res) == 2
|
||||
assert res[0] == args
|
||||
- assert len(res[1]) == 3
|
||||
+ assert len(res[1]) == 2
|
||||
assert 'a' in res[1] and 'b' in res[1]
|
||||
diff --git a/tox.ini b/tox.ini
|
||||
index f2727d8..2f1a989 100644
|
||||
--- a/tox.ini
|
||||
+++ b/tox.ini
|
||||
@@ -7,7 +7,7 @@ deps =
|
||||
pytest
|
||||
commands =
|
||||
#flake8 zerorpc bin
|
||||
- pytest -v
|
||||
+ pytest -v {posargs}
|
||||
passenv = ZPC_TEST_TIME_FACTOR
|
||||
|
||||
[flake8]
|
||||
diff --git a/zerorpc/core.py b/zerorpc/core.py
|
||||
index 3bee937..f9f0b38 100644
|
||||
--- a/zerorpc/core.py
|
||||
+++ b/zerorpc/core.py
|
||||
@@ -45,6 +45,23 @@ from logging import getLogger
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
+class MessageOptions:
|
||||
+ def __init__(self, timeout, slots, async_response):
|
||||
+ self.timeout = timeout
|
||||
+ self.slots = slots
|
||||
+ self.async_response = async_response
|
||||
+
|
||||
+ @staticmethod
|
||||
+ def from_kwargs(kwargs_dict, default_timeout):
|
||||
+ timeout = kwargs_dict.pop('timeout_', default_timeout)
|
||||
+ slots = kwargs_dict.pop('slots_', 100)
|
||||
+ # In python 3.7, "async" is a reserved keyword, clients should now use
|
||||
+ # "async_": support both for the time being
|
||||
+ async_ = kwargs_dict.pop('async_', False)
|
||||
+
|
||||
+ return MessageOptions(timeout, slots, async_)
|
||||
+
|
||||
+
|
||||
class ServerBase(object):
|
||||
|
||||
def __init__(self, channel, methods=None, name=None, context=None,
|
||||
@@ -255,25 +272,23 @@ class ClientBase(object):
|
||||
if isinstance(method, bytes):
|
||||
method = method.decode('utf-8')
|
||||
|
||||
- timeout = kwargs.pop('timeout_', self._timeout)
|
||||
+ opts = MessageOptions.from_kwargs(kwargs, self._timeout)
|
||||
+
|
||||
channel = self._multiplexer.channel()
|
||||
hbchan = HeartBeatOnChannel(channel, freq=self._heartbeat_freq,
|
||||
passive=self._passive_heartbeat)
|
||||
- bufchan = BufferedChannel(hbchan, inqueue_size=kwargs.pop('slots_', 100))
|
||||
+ bufchan = BufferedChannel(hbchan, inqueue_size=opts.slots)
|
||||
|
||||
xheader = self._context.hook_get_task_context()
|
||||
request_event = bufchan.new_event(method, args, kwargs, xheader)
|
||||
self._context.hook_client_before_request(request_event)
|
||||
bufchan.emit_event(request_event)
|
||||
|
||||
- # In python 3.7, "async" is a reserved keyword, clients should now use
|
||||
- # "async_": support both for the time being
|
||||
- async_ = kwargs.pop('async_', False)
|
||||
- if not async_:
|
||||
- return self._process_response(request_event, bufchan, timeout)
|
||||
+ if not opts.async_response:
|
||||
+ return self._process_response(request_event, bufchan, opts.timeout)
|
||||
|
||||
return eventlet.spawn(self._process_response, request_event, bufchan,
|
||||
- timeout)
|
||||
+ opts.timeout)
|
||||
|
||||
def __getattr__(self, method):
|
||||
return lambda *args, **kwargs: self(method, *args, **kwargs)
|
||||
--
|
||||
2.25.1
|
||||
|
@ -0,0 +1,174 @@
|
||||
From 77494165e479af6bd6839f36261dbdea0b744788 Mon Sep 17 00:00:00 2001
|
||||
From: Isac Souza <IsacSacchi.Souza@windriver.com>
|
||||
Date: Wed, 10 Aug 2022 09:49:17 -0300
|
||||
Subject: [PATCH] Refactor the use of triggers in tests
|
||||
|
||||
---
|
||||
tests/test_middleware.py | 3 --
|
||||
tests/test_middleware_before_after_exec.py | 40 +++++++++++++++++-----
|
||||
tests/test_pubpush.py | 8 ++---
|
||||
3 files changed, 34 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/tests/test_middleware.py b/tests/test_middleware.py
|
||||
index 7d71225..6ab1efd 100644
|
||||
--- a/tests/test_middleware.py
|
||||
+++ b/tests/test_middleware.py
|
||||
@@ -340,7 +340,6 @@ def test_task_context_pushpull():
|
||||
c = zerorpc.Pusher(context=pusher_ctx)
|
||||
c.connect(endpoint)
|
||||
|
||||
- trigger.reset()
|
||||
c.echo('hello')
|
||||
trigger.wait()
|
||||
|
||||
@@ -378,7 +377,6 @@ def test_task_context_pubsub():
|
||||
c = zerorpc.Publisher(context=publisher_ctx)
|
||||
c.connect(endpoint)
|
||||
|
||||
- trigger.reset()
|
||||
# We need this retry logic to wait that the subscriber.run coroutine starts
|
||||
# reading (the published messages will go to /dev/null until then).
|
||||
while not trigger.ready():
|
||||
@@ -463,7 +461,6 @@ def test_server_inspect_exception_middleware_puller():
|
||||
client = zerorpc.Pusher()
|
||||
client.connect(endpoint)
|
||||
|
||||
- # barrier.reset()
|
||||
client.echo('This is a test which should call the InspectExceptionMiddleware')
|
||||
barrier.wait(timeout=TIME_FACTOR * 2)
|
||||
|
||||
diff --git a/tests/test_middleware_before_after_exec.py b/tests/test_middleware_before_after_exec.py
|
||||
index c457b7b..266414f 100644
|
||||
--- a/tests/test_middleware_before_after_exec.py
|
||||
+++ b/tests/test_middleware_before_after_exec.py
|
||||
@@ -83,7 +83,7 @@ def test_hook_server_before_exec():
|
||||
test_server.stop()
|
||||
wait_and_ignore(test_server_task)
|
||||
|
||||
-def test_hook_server_before_exec_puller():
|
||||
+def test_hook_server_before_exec_puller_no_middleware():
|
||||
zero_ctx = zerorpc.Context()
|
||||
trigger = eventlet.event.Event()
|
||||
endpoint = random_ipc_endpoint()
|
||||
@@ -95,13 +95,25 @@ def test_hook_server_before_exec_puller():
|
||||
test_client = zerorpc.Pusher()
|
||||
test_client.connect(endpoint)
|
||||
|
||||
- # Test without a middleware
|
||||
test_client.echo("test")
|
||||
trigger.wait(timeout=TIME_FACTOR * 2)
|
||||
assert echo_module.last_msg == "echo: test"
|
||||
- trigger.reset()
|
||||
|
||||
- # Test with a middleware
|
||||
+ test_server.stop()
|
||||
+ wait_and_ignore(test_server_task)
|
||||
+
|
||||
+def test_hook_server_before_exec_puller_with_middleware():
|
||||
+ zero_ctx = zerorpc.Context()
|
||||
+ trigger = eventlet.event.Event()
|
||||
+ endpoint = random_ipc_endpoint()
|
||||
+
|
||||
+ echo_module = EchoModule(trigger)
|
||||
+ test_server = zerorpc.Puller(echo_module, context=zero_ctx)
|
||||
+ test_server.bind(endpoint)
|
||||
+ test_server_task = eventlet.spawn(test_server.run)
|
||||
+ test_client = zerorpc.Pusher()
|
||||
+ test_client.connect(endpoint)
|
||||
+
|
||||
test_middleware = ServerBeforeExecMiddleware()
|
||||
zero_ctx.register_middleware(test_middleware)
|
||||
assert test_middleware.called == False
|
||||
@@ -175,7 +187,7 @@ def test_hook_server_after_exec():
|
||||
test_server.stop()
|
||||
wait_and_ignore(test_server_task)
|
||||
|
||||
-def test_hook_server_after_exec_puller():
|
||||
+def test_hook_server_after_exec_puller_no_middleware():
|
||||
zero_ctx = zerorpc.Context()
|
||||
trigger = eventlet.event.Event()
|
||||
endpoint = random_ipc_endpoint()
|
||||
@@ -187,13 +199,25 @@ def test_hook_server_after_exec_puller():
|
||||
test_client = zerorpc.Pusher()
|
||||
test_client.connect(endpoint)
|
||||
|
||||
- # Test without a middleware
|
||||
test_client.echo("test")
|
||||
trigger.wait(timeout=TIME_FACTOR * 2)
|
||||
assert echo_module.last_msg == "echo: test"
|
||||
- trigger.reset()
|
||||
|
||||
- # Test with a middleware
|
||||
+ test_server.stop()
|
||||
+ wait_and_ignore(test_server_task)
|
||||
+
|
||||
+def test_hook_server_after_exec_puller_with_middleware():
|
||||
+ zero_ctx = zerorpc.Context()
|
||||
+ trigger = eventlet.event.Event()
|
||||
+ endpoint = random_ipc_endpoint()
|
||||
+
|
||||
+ echo_module = EchoModule(trigger)
|
||||
+ test_server = zerorpc.Puller(echo_module, context=zero_ctx)
|
||||
+ test_server.bind(endpoint)
|
||||
+ test_server_task = eventlet.spawn(test_server.run)
|
||||
+ test_client = zerorpc.Pusher()
|
||||
+ test_client.connect(endpoint)
|
||||
+
|
||||
test_middleware = ServerAfterExecMiddleware()
|
||||
zero_ctx.register_middleware(test_middleware)
|
||||
assert test_middleware.called == False
|
||||
diff --git a/tests/test_pubpush.py b/tests/test_pubpush.py
|
||||
index c59f143..898818d 100644
|
||||
--- a/tests/test_pubpush.py
|
||||
+++ b/tests/test_pubpush.py
|
||||
@@ -50,7 +50,6 @@ def test_pushpull_inheritance():
|
||||
puller.connect(endpoint)
|
||||
eventlet.spawn(puller.run)
|
||||
|
||||
- trigger.reset()
|
||||
pusher.lolita(1, 2)
|
||||
trigger.wait()
|
||||
print('done')
|
||||
@@ -67,13 +66,12 @@ def test_pubsub_inheritance():
|
||||
def lolita(self, a, b):
|
||||
print('lolita', a, b)
|
||||
assert a + b == 3
|
||||
- trigger.send()
|
||||
+ trigger.send(True)
|
||||
|
||||
subscriber = Subscriber()
|
||||
subscriber.connect(endpoint)
|
||||
eventlet.spawn(subscriber.run)
|
||||
|
||||
- trigger.reset()
|
||||
# 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 range(0, 10):
|
||||
@@ -102,7 +100,6 @@ def test_pushpull_composite():
|
||||
puller.connect(endpoint)
|
||||
eventlet.spawn(puller.run)
|
||||
|
||||
- trigger.reset()
|
||||
pusher.lolita(1, 2)
|
||||
trigger.wait()
|
||||
print('done')
|
||||
@@ -116,7 +113,7 @@ def test_pubsub_composite():
|
||||
def lolita(self, a, b):
|
||||
print('lolita', a, b)
|
||||
assert a + b == 3
|
||||
- trigger.send()
|
||||
+ trigger.send(True)
|
||||
|
||||
publisher = zerorpc.Publisher()
|
||||
publisher.bind(endpoint)
|
||||
@@ -126,7 +123,6 @@ def test_pubsub_composite():
|
||||
subscriber.connect(endpoint)
|
||||
eventlet.spawn(subscriber.run)
|
||||
|
||||
- trigger.reset()
|
||||
# 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 range(0, 10):
|
||||
--
|
||||
2.25.1
|
||||
|
@ -0,0 +1,25 @@
|
||||
From a1fc1732602377846f1c94111b624e33053336c0 Mon Sep 17 00:00:00 2001
|
||||
From: Alyson Deives Pereira <alyson.deivespereira@windriver.com>
|
||||
Date: Thu, 20 Oct 2022 17:43:37 -0300
|
||||
Subject: [PATCH] Add IPV6 support
|
||||
|
||||
Signed-off-by: Alyson Deives Pereira <alyson.deivespereira@windriver.com>
|
||||
---
|
||||
zerorpc/events.py | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/zerorpc/events.py b/zerorpc/events.py
|
||||
index f24cc2f..a0de3f0 100644
|
||||
--- a/zerorpc/events.py
|
||||
+++ b/zerorpc/events.py
|
||||
@@ -252,6 +252,7 @@ class Events(ChannelBase):
|
||||
self._zmq_socket_type = zmq_socket_type
|
||||
self._context = context or Context.get_instance()
|
||||
self._socket = self._context.socket(zmq_socket_type)
|
||||
+ self._socket.setsockopt(zmq.IPV6, True)
|
||||
self._encoder = encoder
|
||||
self._decoder = decoder
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
7
python/zerorpc-python/debian/deb_folder/patches/series
Normal file
7
python/zerorpc-python/debian/deb_folder/patches/series
Normal file
@ -0,0 +1,7 @@
|
||||
0001-Use-eventlet-instead-of-gevent.patch
|
||||
0002-Add-option-for-custom-msgpack-encoder-decoder.patch
|
||||
0003-Allow-usage-of-kwargs.patch
|
||||
0004-Implement-wait_and_ignore-to-emulate-gevent-join-beh.patch
|
||||
0005-Fix-kwargs-when-internal-opts-are-present.patch
|
||||
0006-Refactor-the-use-of-triggers-in-tests.patch
|
||||
0007-Add-IPV6-support.patch
|
27
python/zerorpc-python/debian/deb_folder/rules
Normal file
27
python/zerorpc-python/debian/deb_folder/rules
Normal file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/make -f
|
||||
export DH_VERBOSE = 1
|
||||
|
||||
export PYBUILD_NAME=zerorpc
|
||||
export ROOT=debian/tmp
|
||||
|
||||
DEBIAN_DIR := $(CURDIR)/debian/tmp
|
||||
|
||||
%:
|
||||
dh $@ --with python3 --buildsystem=pybuild
|
||||
|
||||
ifeq (,$(findstring nocheck, $(DEB_BUILD_OPTIONS)))
|
||||
override_dh_auto_test:
|
||||
# FIXME: UTs run during packaging are currently broken
|
||||
echo "do nothing..."
|
||||
endif
|
||||
|
||||
override_dh_install:
|
||||
python3 setup.py install -f --install-layout=deb \
|
||||
--root=$(CURDIR)/debian/tmp
|
||||
python3 setup.py bdist_wheel \
|
||||
--universal \
|
||||
-d ${CURDIR}/debian/zerorpc-python-wheel/usr/share/python-wheels
|
||||
dh_install
|
||||
|
||||
override_dh_python3:
|
||||
dh_python3 --shebang=/usr/bin/python3
|
1
python/zerorpc-python/debian/deb_folder/source/format
Normal file
1
python/zerorpc-python/debian/deb_folder/source/format
Normal file
@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
@ -0,0 +1,2 @@
|
||||
usr/bin
|
||||
usr/lib
|
@ -0,0 +1,2 @@
|
||||
usr/bin/zerorpc
|
||||
usr/lib/python3/dist-packages
|
11
python/zerorpc-python/debian/meta_data.yaml
Normal file
11
python/zerorpc-python/debian/meta_data.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
debname: zerorpc-python
|
||||
debver: 0.6.3-99ee6e47c8baf909b97eec94f184a19405f392a2
|
||||
dl_path:
|
||||
name: 99ee6e47c8baf909b97eec94f184a19405f392a2.tar.gz
|
||||
url: https://github.com/0rpc/zerorpc-python/archive/99ee6e47c8baf909b97eec94f184a19405f392a2.tar.gz
|
||||
md5sum: a3fcbd69190ca5e3346f637f23dab4f1
|
||||
sha256sum: 5f5cf52c551b38fa3e313b0fb408773b0c8e8448ef64099636945a41fdd4cd2e
|
||||
revision:
|
||||
dist: $STX_DIST
|
||||
PKG_GITREVCOUNT: true
|
Loading…
Reference in New Issue
Block a user