Change which method to be a property and return an enum type.

Old code using which() will still work since the enum type has a
__call__ method.
This commit is contained in:
Jason Paryani
2014-02-13 19:24:06 -08:00
parent 6ccc208757
commit 3d8dc6daa9
4 changed files with 112 additions and 53 deletions

View File

@@ -6,17 +6,6 @@ T fixMaybe(::kj::Maybe<T> val) {
KJ_IF_MAYBE(new_val, val) { KJ_IF_MAYBE(new_val, val) {
return *new_val; return *new_val;
} else { } else {
throw std::invalid_argument("member was null"); throw std::invalid_argument("Member was null.");
}
}
template<typename T>
const char * getEnumString(T & val) {
auto maybe_val = val.which();
KJ_IF_MAYBE(new_val, maybe_val) {
return new_val->getProto().getName().cStr();;
} else {
return "";
} }
} }

View File

@@ -8,9 +8,7 @@ from cpython.ref cimport PyObject
cdef extern from "../helpers/fixMaybe.h": cdef extern from "../helpers/fixMaybe.h":
EnumSchema.Enumerant fixMaybe(Maybe[EnumSchema.Enumerant]) except +reraise_kj_exception EnumSchema.Enumerant fixMaybe(Maybe[EnumSchema.Enumerant]) except +reraise_kj_exception
char * getEnumString(DynamicStruct.Reader val) StructSchema.Field fixMaybe(Maybe[StructSchema.Field]) except +reraise_kj_exception
char * getEnumString(DynamicStruct_Builder val)
char * getEnumString(Request val)
cdef extern from "../helpers/capabilityHelper.h": cdef extern from "../helpers/capabilityHelper.h":
# PyPromise evalLater(EventLoop &, PyObject * func) # PyPromise evalLater(EventLoop &, PyObject * func)

View File

@@ -14,6 +14,6 @@ cdef class _DynamicStructReader:
cdef _init(self, C_DynamicStruct.Reader other, object parent, bint isRoot=?) cdef _init(self, C_DynamicStruct.Reader other, object parent, bint isRoot=?)
cpdef which(self) cpdef _which(self)
cpdef as_builder(self) cpdef as_builder(self)

View File

