The protocol layer
Interface definition
All protocols are implemented by deriving from RPCProtocol
and implementing all of its members.
Every protocol deals with multiple kinds of structures: data
arguments are
always byte strings, either messages or replies, that are sent via or received
from a transport.
Protocol-specific subclasses of RPCRequest
and
RPCResponse
represent well-formed requests and responses.
Protocol specific subclasses of RPCErrorResponse
represent
errors and error responses.
Finally, if an error occurs during parsing of a request, a
BadRequestError
instance must be thrown. These need to be
subclassed for each protocol as well, since they generate error replies.
API Reference
- class tinyrpc.protocols.RPCProtocol
Bases:
ABC
Abstract base class for all protocol implementations.
- supports_out_of_order = False
If true, this protocol can receive responses out of order correctly.
Note that this usually depends on the generation of unique_ids, the generation of these may or may not be thread safe, depending on the protocol. Ideally, only one instance of RPCProtocol should be used per client.
- Type:
- raises_errors = True
If True, this protocol instance will raise an RPCError exception.
On receipt of an RPCErrorResponse instance an RPCError exception is raised. When this flag is False the RPCErrorResponse object is returned to the caller which is then responsible for handling the error.
- Type:
- create_request(method: str, args: List[Any] = None, kwargs: Dict[str, Any] = None, one_way: bool = False) RPCRequest
Creates a new
RPCRequest
object.Called by the client when constructing a request. It is up to the implementing protocol whether or not
args
,kwargs
, one of these, both at once or none of them are supported.- Parameters:
- Returns:
A new request instance
- Return type:
- parse_request(data: bytes) RPCRequest
De-serializes and validates a request.
Called by the server to reconstruct the serialized
RPCRequest
.- Parameters:
data (bytes) – The data stream received by the transport layer containing the serialized request.
- Returns:
A reconstructed request.
- Return type:
- parse_reply(data: bytes) RPCResponse
De-serializes and validates a response.
Called by the client to reconstruct the serialized
RPCResponse
.- Parameters:
data (bytes) – The data stream received by the transport layer containing the serialized response.
- Returns:
A reconstructed response.
- Return type:
- raise_error(error: RPCErrorResponse) RPCError
Raises the exception in the client.
Called by the client to convert the
RPCErrorResponse
into an Exception and raise or return it depending on theraises_errors
attribute.- Parameters:
error (
RPCResponse
) – The error response received from the server.- Return type:
RPCError
whenraises_errors
is False.- Raises:
RPCError
whenraises_errors
is True.
- class tinyrpc.protocols.RPCRequest
Bases:
object
Defines a generic RPC request.
- unique_id
Correlation ID used to match request and response.
Protocol specific, may or may not be set. This value should only be set by
create_request()
.When the protocol permits it this ID allows servers to respond to requests out of order and allows clients to relate a response to the corresponding request.
Only supported if the protocol has its
supports_out_of_order
set toTrue
.Generated by the client, the server copies it from request to corresponding response.
- method
The name of the RPC function to be called.
- Type:
The
method
attribute uses the name of the function as it is known by the public. TheRPCDispatcher
allows the use of public aliases in the@public
decorators. These are the names used in themethod
attribute.
- args
The positional arguments of the method call.
- Type:
The contents of this list are the positional parameters for the
method
called. It is eventually called asmethod(*args)
.
- kwargs
The keyword arguments of the method call.
- Type:
The contents of this dict are the keyword parameters for the
method
called. It is eventually called asmethod(**kwargs)
.
- error_respond(error: Union[Exception, str]) Optional[RPCErrorResponse]
Creates an error response.
Create a response indicating that the request was parsed correctly, but an error has occurred trying to fulfill it.
This is an abstract method that must be overridden in a derived class.
- respond(result: Any) Optional[RPCResponse]
Create a response.
Call this to return the result of a successful method invocation.
This creates and returns an instance of a protocol-specific subclass of
RPCResponse
.This is an abstract method that must be overridden in a derived class.
- Parameters:
result (Any type that can be serialized by the protocol.) – Passed on to new response instance.
- Returns:
A response or
None
to indicate this request does not expect a response.- Return type:
- class tinyrpc.protocols.RPCResponse
Bases:
ABC
Defines a generic RPC response.
Base class for all responses.
- result
When present this attribute contains the result of the RPC call. Otherwise the
error
attribute must be defined.- Type:
Any type that can be serialized by the protocol.
- class tinyrpc.protocols.RPCErrorResponse
Bases:
RPCResponse
,ABC
RPC error response class.
Base class for all deriving responses.
Batch protocols
Some protocols may support batch requests. In this case, they need to derive
from RPCBatchProtocol
.
Batch protocols differ in that their
parse_request()
method may return an instance of
RPCBatchRequest
. They also possess an addional method in
create_batch_request()
.
Handling a batch request is slightly different, while it supports
error_respond()
, to make actual responses,
create_batch_response()
needs to be used.
No assumptions are made whether or not it is okay for batch requests to be handled in parallel. This is up to the server/dispatch implementation, which must be chosen appropriately.
API Reference
- class tinyrpc.protocols.RPCBatchProtocol
Bases:
RPCProtocol
,ABC
Abstract base class for all batch protocol implementations.
- create_batch_request(requests: List[RPCRequest] = None) RPCBatchRequest
Create a new
RPCBatchRequest
object.Called by the client when constructing a request.
- Parameters:
requests (
list
orRPCRequest
) – A list of requests.- Returns:
A new request instance.
- Return type:
- class tinyrpc.protocols.RPCBatchRequest(iterable=(), /)
Bases:
list
Multiple requests batched together.
Protocols that support multiple requests in a single message use this to group them together. Note that not all protocols may support batch requests.
Handling a batch requests is done in any order, responses must be gathered in a batch response and be in the same order as their respective requests.
Any item of a batch request is either an
RPCRequest
or anBadRequestError
, which indicates that there has been an error in parsing the request.- create_batch_response() Optional[RPCBatchResponse]
Creates a response suitable for responding to this request.
This is an abstract method that must be overridden in a derived class.
- Returns:
An
RPCBatchResponse
or None if no response is expected.- Return type:
- class tinyrpc.protocols.RPCBatchResponse(iterable=(), /)
Bases:
list
Multiple response from a batch request. See
RPCBatchRequest
on how to handle.Items in a batch response need to be
RPCResponse
instances or None, meaning no reply should generated for the request.
ID Generators
By default, the JSONRPCProtocol
and MSGPACKRPCProtocol
classes
generates ids as sequential integers starting at 1.
If alternative id generation is needed, you may supply your own
generator.
Example
The following example shows how to use alternative id generators in a protocol that supports them.
from tinyrpc.protocols.jsonrpc import JSONRPCProtocol
def collatz_generator():
"""A sample generator for demonstration purposes ONLY."""
n = 27
while True:
if n % 2 != 0:
n = 3*n + 1
else:
n = n / 2
yield n
rpc = JSONRPCProtocol(id_generator=collatz_generator())
Supported protocols
Any supported protocol is used by instantiating its class and calling the
interface of RPCProtocol
. Note that constructors
are not part of the interface, any protocol may have specific arguments for its
instances.
Protocols usually live in their own module because they may need to import
optional modules that needn’t be a dependency for all of tinyrpc
.