bt2: add boolean field class and field support
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Mon, 12 Aug 2019 02:04:08 +0000 (22:04 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 15 Aug 2019 15:41:44 +0000 (11:41 -0400)
This patch adds boolean field class and field support to the Python
bindings.

A boolean field class has no properties.

A boolean field is a numeric field (like Python's `bool` is a numeric
type). The `BoolFieldTestCase` test case inherits `_TestNumericField`,
making sure the field behaves more or less like the Python `bool` type.
`BoolFieldTestCase` is very similar to `BoolValueTestCase`.

Just like `BoolValue` objects, you can set the value of a `BoolField`
object from a `bool` or `BoolField` object.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: Ib6d0723d69709b7f3b459ba173eb7cbea5d8c435
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1896
Tested-by: jenkins <jenkins@lttng.org>
Reviewed-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Reviewed-by: Simon Marchi <simon.marchi@efficios.com>
src/bindings/python/bt2/bt2/__init__.py
src/bindings/python/bt2/bt2/field.py
src/bindings/python/bt2/bt2/field_class.py
src/bindings/python/bt2/bt2/trace_class.py
tests/bindings/python/bt2/test_field.py
tests/bindings/python/bt2/test_field_class.py
tests/bindings/python/bt2/test_package.py

index abe119a1e9f2c0916c533bed2ae43e48c46dc1a2..9b23828eb8b3739fd7a874a3f47753a0e5de0a08 100644 (file)
@@ -41,6 +41,7 @@ from bt2.error import _ComponentClassErrorCause
 from bt2.error import _MessageIteratorErrorCause
 from bt2.error import _Error
 from bt2.event_class import EventClassLogLevel
+from bt2.field import _BoolField
 from bt2.field import _IntegerField
 from bt2.field import _UnsignedIntegerField
 from bt2.field import _SignedIntegerField
@@ -55,6 +56,7 @@ from bt2.field import _ArrayField
 from bt2.field import _StaticArrayField
 from bt2.field import _DynamicArrayField
 from bt2.field_class import IntegerDisplayBase
+from bt2.field_class import _BoolFieldClass
 from bt2.field_class import _IntegerFieldClass
 from bt2.field_class import _UnsignedIntegerFieldClass
 from bt2.field_class import _SignedIntegerFieldClass
index eb11107c093cc8fcd83953e104de8ed29f65f9fd..2406b90e89e432c4898b195c0da7eeaa67a7fb3e 100644 (file)
@@ -71,8 +71,8 @@ class _Field(object._UniqueObject):
 class _NumericField(_Field):
     @staticmethod
     def _extract_value(other):
-        if isinstance(other, bool):
-            return other
+        if isinstance(other, _BoolField) or isinstance(other, bool):
+            return bool(other)
 
         if isinstance(other, numbers.Integral):
             return int(other)
@@ -208,6 +208,36 @@ class _IntegralField(_NumericField, numbers.Integral):
         return ~self._value
 
 
+class _BoolField(_IntegralField, _Field):
+    _NAME = 'Boolean'
+
+    def __bool__(self):
+        return self._value
+
+    def _value_to_bool(self, value):
+        if isinstance(value, _BoolField):
+            value = value._value
+
+        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):
     pass
 
@@ -591,6 +621,7 @@ class _DynamicArrayField(_ArrayField, _Field):
 
 
 _TYPE_ID_TO_OBJ = {
+    native_bt.FIELD_CLASS_TYPE_BOOL: _BoolField,
     native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerField,
     native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerField,
     native_bt.FIELD_CLASS_TYPE_REAL: _RealField,
index 18dbed930fc34437742755079ddaee23ca61bc3c..85ba78bb1cfa62f999d4b4f2d3419428b64abfc4 100644 (file)
@@ -50,6 +50,10 @@ class _FieldClass(object._SharedObject):
             )
 
 
+class _BoolFieldClass(_FieldClass):
+    _NAME = 'Boolean'
+
+
 class _IntegerFieldClass(_FieldClass):
     @property
     def field_value_range(self):
@@ -583,6 +587,7 @@ class _DynamicArrayFieldClass(_ArrayFieldClass):
 
 
 _FIELD_CLASS_TYPE_TO_OBJ = {
+    native_bt.FIELD_CLASS_TYPE_BOOL: _BoolFieldClass,
     native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerFieldClass,
     native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerFieldClass,
     native_bt.FIELD_CLASS_TYPE_REAL: _RealFieldClass,
index 1643fc8ecca1759a82e57e2bb588e963f89b53ef..db871783590a76ca6c66ffc117a262214b5468f0 100644 (file)
@@ -184,15 +184,21 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping):
 
     # Field class creation methods.
 
-    def _check_create_status(self, ptr, type_name):
+    def _check_field_class_create_status(self, ptr, type_name):
         if ptr is None:
             raise bt2._MemoryError('cannot create {} field class'.format(type_name))
 
+    def create_bool_field_class(self):
+        field_class_ptr = native_bt.field_class_bool_create(self._ptr)
+        self._check_field_class_create_status(field_class_ptr, 'boolean')
+
+        return bt2_field_class._BoolFieldClass._create_from_ptr(field_class_ptr)
+
     def _create_integer_field_class(
         self, create_func, py_cls, type_name, field_value_range, preferred_display_base
     ):
         field_class_ptr = create_func(self._ptr)
-        self._check_create_status(field_class_ptr, type_name)
+        self._check_field_class_create_status(field_class_ptr, type_name)
 
         field_class = py_cls._create_from_ptr(field_class_ptr)
 
@@ -250,7 +256,7 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping):
 
     def create_real_field_class(self, is_single_precision=False):
         field_class_ptr = native_bt.field_class_real_create(self._ptr)
-        self._check_create_status(field_class_ptr, 'real')
+        self._check_field_class_create_status(field_class_ptr, 'real')
 
         field_class = bt2_field_class._RealFieldClass._create_from_ptr(field_class_ptr)
 
@@ -260,13 +266,13 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping):
 
     def create_structure_field_class(self):
         field_class_ptr = native_bt.field_class_structure_create(self._ptr)
-        self._check_create_status(field_class_ptr, 'structure')
+        self._check_field_class_create_status(field_class_ptr, 'structure')
 
         return bt2_field_class._StructureFieldClass._create_from_ptr(field_class_ptr)
 
     def create_string_field_class(self):
         field_class_ptr = native_bt.field_class_string_create(self._ptr)
-        self._check_create_status(field_class_ptr, 'string')
+        self._check_field_class_create_status(field_class_ptr, 'string')
 
         return bt2_field_class._StringFieldClass._create_from_ptr(field_class_ptr)
 
@@ -274,7 +280,7 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping):
         utils._check_type(elem_fc, bt2_field_class._FieldClass)
         utils._check_uint64(length)
         ptr = native_bt.field_class_array_static_create(self._ptr, elem_fc._ptr, length)
-        self._check_create_status(ptr, 'static array')
+        self._check_field_class_create_status(ptr, 'static array')
 
         return bt2_field_class._StaticArrayFieldClass._create_from_ptr_and_get_ref(ptr)
 
@@ -289,7 +295,7 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping):
         ptr = native_bt.field_class_array_dynamic_create(
             self._ptr, elem_fc._ptr, length_fc_ptr
         )
-        self._check_create_status(ptr, 'dynamic array')
+        self._check_field_class_create_status(ptr, 'dynamic array')
         return bt2_field_class._DynamicArrayFieldClass._create_from_ptr(ptr)
 
     def create_variant_field_class(self, selector_fc=None):
@@ -300,7 +306,7 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping):
             selector_fc_ptr = selector_fc._ptr
 
         ptr = native_bt.field_class_variant_create(self._ptr, selector_fc_ptr)
-        self._check_create_status(ptr, 'variant')
+        self._check_field_class_create_status(ptr, 'variant')
         return bt2_field_class._create_field_class_from_ptr_and_get_ref(ptr)
 
     # Add a listener to be called when the trace class is destroyed.
index e1d8fba72e0e5c7abe2ff64b0df324d2bbb0ecd8..174ae2d9ca9d44839099d795dd2d43fd3d34e892 100644 (file)
@@ -1077,6 +1077,52 @@ def _inject_numeric_testing_methods(cls):
         )
 
 
+class BoolFieldTestCase(_TestNumericField, unittest.TestCase):
+    def _create_fc(self, tc):
+        return tc.create_bool_field_class()
+
+    def setUp(self):
+        self._tc = get_default_trace_class()
+        self._def = _create_field(self._tc, self._create_fc(self._tc))
+        self._def.value = True
+        self._def_value = True
+        self._def_new_value = False
+
+    def test_assign_true(self):
+        raw = True
+        self._def.value = raw
+        self.assertEqual(self._def, raw)
+
+    def test_assign_false(self):
+        raw = False
+        self._def.value = raw
+        self.assertEqual(self._def, raw)
+
+    def test_assign_field_true(self):
+        field = _create_field(self._tc, self._create_fc(self._tc))
+        raw = True
+        field.value = raw
+        self._def.value = field
+        self.assertEqual(self._def, raw)
+
+    def test_assign_field_false(self):
+        field = _create_field(self._tc, self._create_fc(self._tc))
+        raw = False
+        field.value = raw
+        self._def.value = field
+        self.assertEqual(self._def, raw)
+
+    def test_assign_invalid_type(self):
+        with self.assertRaises(TypeError):
+            self._def.value = 17
+
+    def test_str_op(self):
+        self.assertEqual(str(self._def), str(self._def_value))
+
+
+_inject_numeric_testing_methods(BoolFieldTestCase)
+
+
 class _TestIntegerFieldCommon(_TestNumericField):
     def test_assign_true(self):
         raw = True
index 804d7d2089bbedc01af4a3fd9732a58bb40a73c5..a25d96ea8942745acd8d3e23e5146470b3b12575 100644 (file)
@@ -21,6 +21,15 @@ import bt2
 from utils import get_default_trace_class
 
 
+class BoolFieldClassTestCase(unittest.TestCase):
+    def setUp(self):
+        tc = get_default_trace_class()
+        self._fc = tc.create_bool_field_class()
+
+    def test_create_default(self):
+        self.assertIsNotNone(self._fc)
+
+
 class _TestIntegerFieldClassProps:
     def test_create_default(self):
         fc = self._create_func()
index d118462b70ab5392f07b92f17f9ada41e92f13d1..836aa0a484a83937a6688df3c8926abd2950d1ab 100644 (file)
@@ -81,6 +81,9 @@ class PackageTestCase(unittest.TestCase):
     def test_has_EventClassLogLevel(self):
         self._assert_in_bt2('EventClassLogLevel')
 
+    def test_has__BoolField(self):
+        self._assert_in_bt2('_BoolField')
+
     def test_has__IntegerField(self):
         self._assert_in_bt2('_IntegerField')
 
@@ -123,6 +126,9 @@ class PackageTestCase(unittest.TestCase):
     def test_has_IntegerDisplayBase(self):
         self._assert_in_bt2('IntegerDisplayBase')
 
+    def test_has__BoolFieldClass(self):
+        self._assert_in_bt2('_BoolFieldClass')
+
     def test_has__IntegerFieldClass(self):
         self._assert_in_bt2('_IntegerFieldClass')
 
This page took 0.029417 seconds and 4 git commands to generate.