# pycapnp

More thorough docs are available at [http://jparyani.github.io/pycapnp/](http://jparyani.github.io/pycapnp/).

## Requirements

pycapnp's distribution has no requirements beyond a C++11 compatible compiler. GCC 4.8+ or Clang 3.3+ should work fine.

pycapnp has additional development dependencies, including cython and py.test. 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-4.8 pip install pycapnp`.

Or you can clone the repo like so:

    git clone https://github.com/jparyani/pycapnp.git
    pip install --install-option '--force-cython' ./pycapnp

Note: for OSX, if using clang from Xcode 5, you may need to set `CFLAGS` like so:

    CFLAGS='-stdlib=libc++' pip install pycapnp

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

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


## Python Versions

Python 2.6/2.7 are supported as well as Python 3.2+. PyPy 2.1+ is also supported.

One oddity to note is that `Text` type fields will be treated as byte strings under Python 2, and unicode strings under Python 3. `Data` fields will always be treated as byte strings.

## Development

This project uses [git-flow](http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/). Essentially, just make sure you do your changes in the `develop` branch. You can run the tests by installing pytest with `pip install pytest`, and then run `py.test` from the `test` directory.

### Binary Packages

Building a dumb binary distribution:

    python setup.py bdist_dumb

Building a Python wheel distributiion:

    python setup.py bdist_wheel

If it fails with an error like `clang: error: no such file or directory: 'capnp/lib/capnp.cpp'`, then you need to cythonize fist. This can be done with:

    python setup.py build --force-cython

## Documentation/Example
There is some basic documentation [here](http://jparyani.github.io/pycapnp/).

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

```python
from __future__ import print_function
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:

```python
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)
```

## Common Problems

If you get an error on installation like:

    ...
    gcc-4.8: error: capnp/capnp.c: No such file or directory

    gcc-4.8: fatal error: no input files

Then you have too old a version of setuptools. Run `pip install -U setuptools` then try again.


[![Build Status](https://travis-ci.org/jparyani/pycapnp.png?branch=develop)](https://travis-ci.org/jparyani/pycapnp)
