From e7e95abeed4e39d3f0e85fb0422d3a4fc1524391 Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Mon, 13 Jan 2014 16:28:05 -0800 Subject: [PATCH] Allow setting of fields with python dicts. This change was a bit complicated because of a bug in cython fused types. I had to flatten DynamicStruct.Builder to DynamicStruct_Builder in order to get fused template specialization working. --- capnp/helpers/helpers.pxd | 4 ++-- capnp/includes/capnp_cpp.pxd | 34 +++++++++++++++++----------------- capnp/includes/schema_cpp.pxd | 9 +++++---- capnp/lib/capnp.pxd | 2 +- capnp/lib/capnp.pyx | 26 ++++++++++++++++++++------ test/test_struct.py | 28 ++++++++++++++++++++++++++++ 6 files changed, 73 insertions(+), 30 deletions(-) diff --git a/capnp/helpers/helpers.pxd b/capnp/helpers/helpers.pxd index 833f65f..9cdf503 100644 --- a/capnp/helpers/helpers.pxd +++ b/capnp/helpers/helpers.pxd @@ -1,4 +1,4 @@ -from .capnp.includes.capnp_cpp cimport Maybe, DynamicStruct, Request, PyPromise, VoidPromise, PyPromiseArray, RemotePromise, DynamicCapability, InterfaceSchema, EnumSchema, StructSchema, DynamicValue, Capability, RpcSystem, MessageBuilder, MessageReader, TwoPartyVatNetwork, PyRestorer, AnyPointer +from .capnp.includes.capnp_cpp cimport Maybe, DynamicStruct, Request, PyPromise, VoidPromise, PyPromiseArray, RemotePromise, DynamicCapability, InterfaceSchema, EnumSchema, StructSchema, DynamicValue, Capability, RpcSystem, MessageBuilder, MessageReader, TwoPartyVatNetwork, PyRestorer, AnyPointer, DynamicStruct_Builder from non_circular cimport reraise_kj_exception @@ -7,7 +7,7 @@ from cpython.ref cimport PyObject cdef extern from "../helpers/fixMaybe.h": EnumSchema.Enumerant fixMaybe(Maybe[EnumSchema.Enumerant]) except +reraise_kj_exception char * getEnumString(DynamicStruct.Reader val) - char * getEnumString(DynamicStruct.Builder val) + char * getEnumString(DynamicStruct_Builder val) char * getEnumString(Request val) cdef extern from "../helpers/capabilityHelper.h": diff --git a/capnp/includes/capnp_cpp.pxd b/capnp/includes/capnp_cpp.pxd index cd4a2f6..f73aa8a 100644 --- a/capnp/includes/capnp_cpp.pxd +++ b/capnp/includes/capnp_cpp.pxd @@ -205,24 +205,24 @@ cdef extern from "capnp/dynamic.h" namespace " ::capnp": bint has(char *) except +reraise_kj_exception StructSchema getSchema() Maybe[StructSchema.Field] which() - cppclass Builder: - Builder() - Builder(Builder &) - DynamicValueForward.Builder get(char *) except +reraise_kj_exception - bint has(char *) except +reraise_kj_exception - void set(char *, DynamicValueForward.Reader) except +reraise_kj_exception - DynamicValueForward.Builder init(char *, uint size) except +reraise_kj_exception - DynamicValueForward.Builder init(char *) except +reraise_kj_exception - StructSchema getSchema() - Maybe[StructSchema.Field] which() - void adopt(char *, DynamicOrphan) except +reraise_kj_exception - DynamicOrphan disown(char *) - DynamicStruct.Reader asReader() cppclass Pipeline: Pipeline() Pipeline(Pipeline &) DynamicValueForward.Pipeline get(char *) StructSchema getSchema() + cdef cppclass DynamicStruct_Builder" ::capnp::DynamicStruct::Builder": # Need to flatten this class out, since nested C++ classes cause havoc with cython fused types + DynamicStruct_Builder() + DynamicStruct_Builder(DynamicStruct_Builder &) + DynamicValueForward.Builder get(char *) except +reraise_kj_exception + bint has(char *) except +reraise_kj_exception + void set(char *, DynamicValueForward.Reader) except +reraise_kj_exception + DynamicValueForward.Builder init(char *, uint size) except +reraise_kj_exception + DynamicValueForward.Builder init(char *) except +reraise_kj_exception + StructSchema getSchema() + Maybe[StructSchema.Field] which() + void adopt(char *, DynamicOrphan) except +reraise_kj_exception + DynamicOrphan disown(char *) + DynamicStruct.Reader asReader() cdef extern from "capnp/dynamic.h" namespace " ::capnp": cdef cppclass DynamicCapability: @@ -282,7 +282,7 @@ cdef extern from "capnp/any.h" namespace " ::capnp": StringPtr getAsText"getAs< ::capnp::Text>"() cppclass Builder: Builder(Builder) - DynamicStruct.Builder getAs"getAs< ::capnp::DynamicStruct>"(StructSchema) + DynamicStruct_Builder getAs"getAs< ::capnp::DynamicStruct>"(StructSchema) StringPtr getAsText"getAs< ::capnp::Text>"() void setAsStruct"setAs< ::capnp::DynamicStruct>"(DynamicStruct.Reader&) except +reraise_kj_exception void setAsText"setAs< ::capnp::Text>"(char*) except +reraise_kj_exception @@ -359,7 +359,7 @@ cdef extern from "capnp/dynamic.h" namespace " ::capnp": double asDouble"as"() StringPtr asText"as< ::capnp::Text>"() DynamicList.Builder asList"as< ::capnp::DynamicList>"() - DynamicStruct.Builder asStruct"as< ::capnp::DynamicStruct>"() + DynamicStruct_Builder asStruct"as< ::capnp::DynamicStruct>"() AnyPointer.Builder asObject"as< ::capnp::AnyPointer>"() DynamicCapability.Client asCapability"as< ::capnp::DynamicCapability>"() DynamicEnum asEnum"as< ::capnp::DynamicEnum>"() @@ -389,8 +389,8 @@ cdef extern from "capnp/capability.h" namespace " ::capnp": DynamicStruct.Reader getParams() except +reraise_kj_exception void releaseParams() except +reraise_kj_exception - DynamicStruct.Builder getResults() - DynamicStruct.Builder initResults() + DynamicStruct_Builder getResults() + DynamicStruct_Builder initResults() void setResults(DynamicStruct.Reader value) # void adoptResults(Orphan&& value); # Orphanage getResultsOrphanage(uint firstSegmentWordSize = 0); diff --git a/capnp/includes/schema_cpp.pxd b/capnp/includes/schema_cpp.pxd index 9766414..2c06ed2 100644 --- a/capnp/includes/schema_cpp.pxd +++ b/capnp/includes/schema_cpp.pxd @@ -18,8 +18,9 @@ cdef extern from "capnp/dynamic.h" namespace " ::capnp": cdef cppclass DynamicStruct: cppclass Reader: pass - cppclass Builder: - pass + + cdef cppclass DynamicStruct_Builder" ::capnp::DynamicStruct::Builder": + pass cdef extern from "capnp/schema.h" namespace " ::capnp": cdef cppclass Schema: @@ -658,8 +659,8 @@ cdef extern from "capnp/message.h" namespace " ::capnp": Annotation.Builder getRootAnnotation'getRoot< ::capnp::schema::Annotation>'() Annotation.Builder initRootAnnotation'initRoot< ::capnp::schema::Annotation>'() - DynamicStruct.Builder getRootDynamicStruct'getRoot< ::capnp::DynamicStruct>'(StructSchema) - DynamicStruct.Builder initRootDynamicStruct'initRoot< ::capnp::DynamicStruct>'(StructSchema) + DynamicStruct_Builder getRootDynamicStruct'getRoot< ::capnp::DynamicStruct>'(StructSchema) + DynamicStruct_Builder initRootDynamicStruct'initRoot< ::capnp::DynamicStruct>'(StructSchema) void setRootDynamicStruct'setRoot< ::capnp::DynamicStruct::Reader>'(DynamicStruct.Reader) AnyPointer.Builder getRootAnyPointer'getRoot< ::capnp::AnyPointer>'() diff --git a/capnp/lib/capnp.pxd b/capnp/lib/capnp.pxd index fd76d2e..179c89a 100644 --- a/capnp/lib/capnp.pxd +++ b/capnp/lib/capnp.pxd @@ -1,6 +1,6 @@ from .capnp.includes cimport capnp_cpp as capnp from .capnp.includes cimport schema_cpp -from .capnp.includes.capnp_cpp cimport Schema as C_Schema, StructSchema as C_StructSchema, InterfaceSchema as C_InterfaceSchema, DynamicStruct as C_DynamicStruct, DynamicValue as C_DynamicValue, Type as C_Type, DynamicList as C_DynamicList, SchemaParser as C_SchemaParser, ParsedSchema as C_ParsedSchema, VOID, ArrayPtr, StringPtr, String, StringTree, DynamicOrphan as C_DynamicOrphan, AnyPointer as C_DynamicObject, DynamicCapability as C_DynamicCapability, Request, Response, RemotePromise, PyPromise, VoidPromise, CallContext, PyRestorer, RpcSystem, makeRpcServer, makeRpcClient, Capability as C_Capability, TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, makeTwoPartyVatNetwork, PromiseFulfillerPair as C_PromiseFulfillerPair, copyPromiseFulfillerPair, newPromiseAndFulfiller, PyArray +from .capnp.includes.capnp_cpp cimport Schema as C_Schema, StructSchema as C_StructSchema, InterfaceSchema as C_InterfaceSchema, DynamicStruct as C_DynamicStruct, DynamicValue as C_DynamicValue, Type as C_Type, DynamicList as C_DynamicList, SchemaParser as C_SchemaParser, ParsedSchema as C_ParsedSchema, VOID, ArrayPtr, StringPtr, String, StringTree, DynamicOrphan as C_DynamicOrphan, AnyPointer as C_DynamicObject, DynamicCapability as C_DynamicCapability, Request, Response, RemotePromise, PyPromise, VoidPromise, CallContext, PyRestorer, RpcSystem, makeRpcServer, makeRpcClient, Capability as C_Capability, TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, makeTwoPartyVatNetwork, PromiseFulfillerPair as C_PromiseFulfillerPair, copyPromiseFulfillerPair, newPromiseAndFulfiller, PyArray, DynamicStruct_Builder from .capnp.includes.schema_cpp cimport Node as C_Node, EnumNode as C_EnumNode from .capnp.includes.types cimport * from .capnp.helpers.non_circular cimport reraise_kj_exception diff --git a/capnp/lib/capnp.pyx b/capnp/lib/capnp.pyx index b83ac8c..dabd7cd 100644 --- a/capnp/lib/capnp.pyx +++ b/capnp/lib/capnp.pyx @@ -132,7 +132,7 @@ cdef public RemotePromise * extract_remote_promise(object obj): cdef extern from "" namespace " ::kj": String strStructReader" ::kj::str"(C_DynamicStruct.Reader) - String strStructBuilder" ::kj::str"(C_DynamicStruct.Builder) + String strStructBuilder" ::kj::str"(DynamicStruct_Builder) String strRequest" ::kj::str"(Request &) String strListReader" ::kj::str"(C_DynamicList.Reader) String strListBuilder" ::kj::str"(C_DynamicList.Builder) @@ -269,7 +269,7 @@ ctypedef fused _DynamicStructReaderOrBuilder: ctypedef fused _DynamicSetterClasses: C_DynamicList.Builder - C_DynamicStruct.Builder + DynamicStruct_Builder Request ctypedef fused PromiseTypes: @@ -307,7 +307,7 @@ cdef extern from "" namespace "std": cdef extern from "" namespace " ::capnp": StringTree printStructReader" ::capnp::prettyPrint"(C_DynamicStruct.Reader) - StringTree printStructBuilder" ::capnp::prettyPrint"(C_DynamicStruct.Builder) + StringTree printStructBuilder" ::capnp::prettyPrint"(DynamicStruct_Builder) StringTree printRequest" ::capnp::prettyPrint"(Request &) StringTree printListReader" ::capnp::prettyPrint"(C_DynamicList.Reader) StringTree printListBuilder" ::capnp::prettyPrint"(C_DynamicList.Builder) @@ -673,6 +673,13 @@ cdef _setDynamicField(_DynamicSetterClasses thisptr, field, value, parent): builder = to_python_builder(thisptr.init(field, len(value)), parent) for (i, v) in enumerate(value): builder[i] = v + elif value_type is dict: + if (_DynamicSetterClasses is DynamicStruct_Builder or _DynamicSetterClasses is Request): + builder = to_python_builder(thisptr.get(field), parent) + _from_dict(builder, value) + else: + builder = to_python_builder(thisptr[field], parent) + _from_dict(builder, value) elif value is None: temp = C_DynamicValue.Reader(VOID) thisptr.set(field, temp) @@ -718,6 +725,13 @@ cdef _setDynamicFieldPtr(_DynamicSetterClasses * thisptr, field, value, parent): builder = to_python_builder(thisptr.init(field, len(value)), parent) for (i, v) in enumerate(value): builder[i] = v + elif value_type is dict: + if (_DynamicSetterClasses is DynamicStruct_Builder or _DynamicSetterClasses is Request): + builder = to_python_builder(thisptr.get(field), parent) + _from_dict(builder, value) + else: + builder = to_python_builder(thisptr[field], parent) + _from_dict(builder, value) elif value is None: temp = C_DynamicValue.Reader(VOID) thisptr.set(field, temp) @@ -869,11 +883,11 @@ cdef class _DynamicStructBuilder: 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 DynamicStruct_Builder thisptr cdef public object _parent cdef public bint is_root cdef bint _is_written - cdef _init(self, C_DynamicStruct.Builder other, object parent, bint isRoot = False): + cdef _init(self, DynamicStruct_Builder other, object parent, bint isRoot = False): self.thisptr = other self._parent = parent self.is_root = isRoot @@ -1496,7 +1510,7 @@ cdef class _Request(_DynamicStructBuilder): cdef _init_child(self, Request other, parent): self.thisptr_child = new Request(moveRequest(other)) - self._init(deref(self.thisptr_child), parent) + self._init(deref(self.thisptr_child), parent) return self def __dealloc__(self): diff --git a/test/test_struct.py b/test/test_struct.py index 95a2c08..3102aac 100644 --- a/test/test_struct.py +++ b/test/test_struct.py @@ -106,3 +106,31 @@ def test_unicode_str(all_types): msg.textField = "f\u00e6oo" assert msg.textField == "f\u00e6oo" + + +def test_new_message(all_types): + msg = all_types.TestAllTypes.new_message(int32Field=100) + + assert msg.int32Field == 100 + + msg = all_types.TestAllTypes.new_message(structField={'int32Field': 100}) + + assert msg.structField.int32Field == 100 + + msg = all_types.TestAllTypes.new_message(structList=[{'int32Field': 100}, {'int32Field': 101}]) + + assert msg.structList[0].int32Field == 100 + assert msg.structList[1].int32Field == 101 + + +def test_set_dict(all_types): + msg = all_types.TestAllTypes.new_message() + + msg.structField = {'int32Field': 100} + + assert msg.structField.int32Field == 100 + + msg.init('structList', 2) + msg.structList[0] = {'int32Field': 102} + + assert msg.structList[0].int32Field == 102