* Use cibuildwheel in ci `cibuildwheel` is a system that automatically compiles and repairs wheels for many python versions and architectures at once. This has some advantages vs the old situation: - Macosx wheels had inconsistent minimum versions ranging between 10.9 and 11.0. I'm not sure why this happens, but for some users this means they have to build from source on macosx. With cibuildwheel, the build is consistent, with 10.9 as the minimum for x86 and 11.0 for arm64. - Consolidation between the packaging tests and manylinux tests. - Addition of musllinux targets and additional cross-compilation to ppc64le and s390x. - With cibuildwheel, new python versions should be automatically picked up. - Separation of the sdist build and lint checks. There is not reason to run that many times. All possible build targets succeed, except for ARM64 on Windows. The upstream capnp build fails. I've disabled it. The cross-compilation builds on linux are pretty slow. This could potentially be sped up by separating the builds of manylinux and musllinux, but I'm not sure if it's worth the extra complexity. (One can also contemplate disabling these targets.) Tests for macosx arm64 cannot be run (but also couldn't be run in the previous system. This should be remedied once apple silicon becomes available on the CI. I've also added some commented-out code that can automatically take care of uploading a build to PyPi when a release is created. One might contemplate using this. * Set CMAKE_OSX_ARCHITECTURES for arm64 and disable universal2
pycapnp
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.10 (>=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.
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)