X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fbindings%2Fpython%2Fbt2%2Fbt2%2Ffield.py;h=4d31f8fa064517795ba0354399cea18c0301381c;hb=4c4935bf825b84aeffa36234e95492fc6d2e9920;hp=99daff5a036a675f090a39c5cbf2029b1704f900;hpb=2b4ea20edfcf8ff93be7fbb98dfde5b4ba574b8f;p=babeltrace.git diff --git a/src/bindings/python/bt2/bt2/field.py b/src/bindings/python/bt2/bt2/field.py index 99daff5a..4d31f8fa 100644 --- a/src/bindings/python/bt2/bt2/field.py +++ b/src/bindings/python/bt2/bt2/field.py @@ -21,32 +21,36 @@ # THE SOFTWARE. from bt2 import native_bt, object, utils -import bt2.field_class +from bt2 import field_class as bt2_field_class import collections.abc import functools import numbers import math -import bt2 def _create_field_from_ptr(ptr, owner_ptr, owner_get_ref, owner_put_ref): field_class_ptr = native_bt.field_borrow_class_const(ptr) - utils._handle_ptr(field_class_ptr, "cannot get field object's class") typeid = native_bt.field_class_get_type(field_class_ptr) field = _TYPE_ID_TO_OBJ[typeid]._create_from_ptr_and_get_ref( - ptr, owner_ptr, owner_get_ref, owner_put_ref) + ptr, owner_ptr, owner_get_ref, owner_put_ref + ) return field -# Get the "effective" field of `field`. If `field` is a variant, return the -# currently selected field. If `field` is of any other type, return `field` +# Get the "effective" field of `field`. If `field` is a variant, return +# the currently selected field. If `field` is an option, return the +# content field. If `field` is of any other type, return `field` # directly. + def _get_leaf_field(field): - if not isinstance(field, _VariantField): - return field + if isinstance(field, _VariantField): + return _get_leaf_field(field.selected_option) + + if isinstance(field, _OptionField): + return _get_leaf_field(field.field) - return _get_leaf_field(field.selected_option) + return field class _Field(object._UniqueObject): @@ -55,10 +59,10 @@ class _Field(object._UniqueObject): return self._spec_eq(other) @property - def field_class(self): + def cls(self): field_class_ptr = native_bt.field_borrow_class_const(self._ptr) assert field_class_ptr is not None - return bt2.field_class._create_field_class_from_ptr_and_get_ref(field_class_ptr) + return bt2_field_class._create_field_class_from_ptr_and_get_ref(field_class_ptr) def _repr(self): raise NotImplementedError @@ -67,12 +71,40 @@ class _Field(object._UniqueObject): return self._repr() +class _BitArrayField(_Field): + _NAME = 'Bit array' + + @property + def value_as_integer(self): + return native_bt.field_bit_array_get_value_as_integer(self._ptr) + + @value_as_integer.setter + def value_as_integer(self, value): + utils._check_uint64(value) + native_bt.field_bit_array_set_value_as_integer(self._ptr, value) + + def _spec_eq(self, other): + if type(other) is not type(self): + return False + + return self.value_as_integer == other.value_as_integer + + def _repr(self): + return repr(self.value_as_integer) + + def __str__(self): + return str(self.value_as_integer) + + def __len__(self): + return self.cls.length + + @functools.total_ordering class _NumericField(_Field): @staticmethod def _extract_value(other): - if other is True or other is False: - return other + if isinstance(other, _BoolField) or isinstance(other, bool): + return bool(other) if isinstance(other, numbers.Integral): return int(other) @@ -83,7 +115,9 @@ class _NumericField(_Field): if isinstance(other, numbers.Complex): return complex(other) - raise TypeError("'{}' object is not a number object".format(other.__class__.__name__)) + raise TypeError( + "'{}' object is not a number object".format(other.__class__.__name__) + ) def __int__(self): return int(self._value) @@ -96,16 +130,19 @@ class _NumericField(_Field): def __lt__(self, other): if not isinstance(other, numbers.Number): - raise TypeError('unorderable types: {}() < {}()'.format(self.__class__.__name__, - other.__class__.__name__)) + raise TypeError( + 'unorderable types: {}() < {}()'.format( + self.__class__.__name__, other.__class__.__name__ + ) + ) - return self._value < float(other) + return self._value < self._extract_value(other) def _spec_eq(self, other): - if not isinstance(other, numbers.Number): - return NotImplemented - - return self._value == complex(other) + try: + return self._value == self._extract_value(other) + except Exception: + return False def __rmod__(self, other): return self._extract_value(other) % self._value @@ -167,34 +204,6 @@ class _NumericField(_Field): def __rpow__(self, base): return self._extract_value(base) ** self._value - def __iadd__(self, other): - self.value = self + other - return self - - def __isub__(self, other): - self.value = self - other - return self - - def __imul__(self, other): - self.value = self * other - return self - - def __itruediv__(self, other): - self.value = self / other - return self - - def __ifloordiv__(self, other): - self.value = self // other - return self - - def __imod__(self, other): - self.value = self % other - return self - - def __ipow__(self, other): - self.value = self ** other - return self - class _IntegralField(_NumericField, numbers.Integral): def __lshift__(self, other): @@ -230,25 +239,35 @@ class _IntegralField(_NumericField, numbers.Integral): def __invert__(self): return ~self._value - def __ilshift__(self, other): - self.value = self << other - return self - def __irshift__(self, other): - self.value = self >> other - return self +class _BoolField(_IntegralField, _Field): + _NAME = 'Boolean' - def __iand__(self, other): - self.value = self & other - return self + def __bool__(self): + return self._value - def __ixor__(self, other): - self.value = self ^ other - return self + def _value_to_bool(self, value): + if isinstance(value, _BoolField): + value = value._value - def __ior__(self, other): - self.value = self | other - return self + if not isinstance(value, bool): + raise TypeError( + "'{}' object is not a 'bool' or '_BoolField' object".format( + value.__class__ + ) + ) + + return value + + @property + def _value(self): + return bool(native_bt.field_bool_get_value(self._ptr)) + + def _set_value(self, value): + value = self._value_to_bool(value) + native_bt.field_bool_set_value(self._ptr, value) + + value = property(fset=_set_value) class _IntegerField(_IntegralField, _Field): @@ -259,8 +278,8 @@ class _UnsignedIntegerField(_IntegerField, _Field): _NAME = 'Unsigned integer' def _value_to_int(self, value): - if not isinstance(value, numbers.Real): - raise TypeError('expecting a real number object') + if not isinstance(value, numbers.Integral): + raise TypeError('expecting an integral number object') value = int(value) utils._check_uint64(value) @@ -269,11 +288,11 @@ class _UnsignedIntegerField(_IntegerField, _Field): @property def _value(self): - return native_bt.field_unsigned_integer_get_value(self._ptr) + return native_bt.field_integer_unsigned_get_value(self._ptr) def _set_value(self, value): value = self._value_to_int(value) - native_bt.field_unsigned_integer_set_value(self._ptr, value) + native_bt.field_integer_unsigned_set_value(self._ptr, value) value = property(fset=_set_value) @@ -282,8 +301,8 @@ class _SignedIntegerField(_IntegerField, _Field): _NAME = 'Signed integer' def _value_to_int(self, value): - if not isinstance(value, numbers.Real): - raise TypeError('expecting a real number object') + if not isinstance(value, numbers.Integral): + raise TypeError('expecting an integral number object') value = int(value) utils._check_int64(value) @@ -292,11 +311,11 @@ class _SignedIntegerField(_IntegerField, _Field): @property def _value(self): - return native_bt.field_signed_integer_get_value(self._ptr) + return native_bt.field_integer_signed_get_value(self._ptr) def _set_value(self, value): value = self._value_to_int(value) - native_bt.field_signed_integer_set_value(self._ptr, value) + native_bt.field_integer_signed_set_value(self._ptr, value) value = property(fset=_set_value) @@ -327,8 +346,8 @@ class _EnumerationField(_IntegerField): @property def labels(self): - ret, labels = self._get_mapping_labels(self._ptr) - utils._handle_ret(ret, "cannot get label for enumeration field") + status, labels = self._get_mapping_labels(self._ptr) + utils._handle_func_status(status, "cannot get label for enumeration field") assert labels is not None return labels @@ -336,12 +355,16 @@ class _EnumerationField(_IntegerField): class _UnsignedEnumerationField(_EnumerationField, _UnsignedIntegerField): _NAME = 'Unsigned Enumeration' - _get_mapping_labels = staticmethod(native_bt.field_unsigned_enumeration_get_mapping_labels) + _get_mapping_labels = staticmethod( + native_bt.field_enumeration_unsigned_get_mapping_labels + ) class _SignedEnumerationField(_EnumerationField, _SignedIntegerField): _NAME = 'Signed Enumeration' - _get_mapping_labels = staticmethod(native_bt.field_signed_enumeration_get_mapping_labels) + _get_mapping_labels = staticmethod( + native_bt.field_enumeration_signed_get_mapping_labels + ) @functools.total_ordering @@ -369,12 +392,10 @@ class _StringField(_Field): def _spec_eq(self, other): try: - other = self._value_to_str(other) + return self._value == self._value_to_str(other) except Exception: return False - return self._value == other - def __lt__(self, other): return self._value < self._value_to_str(other) @@ -395,8 +416,10 @@ class _StringField(_Field): def __iadd__(self, value): value = self._value_to_str(value) - ret = native_bt.field_string_append(self._ptr, value) - utils._handle_ret(ret, "cannot append to string field object's value") + status = native_bt.field_string_append(self._ptr, value) + utils._handle_func_status( + status, "cannot append to string field object's value" + ) return self @@ -417,7 +440,7 @@ class _StructureField(_ContainerField, collections.abc.MutableMapping): _NAME = 'Structure' def _count(self): - return len(self.field_class) + return len(self.cls) def __setitem__(self, key, value): # raises if key is somehow invalid @@ -429,25 +452,24 @@ class _StructureField(_ContainerField, collections.abc.MutableMapping): def __iter__(self): # same name iterator - return iter(self.field_class) + return iter(self.cls) def _spec_eq(self, other): - try: - if len(self) != len(other): - return False + if not isinstance(other, collections.abc.Mapping): + return False - for self_key, self_value in self.items(): - if self_key not in other: - return False + if len(self) != len(other): + # early mismatch + return False - other_value = other[self_key] + for self_key in self: + if self_key not in other: + return False - if self_value != other_value: - return False + if self[self_key] != other[self_key]: + return False - return True - except Exception: - return False + return True def _set_value(self, values): try: @@ -464,14 +486,16 @@ class _StructureField(_ContainerField, collections.abc.MutableMapping): def __getitem__(self, key): utils._check_str(key) - field_ptr = native_bt.field_structure_borrow_member_field_by_name(self._ptr, key) + field_ptr = native_bt.field_structure_borrow_member_field_by_name( + self._ptr, key + ) if field_ptr is None: raise KeyError(key) - return _create_field_from_ptr(field_ptr, self._owner_ptr, - self._owner_get_ref, - self._owner_put_ref) + return _create_field_from_ptr( + field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref + ) def member_at_index(self, index): utils._check_uint64(index) @@ -479,11 +503,57 @@ class _StructureField(_ContainerField, collections.abc.MutableMapping): if index >= len(self): raise IndexError - field_ptr = native_bt.field_structure_borrow_member_field_by_index(self._ptr, index) + field_ptr = native_bt.field_structure_borrow_member_field_by_index( + self._ptr, index + ) assert field_ptr is not None - return _create_field_from_ptr(field_ptr, self._owner_ptr, - self._owner_get_ref, - self._owner_put_ref) + return _create_field_from_ptr( + field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref + ) + + +class _OptionField(_Field): + _NAME = 'Option' + + @property + def field(self): + field_ptr = native_bt.field_option_borrow_field_const(self._ptr) + + if field_ptr is None: + return + + return _create_field_from_ptr( + field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref + ) + + @property + def has_field(self): + return self.field is not None + + @has_field.setter + def has_field(self, value): + utils._check_bool(value) + native_bt.field_option_set_has_field(self._ptr, value) + + def _spec_eq(self, other): + return _get_leaf_field(self) == other + + def __bool__(self): + return self.has_field + + def __str__(self): + return str(self.field) + + def _repr(self): + return repr(self.field) + + def _set_value(self, value): + self.has_field = True + field = self.field + assert field is not None + field.value = value + + value = property(fset=_set_value) class _VariantField(_ContainerField, _Field): @@ -495,20 +565,21 @@ class _VariantField(_ContainerField, _Field): @selected_option_index.setter def selected_option_index(self, index): - native_bt.field_variant_select_option_field(self._ptr, index) + native_bt.field_variant_select_option_field_by_index(self._ptr, index) @property def selected_option(self): + # TODO: Is there a way to check if the variant field has a selected_option, + # so we can raise an exception instead of hitting a pre-condition check? + # If there is something, that check should be added to selected_option_index too. field_ptr = native_bt.field_variant_borrow_selected_option_field(self._ptr) - utils._handle_ptr(field_ptr, "cannot get variant field's selected option") - return _create_field_from_ptr(field_ptr, self._owner_ptr, - self._owner_get_ref, - self._owner_put_ref) + return _create_field_from_ptr( + field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref + ) def _spec_eq(self, other): - new_self = _get_leaf_field(self) - return new_self == other + return _get_leaf_field(self) == other def __bool__(self): raise NotImplementedError @@ -525,8 +596,7 @@ class _VariantField(_ContainerField, _Field): value = property(fset=_set_value) -class _ArrayField(_ContainerField, _Field): - +class _ArrayField(_ContainerField, _Field, collections.abc.MutableSequence): def _get_length(self): return native_bt.field_array_get_length(self._ptr) @@ -534,24 +604,26 @@ class _ArrayField(_ContainerField, _Field): def __getitem__(self, index): if not isinstance(index, numbers.Integral): - raise TypeError("'{}' is not an integral number object: invalid index".format(index.__class__.__name__)) + raise TypeError( + "'{}' is not an integral number object: invalid index".format( + index.__class__.__name__ + ) + ) index = int(index) if index < 0 or index >= len(self): raise IndexError('{} field object index is out of range'.format(self._NAME)) - field_ptr = native_bt.field_array_borrow_element_field_by_index(self._ptr, index) - assert(field_ptr) - return _create_field_from_ptr(field_ptr, self._owner_ptr, - self._owner_get_ref, - self._owner_put_ref) + field_ptr = native_bt.field_array_borrow_element_field_by_index( + self._ptr, index + ) + assert field_ptr + return _create_field_from_ptr( + field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref + ) def __setitem__(self, index, value): - # we can only set numbers and strings - if not isinstance(value, (numbers.Number, _StringField, str)): - raise TypeError('expecting number or string object') - # raises if index is somehow invalid field = self[index] @@ -566,18 +638,19 @@ class _ArrayField(_ContainerField, _Field): raise NotImplementedError def _spec_eq(self, other): - try: - if len(self) != len(other): - return False - - for self_field, other_field in zip(self, other): - if self_field != other_field: - return False + if not isinstance(other, collections.abc.Sequence): + return False - return True - except Exception: + if len(self) != len(other): + # early mismatch return False + for self_elem, other_elem in zip(self, other): + if self_elem != other_elem: + return False + + return True + def _repr(self): return '[{}]'.format(', '.join([repr(v) for v in self])) @@ -590,8 +663,7 @@ class _StaticArrayField(_ArrayField, _Field): def _set_value(self, values): if len(self) != len(values): - raise ValueError( - 'expected length of value and array field to match') + raise ValueError('expected length of value and array field to match') for index, value in enumerate(values): if value is not None: @@ -608,8 +680,8 @@ class _DynamicArrayField(_ArrayField, _Field): def _set_length(self, length): utils._check_uint64(length) - ret = native_bt.field_dynamic_array_set_length(self._ptr, length) - utils._handle_ret(ret, "cannot set dynamic array length") + status = native_bt.field_array_dynamic_set_length(self._ptr, length) + utils._handle_func_status(status, "cannot set dynamic array length") length = property(fget=_ArrayField._get_length, fset=_set_length) @@ -625,6 +697,8 @@ class _DynamicArrayField(_ArrayField, _Field): _TYPE_ID_TO_OBJ = { + native_bt.FIELD_CLASS_TYPE_BOOL: _BoolField, + native_bt.FIELD_CLASS_TYPE_BIT_ARRAY: _BitArrayField, native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerField, native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerField, native_bt.FIELD_CLASS_TYPE_REAL: _RealField, @@ -634,5 +708,8 @@ _TYPE_ID_TO_OBJ = { native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureField, native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayField, native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY: _DynamicArrayField, - native_bt.FIELD_CLASS_TYPE_VARIANT: _VariantField, + native_bt.FIELD_CLASS_TYPE_OPTION: _OptionField, + native_bt.FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: _VariantField, + native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: _VariantField, + native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: _VariantField, }