Skip to main content

Sparrow RPC

Sparrow PRC is a language independent, lightweight Event Based Multi-Transport Peer-to-Peer bidirectional RPC System and Protocol Engine.

The purpose of Sparrow is to not just be a RPC system, but to also be a high level api for the creation of sophisticated protocols without worrying about 'bytes on the wire'.

Core Features

  • Transport Agnostic including TCP sockets, Websockets, Stdin/Stdout and Unix Domain Sockets.
  • Serialisation Agnostic. Currently supports Json, MessagePack and CBOR out of the box.
  • Fully Peer-to-Peer - both sides of any connection are equal.
  • RPC requests can flow both directions, and can be interleaved with each other.
  • RPC calls support multipart responses (ie, can return an iterable).
  • RPC calls can include remote callbacks.
  • Pub / Sub style of calls is also supported.
  • Low network overhead when paired with a compact serialisation library like MessagePack or CBOR.
  • Efficient binary data transfer even when using a serialisation library that does not support binary data.

Platforms

The Python version of Sparrow RPC runs on Python 3.8+, including PyPy and GraalPy. It also runs on MicroPython (currently only tested on the unix port of MicroPython) and under PyScript.

Status

Sparrow RPC is in heavy development and is currently ALPHA.

Most of the core features are done but expect breaking changes at this stage, and a lot of error handling is not yet in place.

Example usages

Keeping in mind that both sides can export functions, with the only difference being that one side listens for incoming connections and the other side initiates the connection, here we refer to the 'listening' side as the 'server' and the initating side as the 'client'.

Server code:

#!/usr/bin/env python3

from random import randint
from time import sleep
from typing import Iterator

from sparrowrpc import export
from sparrowrpc.engine import ProtocolEngine
from sparrowrpc.threaded import ThreadedDispatcher, ThreadedCallbackProxy
from sparrowrpc.threaded.transports import ThreadedTcpListener


@export
def hello_world(name: str = 'world'):
    return f'Hello {name}!'


@export
def demo_progress_update(data: list, progress: ThreadedCallbackProxy):
    progress.set_to_notification()
    item_count = 0
    for item in data:
        time_to_process = randint(5, 20) / 10
        sleep(time_to_process)  # do some work
        progress(message=f'Processed item {item} in {time_to_process} seconds.')
        item_count += 1
    return f'Processed {item_count} items'


@export(multipart_response=True)
def demo_multipart_response(up_to: int):
    for x in range(1, up_to + 1):
        yield (x, x**2 + 1)


@export
def demo_multipart_param(data: Iterator[int]):
    total = 0
    for x in data:
        total += x
    return total


def main():
    engine = ProtocolEngine()
    dispatcher = ThreadedDispatcher(num_threads=5)
    print('Running tcp server on 5000')
    tcp_server = ThreadedTcpListener(engine, dispatcher)
    tcp_server.run_server('0.0.0.0', 5000)
    dispatcher.shutdown()


if __name__ == '__main__':
    main()

Client side, run in the python REPL, you have:

from sparrowrpc.engine import ProtocolEngine
from sparrowrpc.threaded import ThreadedDispatcher
from sparrowrpc.threaded.transports import ThreadedTcpConnector


def show_progress(message):
    print(message)


engine = ProtocolEngine()
dispatcher = ThreadedDispatcher(num_threads=5)
connector = ThreadedTcpConnector(engine, dispatcher)
channel = connector.connect('127.0.0.1', 5000)
channel.start_channel()

result = channel.request(namespace='#sys').ping()
print(result)
# result = 'pong'

result = channel.request.hello_world()
print(result)
# result = 'Hello world!'

result = channel.request.hello_world(name='Bill')
print(result)
# result = 'Hello Bill!'

data = ['apple', 'pear', 'banana']
result = channel.request.demo_progress_update(data=data, progress=show_progress)
# displays:
# Processed item apple in 1.7 seconds.
# Processed item pear in 1.0 seconds.
# Processed item banana in 0.8 seconds.
print(result)
# result = 'Processed 3 items'

result = list()
for x in channel.request(multipart_response=True).demo_multipart_response(up_to=10):
    result.append(x)
print(result)
# result = [[1, 2], [2, 5], [3, 10], [4, 17], [5, 26], [6, 37], [7, 50], [8, 65], [9, 82], [10, 101]]

print('Iterable param (IterableCallback) - Pull')
iter_data = iter([1, 10, 30, 3])
result = channel.request.demo_multipart_param(data=iter_data)
print(result)
# result = 44

channel.shutdown_channel()
dispatcher.shutdown()

Metadata

Release files for sparrowrpc 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sparrowrpc 0.1.2
File Size Uploaded Provenance
sparrowrpc-0.1.2.tar.gz 57.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for sparrowrpc 0.1.2
File Interpreter ABI Platform
sparrowrpc-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 117.8 kB

Release files / sparrowrpc-0.1.2.tar.gz

Download URL sparrowrpc-0.1.2.tar.gz
Size 57.0 kB
Tags Source
SHA-256 checksum
How to use checksums
d6e9dc0c8f23c5a435f9114a6cf4a30c874cb6b4485119da886f3b87d74b36a1
BLAKE2b-256 checksum
How to use checksums
8974dcd0334ef71fb0c232e5912be76d9d598fdbcab9d9098b6a1bab07910abf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / sparrowrpc-0.1.2-py3-none-any.whl

Download URL sparrowrpc-0.1.2-py3-none-any.whl
Size 60.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
821407c8b5c3b1fef2f084ea6d34633355a471668bbc867fdfea0aab78cc9450
BLAKE2b-256 checksum
How to use checksums
4d48909fb7534fff20071ecba8f04f5628570baeda46b5c921592afa49c1bcb6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Security for sparrowrpc 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page