pycapnp/capnp/capnp.pyx

954 lines
33 KiB
Cython

# capnp.pyx
# distutils: language = c++
# distutils: extra_compile_args = --std=c++11 -fpermissive
# distutils: libraries = capnpc
# cython: c_string_type = str
# cython: c_string_encoding = default
# cython: embedsignature = True
cimport cython
cimport capnp_cpp as capnp
cimport schema_cpp
from capnp_cpp cimport Schema as C_Schema, StructSchema as C_StructSchema, DynamicStruct as C_DynamicStruct, DynamicValue as C_DynamicValue, Type as C_Type, DynamicList as C_DynamicList, fixMaybe, SchemaParser as C_SchemaParser, ParsedSchema as C_ParsedSchema, VOID, ArrayPtr, StringPtr, DynamicOrphan as C_DynamicOrphan
from schema_cpp cimport Node as C_Node, EnumNode as C_EnumNode
from cython.operator cimport dereference as deref
from libc.stdint cimport *
ctypedef unsigned int uint
ctypedef uint8_t UInt8
ctypedef uint16_t UInt16
ctypedef uint32_t UInt32
ctypedef uint64_t UInt64
ctypedef int8_t Int8
ctypedef int16_t Int16
ctypedef int32_t Int32
ctypedef int64_t Int64
ctypedef char * Object
ctypedef bint Bool
ctypedef float Float32
ctypedef double Float64
from libc.stdlib cimport malloc, free
ctypedef fused valid_values:
int
long
float
double
bint
cython.p_char
def _make_enum(enum_name, *sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type(enum_name, (), enums)
_Type = _make_enum('DynamicValue.Type',
UNKNOWN = capnp.TYPE_UNKNOWN,
VOID = capnp.TYPE_VOID,
BOOL = capnp.TYPE_BOOL,
INT = capnp.TYPE_INT,
UINT = capnp.TYPE_UINT,
FLOAT = capnp.TYPE_FLOAT,
TEXT = capnp.TYPE_TEXT,
DATA = capnp.TYPE_DATA,
LIST = capnp.TYPE_LIST,
ENUM = capnp.TYPE_ENUM,
STRUCT = capnp.TYPE_STRUCT,
INTERFACE = capnp.TYPE_INTERFACE,
OBJECT = capnp.TYPE_OBJECT)
# Templated classes are weird in cython. I couldn't put it in a pxd header for some reason
cdef extern from "capnp/list.h" namespace " ::capnp":
cdef cppclass List[T]:
cppclass Reader:
T operator[](uint) except +ValueError
uint size()
cppclass Builder:
T operator[](uint) except +ValueError
uint size()
cdef extern from "<utility>" namespace "std":
C_DynamicOrphan moveOrphan"std::move"(C_DynamicOrphan)
cdef class _NodeReader:
cdef C_Node.Reader thisptr
cdef init(self, C_Node.Reader other):
self.thisptr = other
return self
property displayName:
def __get__(self):
return self.thisptr.getDisplayName().cStr()
property scopeId:
def __get__(self):
return self.thisptr.getScopeId()
property id:
def __get__(self):
return self.thisptr.getId()
property nestedNodes:
def __get__(self):
return _List_NestedNode_Reader()._init(self.thisptr.getNestedNodes())
property isStruct:
def __get__(self):
return self.thisptr.isStruct()
property isConst:
def __get__(self):
return self.thisptr.isConst()
cdef class _NestedNodeReader:
cdef C_Node.NestedNode.Reader thisptr
cdef init(self, C_Node.NestedNode.Reader other):
self.thisptr = other
return self
property name:
def __get__(self):
return self.thisptr.getName().cStr()
property id:
def __get__(self):
return self.thisptr.getId()
cdef class _DynamicListReader:
"""Class for reading Cap'n Proto Lists
This class thinly wraps the C++ Cap'n Proto DynamicList::Reader class. __getitem__ and __len__ have been defined properly, so you can treat this class mostly like any other iterable class::
...
person = message.getRoot(addressbook.Person)
phones = person.phones # This returns a _DynamicListReader
phone = phones[0]
print phone.number
for phone in phones:
print phone.number
"""
cdef C_DynamicList.Reader thisptr
cdef public object _parent
cdef _init(self, C_DynamicList.Reader other, object parent):
self.thisptr = other
self._parent = parent
return self
def __getitem__(self, index):
size = self.thisptr.size()
if index >= size:
raise IndexError('Out of bounds')
index = index % size
return toPythonReader(self.thisptr[index], self._parent)
def __len__(self):
return self.thisptr.size()
cdef class _DynamicResizableListBuilder:
cdef public object _parent, _message, _field, _schema
cdef public list _list
def __init__(self, parent, field, schema):
self._parent = parent
self._message = parent._parent
self._field = field
self._schema = schema
self._list = list()
cpdef add(self):
orphan = self._message.newOrphan(self._schema)
orphan_val = orphan.get()
self._list.append((orphan, orphan_val))
return orphan_val
def __getitem__(self, index):
return self._list[index][1]
# def __setitem__(self, index, val):
# self._list[index] = val
def __len__(self):
return len(self._list)
def finish(self):
cdef int i = 0
new_list = self._parent.init(self._field, len(self))
for orphan, _ in self._list:
new_list.adopt(i, orphan)
i += 1
cdef class _DynamicListBuilder:
"""Class for building Cap'n Proto Lists
This class thinly wraps the C++ Cap'n Proto DynamicList::Bulder class. __getitem__, __setitem__, and __len__ have been defined properly, so you can treat this class mostly like any other iterable class::
...
person = message.initRoot(addressbook.Person)
phones = person.init('phones', 2) # This returns a _DynamicListBuilder
phone = phones[0]
phone.number = 'foo'
phone = phones[1]
phone.number = 'bar'
for phone in phones:
print phone.number
"""
cdef C_DynamicList.Builder * thisptr
cdef public object _parent
cdef _init(self, C_DynamicList.Builder other, object parent):
self.thisptr = new C_DynamicList.Builder(other)
self._parent = parent
return self
def __dealloc__(self):
del self.thisptr
cdef _get(self, index) except +ValueError:
return toPython(deref(self.thisptr)[index], self._parent)
def __getitem__(self, index):
size = self.thisptr.size()
if index >= size:
raise IndexError('Out of bounds')
index = index % size
return self._get(index)
def _setitem(self, index, valid_values value):
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(value)
self.thisptr.set(index, temp)
def __setitem__(self, index, value):
size = self.thisptr.size()
if index >= size:
raise IndexError('Out of bounds')
index = index % size
self._setitem(index, value)
def __len__(self):
return self.thisptr.size()
cpdef adopt(self, index, _DynamicOrphan orphan):
"""A method for adopting Cap'n Proto orphans
Don't use this method unless you know what you're doing. Orphans are useful for dynamically allocating objects for an unkown sized list, ie::
message = capnp.MallocMessageBuilder()
alice = m.newOrphan(addressbook.Person)
alice.get().name = 'alice'
bob = m.newOrphan(addressbook.Person)
bob.get().name = 'bob'
addressBook = message.initRoot(addressbook.AddressBook)
people = addressBook.init('people', 2)
people.adopt(0, alice)
people.adopt(1, bob)
:type index: int
:param index: The index of the element in the list to replace with the newly adopted object
:type orphan: :class:`_DynamicOrphan`
:param orphan: A Cap'n proto orphan to adopt. It will be unusable after this operation.
:rtype: void
"""
self.thisptr.adopt(index, orphan.move())
cpdef disown(self, index):
"""A method for disowning Cap'n Proto orphans
Don't use this method unless you know what you're doing.
:type index: int
:param index: The index of the element in the list to disown
:rtype: :class:`_DynamicOrphan`
"""
return _DynamicOrphan()._init(self.thisptr.disown(index), self._parent)
cdef class _List_NestedNode_Reader:
cdef List[C_Node.NestedNode].Reader thisptr
cdef _init(self, List[C_Node.NestedNode].Reader other):
self.thisptr = other
return self
def __getitem__(self, index):
size = self.thisptr.size()
if index >= size:
raise IndexError('Out of bounds')
index = index % size
return _NestedNodeReader().init(<C_Node.NestedNode.Reader>self.thisptr[index])
def __len__(self):
return self.thisptr.size()
cdef toPythonReader(C_DynamicValue.Reader self, object parent):
cdef int type = self.getType()
if type == capnp.TYPE_BOOL:
return self.asBool()
elif type == capnp.TYPE_INT:
return self.asInt()
elif type == capnp.TYPE_UINT:
return self.asUint()
elif type == capnp.TYPE_FLOAT:
return self.asDouble()
elif type == capnp.TYPE_TEXT:
return self.asText()[:]
elif type == capnp.TYPE_DATA:
temp = self.asData()
return (<char*>temp.begin())[:temp.size()]
elif type == capnp.TYPE_LIST:
print 'list'
return list(_DynamicListReader()._init(self.asList(), parent))
elif type == capnp.TYPE_STRUCT:
return _DynamicStructReader()._init(self.asStruct(), parent)
elif type == capnp.TYPE_ENUM:
return fixMaybe(self.asEnum().getEnumerant()).getProto().getName().cStr()
elif type == capnp.TYPE_VOID:
return None
elif type == capnp.TYPE_UNKOWN:
raise ValueError("Cannot convert type to Python. Type is unknown by capnproto library")
else:
raise ValueError("Cannot convert type to Python. Type is unhandled by capnproto library")
cdef toPython(C_DynamicValue.Builder self, object parent):
cdef int type = self.getType()
if type == capnp.TYPE_BOOL:
return self.asBool()
elif type == capnp.TYPE_INT:
return self.asInt()
elif type == capnp.TYPE_UINT:
return self.asUint()
elif type == capnp.TYPE_FLOAT:
return self.asDouble()
elif type == capnp.TYPE_TEXT:
return self.asText()[:]
elif type == capnp.TYPE_DATA:
temp = self.asData()
return (<char*>temp.begin())[:temp.size()]
elif type == capnp.TYPE_LIST:
return _DynamicListBuilder()._init(self.asList(), parent)
elif type == capnp.TYPE_STRUCT:
return _DynamicStructBuilder()._init(self.asStruct(), parent)
elif type == capnp.TYPE_ENUM:
return fixMaybe(self.asEnum().getEnumerant()).getProto().getName().cStr()
elif type == capnp.TYPE_VOID:
return None
elif type == capnp.TYPE_UNKOWN:
raise ValueError("Cannot convert type to Python. Type is unknown by capnproto library")
else:
raise ValueError("Cannot convert type to Python. Type is unhandled by capnproto library")
cdef class _DynamicStructReader:
"""Reads Cap'n Proto structs
This class is almost a 1 for 1 wrapping of the Cap'n Proto C++ DynamicStruct::Reader. The only difference is that instead of a `get` method, __getattr__ is overloaded and the field name is passed onto the C++ equivalent `get`. This means you just use . syntax to access any field. For field names that don't follow valid python naming convention for fields, use the global function :py:func:`getattr`::
person = message.getRoot(addressbook.Person) # This returns a _DynamicStructReader
print person.name # using . syntax
print getattr(person, 'field-with-hyphens') # for names that are invalid for python, use getattr
"""
cdef C_DynamicStruct.Reader thisptr
cdef public object _parent
cdef object _obj_to_pin
cdef _init(self, C_DynamicStruct.Reader other, object parent):
self.thisptr = other
self._parent = parent
return self
def __getattr__(self, field):
return toPythonReader(self.thisptr.get(field), self._parent)
def _has(self, field):
return self.thisptr.has(field)
cpdef which(self) except +ValueError:
"""Returns the enum corresponding to the union in this struct
Enums are just strings in the python Cap'n Proto API, so this function will either return a string equal to the field name of the active field in the union, or throw a ValueError if this isn't a union, or a struct with an unnamed union::
person = message.initRoot(addressbook.Person)
person.which()
# ValueError: member was null
a.employment.employer = 'foo'
print employment.which()
# 'employer'
:rtype: str
:return: A string/enum corresponding to what field is set in the union
:Raises: :exc:`exceptions.ValueError` if this struct doesn't contain a union
"""
return fixMaybe(self.thisptr.which()).getProto().getName().cStr()
property schema:
"""A _StructSchema object matching this reader"""
def __get__(self):
return _StructSchema()._init(self.thisptr.getSchema())
def __dir__(self):
return list(self.schema.fieldnames)
cdef class _DynamicStructBuilder:
"""Builds Cap'n Proto structs
This class is almost a 1 for 1 wrapping of the Cap'n Proto C++ DynamicStruct::Builder. The only difference is that instead of a `get`/`set` method, __getattr__/__setattr__ is overloaded and the field name is passed onto the C++ equivalent function. This means you just use . syntax to access or set any field. For field names that don't follow valid python naming convention for fields, use the global functions :py:func:`getattr`/:py:func:`setattr`::
person = message.initRoot(addressbook.Person) # This returns a _DynamicStructBuilder
person.name = 'foo' # using . syntax
print person.name # using . syntax
setattr(person, 'field-with-hyphens', 'foo') # for names that are invalid for python, use setattr
print getattr(person, 'field-with-hyphens') # for names that are invalid for python, use getattr
"""
cdef C_DynamicStruct.Builder * thisptr
cdef public object _parent
cdef _init(self, C_DynamicStruct.Builder other, object parent):
self.thisptr = new C_DynamicStruct.Builder(other)
self._parent = parent
return self
def __dealloc__(self):
del self.thisptr
cdef _get(self, field) except +ValueError:
return toPython(self.thisptr.get(field), self._parent)
def __getattr__(self, field):
return self._get(field)
cdef _setattrInt(self, field, value):
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(<long long>value)
self.thisptr.set(field, temp)
cdef _setattrDouble(self, field, value):
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(<double>value)
self.thisptr.set(field, temp)
cdef _setattrBool(self, field, value):
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(<bint>value)
self.thisptr.set(field, temp)
cdef _setattrString(self, field, value):
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(<char*>value)
self.thisptr.set(field, temp)
cdef _setattrVoid(self, field):
cdef C_DynamicValue.Reader temp = C_DynamicValue.Reader(VOID)
self.thisptr.set(field, temp)
def __setattr__(self, field, value):
value_type = type(value)
if value_type is int:
self._setattrInt(field, value)
elif value_type is float:
self._setattrDouble(field, value)
elif value_type is bool:
self._setattrBool(field, value)
elif value_type is str:
self._setattrString(field, value)
elif value is None:
self._setattrVoid(field)
else:
raise ValueError("Non primitive type")
def _has(self, field):
return self.thisptr.has(field)
cpdef init(self, field, size=None) except +AttributeError:
"""Method for initializing fields that are of type union/struct/list
Typically, you don't have to worry about initializing structs/unions, so this method is mainly for lists.
:type field: str
:param field: The field name to initialize
:type size: int
:param size: The size of the list to initiialize. This should be None for struct/union initialization.
:rtype: :class:`_DynamicStructBuilder` or :class:`_DynamicListBuilder`
:Raises: :exc:`exceptions.AttributeError` if the field isn't in this struct
"""
if size is None:
return toPython(self.thisptr.init(field), self._parent)
else:
return toPython(self.thisptr.init(field, size), self._parent)
cpdef initResizableList(self, field):
return _DynamicResizableListBuilder(self, field, _StructSchema()._init((<C_DynamicValue.Builder>self.thisptr.get(field)).asList().getStructElementType()))
cpdef which(self) except +ValueError:
"""Returns the enum corresponding to the union in this struct
Enums are just strings in the python Cap'n Proto API, so this function will either return a string equal to the field name of the active field in the union, or throw a ValueError if this isn't a union, or a struct with an unnamed union::
person = message.initRoot(addressbook.Person)
person.which()
# ValueError: member was null
a.employment.employer = 'foo'
print employment.which()
# 'employer'
:rtype: str
:return: A string/enum corresponding to what field is set in the union
:Raises: :exc:`exceptions.ValueError` if this struct doesn't contain a union
"""
return fixMaybe(self.thisptr.which()).getProto().getName().cStr()
cpdef adopt(self, field, _DynamicOrphan orphan):
"""A method for adopting Cap'n Proto orphans
Don't use this method unless you know what you're doing. Orphans are useful for dynamically allocating objects for an unkown sized list, ie::
message = capnp.MallocMessageBuilder()
alice = m.newOrphan(addressbook.Person)
alice.get().name = 'alice'
bob = m.newOrphan(addressbook.Person)
bob.get().name = 'bob'
addressBook = message.initRoot(addressbook.AddressBook)
people = addressBook.init('people', 2)
people.adopt(0, alice)
people.adopt(1, bob)
:type field: str
:param field: The field name in the struct
:type orphan: :class:`_DynamicOrphan`
:param orphan: A Cap'n proto orphan to adopt. It will be unusable after this operation.
:rtype: void
"""
self.thisptr.adopt(field, orphan.move())
cpdef disown(self, field):
"""A method for disowning Cap'n Proto orphans
Don't use this method unless you know what you're doing.
:type field: str
:param field: The field name in the struct
:rtype: :class:`_DynamicOrphan`
"""
return _DynamicOrphan()._init(self.thisptr.disown(field), self._parent)
cpdef asReader(self):
cdef _DynamicStructReader reader
reader = _DynamicStructReader()._init(self.thisptr.asReader(),
self._parent)
reader._obj_to_pin = self
return reader
property schema:
"""A _StructSchema object matching this reader"""
def __get__(self):
return _StructSchema()._init(self.thisptr.getSchema())
def __dir__(self):
return list(self.schema.fieldnames)
cdef class _DynamicOrphan:
cdef C_DynamicOrphan thisptr
cdef public object _parent
cdef _init(self, C_DynamicOrphan other, object parent):
self.thisptr = moveOrphan(other)
self._parent = parent
return self
cdef C_DynamicOrphan move(self):
return moveOrphan(self.thisptr)
cpdef get(self):
"""Returns a python object corresponding to the DynamicValue owned by this orphan
Use this DynamicValue to set fields inside the orphan
"""
return toPython(self.thisptr.get(), self._parent)
cdef class _Schema:
cdef C_Schema thisptr
cdef _init(self, C_Schema other):
self.thisptr = other
return self
cpdef asConstValue(self):
return toPythonReader(<C_DynamicValue.Reader>self.thisptr.asConst(), self)
cpdef asStruct(self):
return _StructSchema()._init(self.thisptr.asStruct())
cpdef getDependency(self, id):
return _Schema()._init(self.thisptr.getDependency(id))
cpdef getProto(self):
return _NodeReader().init(self.thisptr.getProto())
cdef class _StructSchema:
cdef C_StructSchema thisptr
cdef object __fieldnames
cdef _init(self, C_StructSchema other):
self.thisptr = other
self.__fieldnames = None
return self
property fieldnames:
"""A tuple of the field names in the struct."""
def __get__(self):
if self.__fieldnames is not None:
return self.__fieldnames
fieldlist = self.thisptr.getFields()
nfields = fieldlist.size()
self.__fieldnames = tuple(fieldlist[i].getProto().getName().cStr()
for i in xrange(nfields))
return self.__fieldnames
property node:
"""The raw schema node"""
def __get__(self):
return _DynamicStructReader()._init(self.thisptr.getProto(), None)
cdef class _ParsedSchema:
cdef C_ParsedSchema thisptr
cdef _init(self, C_ParsedSchema other):
self.thisptr = other
return self
cpdef asConstValue(self):
return toPythonReader(<C_DynamicValue.Reader>self.thisptr.asConst(), self)
cpdef asStruct(self):
return _StructSchema()._init(self.thisptr.asStruct())
cpdef getDependency(self, id):
return _Schema()._init(self.thisptr.getDependency(id))
cpdef getProto(self):
return _NodeReader().init(self.thisptr.getProto())
cpdef getNested(self, name):
return _ParsedSchema()._init(self.thisptr.getNested(name))
cdef class _SchemaParser:
cdef C_SchemaParser * thisptr
def __cinit__(self):
self.thisptr = new C_SchemaParser()
def __dealloc__(self):
del self.thisptr
def parseDiskFile(self, displayName, diskPath, imports):
cdef StringPtr * importArray = <StringPtr *>malloc(sizeof(StringPtr) * len(imports))
for i in range(len(imports)):
importArray[i] = StringPtr(imports[i])
cdef ArrayPtr[StringPtr] importsPtr = ArrayPtr[StringPtr](importArray, <size_t>len(imports))
ret = _ParsedSchema()
ret._init(self.thisptr.parseDiskFile(displayName, diskPath, importsPtr))
free(importArray)
return ret
cdef class MessageBuilder:
"""An abstract base class for building Cap'n Proto messages
.. warning:: Don't ever instantiate this class directly. It is only used for inheritance.
"""
cdef schema_cpp.MessageBuilder * thisptr
def __dealloc__(self):
del self.thisptr
def __init__(self):
raise NotImplementedError("This is an abstract base class. You should use MallocMessageBuilder instead")
cpdef initRoot(self, schema):
"""A method for instantiating Cap'n Proto structs
You will need to pass in a schema to specify which struct to
instantiate. Schemas are available in a loaded Cap'n Proto module::
addressbook = capnp.load('addressbook.capnp')
...
person = message.initRoot(addressbook.Person)
:type schema: Schema
:param schema: A Cap'n proto schema specifying which struct to instantiate
:rtype: :class:`_DynamicStructBuilder`
:return: An object where you will set all the members
"""
cdef _StructSchema s
if hasattr(schema, 'schema'):
s = schema.schema
else:
s = schema
return _DynamicStructBuilder()._init(self.thisptr.initRootDynamicStruct(s.thisptr), self)
cpdef getRoot(self, schema):
"""A method for instantiating Cap'n Proto structs, from an already pre-written buffer
Don't use this method unless you know what you're doing. You probably
want to use initRoot instead::
addressbook = capnp.load('addressbook.capnp')
...
person = message.initRoot(addressbook.Person)
...
person = message.getRoot(addressbook.Person)
:type schema: Schema
:param schema: A Cap'n proto schema specifying which struct to instantiate
:rtype: :class:`_DynamicStructBuilder`
:return: An object where you will set all the members
"""
cdef _StructSchema s
if hasattr(schema, 'schema'):
s = schema.schema
else:
s = schema
return _DynamicStructBuilder()._init(self.thisptr.getRootDynamicStruct(s.thisptr), self)
cpdef newOrphan(self, schema):
"""A method for instantiating Cap'n Proto orphans
Don't use this method unless you know what you're doing. Orphans are useful for dynamically allocating objects for an unkown sized list, ie::
addressbook = capnp.load('addressbook.capnp')
alice = m.newOrphan(addressbook.Person)
:type schema: Schema
:param schema: A Cap'n proto schema specifying which struct to instantiate
:rtype: :class:`_DynamicOrphan`
:return: An orphan representing a :class:`_DynamicStructBuilder`
"""
cdef _StructSchema s
if hasattr(schema, 'schema'):
s = schema.schema
else:
s = schema
return _DynamicOrphan()._init(self.thisptr.newOrphan(s.thisptr), self)
cdef class MallocMessageBuilder(MessageBuilder):
"""The main class for building Cap'n Proto messages
You will use this class to handle arena allocation of the Cap'n Proto
messages. You also use this object when you're done assigning to Cap'n
Proto objects, and wish to serialize them::
addressbook = capnp.load('addressbook.capnp')
message = capnp.MallocMessageBuilder()
person = message.initRoot(addressbook.Person)
person.name = 'alice'
...
f = open('out.txt', 'w')
writeMessageToFd(f.fileno(), message)
"""
def __cinit__(self):
self.thisptr = new schema_cpp.MallocMessageBuilder()
def __init__(self):
pass
cdef class _MessageReader:
"""An abstract base class for reading Cap'n Proto messages
.. warning:: Don't ever instantiate this class. It is only used for inheritance.
"""
cdef schema_cpp.MessageReader * thisptr
def __dealloc__(self):
del self.thisptr
def __init__(self):
raise NotImplementedError("This is an abstract base class")
cpdef _getRootNode(self):
return _NodeReader().init(self.thisptr.getRootNode())
cpdef getRoot(self, schema):
"""A method for instantiating Cap'n Proto structs
You will need to pass in a schema to specify which struct to
instantiate. Schemas are available in a loaded Cap'n Proto module::
addressbook = capnp.load('addressbook.capnp')
...
person = message.getRoot(addressbook.Person)
:type schema: Schema
:param schema: A Cap'n proto schema specifying which struct to instantiate
:rtype: :class:`_DynamicStructReader`
:return: An object with all the data of the read Cap'n Proto message.
Access members with . syntax.
"""
cdef _StructSchema s
if hasattr(schema, 'schema'):
s = schema.schema
else:
s = schema
return _DynamicStructReader()._init(self.thisptr.getRootDynamicStruct(s.thisptr), self)
cdef class StreamFdMessageReader(_MessageReader):
"""Read a Cap'n Proto message from a file descriptor
You use this class to for reading message(s) from a file. It's analagous to the inverse of :func:`writeMessageToFd` and :class:`MessageBuilder`, but in one class::
f = open('out.txt')
message = StreamFdMessageReader(f.fileno())
person = message.getRoot(addressbook.Person)
print person.name
:Parameters: - fd (`int`) - A file descriptor
"""
def __init__(self, int fd):
self.thisptr = new schema_cpp.StreamFdMessageReader(fd)
cdef class PackedFdMessageReader(_MessageReader):
"""Read a Cap'n Proto message from a file descriptor in a packed manner
You use this class to for reading message(s) from a file. It's analagous to the inverse of writePackedMessageToFd and :class:`MessageBuilder`, but in one class.::
f = open('out.txt')
message = StreamFdMessageReader(f.fileno())
person = message.getRoot(addressbook.Person)
print person.name
:Parameters: - fd (`int`) - A file descriptor
"""
def __init__(self, int fd):
self.thisptr = new schema_cpp.PackedFdMessageReader(fd)
def writeMessageToFd(int fd, MessageBuilder message):
"""Serialize a Cap'n Proto message to a file descriptor
You use this method to serialize your message to a file. Please note that
you must pass a file descriptor (ie. an int), not a file object. Make sure
you use the proper reader to match this (ie. don't use PackedFdMessageReader)::
message = capnp.MallocMessageBuilder()
...
f = open('out.txt', 'w')
writeMessageToFd(f.fileno(), message)
...
f = open('out.txt')
StreamFdMessageReader(f.fileno())
:type fd: int
:param fd: A file descriptor
:type message: :class:`MessageBuilder`
:param message: The Cap'n Proto message to serialize
:rtype: void
"""
schema_cpp.writeMessageToFd(fd, deref(message.thisptr))
def writePackedMessageToFd(int fd, MessageBuilder message):
"""Serialize a Cap'n Proto message to a file descriptor in a packed manner
You use this method to serialize your message to a file. Please note that
you must pass a file descriptor (ie. an int), not a file object. Also, note
the difference in names with writeMessageToFd. This method uses a different
serialization specification, and your reader will need to match.::
message = capnp.MallocMessageBuilder()
...
f = open('out.txt', 'w')
writePackedMessageToFd(f.fileno(), message)
...
f = open('out.txt')
PackedFdMessageReader(f.fileno())
:type fd: int
:param fd: A file descriptor
:type message: :class:`MessageBuilder`
:param message: The Cap'n Proto message to serialize
:rtype: void
"""
schema_cpp.writePackedMessageToFd(fd, deref(message.thisptr))
from types import ModuleType as _ModuleType
import os as _os
def load(file_name, display_name=None, imports=[]):
"""Load a Cap'n Proto schema from a file
You will have to load a schema before you can begin doing anything
meaningful with this library. Loading a schema is much like Loading
a Python module (and load even returns a `ModuleType`). Once it's been
loaded, you use it much like any other Module::
addressbook = capnp.load('addressbook.capnp')
print addressbook.qux # qux is a top level constant
# 123
message = capnp.MallocMessageBuilder()
person = message.initRoot(addressbook.Person)
:type file_name: str
:param file_name: A relative or absolute path to a Cap'n Proto schema
:type display_name: str
:param display_name: The name internally used by the Cap'n Proto library
for the loaded schema. By default, it's just os.path.basename(file_name)
:type imports: list
:param imports: A list of str directories to add to the import path.
:rtype: ModuleType
:return: A module corresponding to the loaded schema. You can access
parsed schemas and constants with . syntax
:Raises: :exc:`exceptions.ValueError` if `file_name` doesn't exist
"""
def _load(nodeSchema, module):
module._nodeSchema = nodeSchema
nodeProto = nodeSchema.getProto()
module._nodeProto = nodeProto
for node in nodeProto.nestedNodes:
local_module = _ModuleType(node.name)
module.__dict__[node.name] = local_module
schema = nodeSchema.getNested(node.name)
proto = schema.getProto()
if proto.isStruct:
local_module.schema = schema.asStruct()
elif proto.isConst:
module.__dict__[node.name] = schema.asConstValue()
_load(schema, local_module)
if display_name is None:
display_name = _os.path.basename(file_name)
module = _ModuleType(display_name)
parser = _SchemaParser()
module._parser = parser
fileSchema = parser.parseDiskFile(display_name, file_name, imports)
_load(fileSchema, module)
return module