Cap'n Proto serialization/RPC system - Python bindings
Find a file
Tobias Ahrens 7a4970605e Disable the use of ninja for windows builds
Aperantly github added ninja to all of there runners now. This
causes the windows build to fail. This is expected because we
add the architecture as a compiler arg which is not known to
ninja. Even with this the build fails.

This commit disables ninja on windows for now. Once we fixed the
underlying issue with ninja and windows we can reenable it.
2023-10-23 10:23:16 -07:00
.github/workflows Prepare for v2.0.0b1 release 2023-10-03 12:29:48 -07:00
_custom_build Add custom build backend to support build args (#328) 2023-10-02 22:30:51 -07:00
benchmark Fix formatting 2023-06-08 08:18:50 +02:00
buildutils Disable the use of ninja for windows builds 2023-10-23 10:23:16 -07:00
capnp Handle exceptions from server callbacks 2023-10-22 23:29:47 -07:00
docs Update documentation to async code (#331) (#332) 2023-10-16 11:05:27 -07:00
examples Experiment: Wrap all capnp code in a context-manager to avoid segfaults (#317) 2023-10-03 09:04:51 -07:00
scripts Fixed issue where pickle helpers didnt use new from_bytes with context 2022-05-24 11:38:27 +10:00
test Fixes for capnp 1.0 (#1) 2023-10-11 11:28:24 -07:00
.flake8 Applying black formatting 2021-10-01 11:12:21 -07:00
.gitignore Fixes for capnp 1.0 (#1) 2023-10-11 11:28:24 -07:00
CHANGELOG.md Fixes for capnp 1.0 (#1) 2023-10-11 11:28:24 -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 Pin cython to below version 3, Python 3.11 support (#320) 2023-07-21 01:40:49 -07:00
pyproject.toml Add custom build backend to support build args (#328) 2023-10-02 22:30:51 -07:00
README.md Update documentation to async code (#331) (#332) 2023-10-16 11:05:27 -07:00
requirements.txt Pin cython to below version 3, Python 3.11 support (#320) 2023-07-21 01:40:49 -07:00
setup.cfg Add custom build backend to support build args (#328) 2023-10-02 22:30:51 -07:00
setup.py Fixes for capnp 1.0 (#1) 2023-10-11 11:28:24 -07:00
tox.ini Prepare for v2.0.0b1 release 2023-10-03 12:29:48 -07:00

pycapnp

Packaging Status manylinux2014 Status PyPI version

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-1.0 (>=0.8.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 .

By default, the setup script will automatically use the locally installed Cap'n Proto. If Cap'n Proto is not installed, it will bundle and build the matching Cap'n Proto library.

To enforce bundling, the Cap'n Proto library:

pip install . -C force-bundled-libcapnp=True

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

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

To enforce using the installed Cap'n Proto from the system:

pip install . -C force-system-libcapnp=True

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

Stub-file generation

While not directly supported by pycapnp, a tool has been created to help generate pycapnp stubfile to assist with development (this is very helpful if you're new to pypcapnp!). See #289 for more details.

Python Capnp Stub Generator

Python Versions

Python 3.8+ is supported.

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 Python wheel distributiion

pip 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 asyncio
import capnp
import socket

import test_capability_capnp


class Server(test_capability_capnp.TestInterface.Server):

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

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


async 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 = await remote

    assert response.x == '125'

async def main():
    client_end, server_end = socket.socketpair(socket.AF_UNIX)
    # This is a toy example using socketpair.
    # In real situations, you can use any socket.

    client_end = await capnp.AsyncIoStream.create_connection(sock=client_end)
    server_end = await capnp.AsyncIoStream.create_connection(sock=server_end)

    _ = capnp.TwoPartyServer(server_end, bootstrap=Server(100))
    await client(client_end)


if __name__ == '__main__':
    asyncio.run(capnp.run(main()))