@@ -768,11 +768,11 @@ cdef class _DynamicEnum:
def __repr__(self): def __repr__(self):
return '<%s enum>' % str(self) return '<%s enum>' % str(self)
def __richcmp__(self, right, int op): def __richcmp__(_DynamicEnum self, right, int op):
if isinstance(right, basestring): if isinstance(right, basestring):
left = str(self) left = self._as_str()
else: else:
left = self.raw left = self.thisptr.getRaw()
if op == 2: # == if op == 2: # ==
return left == right return left == right
@@ -787,6 +787,45 @@ cdef class _DynamicEnum:
elif op == 5: # >= elif op == 5: # >=
return left >= right return left >= right
cdef class _DynamicEnumField:
cdef object thisptr
cdef _init(self, proto):
self.thisptr = proto
return self
property raw:
"""A property that returns the raw int of the enum"""
def __get__(self):
return self.thisptr.discriminantValue
def __str__(self):
return self.thisptr.name
def __repr__(self):
return '<%s which-enum>' % str(self)
def __richcmp__(_DynamicEnumField self, right, int op):
if isinstance(right, basestring):
left = self.thisptr.name
else:
left = self.thisptr.discriminantValue
if op == 2: # ==
return left == right
elif op == 3: # !=
return left != right
elif op == 0: # <
return left < right
elif op == 1: # <=
return left <= right
elif op == 4: # >
return left > right
elif op == 5: # >=
return left >= right
def __call__(self):
return str(self)
cdef class _DynamicStructReader: cdef class _DynamicStructReader:
"""Reads Cap'n Proto structs """Reads Cap'n Proto structs
@@ -809,31 +848,32 @@ cdef class _DynamicStructReader:
def _has(self, field): def _has(self, field):
return self.thisptr.has(field) return self.thisptr.has(field)
cpdef which(self): cpdef _which(self):
"""Returns the enum corresponding to the union in this struct """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:: :rtype: :class:`_DynamicEnumField`
person = addressbook.Person.new_message()
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 :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 :Raises: :exc:`exceptions.ValueError` if this struct doesn't contain a union
""" """
cdef object which = <char*>helpers.getEnumString(self.thisptr) try:
if len(which) == 0: which = _DynamicEnumField()._init(_StructSchemaField()._init(helpers.fixMaybe(self.thisptr.which()), self).proto)
except:
raise ValueError("Attempted to call which on a non-union type") raise ValueError("Attempted to call which on a non-union type")
return which return which
property which:
"""Returns the enum corresponding to the union in this struct
:rtype: :class:`_DynamicEnumField`
: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
"""
def __get__(_DynamicStructReader self):
return self._which()
property schema: property schema:
"""A property that returns the _StructSchema object matching this reader""" """A property that returns the _StructSchema object matching this reader"""
def __get__(self): def __get__(self):
@@ -1004,31 +1044,32 @@ cdef class _DynamicStructBuilder:
""" """
return _DynamicResizableListBuilder(self, field, _StructSchema()._init((<C_DynamicValue.Builder>self.thisptr.get(field)).asList().getStructElementType())) return _DynamicResizableListBuilder(self, field, _StructSchema()._init((<C_DynamicValue.Builder>self.thisptr.get(field)).asList().getStructElementType()))
cpdef which(self): cpdef _which(self):
"""Returns the enum corresponding to the union in this struct """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:: :rtype: :class:`_DynamicEnumField`
person = addressbook.Person.new_message()
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 :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 :Raises: :exc:`exceptions.ValueError` if this struct doesn't contain a union
""" """
cdef object which = <char*>helpers.getEnumString(self.thisptr) try:
if len(which) == 0: which = _DynamicEnumField()._init(_StructSchemaField()._init(helpers.fixMaybe(self.thisptr.which()), self).proto)
except:
raise ValueError("Attempted to call which on a non-union type") raise ValueError("Attempted to call which on a non-union type")
return which return which
property which:
"""Returns the enum corresponding to the union in this struct
:rtype: :class:`_DynamicEnumField`
: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
"""
def __get__(_DynamicStructBuilder self):
return self._which()
cpdef adopt(self, field, _DynamicOrphan orphan): cpdef adopt(self, field, _DynamicOrphan orphan):
"""A method for adopting Cap'n Proto orphans """A method for adopting Cap'n Proto orphans
@@ -1991,6 +2032,22 @@ cdef class _StructSchema:
def __repr__(self): def __repr__(self):
return '<schema for %s>' % self.node.displayName return '<schema for %s>' % self.node.displayName
cdef class _StructSchemaField:
cdef C_StructSchema.Field thisptr
cdef object _parent
cdef _init(self, C_StructSchema.Field other, parent=None):
self.thisptr = other
self._parent = parent
return self
property proto:
"""The raw schema proto"""
def __get__(self):
return _DynamicStructReader()._init(self.thisptr.getProto(), self)
def __repr__(self):
return '<field schema for %s>' % self.proto.name
cdef class _InterfaceSchema: cdef class _InterfaceSchema:
cdef C_InterfaceSchema thisptr cdef C_InterfaceSchema thisptr
cdef object __method_names cdef object __method_names
@@ -2069,15 +2126,32 @@ cdef _new_message(self, kwargs):
class _RestorerImpl(object): class _RestorerImpl(object):
pass pass
class _StructModuleWhich(object):
pass
class _StructModule(object): class _StructModule(object):
def __init__(self, schema, name): def __init__(self, schema, name):
def blank_init(server_self):
pass
def _restore(self, obj): def _restore(self, obj):
return self.restore(obj.as_struct(self.schema)) return self.restore(obj.as_struct(self.schema))
self.schema = schema self.schema = schema
self.Restorer = type(name + '.Restorer', (_RestorerImpl,), {'schema':schema, '_restore':_restore}) self.Restorer = type(name + '.Restorer', (_RestorerImpl,), {'schema':schema, '_restore':_restore})
# Add enums for union fields
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
if union_schema.discriminantCount == 0:
continue
union_module = _StructModuleWhich()
setattr(union_module, 'schema', union_schema)
for union_field in union_schema.fields:
setattr(union_module, union_field.name, union_field.discriminantValue)
setattr(self, name, union_module)
def read(self, file, traversal_limit_in_words = None, nesting_limit = None): def read(self, file, traversal_limit_in_words = None, nesting_limit = None):
"""Returns a Reader for the unpacked object read from file. """Returns a Reader for the unpacked object read from file.
@@ -2209,8 +2283,6 @@ class _InterfaceModule(object):
class _EnumModule(object): class _EnumModule(object):
def __init__(self, schema, name): def __init__(self, schema, name):
def server_init(server_self):
pass
self.schema = schema self.schema = schema
for name, val in schema.enumerants.items(): for name, val in schema.enumerants.items():
setattr(self, name, val) setattr(self, name, val)