/usr/lib/python3/dist-packages/tinyrpc/client.py is in python3-tinyrpc 0.6-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | #!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from collections import namedtuple
from .exc import RPCError
RPCCall = namedtuple('RPCCall', 'method args kwargs')
"""Defines the elements of a RPC call.
RPCCall is used with :py:meth:`~tinyrpc.client.RPCClient.call_all`
to provide the list of requests to be processed. Each request contains the
elements defined in this tuple.
"""
RPCCallTo = namedtuple('RPCCallTo', 'transport method args kwargs')
"""Defines the elements of a RPC call directed to multiple transports.
RPCCallTo is used with :py:meth:`~tinyrpc.client.RPCClient.call_all`
to provide the list of requests to be processed.
"""
class RPCClient(object):
"""Client for making RPC calls to connected servers.
:param protocol: An :py:class:`~tinyrpc.RPCProtocol` instance.
:param transport: A :py:class:`~tinyrpc.transports.ClientTransport`
instance.
"""
def __init__(self, protocol, transport):
self.protocol = protocol
self.transport = transport
def _send_and_handle_reply(self, req, one_way, transport=None, no_exception=False):
tport = self.transport if transport is None else transport
# sends ...
reply = tport.send_message(req.serialize())
if one_way:
# ... and be done
return
# ... or process the reply
response = self.protocol.parse_reply(reply)
if not no_exception and hasattr(response, 'error'):
raise RPCError('Error calling remote procedure: %s' %\
response.error)
return response
def call(self, method, args, kwargs, one_way=False):
"""Calls the requested method and returns the result.
If an error occured, an :py:class:`~tinyrpc.exc.RPCError` instance
is raised.
:param method: Name of the method to call.
:param args: Arguments to pass to the method.
:param kwargs: Keyword arguments to pass to the method.
:param one_way: Whether or not a reply is desired.
"""
req = self.protocol.create_request(method, args, kwargs, one_way)
rep = self._send_and_handle_reply(req, one_way)
if one_way:
return
return rep.result
def call_all(self, requests):
"""Calls the methods in the request in parallel.
When the :py:mod:`gevent` module is already loaded it is assumed to be
correctly initialized, including monkey patching if necessary.
In that case the RPC calls defined by ``requests`` is performed in
parallel otherwise the methods are called sequentially.
:param requests: A listof either RPCCall or RPCCallTo elements.
When RPCCallTo is used each element defines a transport.
Otherwise the default transport set when RPCClient is
created is used.
:return: A list with replies matching the order of the requests.
"""
threads = []
if 'gevent' in sys.modules:
# assume that gevent is available and functional, make calls in parallel
import gevent
for r in requests:
req = self.protocol.create_request(r.method, r.args, r.kwargs)
tr = r.transport.transport if len(r) == 4 else None
threads.append(gevent.spawn(self._send_and_handle_reply, req, False, tr, True))
gevent.joinall(threads)
return [t.value for t in threads]
else:
# call serially
for r in requests:
req = self.protocol.create_request(r.method, r.args, r.kwargs)
tr = r.transport.transport if len(r) == 4 else None
threads.append(self._send_and_handle_reply(req, False, tr, True))
return threads
def get_proxy(self, prefix='', one_way=False):
"""Convenience method for creating a proxy.
:param prefix: Passed on to :py:class:`~tinyrpc.client.RPCProxy`.
:param one_way: Passed on to :py:class:`~tinyrpc.client.RPCProxy`.
:return: :py:class:`~tinyrpc.client.RPCProxy` instance."""
return RPCProxy(self, prefix, one_way)
def batch_call(self, calls):
"""Experimental, use at your own peril."""
req = self.protocol.create_batch_request()
for call_args in calls:
req.append(self.protocol.create_request(*call_args))
return self._send_and_handle_reply(req)
class RPCProxy(object):
"""Create a new remote proxy object.
Proxies allow calling of methods through a simpler interface. See the
documentation for an example.
:param client: An :py:class:`~tinyrpc.client.RPCClient` instance.
:param prefix: Prefix to prepend to every method name.
:param one_way: Passed to every call of
:py:func:`~tinyrpc.client.call`.
"""
def __init__(self, client, prefix='', one_way=False):
self.client = client
self.prefix = prefix
self.one_way = one_way
def __getattr__(self, name):
"""Returns a proxy function that, when called, will call a function
name ``name`` on the client associated with the proxy.
"""
proxy_func = lambda *args, **kwargs: self.client.call(
self.prefix + name,
args,
kwargs,
one_way=self.one_way
)
return proxy_func
|