diff --git a/.gitignore b/.gitignore index f3ee520..a0f6c78 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ capnp/*.cpp capnp/version.py MANIFEST +docs/_build diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..38d76dd --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,153 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/capnp.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/capnp.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/capnp" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/capnp" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/capnp.rst b/docs/capnp.rst new file mode 100644 index 0000000..44b606d --- /dev/null +++ b/docs/capnp.rst @@ -0,0 +1,35 @@ +.. _api: + +API Reference +=================== + +.. automodule:: capnp + +.. currentmodule:: capnp + +Functions +------------- +.. autofunction:: load +.. autofunction:: writeMessageToFd +.. autofunction:: writePackedMessageToFd + +Readers +------------- + +.. autoclass:: StreamFdMessageReader + :members: + :undoc-members: + :inherited-members: + +.. autoclass:: PackedFdMessageReader + :members: + :undoc-members: + :inherited-members: + +Writers +------------- + +.. autoclass:: MallocMessageBuilder + :members: + :undoc-members: + :inherited-members: diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..4dcf5e2 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# +# capnp documentation build configuration file, created by +# sphinx-quickstart on Sat Aug 17 18:00:25 2013. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os, string + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'capnp' +copyright = u'2013, Author' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +import pkg_resources +try: + release = pkg_resources.get_distribution('capnp').version +except pkg_resources.DistributionNotFound: + print 'To build the documentation, The distribution information of sandman' + print 'Has to be available. Either install the package into your' + print 'development environment or run "setup.py develop" to setup the' + print 'metadata. A virtualenv is recommended!' + sys.exit(1) +del pkg_resources + +version = '.'.join(release.split('.')[:2]) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'nature' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'capnpdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'capnp.tex', u'capnp Documentation', + u'Author', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'capnp', u'capnp Documentation', + [u'Author'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'capnp', u'capnp Documentation', + u'Author', 'capnp', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + + +# -- Options for Epub output --------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'capnp' +epub_author = u'Author' +epub_publisher = u'Author' +epub_copyright = u'2013, Author' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +#epub_exclude_files = [] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..e450a45 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,28 @@ +.. capnp documentation master file + +Welcome to capnp's documentation! +================================= + +This is a python wrapping of the C++ implementation of the `Capnproto `_ library. Here is a description, quoted from its docs: + + Cap’n Proto is an insanely fast data interchange format and capability-based RPC system. Think JSON, except binary. Or think Protocol Buffers, except faster. In fact, in benchmarks, Cap’n Proto is INFINITY TIMES faster than Protocol Buffers. + +The INFINITY TIMES faster part isn't so true for python, but in some simplistic benchmarks (available in the `benchmark directory of the repo `_), capnp is 4x faster than the pure python Protocol Buffer library, and 2x faster than the C++ implementation. + +Contents: + +.. toctree:: + :maxdepth: 4 + + install + quickstart + capnp + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 0000000..db24525 --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,43 @@ +.. _install: + +Installation +=================== + +C++ Capnproto Library +--------------------- + +You need to install the C++ Capnproto library first. It requires a C++ compiler with C++11 support, such as GCC 4.7+ or Clang 3.2+. Follow installation docs at `http://kentonv.github.io/capnproto/install.html `_ with an added `sudo ldconfig` after you're done installing, or if you're feeling lazy, you can run the commands below:: + + wget https://github.com/kentonv/capnproto/archive/master.zip + unzip master.zip + cd capnproto-master/c++ + ./setup-autotools.sh + autoreconf -i + ./configure + make -j6 check + sudo make install + sudo ldconfig + +Pip +--------------------- + +Using pip is by far the easiest way to install the library. After you've installed the C++ library, all you need to run is:: + + pip install capnp + +From Source +--------------------- + +If you want the latest development version, you can clone the github repo and install like so:: + + git clone https://github.com/jparyani/capnpc-python-cpp.git + pip install capnpc-python-cpp + +or:: + + cd capnpc-python-cpp + python setup.py install + +If you don't use pip, you will need to manually install Cython, and a setuptools with a version > .7. + +Once you're done installing, take a look at the :ref:`quickstart` diff --git a/docs/quickstart.rst b/docs/quickstart.rst new file mode 100644 index 0000000..dc97d5a --- /dev/null +++ b/docs/quickstart.rst @@ -0,0 +1,268 @@ +.. _quickstart: + +Quickstart +=================== + +This assumes you already have the capnp library installed. If you don't, please follow the instructions at :ref:`Installation ` first. + +In general, this library is a very light wrapping of the `Capnproto C++ library `_. You can refer to its docs for more advanced concepts, or just to get a basic idea of how the python library is structured. + +Load a Capnproto Schema +------------- + +First you need to import the library:: + + import capnp + +Then you can load the Capnproto schema with:: + + capnp.load('addressbook.capnp') + +For future reference, here is the capnproto schema. Also available in the github repository under examples/addressbook.capnp:: + + # addressbook.capnp + 0x934efea7f017fff0; + + struct Person { + id @0 :UInt32; + name @1 :Text; + email @2 :Text; + phones @3 :List(PhoneNumber); + + struct PhoneNumber { + number @0 :Text; + type @1 :Type; + + enum Type { + mobile @0; + home @1; + work @2; + } + } + + employment @4 union { + unemployed @5 :Void; + employer @6 :Text; + school @7 :Text; + selfEmployed @8 :Void; + # We assume that a person is only one of these. + } + } + + struct AddressBook { + people @0 :List(Person); + } + +Build a message +------------- + +Message Builder +~~~~~~~~~~~~~~~~~~~ + +First you need to allocate a MessageBuilder for your message to go in. There is only 1 message allocator available at the moment (Malloc), although there may be more varied kinds in the future:: + + message = capnp.MallocMessageBuilder() + +Initialize a New Capnproto Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now that you have a message buffer, you need to allocate an actual object that is from your schema. In this case, we will allocate an `AddressBook`:: + + addressBook = message.initRoot(addressbook.AddressBook) + +Notice that we used `addressbook` from the previous section: `Load a Capnproto Schema`_. + +List +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Allocating a list inside of an object requires use of the `init` function:: + + people = addressBook.init('people', 2) + +For now, let's grab the first element out of this list and assign it to a variable named `alice`:: + + alice = people[0] + +Primitive Types +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For all primitive types, from the Capnproto docs: + +- Boolean: Bool +- Integers: Int8, Int16, Int32, Int64 +- Unsigned integers: UInt8, UInt16, UInt32, UInt64 +- Floating-point: Float32, Float64 +- Blobs: Text, Data + +You can just assign straight to the variable with the corresponding Python type. For Blobs, you just use strings. Assignment happens just by using the `.` syntax on the object you contstructed above:: + + alice.id = 123 + alice.name = 'Alice' + alice.email = 'alice@example.com' + +Enums +~~~~~~~~~~~~~~ + +First we'll allocate a length one list of phonenumbers for `alice`:: + + alicePhone = alice.init('phones', 1)[0] + +Note that even though it was a length 1 list, it was still a list that was returned, and we extracted the first (and only) element with `[0]`. + +Now, enums are treated like strings, and you just assign to them like there were a Text field:: + + alicePhone.type = 'mobile' + +If you assign an invalid value to one, you will get a ValueError:: + + alicePhone.type = 'foo' + --------------------------------------------------------------------------- + ValueError Traceback (most recent call last) + ... + ValueError: src/capnp/schema.c++:326: requirement not met: enum has no such enumerant; name = foo + +Unions +~~~~~~~~~~~~~~~~~~ +For the most part, you just treat them like structs:: + + alice.employment.school = "MIT" + +Now the `school` field is the active part of the union, and we've assigned `'MIT'` to it. You can query which field is set in a union with `which()`, shown in `Reading Unions`_ + +Also, one weird case is for Void types in Unions (and in general, but Void is really only used in Unions). For these, you will have to assign `None` to them:: + bob.employment.unemployed = None + +Writing to a File +~~~~~~~~~~~~~~~~~~~ + +For now, the only way to serialize a message is to write it directly to a file descriptor (expect serializing to strings at some point soon):: + + f = open('example.bin', 'w') + capnp.writePackedMessageToFd(f.fileno(), message) + +Note the call to fileno(), since it expects a raw file descriptor. There is also `writeMessageToFd` instead of `writePackedMessageToFd`. Make sure your reader uses the same packing type. + +Read a message +------------- + +Reading from a file +~~~~~~~~~~~~~~~~~~~~~~ + +Much like before, you will have to de-serialize the message from a file descriptor:: + + f = open('example.bin') + message = capnp.PackedFdMessageReader(f.fileno()) + +Initialize a New Capnproto Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Just like when building, you have to actually specify which message you want to read out of buffer:: + + addressBook = message.getRoot(addressbook.AddressBook) + +Note that this very much needs to match the type you wrote out. In general, you will always be sending the same message types out over a given channel, wrap all your types in an unnamed enum, or you need some out of band method for communicating what type a message is. Unnamed unions are defined in the .capnp file like so:: + + struct Message { + union { + person @0 :Person; + addressbook @1 :AddressBook; + } + } + +Reading Fields +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Fields are very easy to read. You just use the `.` syntax as before. Lists behave just like normal Python lists:: + + for person in addressBook.people: + print(person.name, ':', person.email) + for phone in person.phones: + print(phone.type, ':', phone.number) + +Reading Unions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The only tricky one is unions, where you need to call `.which()` to determine the union type. The `.which()` call returns an enum, ie. a string, corresponding to the field name:: + + 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() + +Full Example +------------------ + +Here is a full example reproduced from `examples/example.py `_:: + + from __future__ import print_function + import os + import capnp + + this_dir = os.path.dirname(__file__) + addressbook = capnp.load(os.path.join(this_dir, 'addressbook.capnp')) + + def writeAddressBook(fd): + message = capnp.MallocMessageBuilder() + addressBook = message.initRoot(addressbook.AddressBook) + people = addressBook.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 + + capnp.writePackedMessageToFd(fd, message) + + + def printAddressBook(fd): + message = capnp.PackedFdMessageReader(f.fileno()) + addressBook = message.getRoot(addressbook.AddressBook) + + for person in addressBook.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.fileno()) + + f = open('example', 'r') + printAddressBook(f.fileno())