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.
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
consisting of two visible methods:
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:
When writing a server application, a higher level dispatching method is
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
Class, static and unbound method dispatching¶
Although you will only rarely use these method types they do work and here we show you how.
Class methods do not have self as the initial parameter but rather a reference to their class. You may want to use such methods to instantiate class instances.
class ShowClassMethod: @classmethod @public def func(cls, a, b): return a-b
Note the ordering of the decorators. Ordering them differently will not work. You call dispatch to the func method just as you would dispatch to any other method.
Static methods have neither a class nor instance reference as first parameter:
class ShowStaticMethod: @staticmethod @public def func(a, b): return a-b
Again the ordering of the decorators is critical and you dispatch them as any other method.
Finally it is possible to dispatch to unbound methods but I strongly advise against it. If you really want to do that see the tests to learn how. Everyone else should use static methods instead.
Stores name-to-method mappings.
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: tinyrpc.dispatch.RPCDispatcher, prefix: str = '')¶
Adds a subdispatcher, possibly in its own namespace.
add_method(f: Callable, name: str = None) → None¶
Add a method to the dispatcher.
- f (callable) – Callable to be added.
- name (str) – Name to register it with. If
f.__name__will be used.
RPCError – When the name is already registered.
get_method(name: str) → Callable¶
Retrieve a previously registered method.
Checks if a method matching
namehas been registered.
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:
register_instance(obj: object, prefix: str = '') → None¶
Create new subdispatcher and register all public object methods on it.
dispatch(request: Union[tinyrpc.protocols.RPCRequest, tinyrpc.protocols.RPCBatchRequest], caller: Callable = None) → Union[tinyrpc.protocols.RPCResponse, tinyrpc.protocols.RPCBatchResponse]¶
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
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.
RPCBatchRequestinstances are handled by handling all its children in order and collecting the results, then returning an
RPCBatchResponsewith the results.
The result produced by calling the requested function.
Return type: Raises:
validate_parameters(method: Callable, args: List[Any], kwargs: Dict[str, Any]) → None¶
Verify that *args and **kwargs are appropriate parameters for method.
This function has changed to a static function. This will make it easier to replace it with a regular function instead of having to subclass only to replace it.
- method – A callable.
- args – List of positional arguments for method
- kwargs – Keyword arguments for method
InvalidParamsError – Raised when the provided arguments are not acceptable for method.
validator(method: Callable, args: List[Any], kwargs: Dict[str, Any]) → None¶
Dispatched function parameter validation.
Classes can be made to support an RPC interface without coupling it to a dispatcher using a decorator:
Decorator. Mark a method as eligible for registration by a dispatcher.
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 – The name to register the function with.
def class Baz(object): def not_exposed(self); # ... @public('do_something') def visible_method(self, arg1): # ... baz = Baz() dispatch = RPCDispatcher() dispatch.register_instance(baz, 'bazzies`) # Baz.visible_method is now callable via RPC as bazzies.do_something('hello')
@publicis a shortcut for