diff --git a/capnp/includes/capnp_cpp.pxd b/capnp/includes/capnp_cpp.pxd index 7b7b4b8..5be4180 100644 --- a/capnp/includes/capnp_cpp.pxd +++ b/capnp/includes/capnp_cpp.pxd @@ -140,10 +140,10 @@ cdef extern from "capnp/schema.h" namespace " ::capnp": cbool isStruct() cbool isInterface() - StructSchema asStruct() - EnumSchema asEnum() - InterfaceSchema asInterface() - # ListSchema asList() + StructSchema asStruct() except +reraise_kj_exception + EnumSchema asEnum() except +reraise_kj_exception + InterfaceSchema asInterface() except +reraise_kj_exception + ListSchema asList() except +reraise_kj_exception cdef cppclass Schema: Node.Reader getProto() except +reraise_kj_exception @@ -214,6 +214,9 @@ cdef extern from "capnp/schema.h" namespace " ::capnp": Enumerant getEnumerantByName(char * name) Node.Reader getProto() + cdef cppclass ListSchema: + SchemaType getElementType() + cdef cppclass ConstSchema: pass diff --git a/capnp/lib/capnp.pxd b/capnp/lib/capnp.pxd index 3c4fdd7..1f5ddea 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, EnumSchema as C_EnumSchema, 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.capnp_cpp cimport Schema as C_Schema, StructSchema as C_StructSchema, InterfaceSchema as C_InterfaceSchema, EnumSchema as C_EnumSchema, ListSchema as C_ListSchema, 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 d134191..96a3c1d 100644 --- a/capnp/lib/capnp.pyx +++ b/capnp/lib/capnp.pyx @@ -2419,6 +2419,19 @@ cdef class _StructSchema: def __repr__(self): return '' % self.node.displayName +cdef typeAsSchema(capnp.SchemaType fieldType): + # TODO(soon): make sure this is memory safe + if fieldType.isInterface(): + return _InterfaceSchema()._init(fieldType.asInterface()) + elif fieldType.isStruct(): + return _StructSchema()._init(fieldType.asStruct()) + elif fieldType.isEnum(): + return _EnumSchema()._init(fieldType.asEnum()) + elif fieldType.isList(): + return ListSchema()._init(fieldType.asList()) + else: + raise ValueError("Schema type is unknown") + cdef class _StructSchemaField: cdef _init(self, C_StructSchema.Field other, parent=None): self.thisptr = other @@ -2433,17 +2446,7 @@ cdef class _StructSchemaField: property schema: """The schema of this field, or None if it's a type without a schema""" def __get__(self): - cdef capnp.SchemaType fieldType = self.thisptr.getType() - - # TODO(soon): make sure this is memory safe - if fieldType.isInterface(): - return _InterfaceSchema()._init(fieldType.asInterface()) - elif fieldType.isStruct(): - return _StructSchema()._init(fieldType.asStruct()) - elif fieldType.isEnum(): - return _EnumSchema()._init(fieldType.asEnum()) - else: - return None + return typeAsSchema(self.thisptr.getType()) def __repr__(self): return '' % self.proto.name @@ -2563,6 +2566,18 @@ cdef class _EnumSchema: def __get__(self): return _DynamicStructReader()._init(self.thisptr.getProto(), self) +cdef class ListSchema: + cdef C_ListSchema thisptr + + cdef _init(self, C_ListSchema other): + self.thisptr = other + return self + + property elementType: + """The schema of the element type of this list""" + def __get__(self): + return typeAsSchema(self.thisptr.getElementType()) + cdef class _ParsedSchema(_Schema): cdef C_ParsedSchema thisptr_child cdef _init_child(self, C_ParsedSchema other): diff --git a/test/test_schema.py b/test/test_schema.py new file mode 100644 index 0000000..cc34e52 --- /dev/null +++ b/test/test_schema.py @@ -0,0 +1,20 @@ +import pytest +import capnp +import os + +this_dir = os.path.dirname(__file__) + + +@pytest.fixture +def addressbook(): + return capnp.load(os.path.join(this_dir, 'addressbook.capnp')) + + +def test_basic_schema(addressbook): + assert addressbook.Person.schema.fieldnames[0] == 'id' + +def test_list_schema(addressbook): + peopleField = addressbook.AddressBook.schema.fields['people'] + personType = peopleField.schema.elementType + + assert personType.node.id == addressbook.Person.schema.node.id