Add {_get,_set,_has,_init}_by_field methods for faster field access
This commit is contained in:
@@ -225,7 +225,9 @@ cdef extern from "capnp/dynamic.h" namespace " ::capnp":
|
||||
cdef cppclass DynamicStruct:
|
||||
cppclass Reader:
|
||||
DynamicValueForward.Reader get(char *) except +reraise_kj_exception
|
||||
DynamicValueForward.Reader getByField"get"(StructSchema.Field) except +reraise_kj_exception
|
||||
bint has(char *) except +reraise_kj_exception
|
||||
bint hasByField"has"(StructSchema.Field) except +reraise_kj_exception
|
||||
StructSchema getSchema()
|
||||
Maybe[StructSchema.Field] which()
|
||||
MessageSize totalSize()
|
||||
@@ -239,10 +241,15 @@ cdef extern from "capnp/dynamic.h" namespace " ::capnp":
|
||||
DynamicStruct_Builder()
|
||||
DynamicStruct_Builder(DynamicStruct_Builder &)
|
||||
DynamicValueForward.Builder get(char *) except +reraise_kj_exception
|
||||
DynamicValueForward.Builder getByField"get"(StructSchema.Field) except +reraise_kj_exception
|
||||
bint has(char *) except +reraise_kj_exception
|
||||
bint hasByField"has"(StructSchema.Field) except +reraise_kj_exception
|
||||
void set(char *, DynamicValueForward.Reader) except +reraise_kj_exception
|
||||
void setByField"set"(StructSchema.Field, DynamicValueForward.Reader) except +reraise_kj_exception
|
||||
DynamicValueForward.Builder init(char *, uint size) except +reraise_kj_exception
|
||||
DynamicValueForward.Builder init(char *) except +reraise_kj_exception
|
||||
DynamicValueForward.Builder initByField"init"(StructSchema.Field, uint size) except +reraise_kj_exception
|
||||
DynamicValueForward.Builder initByField"init"(StructSchema.Field) except +reraise_kj_exception
|
||||
StructSchema getSchema()
|
||||
Maybe[StructSchema.Field] which()
|
||||
void adopt(char *, DynamicOrphan) except +reraise_kj_exception
|
||||
|
||||
@@ -872,9 +872,15 @@ cdef class _DynamicStructReader:
|
||||
def __getattr__(self, field):
|
||||
return to_python_reader(self.thisptr.get(field), self._parent)
|
||||
|
||||
def _get_by_field(self, _StructSchemaField field):
|
||||
return to_python_reader(self.thisptr.getByField(field.thisptr), self._parent)
|
||||
|
||||
def _has(self, field):
|
||||
return self.thisptr.has(field)
|
||||
|
||||
def _has_by_field(self, _StructSchemaField field):
|
||||
return self.thisptr.hasByField(field.thisptr)
|
||||
|
||||
cpdef _which(self):
|
||||
"""Returns the enum corresponding to the union in this struct
|
||||
|
||||
@@ -1048,18 +1054,28 @@ cdef class _DynamicStructBuilder:
|
||||
|
||||
return to_python_builder(value, self._parent)
|
||||
|
||||
def _get_by_field(self, _StructSchemaField field):
|
||||
return to_python_builder(self.thisptr.getByField(field.thisptr), self._parent)
|
||||
|
||||
def __getattr__(self, field):
|
||||
return self._get(field)
|
||||
|
||||
cdef _set(self, field, value):
|
||||
_setDynamicField(self.thisptr, field, value, self._parent)
|
||||
|
||||
def _set_by_field(self, _StructSchemaField field, value):
|
||||
# TODO: make this faster
|
||||
_setDynamicField(self.thisptr, field.proto.name, value, self._parent)
|
||||
|
||||
def __setattr__(self, field, value):
|
||||
self._set(field, value)
|
||||
|
||||
def _has(self, field):
|
||||
return self.thisptr.has(field)
|
||||
|
||||
def _has_by_field(self, _StructSchemaField field):
|
||||
return self.thisptr.hasByField(field.thisptr)
|
||||
|
||||
cpdef init(self, field, size=None):
|
||||
"""Method for initializing fields that are of type union/struct/list
|
||||
|
||||
@@ -1080,6 +1096,26 @@ cdef class _DynamicStructBuilder:
|
||||
else:
|
||||
return to_python_builder(self.thisptr.init(field, size), self._parent)
|
||||
|
||||
def _init_by_field(self, _StructSchemaField field, size=None):
|
||||
"""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.ValueError` if the field isn't in this struct
|
||||
"""
|
||||
if size is None:
|
||||
return to_python_builder(self.thisptr.initByField(field.thisptr), self._parent)
|
||||
else:
|
||||
return to_python_builder(self.thisptr.initByField(field.thisptr, size), self._parent)
|
||||
|
||||
cpdef init_resizable_list(self, field):
|
||||
"""Method for initializing fields that are of type list (of structs)
|
||||
|
||||
@@ -2129,12 +2165,13 @@ cdef class _Schema:
|
||||
|
||||
cdef class _StructSchema:
|
||||
cdef C_StructSchema thisptr
|
||||
cdef object __fieldnames, __union_fields, __non_union_fields
|
||||
cdef object __fieldnames, __union_fields, __non_union_fields, __fields
|
||||
cdef _init(self, C_StructSchema other):
|
||||
self.thisptr = other
|
||||
self.__fieldnames = None
|
||||
self.__union_fields = None
|
||||
self.__non_union_fields = None
|
||||
self.__fields = None
|
||||
return self
|
||||
|
||||
property fieldnames:
|
||||
@@ -2170,6 +2207,17 @@ cdef class _StructSchema:
|
||||
for i in xrange(nfields))
|
||||
return self.__non_union_fields
|
||||
|
||||
property fields:
|
||||
"""A tuple of the field names in the struct."""
|
||||
def __get__(self):
|
||||
if self.__fields is not None:
|
||||
return self.__fields
|
||||
fieldlist = self.thisptr.getFields()
|
||||
nfields = fieldlist.size()
|
||||
self.__fields = {<char*>fieldlist[i].getProto().getName().cStr() : _StructSchemaField()._init(fieldlist[i], self)
|
||||
for i in xrange(nfields)}
|
||||
return self.__fields
|
||||
|
||||
property node:
|
||||
"""The raw schema node"""
|
||||
def __get__(self):
|
||||
@@ -2315,13 +2363,14 @@ class _StructModule(object):
|
||||
for field in schema.node.struct.fields:
|
||||
if field.which() == 'group':
|
||||
name = field.name.capitalize()
|
||||
union_schema = schema.get_dependency(field.group.typeId).node.struct
|
||||
raw_schema = schema.get_dependency(field.group.typeId)
|
||||
union_schema = raw_schema.node.struct
|
||||
|
||||
if union_schema.discriminantCount == 0:
|
||||
continue
|
||||
|
||||
union_module = _StructModuleWhich()
|
||||
setattr(union_module, 'schema', union_schema)
|
||||
setattr(union_module, 'schema', raw_schema.as_struct())
|
||||
for union_field in union_schema.fields:
|
||||
setattr(union_module, union_field.name, union_field.discriminantValue)
|
||||
setattr(self, name, union_module)
|
||||
|
||||
@@ -192,6 +192,75 @@ def test_addressbook_resizable(addressbook):
|
||||
f = open('example', 'r')
|
||||
printAddressBook(f)
|
||||
|
||||
def test_addressbook_explicit_fields(addressbook):
|
||||
def writeAddressBook(file):
|
||||
addresses = addressbook.AddressBook.new_message()
|
||||
address_fields = addressbook.AddressBook.schema.fields
|
||||
person_fields = addressbook.Person.schema.fields
|
||||
phone_fields = addressbook.Person.PhoneNumber.schema.fields
|
||||
people = addresses._init_by_field(address_fields['people'], 2)
|
||||
|
||||
alice = people[0]
|
||||
alice._set_by_field(person_fields['id'], 123)
|
||||
alice._set_by_field(person_fields['name'], 'Alice')
|
||||
alice._set_by_field(person_fields['email'], 'alice@example.com')
|
||||
alicePhones = alice._init_by_field(person_fields['phones'], 1)
|
||||
alicePhones[0]._set_by_field(phone_fields['number'], "555-1212")
|
||||
alicePhones[0]._set_by_field(phone_fields['type'], 'mobile')
|
||||
employment = alice._get_by_field(person_fields['employment'])
|
||||
employment._set_by_field(addressbook.Person.Employment.schema.fields['school'], "MIT")
|
||||
|
||||
bob = people[1]
|
||||
bob._set_by_field(person_fields['id'], 456)
|
||||
bob._set_by_field(person_fields['name'], 'Bob')
|
||||
bob._set_by_field(person_fields['email'], 'bob@example.com')
|
||||
bobPhones = bob._init_by_field(person_fields['phones'], 2)
|
||||
bobPhones[0]._set_by_field(phone_fields['number'], "555-4567")
|
||||
bobPhones[0]._set_by_field(phone_fields['type'], 'home')
|
||||
bobPhones[1]._set_by_field(phone_fields['number'], "555-7654")
|
||||
bobPhones[1]._set_by_field(phone_fields['type'], 'work')
|
||||
employment = bob._get_by_field(person_fields['employment'])
|
||||
employment._set_by_field(addressbook.Person.Employment.schema.fields['unemployed'], None)
|
||||
|
||||
addresses.write(file)
|
||||
|
||||
|
||||
def printAddressBook(file):
|
||||
addresses = addressbook.AddressBook.read(file)
|
||||
address_fields = addressbook.AddressBook.schema.fields
|
||||
person_fields = addressbook.Person.schema.fields
|
||||
phone_fields = addressbook.Person.PhoneNumber.schema.fields
|
||||
|
||||
people = addresses._get_by_field(address_fields['people'])
|
||||
|
||||
alice = people[0]
|
||||
assert alice._get_by_field(person_fields['id']) == 123
|
||||
assert alice._get_by_field(person_fields['name']) == 'Alice'
|
||||
assert alice._get_by_field(person_fields['email']) == 'alice@example.com'
|
||||
alicePhones = alice._get_by_field(person_fields['phones'])
|
||||
assert alicePhones[0]._get_by_field(phone_fields['number']) == "555-1212"
|
||||
assert alicePhones[0]._get_by_field(phone_fields['type']) == 'mobile'
|
||||
employment = alice._get_by_field(person_fields['employment'])
|
||||
employment._get_by_field(addressbook.Person.Employment.schema.fields['school']) == "MIT"
|
||||
|
||||
bob = people[1]
|
||||
assert bob._get_by_field(person_fields['id']) == 456
|
||||
assert bob._get_by_field(person_fields['name']) == 'Bob'
|
||||
assert bob._get_by_field(person_fields['email']) == 'bob@example.com'
|
||||
bobPhones = bob._get_by_field(person_fields['phones'])
|
||||
assert bobPhones[0]._get_by_field(phone_fields['number']) == "555-4567"
|
||||
assert bobPhones[0]._get_by_field(phone_fields['type']) == 'home'
|
||||
assert bobPhones[1]._get_by_field(phone_fields['number']) == "555-7654"
|
||||
assert bobPhones[1]._get_by_field(phone_fields['type']) == 'work'
|
||||
employment = bob._get_by_field(person_fields['employment'])
|
||||
employment._get_by_field(addressbook.Person.Employment.schema.fields['unemployed']) == None
|
||||
|
||||
|
||||
f = open('example', 'w')
|
||||
writeAddressBook(f)
|
||||
|
||||
f = open('example', 'r')
|
||||
printAddressBook(f)
|
||||
|
||||
@pytest.fixture
|
||||
def all_types():
|
||||
|
||||
@@ -187,3 +187,12 @@ def test_to_dict_enum(addressbook):
|
||||
field = person.to_dict()['phones'][0]['type']
|
||||
assert isstr(field)
|
||||
assert field == 'mobile'
|
||||
|
||||
def test_explicit_field(addressbook):
|
||||
person = addressbook.Person.new_message(**{'name': 'Test'})
|
||||
|
||||
name_field = addressbook.Person.schema.fields['name']
|
||||
|
||||
assert person.name == person._get_by_field(name_field)
|
||||
assert person.name == person.as_reader()._get_by_field(name_field)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user