Cap'n Proto serialization/RPC system - Python bindings
Find a file
2022-12-01 21:58:30 -08:00
.github/workflows Fixing issue with m1 build (#297) 2022-09-09 22:14:23 -07:00
benchmark Fixed issue where pickle helpers didnt use new from_bytes with context 2022-05-24 11:38:27 +10:00
buildutils Update bundled bundled capnp to 0.8.1 due to CVE-2022-46149 2022-11-30 10:18:06 -08:00
capnp Avoid reading random values for reader options from dangling reference (#300) 2022-11-01 13:00:01 -07:00
docs Update documentation about from_bytes to use context manager. #287 2022-07-12 09:19:54 -07:00
examples Fixed black issues 2022-04-06 13:32:52 +10:00
scripts Fixed issue where pickle helpers didnt use new from_bytes with context 2022-05-24 11:38:27 +10:00
test Fixed linting issues 2022-05-24 11:42:53 +10:00
.flake8 Applying black formatting 2021-10-01 11:12:21 -07:00
.gitignore Updating to capnproto v0.8.0 2020-06-08 11:49:17 -07:00
CHANGELOG.md Incrementing version to v1.2.1 2022-09-11 23:08:45 -07:00
LICENSE.md Updating LICENSE file and adding to setup.cfg 2020-10-16 21:51:08 -07:00
MANIFEST.in MANIFEST.in: Add test data 2021-04-04 17:01:19 +08:00
Pipfile Updating docs for v1.0.0b2 2020-06-14 17:05:45 -07:00
pyproject.toml Add pyproject.yaml. 2020-12-16 12:21:58 -08:00
README.md Update bundled bundled capnp to 0.8.1 due to CVE-2022-46149 2022-11-30 10:18:06 -08:00
requirements.txt Updating docs for v1.0.0b2 2020-06-14 17:05:45 -07:00
setup.cfg Updating LICENSE file and adding to setup.cfg 2020-10-16 21:51:08 -07:00
setup.py Update to v1.2.2 2022-12-01 21:58:30 -08:00
tox.ini Incrementing version to v1.1.1 2022-05-23 21:39:51 -07:00

pycapnp

Packaging Status manylinux2010 Status PyPI version Total alerts Language grade: Python Language grade: C/C++

Cap'n'proto Mailing List Documentation

Requirements

  • C++14 supported compiler
    • gcc 6.1+ (5+ may work)
    • clang 6 (3.4+ may work)
    • Visual Studio 2017+
  • cmake (needed for bundled capnproto)
    • ninja (macOS + Linux)
    • Visual Studio 2017+
  • capnproto-0.8.0 (>=0.7.0 will also work if linking to system libraries)
    • Not necessary if using bundled capnproto
  • Python development headers (i.e. Python.h)
    • Distributables from python.org include these, however they are usually in a separate package on Linux distributions

32-bit Linux requires that capnproto be compiled with -fPIC. This is usually set correctly unless you are compiling canproto yourself. This is also called -DCMAKE_POSITION_INDEPENDENT_CODE=1 for cmake.

pycapnp has additional development dependencies, including cython and pytest. See requirements.txt for them all.

Building and installation

Install with pip install pycapnp. You can set the CC environment variable to control which compiler is used, ie CC=gcc-8.2 pip install pycapnp.

Or you can clone the repo like so:

git clone https://github.com/capnproto/pycapnp.git
cd pycapnp
pip install .

If you wish to install using the latest upstream C++ Cap'n Proto:

pip install \
    --install-option "--libcapnp-url" \
    --install-option "https://github.com/capnproto/capnproto/archive/master.tar.gz" \
    --install-option "--force-bundled-libcapnp" .

To force bundled python:

pip install --install-option "--force-bundled-libcapnp" .

Slightly more prompt error messages using distutils rather than pip.

python setup.py install --force-bundled-libcapnp

The bundling system isn't that smart so it might be necessary to clean up the bundled build when changing versions:

python setup.py clean

Python Versions

Python 3.7+ is supported. Earlier versions of Python have asyncio bugs that might be possible to work around, but may require significant work (3.5 and 3.6).

Development

Git flow has been abandoned, use master.

To test, use a pipenv (or install requirements.txt and run pytest manually).

pip install pipenv
pipenv install
pipenv run pytest

Binary Packages

Building a dumb binary distribution:

python setup.py bdist_dumb

Building a Python wheel distributiion:

python setup.py bdist_wheel

Documentation/Example

There is some basic documentation here.

Make sure to look at the examples. The examples are generally kept up to date with the recommended usage of the library.

The examples directory has one example that shows off pycapnp quite nicely. Here it is, reproduced:

import os
import capnp

import addressbook_capnp

def writeAddressBook(file):
    addresses = addressbook_capnp.AddressBook.new_message()
    people = addresses.init('people', 2)

    alice = people[0]
    alice.id = 123
    alice.name = 'Alice'
    alice.email = 'alice@example.com'
    alicePhones = alice.init('phones', 1)
    alicePhones[0].number = "555-1212"
    alicePhones[0].type = 'mobile'
    alice.employment.school = "MIT"

    bob = people[1]
    bob.id = 456
    bob.name = 'Bob'
    bob.email = 'bob@example.com'
    bobPhones = bob.init('phones', 2)
    bobPhones[0].number = "555-4567"
    bobPhones[0].type = 'home'
    bobPhones[1].number = "555-7654"
    bobPhones[1].type = 'work'
    bob.employment.unemployed = None

    addresses.write(file)


def printAddressBook(file):
    addresses = addressbook_capnp.AddressBook.read(file)

    for person in addresses.people:
        print(person.name, ':', person.email)
        for phone in person.phones:
            print(phone.type, ':', phone.number)

        which = person.employment.which()
        print(which)

        if which == 'unemployed':
            print('unemployed')
        elif which == 'employer':
            print('employer:', person.employment.employer)
        elif which == 'school':
            print('student at:', person.employment.school)
        elif which == 'selfEmployed':
            print('self employed')
        print()


if __name__ == '__main__':
    f = open('example', 'w')
    writeAddressBook(f)

    f = open('example', 'r')
    printAddressBook(f)

Also, pycapnp has gained RPC features that include pipelining and a promise style API. Refer to the calculator example in the examples directory for a much better demonstration:

import capnp
import socket

import test_capability_capnp


class Server(test_capability_capnp.TestInterface.Server):

    def __init__(self, val=1):
        self.val = val

    def foo(self, i, j, **kwargs):
        return str(i * 5 + self.val)


def server(write_end):
    server = capnp.TwoPartyServer(write_end, bootstrap=Server(100))


def client(read_end):
    client = capnp.TwoPartyClient(read_end)

    cap = client.bootstrap()
    cap = cap.cast_as(test_capability_capnp.TestInterface)

    remote = cap.foo(i=5)
    response = remote.wait()

    assert response.x == '125'


if __name__ == '__main__':
    read_end, write_end = socket.socketpair(socket.AF_UNIX)
    # This is a toy example using socketpair.
    # In real situations, you can use any socket.

    server(write_end)
    client(read_end)