Dispatching

Dispatching in tinyrpc is very similiar to url-routing in web frameworks. Functions are registered with a specific name and made public, i.e. callable, to remote clients.

Examples

Exposing a few functions:

from tinyrpc.dispatch import RPCDispatcher

dispatch = RPCDispatcher()

@dispatch.public
def foo():
    # ...

@dispatch.public
def bar(arg):
    # ...

# later on, assuming we know we want to call foo(*args, **kwargs):

f = dispatch.get_method('foo')
f(*args, **kwargs)

Using prefixes and instance registration:

from tinyrpc.dispatch import public

class SomeWebsite(object):
    def __init__(self, ...):
        # note: this method will not be exposed

    def secret(self):
        # another unexposed method

    @public
    def get_user_info(self, user):
        # ...

    # using a different name
    @public('get_user_comment')
    def get_comment(self, comment_id):
        # ...

The code above declares an RPC interface for SomeWebsite objects, consisting of two visible methods: get_user_info(user) and get_user_comment(commend_id).

These can be used with a dispatcher now:

def hello():
    # ...

website1 = SomeWebsite(...)
website2 = SomeWebsite(...)

from tinyrpc.dispatch import RPCDispatcher

dispatcher = RPCDispatcher()

# directly register version method
@dispatcher.public
def version():
    # ...

# add earlier defined method
dispatcher.add_method(hello)

# register the two website instances
dispatcher.register_instance(website1, 'sitea.')
dispatcher.register_instance(website2, 'siteb.')

In the example above, the RPCDispatcher now knows a total of six registered methods: version, hello, sitea.get_user_info, sitea.get_user_comment, siteb.get_user_info, siteb.get_user_comment.

Automatic dispatching

When writing a server application, a higher level dispatching method is available with dispatch():

from tinyrpc.dispatch import RPCDispatcher

dispatcher = RPCDispatcher()

# register methods like in the examples above
# ...
# now assumes that a valid RPCRequest has been obtained, as `request`

response = dispatcher.dispatch(request)

# response can be directly processed back to the client, all Exceptions have
# been handled already

API reference

class tinyrpc.dispatch.RPCDispatcher

Bases: object

Stores name-to-method mappings.

public(name=None)

Convenient decorator.

Allows easy registering of functions to this dispatcher. Example:

dispatch = RPCDispatcher()

@dispatch.public
def foo(bar):
    # ...

class Baz(object):
    def not_exposed(self):
        # ...

    @dispatch.public(name='do_something')
    def visible_method(arg1)
        # ...
Parameters

name (str) – Name to register callable with.

add_subdispatch(dispatcher, prefix='')

Adds a subdispatcher, possibly in its own namespace.

Parameters
  • dispatcher (RPCDispatcher) – The dispatcher to add as a subdispatcher.

  • prefix (str) – A prefix. All of the new subdispatchers methods will be available as prefix + their original name.

add_method(f, name=None)

Add a method to the dispatcher.

Parameters
  • f (callable) – Callable to be added.

  • name (str) – Name to register it with. If None, f.__name__ will be used.

Raises

RPCError – When the name is already registered.

get_method(name)

Retrieve a previously registered method.

Checks if a method matching name has been registered.

If get_method() cannot find a method, every subdispatcher with a prefix matching the method name is checked as well.

Parameters

name (str) – Function to find.

Returns

The callable implementing the function.

Return type

callable

Raises

MethodNotFoundError

register_instance(obj, prefix='')

Create new subdispatcher and register all public object methods on it.

To be used in conjunction with the public() decorator (not RPCDispatcher.public()).

Parameters
  • obj (object) – The object whose public methods should be made available.

  • prefix (str) – A prefix for the new subdispatcher.

dispatch(request)

Fully handle request.

The dispatch method determines which method to call, calls it and returns a response containing a result.

No exceptions will be thrown, rather, every exception will be turned into a response using error_respond().

If a method isn’t found, a MethodNotFoundError response will be returned. If any error occurs outside of the requested method, a ServerError without any error information will be returend.

If the method is found and called but throws an exception, the exception thrown is used as a response instead. This is the only case in which information from the exception is possibly propagated back to the client, as the exception is part of the requested method.

RPCBatchRequest instances are handled by handling all its children in order and collecting the results, then returning an RPCBatchResponse with the results.

Parameters

request (RPCRequest) – The request containing the function to be called and its parameters.

Returns

The result produced by calling the requested function.

Return type

RPCResponse

Raises
  • MethodNotFoundError – If the requested function is not published.

  • ServerError – If some other error occurred.

Note

The ServerError is raised for any kind of exception not raised by the called function itself or MethodNotFoundError.

validate_parameters(method, args, kwargs)

Verify that *args and **kwargs are appropriate parameters for method.

Parameters
  • method – A callable.

  • args – List of positional arguments for method

  • kwargs – Keyword arguments for method

Raises

InvalidParamsError – Raised when the provided arguments are not acceptable for method.

validator(method, args, kwargs)

Dispatched function parameter validatation.

Type

callable

By default this attribute is set to validate_parameters(). The value can be set to any callable implementing the same interface as validate_parameters() or to None to disable validation entirely.

Classes can be made to support an RPC interface without coupling it to a dispatcher using a decorator:

tinyrpc.dispatch.public(name=None)

Decorator. Mark a method as eligible for registration by a dispatcher.

The dispatchers register_instance() function will do the actual registration of the marked method.

The difference with public() is that this decorator does not register with a dispatcher, therefore binding the marked methods with a dispatcher is delayed until runtime. It also becomes possible to bind with multiple dispatchers.

Parameters

name (str or None) – The name to register the function with.

Example:

def class Baz(object):
    def not_exposed(self);
        # ...

    @public('do_something')
    def visible_method(arg1):
        # ...

baz = Baz()
dispatch = RPCDispatcher()
dispatch.register_instance(baz, 'bazzies`)
# Baz.visible_method is now callable via RPC as bazzies.do_something

@public is a shortcut for @public().