aiomas.rpc

This module implements remote procedure calls (RPC) on top of request-reply channels (see aiomas.channel).

RPC connections are represented by instances of RpcClient (one for each side of a aiomas.channel.Channel). They provide access to the functions served by the peer via Proxy instances. Optionally, they can provide their own RPC service so that the peer can make calls as well.

An RPC service is an object with a router attribute which is an instance of Router. A router resolves paths requested by the peer. It can also handle sub-routers (which allows you to build hierarchies for nested calls) and is able to perform a reverse-lookup of a router (mapping a fuction to its path).

Routers an be attached to both, classes and dictionaries with functions. Dictionaires need to be wrapped with a ServiceDict. Classes need to have a Service class attribute named router. Service is a descriptor which creates a Router for every instance of that class.

Functions that should be callable from the remote side must be decorated with expose(); Router.expose() and Service.expose() are aliases for it.

aiomas.rpc.open_connection(addr, *, rpc_service=None, **kwds)[source]

Return an RpcClient connected to addr.

This is a convenience wrapper for aiomas.channel.open_connection(). All keyword arguments (kwds) are forwared to it.

You can optionally pass a rpc_service to allow the peer to call back to us.

This function is a coroutine.

aiomas.rpc.start_server(addr, rpc_service, client_connected_cb=None, **kwds)[source]

Start a server socket on host:port and create an RPC service with the provided handler for each new client.

This is a convenience wrapper for aiomas.channel.start_server(). All keyword arguments (kwds) are forwared to it.

rpc_service must be an RPC service (an object with a router attribute that is an instance of Router).

client_connected_cb is an optional callback that will be called with with the RpcClient instance for each new connection.

Raise a ValueError if handler is not decorated properly.

This function is a coroutine.

aiomas.rpc.rpc_service_process(rpc_client, router, channel)[source]

RPC service process for a connection rpc_lient.

Serves the functions provided by the Router router via the Channel channel.

Forward errors raised by the handler to the caller.

Stop running when the connection closes.

This function is a coroutine.

aiomas.rpc.expose(func)[source]

Decorator that enables RPC access to the decorated function.

func will not be wrapped but only gain an __rpc__ attribute.

class aiomas.rpc.ServiceDict(dict=None)[source]

Wrapper for dicts so that they can be used as RPC routers.

dict = None

The wrapped dict.

router = None

The dict’s router instance.

class aiomas.rpc.Service(sub_routers=())[source]

A Data Descriptor that creates a new Router instance for each class instance to which it is set.

The attribute name for the Service should always be router:

class Spam:
    router = aiomas.rpc.Service()

You can optionally pass a list with the attribute names of classes with sub-routers. This required to build hierarchies of routers, e.g.:

class Eggs:
    router = aiomas.rpc.Service()


class Spam:
    router = aiomas.rpc.Service(['eggs'])

    def __init__(self):
        self.eggs = Eggs()  # Instance with a sub-router
static expose(func)

Alias for expose().

class aiomas.rpc.Router(obj)[source]

The Router resolves paths to functions provided by their object obj (or its children). It can also perform a reverse lookup to get the path of the router (and the router’s obj).

The obj can be a class, an instance or a dict.

obj = None

The object to which this router belongs to.

name = None

The name of the router (empty for root routers).

parent = None

The parent router or None for root routers.

path

The path to this router (without trailing slash).

resolve(path)[source]

Resolve path and return the corresponding function.

path is a string with path components separated by / (without trailing slash).

Raise a LookupError if no handler function can be found for path or if the function is not exposed (see expose()).

static expose(func)

Alias for expose().

add(name)[source]

Add the sub-router name (stored at self.obj.<name>) to this router.

Convenience wrapper for set_sub_router().

set_sub_router(router, name)[source]

Set self as parent for the router named name.

class aiomas.rpc.RpcClient(channel, rpc_service=None)[source]

The RpcClient provides proxy objects for remote calls via its remote attribute.

channel is a Channel instance for communicating with the remote side.

If rpc_service is not None, it will also start its own RPC service so the peer can call the functions we provide.

channel

The communication Channel of this instance.

service

The RPC service process for this connection.

remote

A Proxy for remote methods.

on_connection_reset(callback)[source]

Add a callback that gets called if the peer closes the connection and thus causing the service process to abort.

callback is a callable with a single argument, the exception that the service process raises if the connection is reset by the peer.

If this method is called multiple times, override the current callback with the new one. If callback is None, delete the current callback.

Raise a ValueError if callback is neither callable nor None.

Raise a RuntimeError if this instance has not service task running.

close()[source]

Coroutine that closes the connection and waits for all sub tasks to finish.

class aiomas.rpc.Proxy(channel, path)[source]

Proxy object for remote objects and functions.

__weakref__

list of weak references to the object (if defined)

__getattr__(name)[source]

Return a new proxy for name.

__call__(*args, **kwargs)[source]

Call the remote method represented by this proxy and return its result.

The result is a future, so you need to yield from it in order to get the actual return value (or exception).