From bbd458985eaa5218cc1e6df31d4bfc0657cac54f Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Sun, 18 Aug 2013 00:25:51 -0700 Subject: [PATCH 01/12] Add setuptools to install_requires --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 55700d3..b9243ea 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,9 @@ setup( version=VERSION, package_data={'capnp': ['*.pxd', '*.pyx', '*.h']}, ext_modules=cythonize('capnp/*.pyx', language="c++"), - install_requires=['cython > 0.19'], + install_requires=[ + 'cython > 0.19', + 'setuptools >= 0.8'], # PyPi info description='A cython wrapping of the C++ capnproto library', long_description=long_description, From ba2a05e8729b069beaf9de9ac478888d90a05675 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Sun, 18 Aug 2013 21:42:33 -0700 Subject: [PATCH 02/12] Remove warning about Void syntax changing --- examples/example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example.py b/examples/example.py index d864e5b..3a86be0 100644 --- a/examples/example.py +++ b/examples/example.py @@ -28,7 +28,7 @@ def writeAddressBook(fd): bobPhones[0].type = 'home' bobPhones[1].number = "555-7654" bobPhones[1].type = 'work' - bob.employment.unemployed = None # This is definitely bad, syntax will change at some point + bob.employment.unemployed = None capnp.writePackedMessageToFd(fd, message) From 8b92a251e41e0d1cb1dec8f716511b198d8acfbf Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Sun, 18 Aug 2013 21:48:49 -0700 Subject: [PATCH 03/12] Clean up namespace a bit and add cython exporting of function signatures --- capnp/capnp.pyx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/capnp/capnp.pyx b/capnp/capnp.pyx index bd233da..9c8c34d 100644 --- a/capnp/capnp.pyx +++ b/capnp/capnp.pyx @@ -4,6 +4,7 @@ # distutils: libraries = capnpc # cython: c_string_type = str # cython: c_string_encoding = default +# cython: embedsignature = True cimport cython cimport capnp_cpp as capnp @@ -598,12 +599,10 @@ cdef class MessageReader: def __init__(self): raise NotImplementedError("This is an abstract base class") - cpdef getRootNode(self): + cpdef _getRootNode(self): return _NodeReader().init(self.thisptr.getRootNode()) - cpdef getRootCodeGeneratorRequest(self): + cpdef _getRootCodeGeneratorRequest(self): return _CodeGeneratorRequestReader()._init(self.thisptr.getRootCodeGeneratorRequest()) - cpdef getRootDynamicStruct(self, StructSchema schema): - return _DynamicStructReader()._init(self.thisptr.getRootDynamicStruct(schema.thisptr), self) cpdef getRoot(self, schema): cdef StructSchema s if hasattr(schema, 'Schema'): From 22b31993352ba3fca4a9efc7c40850b61c2d93f7 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Sun, 18 Aug 2013 21:49:12 -0700 Subject: [PATCH 04/12] Initial commit of docs --- .gitignore | 1 + docs/Makefile | 153 +++++++++++++++++++++++ docs/capnp.rst | 35 ++++++ docs/conf.py | 294 ++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 28 +++++ docs/install.rst | 43 +++++++ docs/quickstart.rst | 268 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 822 insertions(+) create mode 100644 docs/Makefile create mode 100644 docs/capnp.rst create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/install.rst create mode 100644 docs/quickstart.rst 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()) From 3c74c5d244739f40bc20ca405a3f5b750d30aec7 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Sun, 18 Aug 2013 22:07:19 -0700 Subject: [PATCH 05/12] Add requirements file --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d6f0462 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +cython > 0.19 +setuptools >= 0.8 From fdb427fb5c926377af9e76707923f1d373c673a0 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Sun, 18 Aug 2013 22:20:37 -0700 Subject: [PATCH 06/12] Change the docs to not require library installation --- docs/capnp.rst | 31 ------------------------------- docs/conf.py | 26 +++++++++++++++----------- 2 files changed, 15 insertions(+), 42 deletions(-) diff --git a/docs/capnp.rst b/docs/capnp.rst index 44b606d..a772f03 100644 --- a/docs/capnp.rst +++ b/docs/capnp.rst @@ -2,34 +2,3 @@ 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 index 4dcf5e2..764c8fd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,18 +48,22 @@ copyright = u'2013, Author' # 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 +def extract_version(): + """extract version from version.py, so it's not multiply defined""" + with open(os.path.join('..', 'capnp', 'version.py')) as f: + line = f.readline() + while not line.startswith("version"): + line = f.readline() + print line + exec(line) + return version -version = '.'.join(release.split('.')[:2]) +vs = extract_version() +# The short X.Y version. +import string +version = vs.rstrip(string.letters) +# The full version, including alpha/beta/rc tags. +release = vs # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From 6c3041a9c682c04006af301fb152baeb60df2460 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Sun, 18 Aug 2013 22:43:40 -0700 Subject: [PATCH 07/12] Fix up docs --- docs/capnp.rst | 31 +++++++++++++++++++++++++++++++ docs/quickstart.rst | 10 +++++----- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/docs/capnp.rst b/docs/capnp.rst index a772f03..44b606d 100644 --- a/docs/capnp.rst +++ b/docs/capnp.rst @@ -2,3 +2,34 @@ 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/quickstart.rst b/docs/quickstart.rst index dc97d5a..eb59a88 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -8,7 +8,7 @@ This assumes you already have the capnp library installed. If you don't, please 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:: @@ -54,7 +54,7 @@ For future reference, here is the capnproto schema. Also available in the github } Build a message -------------- +------------------ Message Builder ~~~~~~~~~~~~~~~~~~~ @@ -64,7 +64,7 @@ First you need to allocate a MessageBuilder for your message to go in. There is 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`:: @@ -143,7 +143,7 @@ For now, the only way to serialize a message is to write it directly to a file d 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 ~~~~~~~~~~~~~~~~~~~~~~ @@ -154,7 +154,7 @@ Much like before, you will have to de-serialize the message from a file descript 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:: From 4373ecc50ba454df9aaff08872f24d4e4984ca9d Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Sun, 18 Aug 2013 23:49:07 -0700 Subject: [PATCH 08/12] Fix spacing typo --- docs/quickstart.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index eb59a88..31bbf15 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -130,6 +130,7 @@ For the most part, you just treat them like structs:: 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 From 934a204ea56fac162829bc1b17a475d309a49e41 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Tue, 20 Aug 2013 00:58:34 -0700 Subject: [PATCH 09/12] Fixed up the docs a bit with sugesstions from Kenton --- docs/index.rst | 4 ++-- docs/install.rst | 4 ++-- docs/quickstart.rst | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index e450a45..3774848 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,11 +3,11 @@ 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: +This is a python wrapping of the C++ implementation of the `Cap'n Proto `_ library. Here is a short 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. +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 has proven to be decently faster than Protocol Buffers. Also, the python capnp library can load Cap'n Proto schema files directly, without the need for a seperate compile step like with Protocol Buffers or Thrift. Contents: diff --git a/docs/install.rst b/docs/install.rst index db24525..fca0e8d 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -3,10 +3,10 @@ Installation =================== -C++ Capnproto Library +C++ Cap'n Proto 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:: +You need to install the C++ Cap'n Proto 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 diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 31bbf15..7f36d30 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -5,20 +5,20 @@ 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. +In general, this library is a very light wrapping of the `Cap'n Proto 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 +Load a Cap'n Proto Schema ------------------------ First you need to import the library:: import capnp -Then you can load the Capnproto schema with:: +Then you can load the Cap'n Proto schema with:: capnp.load('addressbook.capnp') -For future reference, here is the capnproto schema. Also available in the github repository under examples/addressbook.capnp:: +For future reference, here is the Cap'n Proto schema. Also available in the github repository under examples/addressbook.capnp:: # addressbook.capnp 0x934efea7f017fff0; @@ -63,14 +63,14 @@ First you need to allocate a MessageBuilder for your message to go in. There is message = capnp.MallocMessageBuilder() -Initialize a New Capnproto Object +Initialize a New Cap'n Proto 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`_. +Notice that we used `addressbook` from the previous section: `Load a Cap'n Proto Schema`_. List ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -86,7 +86,7 @@ For now, let's grab the first element out of this list and assign it to a variab Primitive Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For all primitive types, from the Capnproto docs: +For all primitive types, from the Cap'n Proto docs: - Boolean: Bool - Integers: Int8, Int16, Int32, Int64 @@ -154,7 +154,7 @@ Much like before, you will have to de-serialize the message from a file descript f = open('example.bin') message = capnp.PackedFdMessageReader(f.fileno()) -Initialize a New Capnproto Object +Initialize a New Cap'n Proto Object ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Just like when building, you have to actually specify which message you want to read out of buffer:: From 79653ca260937204d8aca4a89c7eb4893cbf1404 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Wed, 21 Aug 2013 17:18:02 -0700 Subject: [PATCH 10/12] Add doc about abasolute paths for load function --- docs/quickstart.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 7f36d30..4ee5b7d 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -18,6 +18,8 @@ Then you can load the Cap'n Proto schema with:: capnp.load('addressbook.capnp') +You can also provide an absolute path to the Cap'n Proto schema you wish to load. Otherwise, it will only look in the current working directory. + For future reference, here is the Cap'n Proto schema. Also available in the github repository under examples/addressbook.capnp:: # addressbook.capnp From d2701de59004bca15b323d75d7656b3799972d68 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Wed, 21 Aug 2013 17:28:02 -0700 Subject: [PATCH 11/12] Update README for 0.3.0 --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 20c3fce..99c1a75 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,17 @@ ## Requirements -First you need a system-wide installation of the Capnproto C++ library >= 0.2. All you need to do is follow the official [installation docs](http://kentonv.github.io/capnproto/install.html). -Also on my ubuntu 12.10 box, I had to run `sudo ldconfig` after installation to make sure the libcapnp library was picked up by the linker. +First you need a system-wide installation of the Capnproto C++ library >= 0.3. Unfortunately, as of now, that means you have to build from the HEAD of Cap'n Proto. Follow these instructions to do so: -You also need a working version of the latest [Cython](http://cython.org/) and the latest version of setuptools. This is easily done (assuming you've already installed pip): - - pip install -U cython setuptools + 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 ## Building and installation @@ -20,7 +25,7 @@ Or you can clone the repo like so: `cd` into the repo directory and run `pip install .` ## Documentation/Example -At the moment, there is no documenation, but the library is almost a 1:1 clone of the [Capnproto C++ Library](http://kentonv.github.io/capnproto/cxx.html) +There is some basic documentation [here](http://jparyani.github.io/capnpc-python-cpp/). The examples directory has one example that shows off the capabilities quite nicely. Here it is, reproduced: From 0e178c8bcb0bad2146fede1e6361bc57bdbf8102 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Wed, 21 Aug 2013 17:28:14 -0700 Subject: [PATCH 12/12] Bump version for 0.3.0 --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index b9243ea..024d256 100644 --- a/setup.py +++ b/setup.py @@ -12,8 +12,8 @@ from distutils.core import setup import os MAJOR = 0 -MINOR = 2 -MICRO = 1 +MINOR = 3 +MICRO = 0 VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO)