python: factor out user_attributes getters and setters
authorSimon Marchi <simon.marchi@efficios.com>
Mon, 16 Oct 2023 20:25:32 +0000 (16:25 -0400)
committerSimon Marchi <simon.marchi@efficios.com>
Mon, 4 Nov 2024 16:17:44 +0000 (11:17 -0500)
To avoid repeating the `user_attributes()` methods everywhere, define
two mixin classes (_WithUserAttributesConst and _WithUserAttributes) and
use them throughout.

Note that this fixes a bug where _StreamClassConst.user_attributes would
return a (non-const) MapValue, since it used
bt2_value._create_from_ptr_and_get_ref, instead of
bt2_value._create_from_const_ptr_and_get_ref.

Improve tests to fill in some gaps we had in the testing of user
attributes.  For all objects types that have user attributes, test
getting the user attributes from both the non-const and const versions
of the object, and verify that the return value of the
`user_attributes()` method is of the correct type.

Change-Id: I4a7542f015b5f3245395d64175761fe34aa1753f
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/10243
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
15 files changed:
src/bindings/python/bt2/Makefile.am
src/bindings/python/bt2/bt2/clock_class.py
src/bindings/python/bt2/bt2/event_class.py
src/bindings/python/bt2/bt2/field_class.py
src/bindings/python/bt2/bt2/stream.py
src/bindings/python/bt2/bt2/stream_class.py
src/bindings/python/bt2/bt2/trace.py
src/bindings/python/bt2/bt2/trace_class.py
src/bindings/python/bt2/bt2/user_attributes.py [new file with mode: 0644]
tests/bindings/python/bt2/test_clock_class.py
tests/bindings/python/bt2/test_stream.py
tests/bindings/python/bt2/test_stream_class.py
tests/bindings/python/bt2/test_trace.py
tests/bindings/python/bt2/test_trace_class.py
tests/bindings/python/bt2/utils.py

index af203041e94b0047359f50a1a0eb0db6e7f8f6da..c723a2f21841e0c82098c539190fa6893bb2338c 100644 (file)
@@ -90,6 +90,7 @@ STATIC_BINDINGS_DEPS =                                        \
        bt2/trace.py                                    \
        bt2/trace_class.py                              \
        bt2/trace_collection_message_iterator.py        \
+       bt2/user_attributes.py                          \
        bt2/utils.py                                    \
        bt2/value.py
 
index c7527c7722d91bc447b70807df3d24c870484270..e87e6825931fa4de0f55801801eb5a36014eea67 100644 (file)
@@ -5,9 +5,9 @@
 import uuid as uuidp
 
 from bt2 import utils as bt2_utils
-from bt2 import value as bt2_value
 from bt2 import object as bt2_object
 from bt2 import native_bt
+from bt2 import user_attributes as bt2_user_attrs
 
 
 class ClockClassOffset:
@@ -33,7 +33,7 @@ class ClockClassOffset:
         return (self.seconds, self.cycles) == (other.seconds, other.cycles)
 
 
-class _ClockClassConst(bt2_object._SharedObject):
+class _ClockClassConst(bt2_object._SharedObject, bt2_user_attrs._WithUserAttrsConst):
     @staticmethod
     def _get_ref(ptr):
         native_bt.clock_class_get_ref(ptr)
@@ -42,18 +42,9 @@ class _ClockClassConst(bt2_object._SharedObject):
     def _put_ref(ptr):
         native_bt.clock_class_put_ref(ptr)
 
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_const_ptr_and_get_ref
-    )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.clock_class_borrow_user_attributes_const
-    )
-
-    @property
-    def user_attributes(self):
-        ptr = self._borrow_user_attributes_ptr(self._ptr)
-        assert ptr is not None
-        return self._create_value_from_ptr_and_get_ref(ptr)
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.clock_class_borrow_user_attributes_const(ptr)
 
     @property
     def name(self):
@@ -98,20 +89,14 @@ class _ClockClassConst(bt2_object._SharedObject):
         return ns
 
 
-class _ClockClass(_ClockClassConst):
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_ptr_and_get_ref
-    )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.clock_class_borrow_user_attributes
-    )
-
-    def _user_attributes(self, user_attributes):
-        value = bt2_value.create_value(user_attributes)
-        bt2_utils._check_type(value, bt2_value.MapValue)
-        native_bt.clock_class_set_user_attributes(self._ptr, value._ptr)
+class _ClockClass(bt2_user_attrs._WithUserAttrs, _ClockClassConst):
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.clock_class_borrow_user_attributes(ptr)
 
-    _user_attributes = property(fset=_user_attributes)
+    @staticmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        native_bt.clock_class_set_user_attributes(obj_ptr, value_ptr)
 
     def _name(self, name):
         bt2_utils._check_str(name)
index 54ca10a6a4bc93336f592ecaddcd4746620d2df8..a6745c174ddc5d210b71480ef7093be372cbc76a 100644 (file)
@@ -7,6 +7,7 @@ from bt2 import value as bt2_value
 from bt2 import object as bt2_object
 from bt2 import native_bt
 from bt2 import field_class as bt2_field_class
+from bt2 import user_attributes as bt2_user_attrs
 
 
 def _bt2_stream_class():
@@ -33,7 +34,7 @@ class EventClassLogLevel:
     DEBUG = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG
 
 
-class _EventClassConst(bt2_object._SharedObject):
+class _EventClassConst(bt2_object._SharedObject, bt2_user_attrs._WithUserAttrsConst):
     @staticmethod
     def _get_ref(ptr):
         native_bt.event_class_get_ref(ptr)
@@ -57,9 +58,6 @@ class _EventClassConst(bt2_object._SharedObject):
     _create_field_class_from_ptr_and_get_ref = staticmethod(
         bt2_field_class._create_field_class_from_const_ptr_and_get_ref
     )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_const_ptr_and_get_ref
-    )
     _stream_class_pycls = property(lambda s: _bt2_stream_class()._StreamClassConst)
 
     @property
@@ -69,12 +67,6 @@ class _EventClassConst(bt2_object._SharedObject):
         if sc_ptr is not None:
             return self._stream_class_pycls._create_from_ptr_and_get_ref(sc_ptr)
 
-    @property
-    def user_attributes(self):
-        ptr = self._borrow_user_attributes_ptr(self._ptr)
-        assert ptr is not None
-        return self._create_value_from_ptr_and_get_ref(ptr)
-
     @property
     def name(self):
         return native_bt.event_class_get_name(self._ptr)
@@ -116,7 +108,7 @@ class _EventClassConst(bt2_object._SharedObject):
         return self._create_field_class_from_ptr_and_get_ref(fc_ptr)
 
 
-class _EventClass(_EventClassConst):
+class _EventClass(bt2_user_attrs._WithUserAttrs, _EventClassConst):
     _borrow_stream_class_ptr = staticmethod(native_bt.event_class_borrow_stream_class)
     _borrow_specific_context_field_class_ptr = staticmethod(
         native_bt.event_class_borrow_specific_context_field_class
@@ -130,16 +122,11 @@ class _EventClass(_EventClassConst):
     _create_field_class_from_ptr_and_get_ref = staticmethod(
         bt2_field_class._create_field_class_from_ptr_and_get_ref
     )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_ptr_and_get_ref
-    )
     _stream_class_pycls = property(lambda s: _bt2_stream_class()._StreamClass)
 
-    def _user_attributes(self, user_attributes):
-        value = bt2_value.create_value(user_attributes)
-        native_bt.event_class_set_user_attributes(self._ptr, value._ptr)
-
-    _user_attributes = property(fset=_user_attributes)
+    @staticmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        native_bt.event_class_set_user_attributes(obj_ptr, value_ptr)
 
     def _name(self, name):
         return native_bt.event_class_set_name(self._ptr, name)
index 8594b496d08609f1e4ea31d7a6bc0bb116572ebc..7396535772d3ccd126b62f9a2d62b147400b68e6 100644 (file)
@@ -10,6 +10,7 @@ from bt2 import value as bt2_value
 from bt2 import object as bt2_object
 from bt2 import native_bt
 from bt2 import field_path as bt2_field_path
+from bt2 import user_attributes as bt2_user_attrs
 from bt2 import integer_range_set as bt2_integer_range_set
 
 
@@ -47,7 +48,7 @@ class IntegerDisplayBase:
     HEXADECIMAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
 
 
-class _FieldClassConst(bt2_object._SharedObject):
+class _FieldClassConst(bt2_object._SharedObject, bt2_user_attrs._WithUserAttrsConst):
     @staticmethod
     def _get_ref(ptr):
         native_bt.field_class_get_ref(ptr)
@@ -56,12 +57,9 @@ class _FieldClassConst(bt2_object._SharedObject):
     def _put_ref(ptr):
         native_bt.field_class_put_ref(ptr)
 
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.field_class_borrow_user_attributes_const
-    )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_const_ptr_and_get_ref
-    )
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.field_class_borrow_user_attributes_const(ptr)
 
     def _check_create_status(self, ptr):
         if ptr is None:
@@ -69,27 +67,15 @@ class _FieldClassConst(bt2_object._SharedObject):
                 "cannot create {} field class object".format(self._NAME.lower())
             )
 
-    @property
-    def user_attributes(self):
-        ptr = self._borrow_user_attributes_ptr(self._ptr)
-        assert ptr is not None
-        return self._create_value_from_ptr_and_get_ref(ptr)
-
 
-class _FieldClass(_FieldClassConst):
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.field_class_borrow_user_attributes
-    )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_ptr_and_get_ref
-    )
-
-    def _user_attributes(self, user_attributes):
-        value = bt2_value.create_value(user_attributes)
-        bt2_utils._check_type(value, bt2_value.MapValue)
-        native_bt.field_class_set_user_attributes(self._ptr, value._ptr)
+class _FieldClass(bt2_user_attrs._WithUserAttrs, _FieldClassConst):
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.field_class_borrow_user_attributes(ptr)
 
-    _user_attributes = property(fset=_user_attributes)
+    @staticmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        native_bt.field_class_set_user_attributes(obj_ptr, value_ptr)
 
 
 class _BoolFieldClassConst(_FieldClassConst):
@@ -348,67 +334,59 @@ class _StringFieldClass(_StringFieldClassConst, _FieldClass):
     _NAME = "String"
 
 
-class _StructureFieldClassMemberConst:
+class _StructureFieldClassMemberConst(bt2_user_attrs._WithUserAttrsConst):
+    @property
+    def _ptr(self):
+        return self._member_ptr
+
     _create_field_class_from_ptr_and_get_ref = staticmethod(
         _create_field_class_from_const_ptr_and_get_ref
     )
     _borrow_field_class_ptr = staticmethod(
         native_bt.field_class_structure_member_borrow_field_class_const
     )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.field_class_structure_member_borrow_user_attributes_const
-    )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_const_ptr_and_get_ref
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.field_class_structure_member_borrow_user_attributes_const(ptr)
 
     def __init__(self, owning_struct_fc, member_ptr):
         # this field class owns the member; keeping it here maintains
         # the member alive as members are not shared objects
         self._owning_struct_fc = owning_struct_fc
-        self._ptr = member_ptr
+        self._member_ptr = member_ptr
 
     @property
     def name(self):
-        name = native_bt.field_class_structure_member_get_name(self._ptr)
+        name = native_bt.field_class_structure_member_get_name(self._member_ptr)
         assert name is not None
         return name
 
     @property
     def field_class(self):
-        fc_ptr = self._borrow_field_class_ptr(self._ptr)
+        fc_ptr = self._borrow_field_class_ptr(self._member_ptr)
         assert fc_ptr is not None
         return self._create_field_class_from_ptr_and_get_ref(fc_ptr)
 
-    @property
-    def user_attributes(self):
-        ptr = self._borrow_user_attributes_ptr(self._ptr)
-        assert ptr is not None
-        return self._create_value_from_ptr_and_get_ref(ptr)
-
 
-class _StructureFieldClassMember(_StructureFieldClassMemberConst):
+class _StructureFieldClassMember(
+    bt2_user_attrs._WithUserAttrs, _StructureFieldClassMemberConst
+):
     _borrow_field_class_ptr = staticmethod(
         native_bt.field_class_structure_member_borrow_field_class
     )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.field_class_structure_member_borrow_user_attributes
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.field_class_structure_member_borrow_user_attributes(ptr)
+
     _create_field_class_from_ptr_and_get_ref = staticmethod(
         _create_field_class_from_ptr_and_get_ref
     )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_ptr_and_get_ref
-    )
-
-    def _user_attributes(self, user_attributes):
-        value = bt2_value.create_value(user_attributes)
-        bt2_utils._check_type(value, bt2_value.MapValue)
-        native_bt.field_class_structure_member_set_user_attributes(
-            self._ptr, value._ptr
-        )
 
-    _user_attributes = property(fset=_user_attributes)
+    @staticmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        native_bt.field_class_structure_member_set_user_attributes(obj_ptr, value_ptr)
 
 
 class _StructureFieldClassConst(_FieldClassConst, collections.abc.Mapping):
@@ -619,65 +597,58 @@ class _OptionWithSignedIntegerSelectorFieldClass(
     _NAME = "Option (with signed integer selector)"
 
 
-class _VariantFieldClassOptionConst:
+class _VariantFieldClassOptionConst(bt2_user_attrs._WithUserAttrsConst):
+    @property
+    def _ptr(self):
+        return self._opt_ptr
+
     _create_field_class_from_ptr_and_get_ref = staticmethod(
         _create_field_class_from_const_ptr_and_get_ref
     )
     _borrow_field_class_ptr = staticmethod(
         native_bt.field_class_variant_option_borrow_field_class_const
     )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.field_class_variant_option_borrow_user_attributes_const
-    )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_const_ptr_and_get_ref
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.field_class_variant_option_borrow_user_attributes_const(ptr)
 
     def __init__(self, owning_var_fc, option_ptr):
         # this field class owns the option; keeping it here maintains
         # the option alive as options are not shared objects
         self._owning_var_fc = owning_var_fc
-        self._ptr = option_ptr
+        self._opt_ptr = option_ptr
 
     @property
     def name(self):
-        name = native_bt.field_class_variant_option_get_name(self._ptr)
+        name = native_bt.field_class_variant_option_get_name(self._opt_ptr)
         assert name is not None
         return name
 
     @property
     def field_class(self):
-        fc_ptr = self._borrow_field_class_ptr(self._ptr)
+        fc_ptr = self._borrow_field_class_ptr(self._opt_ptr)
         assert fc_ptr is not None
         return self._create_field_class_from_ptr_and_get_ref(fc_ptr)
 
-    @property
-    def user_attributes(self):
-        ptr = self._borrow_user_attributes_ptr(self._ptr)
-        assert ptr is not None
-        return self._create_value_from_ptr_and_get_ref(ptr)
-
 
-class _VariantFieldClassOption(_VariantFieldClassOptionConst):
+class _VariantFieldClassOption(
+    bt2_user_attrs._WithUserAttrs, _VariantFieldClassOptionConst
+):
     _create_field_class_from_ptr_and_get_ref = staticmethod(
         _create_field_class_from_ptr_and_get_ref
     )
     _borrow_field_class_ptr = staticmethod(
         native_bt.field_class_variant_option_borrow_field_class
     )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.field_class_variant_option_borrow_user_attributes
-    )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_ptr_and_get_ref
-    )
 
-    def _user_attributes(self, user_attributes):
-        value = bt2_value.create_value(user_attributes)
-        bt2_utils._check_type(value, bt2_value.MapValue)
-        native_bt.field_class_variant_option_set_user_attributes(self._ptr, value._ptr)
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.field_class_variant_option_borrow_user_attributes(ptr)
 
-    _user_attributes = property(fset=_user_attributes)
+    @staticmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        native_bt.field_class_variant_option_set_user_attributes(obj_ptr, value_ptr)
 
 
 class _VariantFieldClassWithIntegerSelectorOptionConst(_VariantFieldClassOptionConst):
index 9d8d1ae9a816138a974c84c5c85a48f4219b743b..1583645523731677462824c7cceab32096dbc1f2 100644 (file)
@@ -4,11 +4,11 @@
 
 from bt2 import error as bt2_error
 from bt2 import utils as bt2_utils
-from bt2 import value as bt2_value
 from bt2 import object as bt2_object
 from bt2 import packet as bt2_packet
 from bt2 import native_bt
 from bt2 import stream_class as bt2_stream_class
+from bt2 import user_attributes as bt2_user_attrs
 
 
 def _bt2_trace():
@@ -17,7 +17,7 @@ def _bt2_trace():
     return bt2_trace
 
 
-class _StreamConst(bt2_object._SharedObject):
+class _StreamConst(bt2_object._SharedObject, bt2_user_attrs._WithUserAttrsConst):
     @staticmethod
     def _get_ref(ptr):
         native_bt.stream_get_ref(ptr)
@@ -27,12 +27,11 @@ class _StreamConst(bt2_object._SharedObject):
         native_bt.stream_put_ref(ptr)
 
     _borrow_class_ptr = staticmethod(native_bt.stream_borrow_class_const)
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.stream_borrow_user_attributes_const
-    )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_const_ptr_and_get_ref
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.stream_borrow_user_attributes_const(ptr)
+
     _borrow_trace_ptr = staticmethod(native_bt.stream_borrow_trace_const)
     _stream_class_pycls = bt2_stream_class._StreamClassConst
     _trace_pycls = property(lambda _: _bt2_trace()._TraceConst)
@@ -47,12 +46,6 @@ class _StreamConst(bt2_object._SharedObject):
     def name(self):
         return native_bt.stream_get_name(self._ptr)
 
-    @property
-    def user_attributes(self):
-        ptr = self._borrow_user_attributes_ptr(self._ptr)
-        assert ptr is not None
-        return self._create_value_from_ptr_and_get_ref(ptr)
-
     @property
     def id(self):
         id = native_bt.stream_get_id(self._ptr)
@@ -65,12 +58,13 @@ class _StreamConst(bt2_object._SharedObject):
         return self._trace_pycls._create_from_ptr_and_get_ref(trace_ptr)
 
 
-class _Stream(_StreamConst):
+class _Stream(bt2_user_attrs._WithUserAttrs, _StreamConst):
     _borrow_class_ptr = staticmethod(native_bt.stream_borrow_class)
-    _borrow_user_attributes_ptr = staticmethod(native_bt.stream_borrow_user_attributes)
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_ptr_and_get_ref
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.stream_borrow_user_attributes(ptr)
+
     _borrow_trace_ptr = staticmethod(native_bt.stream_borrow_trace)
     _stream_class_pycls = bt2_stream_class._StreamClass
     _trace_pycls = property(lambda _: _bt2_trace()._Trace)
@@ -88,14 +82,9 @@ class _Stream(_StreamConst):
 
         return bt2_packet._Packet._create_from_ptr(packet_ptr)
 
-    def _user_attributes(self, user_attributes):
-        value = bt2_value.create_value(user_attributes)
-        bt2_utils._check_type(value, bt2_value.MapValue)
-        native_bt.stream_set_user_attributes(self._ptr, value._ptr)
-
-    _user_attributes = property(
-        fget=_StreamConst.user_attributes.fget, fset=_user_attributes
-    )
+    @staticmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        native_bt.stream_set_user_attributes(obj_ptr, value_ptr)
 
     def _name(self, name):
         bt2_utils._check_str(name)
index 5c6faa07fd6c25c3bd1352ffcb94e9534646200f..41fa12abf514628c1f2c5161a3c426af83a67ef4 100644 (file)
@@ -11,6 +11,7 @@ from bt2 import native_bt
 from bt2 import clock_class as bt2_clock_class
 from bt2 import event_class as bt2_event_class
 from bt2 import field_class as bt2_field_class
+from bt2 import user_attributes as bt2_user_attrs
 
 
 def _bt2_trace_class():
@@ -19,7 +20,11 @@ def _bt2_trace_class():
     return bt2_trace_class
 
 
-class _StreamClassConst(bt2_object._SharedObject, collections.abc.Mapping):
+class _StreamClassConst(
+    bt2_object._SharedObject,
+    bt2_user_attrs._WithUserAttrsConst,
+    collections.abc.Mapping,
+):
     @staticmethod
     def _get_ref(ptr):
         native_bt.stream_class_get_ref(ptr)
@@ -46,9 +51,10 @@ class _StreamClassConst(bt2_object._SharedObject, collections.abc.Mapping):
     _borrow_default_clock_class_ptr = staticmethod(
         native_bt.stream_class_borrow_default_clock_class_const
     )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.stream_class_borrow_user_attributes_const
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.stream_class_borrow_user_attributes_const(ptr)
 
     _event_class_cls = property(lambda _: bt2_event_class._EventClassConst)
     _trace_class_cls = property(lambda _: _bt2_trace_class()._TraceClassConst)
@@ -85,12 +91,6 @@ class _StreamClassConst(bt2_object._SharedObject, collections.abc.Mapping):
         if tc_ptr is not None:
             return self._trace_class_cls._create_from_ptr_and_get_ref(tc_ptr)
 
-    @property
-    def user_attributes(self):
-        ptr = self._borrow_user_attributes_ptr(self._ptr)
-        assert ptr is not None
-        return bt2_value._create_from_ptr_and_get_ref(ptr)
-
     @property
     def name(self):
         return native_bt.stream_class_get_name(self._ptr)
@@ -173,7 +173,7 @@ class _StreamClassConst(bt2_object._SharedObject, collections.abc.Mapping):
         return self._clock_class_cls._create_from_ptr_and_get_ref(cc_ptr)
 
 
-class _StreamClass(_StreamClassConst):
+class _StreamClass(bt2_user_attrs._WithUserAttrs, _StreamClassConst):
     @staticmethod
     def _get_ref(ptr):
         native_bt.stream_class_get_ref(ptr)
@@ -198,9 +198,10 @@ class _StreamClass(_StreamClassConst):
     _borrow_default_clock_class_ptr = staticmethod(
         native_bt.stream_class_borrow_default_clock_class
     )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.stream_class_borrow_user_attributes
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.stream_class_borrow_user_attributes(ptr)
 
     _event_class_cls = property(lambda s: bt2_event_class._EventClass)
     _trace_class_cls = property(lambda s: _bt2_trace_class()._TraceClass)
@@ -264,11 +265,9 @@ class _StreamClass(_StreamClassConst):
 
         return event_class
 
-    def _user_attributes(self, user_attributes):
-        value = bt2_value.create_value(user_attributes)
-        native_bt.stream_class_set_user_attributes(self._ptr, value._ptr)
-
-    _user_attributes = property(fset=_user_attributes)
+    @staticmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        native_bt.stream_class_set_user_attributes(obj_ptr, value_ptr)
 
     def _name(self, name):
         status = native_bt.stream_class_set_name(self._ptr, name)
index a7038b2880757ec0f713f36eac8196be853a14bf..b5363e49807544115505cd684684cebb65d175ec 100644 (file)
@@ -13,6 +13,7 @@ from bt2 import object as bt2_object
 from bt2 import stream as bt2_stream
 from bt2 import native_bt
 from bt2 import stream_class as bt2_stream_class
+from bt2 import user_attributes as bt2_user_attrs
 
 
 def _bt2_trace_class():
@@ -77,7 +78,11 @@ class _TraceEnvironment(_TraceEnvironmentConst, collections.abc.MutableMapping):
         raise NotImplementedError
 
 
-class _TraceConst(bt2_object._SharedObject, collections.abc.Mapping):
+class _TraceConst(
+    bt2_object._SharedObject,
+    bt2_user_attrs._WithUserAttrsConst,
+    collections.abc.Mapping,
+):
     @staticmethod
     def _get_ref(ptr):
         native_bt.trace_get_ref(ptr)
@@ -91,12 +96,11 @@ class _TraceConst(bt2_object._SharedObject, collections.abc.Mapping):
         native_bt.trace_borrow_stream_by_index_const
     )
     _borrow_class_ptr = staticmethod(native_bt.trace_borrow_class_const)
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.trace_borrow_user_attributes_const
-    )
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_const_ptr_and_get_ref
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.trace_borrow_user_attributes_const(ptr)
+
     _stream_pycls = property(lambda _: bt2_stream._StreamConst)
     _trace_class_pycls = property(lambda _: _bt2_trace_class()._TraceClassConst)
     _trace_env_pycls = property(lambda _: _TraceEnvironmentConst)
@@ -132,12 +136,6 @@ class _TraceConst(bt2_object._SharedObject, collections.abc.Mapping):
         assert trace_class_ptr is not None
         return self._trace_class_pycls._create_from_ptr_and_get_ref(trace_class_ptr)
 
-    @property
-    def user_attributes(self):
-        ptr = self._borrow_user_attributes_ptr(self._ptr)
-        assert ptr is not None
-        return self._create_value_from_ptr_and_get_ref(ptr)
-
     @property
     def name(self):
         return native_bt.trace_get_name(self._ptr)
@@ -193,14 +191,15 @@ class _TraceConst(bt2_object._SharedObject, collections.abc.Mapping):
         listener_handle._invalidate()
 
 
-class _Trace(_TraceConst):
+class _Trace(bt2_user_attrs._WithUserAttrs, _TraceConst):
     _borrow_stream_ptr_by_id = staticmethod(native_bt.trace_borrow_stream_by_id)
     _borrow_stream_ptr_by_index = staticmethod(native_bt.trace_borrow_stream_by_index)
     _borrow_class_ptr = staticmethod(native_bt.trace_borrow_class)
-    _borrow_user_attributes_ptr = staticmethod(native_bt.trace_borrow_user_attributes)
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_ptr_and_get_ref
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.trace_borrow_user_attributes(ptr)
+
     _stream_pycls = property(lambda _: bt2_stream._Stream)
     _trace_class_pycls = property(lambda _: _bt2_trace_class()._TraceClass)
     _trace_env_pycls = property(lambda _: _TraceEnvironment)
@@ -212,12 +211,9 @@ class _Trace(_TraceConst):
 
     _name = property(fset=_name)
 
-    def _user_attributes(self, user_attributes):
-        value = bt2_value.create_value(user_attributes)
-        bt2_utils._check_type(value, bt2_value.MapValue)
-        native_bt.trace_set_user_attributes(self._ptr, value._ptr)
-
-    _user_attributes = property(fset=_user_attributes)
+    @staticmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        native_bt.trace_set_user_attributes(obj_ptr, value_ptr)
 
     def _uuid(self, uuid):
         bt2_utils._check_type(uuid, uuidp.UUID)
index a691da30d1492748a950d12cff8ea0a06fb8614d..dc872eab419d5ad738703c8a363d3ad32d60819a 100644 (file)
@@ -10,11 +10,11 @@ import collections.abc
 from bt2 import error as bt2_error
 from bt2 import trace as bt2_trace
 from bt2 import utils as bt2_utils
-from bt2 import value as bt2_value
 from bt2 import object as bt2_object
 from bt2 import native_bt
 from bt2 import field_class as bt2_field_class
 from bt2 import stream_class as bt2_stream_class
+from bt2 import user_attributes as bt2_user_attrs
 from bt2 import integer_range_set as bt2_integer_range_set
 
 
@@ -26,7 +26,11 @@ def _trace_class_destruction_listener_from_native(
     handle._invalidate()
 
 
-class _TraceClassConst(bt2_object._SharedObject, collections.abc.Mapping):
+class _TraceClassConst(
+    bt2_object._SharedObject,
+    bt2_user_attrs._WithUserAttrsConst,
+    collections.abc.Mapping,
+):
     @staticmethod
     def _get_ref(ptr):
         native_bt.trace_class_get_ref(ptr)
@@ -41,19 +45,12 @@ class _TraceClassConst(bt2_object._SharedObject, collections.abc.Mapping):
     _borrow_stream_class_ptr_by_id = staticmethod(
         native_bt.trace_class_borrow_stream_class_by_id_const
     )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.trace_class_borrow_user_attributes_const
-    )
-    _stream_class_pycls = bt2_stream_class._StreamClassConst
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_const_ptr_and_get_ref
-    )
 
-    @property
-    def user_attributes(self):
-        ptr = self._borrow_user_attributes_ptr(self._ptr)
-        assert ptr is not None
-        return self._create_value_from_ptr_and_get_ref(ptr)
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.trace_class_borrow_user_attributes_const(ptr)
+
+    _stream_class_pycls = bt2_stream_class._StreamClassConst
 
     # Number of stream classes in this trace class.
 
@@ -129,20 +126,19 @@ class _TraceClassConst(bt2_object._SharedObject, collections.abc.Mapping):
         listener_handle._invalidate()
 
 
-class _TraceClass(_TraceClassConst):
+class _TraceClass(bt2_user_attrs._WithUserAttrs, _TraceClassConst):
     _borrow_stream_class_ptr_by_index = staticmethod(
         native_bt.trace_class_borrow_stream_class_by_index
     )
     _borrow_stream_class_ptr_by_id = staticmethod(
         native_bt.trace_class_borrow_stream_class_by_id
     )
-    _borrow_user_attributes_ptr = staticmethod(
-        native_bt.trace_class_borrow_user_attributes
-    )
+
+    @staticmethod
+    def _borrow_user_attributes_ptr(ptr):
+        return native_bt.trace_class_borrow_user_attributes(ptr)
+
     _stream_class_pycls = bt2_stream_class._StreamClass
-    _create_value_from_ptr_and_get_ref = staticmethod(
-        bt2_value._create_from_ptr_and_get_ref
-    )
 
     # Instantiate a trace of this class.
 
@@ -261,12 +257,9 @@ class _TraceClass(_TraceClassConst):
         )
         return sc
 
-    def _user_attributes(self, user_attributes):
-        value = bt2_value.create_value(user_attributes)
-        bt2_utils._check_type(value, bt2_value.MapValue)
-        native_bt.trace_class_set_user_attributes(self._ptr, value._ptr)
-
-    _user_attributes = property(fset=_user_attributes)
+    @staticmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        native_bt.trace_class_set_user_attributes(obj_ptr, value_ptr)
 
     def _assigns_automatic_stream_class_id(self, auto_id):
         bt2_utils._check_bool(auto_id)
diff --git a/src/bindings/python/bt2/bt2/user_attributes.py b/src/bindings/python/bt2/bt2/user_attributes.py
new file mode 100644 (file)
index 0000000..810dcbd
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: MIT
+#
+# Copyright (c) 2023 EfficiOS, Inc.
+
+import abc
+
+from bt2 import utils as bt2_utils
+from bt2 import value as bt2_value
+
+
+class _WithUserAttrsBase(abc.ABC):
+    @staticmethod
+    @abc.abstractmethod
+    def _borrow_user_attributes_ptr(ptr):
+        raise NotImplementedError
+
+    @property
+    @abc.abstractmethod
+    def _ptr(self):
+        raise NotImplementedError
+
+
+# Mixin class for objects with user attributes (const version).
+class _WithUserAttrsConst(_WithUserAttrsBase):
+    @property
+    def user_attributes(self) -> bt2_value._MapValueConst:
+        return bt2_value._MapValueConst._create_from_ptr_and_get_ref(
+            self._borrow_user_attributes_ptr(self._ptr)
+        )
+
+
+# Mixin class for objects with user attributes (non-const version).
+class _WithUserAttrs(_WithUserAttrsBase, abc.ABC):
+    @property
+    def user_attributes(self) -> bt2_value.MapValue:
+        return bt2_value.MapValue._create_from_ptr_and_get_ref(
+            self._borrow_user_attributes_ptr(self._ptr)
+        )
+
+    @staticmethod
+    @abc.abstractmethod
+    def _set_user_attributes_ptr(obj_ptr, value_ptr):
+        raise NotImplementedError
+
+    def _user_attributes(self, user_attributes):
+        value = bt2_value.create_value(user_attributes)
+        bt2_utils._check_type(value, bt2_value.MapValue)
+        self._set_user_attributes_ptr(self._ptr, value._ptr)
+
+    _user_attributes = property(fset=_user_attributes)
index 843333c8d6df91e0ccf0047d00dff3406ffaf04c..b705803dd83dfb5681b0bc3756c7c6bdb2cfe898 100644 (file)
@@ -7,10 +7,13 @@ import uuid
 import unittest
 
 import bt2
-import utils
 from bt2 import value as bt2_value
 from bt2 import clock_class as bt2_clock_class
-from utils import TestOutputPortMessageIterator, run_in_component_init
+from utils import (
+    TestOutputPortMessageIterator,
+    run_in_component_init,
+    get_const_event_message,
+)
 
 
 class ClockClassOffsetTestCase(unittest.TestCase):
@@ -198,6 +201,11 @@ class ClockClassTestCase(unittest.TestCase):
         self.assertEqual(cc.user_attributes, {"salut": 23})
         self.assertIs(type(cc.user_attributes), bt2_value.MapValue)
 
+    def test_const_user_attributes(self):
+        cc = get_const_event_message().default_clock_snapshot.clock_class
+        self.assertEqual(cc.user_attributes, {"a-clock-class-attribute": 1})
+        self.assertIs(type(cc.user_attributes), bt2._MapValueConst)
+
     def test_create_invalid_user_attributes(self):
         def f(comp_self):
             return comp_self._create_clock_class(user_attributes=object())
@@ -210,10 +218,6 @@ class ClockClassTestCase(unittest.TestCase):
 
         self.assertRaisesInComponentInit(TypeError, f)
 
-    def test_const_user_attributes(self):
-        cc = utils.get_const_event_message().default_clock_snapshot.clock_class
-        self.assertIs(type(cc.user_attributes), bt2_value._MapValueConst)
-
 
 class ClockSnapshotTestCase(unittest.TestCase):
     def setUp(self):
index bae158b16565e4dfc335948fa6a1b295a62d69fc..ab3d370ff037bbd56049493294437f1c8ee48713 100644 (file)
@@ -43,7 +43,7 @@ class StreamTestCase(unittest.TestCase):
 
     def test_const_user_attributes(self):
         stream = utils.get_const_stream_beginning_message().stream
-        self.assertEqual(stream.user_attributes, {"salut": 23})
+        self.assertEqual(stream.user_attributes, {"a-stream-attribute": 1})
         self.assertIs(type(stream.user_attributes), bt2_value._MapValueConst)
 
     def test_create_invalid_user_attributes(self):
index 3668fe865bb8df2c33ec8ee76d08e7b0afc49ebc..635f8644325410b3d993ac4ea3b1c9f5f47d09d7 100644 (file)
@@ -5,12 +5,13 @@
 
 import unittest
 
+from bt2 import value as bt2_value
 from bt2 import clock_class as bt2_clock_class
 from bt2 import event_class as bt2_event_class
 from bt2 import field_class as bt2_field_class
 from bt2 import trace_class as bt2_trace_class
 from bt2 import stream_class as bt2_stream_class
-from utils import run_in_component_init
+from utils import run_in_component_init, get_const_stream_beginning_message
 
 
 class StreamClassTestCase(unittest.TestCase):
@@ -118,6 +119,12 @@ class StreamClassTestCase(unittest.TestCase):
     def test_create_user_attributes(self):
         sc = self._tc.create_stream_class(user_attributes={"salut": 23})
         self.assertEqual(sc.user_attributes, {"salut": 23})
+        self.assertIs(type(sc.user_attributes), bt2_value.MapValue)
+
+    def test_const_user_attributes(self):
+        sc = get_const_stream_beginning_message().stream.cls
+        self.assertEqual(sc.user_attributes, {"a-stream-class-attribute": 1})
+        self.assertIs(type(sc.user_attributes), bt2_value._MapValueConst)
 
     def test_create_invalid_user_attributes(self):
         with self.assertRaisesRegex(
index 0ce6e1358a89c886043e9eb7545b4ef55300a1e2..c984f85a9759cfdd076553f78385d5f6f7240f00 100644 (file)
@@ -12,7 +12,7 @@ from bt2 import utils as bt2_utils
 from bt2 import value as bt2_value
 from bt2 import stream as bt2_stream
 from bt2 import trace_class as bt2_trace_class
-from utils import get_default_trace_class
+from utils import get_default_trace_class, get_const_stream_beginning_message
 
 
 class TraceTestCase(unittest.TestCase):
@@ -35,6 +35,11 @@ class TraceTestCase(unittest.TestCase):
         self.assertEqual(trace.user_attributes, {"salut": 23})
         self.assertIs(type(trace.user_attributes), bt2_value.MapValue)
 
+    def test_const_user_attributes(self):
+        trace = get_const_stream_beginning_message().stream.trace
+        self.assertEqual(trace.user_attributes, {"a-trace-attribute": 1})
+        self.assertIs(type(trace.user_attributes), bt2_value._MapValueConst)
+
     def test_create_invalid_user_attributes(self):
         with self.assertRaises(TypeError):
             self._tc(user_attributes=object())
index fd5f8deb26b1a1f75691bbb14176103e7335a967..a8120645bfdc73c53e42823d5e17a42faa44401b 100644 (file)
@@ -6,6 +6,7 @@
 import unittest
 
 from bt2 import utils as bt2_utils
+from bt2 import value as bt2_value
 from bt2 import trace_class as bt2_trace_class
 from bt2 import stream_class as bt2_stream_class
 from utils import (
@@ -44,6 +45,12 @@ class TraceClassTestCase(unittest.TestCase):
 
         tc = run_in_component_init(f)
         self.assertEqual(tc.user_attributes, {"salut": 23})
+        self.assertIs(type(tc.user_attributes), bt2_value.MapValue)
+
+    def test_const_user_attributes(self):
+        tc = get_const_stream_beginning_message().stream.trace.cls
+        self.assertEqual(tc.user_attributes, {"a-trace-class-attribute": 1})
+        self.assertIs(type(tc.user_attributes), bt2_value._MapValueConst)
 
     def test_create_invalid_user_attributes(self):
         def f(comp_self):
index 3a5fcb058fdad8327442aa714506e1b0216ca842..8d25dcfd5527e2da650e1c7dfa5abc3d90d4b9fe 100644 (file)
@@ -113,8 +113,12 @@ def _get_all_message_types(with_packet=True):
 
     class MySrc(bt2._UserSourceComponent, message_iterator_class=MyIter):
         def __init__(self, config, params, obj):
-            tc = self._create_trace_class()
-            clock_class = self._create_clock_class(frequency=1000)
+            tc = self._create_trace_class(
+                user_attributes={"a-trace-class-attribute": 1}
+            )
+            clock_class = self._create_clock_class(
+                frequency=1000, user_attributes={"a-clock-class-attribute": 1}
+            )
 
             # event common context (stream-class-defined)
             cc = tc.create_structure_field_class()
@@ -132,6 +136,7 @@ def _get_all_message_types(with_packet=True):
                 event_common_context_field_class=cc,
                 packet_context_field_class=pc,
                 supports_packets=with_packet,
+                user_attributes={"a-stream-class-attribute": 1},
             )
 
             # specific context (event-class-defined)
@@ -143,11 +148,18 @@ def _get_all_message_types(with_packet=True):
             ep += [("giraffe", tc.create_signed_integer_field_class(32))]
 
             event_class = stream_class.create_event_class(
-                name="garou", specific_context_field_class=sc, payload_field_class=ep
+                name="garou",
+                specific_context_field_class=sc,
+                payload_field_class=ep,
+                user_attributes={"an-event-class-attribute": 1},
             )
 
-            trace = tc(environment={"patate": 12})
-            stream = trace.create_stream(stream_class, user_attributes={"salut": 23})
+            trace = tc(
+                environment={"patate": 12}, user_attributes={"a-trace-attribute": 1}
+            )
+            stream = trace.create_stream(
+                stream_class, user_attributes={"a-stream-attribute": 1}
+            )
 
             if with_packet:
                 packet = stream.create_packet()
This page took 0.044371 seconds and 4 git commands to generate.