From 568865d9b2138625f9c4f99adcc94dea6affac69 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 16 Oct 2023 16:25:32 -0400 Subject: [PATCH] python: factor out user_attributes getters and setters 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 Reviewed-on: https://review.lttng.org/c/babeltrace/+/10243 Reviewed-by: Philippe Proulx --- src/bindings/python/bt2/Makefile.am | 1 + src/bindings/python/bt2/bt2/clock_class.py | 39 ++--- src/bindings/python/bt2/bt2/event_class.py | 25 +--- src/bindings/python/bt2/bt2/field_class.py | 141 +++++++----------- src/bindings/python/bt2/bt2/stream.py | 43 ++---- src/bindings/python/bt2/bt2/stream_class.py | 37 +++-- src/bindings/python/bt2/bt2/trace.py | 44 +++--- src/bindings/python/bt2/bt2/trace_class.py | 47 +++--- .../python/bt2/bt2/user_attributes.py | 50 +++++++ tests/bindings/python/bt2/test_clock_class.py | 16 +- tests/bindings/python/bt2/test_stream.py | 2 +- .../bindings/python/bt2/test_stream_class.py | 9 +- tests/bindings/python/bt2/test_trace.py | 7 +- tests/bindings/python/bt2/test_trace_class.py | 7 + tests/bindings/python/bt2/utils.py | 22 ++- 15 files changed, 248 insertions(+), 242 deletions(-) create mode 100644 src/bindings/python/bt2/bt2/user_attributes.py diff --git a/src/bindings/python/bt2/Makefile.am b/src/bindings/python/bt2/Makefile.am index af203041..c723a2f2 100644 --- a/src/bindings/python/bt2/Makefile.am +++ b/src/bindings/python/bt2/Makefile.am @@ -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 diff --git a/src/bindings/python/bt2/bt2/clock_class.py b/src/bindings/python/bt2/bt2/clock_class.py index c7527c77..e87e6825 100644 --- a/src/bindings/python/bt2/bt2/clock_class.py +++ b/src/bindings/python/bt2/bt2/clock_class.py @@ -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) diff --git a/src/bindings/python/bt2/bt2/event_class.py b/src/bindings/python/bt2/bt2/event_class.py index 54ca10a6..a6745c17 100644 --- a/src/bindings/python/bt2/bt2/event_class.py +++ b/src/bindings/python/bt2/bt2/event_class.py @@ -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) diff --git a/src/bindings/python/bt2/bt2/field_class.py b/src/bindings/python/bt2/bt2/field_class.py index 8594b496..73965357 100644 --- a/src/bindings/python/bt2/bt2/field_class.py +++ b/src/bindings/python/bt2/bt2/field_class.py @@ -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): diff --git a/src/bindings/python/bt2/bt2/stream.py b/src/bindings/python/bt2/bt2/stream.py index 9d8d1ae9..15836455 100644 --- a/src/bindings/python/bt2/bt2/stream.py +++ b/src/bindings/python/bt2/bt2/stream.py @@ -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) diff --git a/src/bindings/python/bt2/bt2/stream_class.py b/src/bindings/python/bt2/bt2/stream_class.py index 5c6faa07..41fa12ab 100644 --- a/src/bindings/python/bt2/bt2/stream_class.py +++ b/src/bindings/python/bt2/bt2/stream_class.py @@ -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) diff --git a/src/bindings/python/bt2/bt2/trace.py b/src/bindings/python/bt2/bt2/trace.py index a7038b28..b5363e49 100644 --- a/src/bindings/python/bt2/bt2/trace.py +++ b/src/bindings/python/bt2/bt2/trace.py @@ -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) diff --git a/src/bindings/python/bt2/bt2/trace_class.py b/src/bindings/python/bt2/bt2/trace_class.py index a691da30..dc872eab 100644 --- a/src/bindings/python/bt2/bt2/trace_class.py +++ b/src/bindings/python/bt2/bt2/trace_class.py @@ -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 index 00000000..810dcbdb --- /dev/null +++ b/src/bindings/python/bt2/bt2/user_attributes.py @@ -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) diff --git a/tests/bindings/python/bt2/test_clock_class.py b/tests/bindings/python/bt2/test_clock_class.py index 843333c8..b705803d 100644 --- a/tests/bindings/python/bt2/test_clock_class.py +++ b/tests/bindings/python/bt2/test_clock_class.py @@ -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): diff --git a/tests/bindings/python/bt2/test_stream.py b/tests/bindings/python/bt2/test_stream.py index bae158b1..ab3d370f 100644 --- a/tests/bindings/python/bt2/test_stream.py +++ b/tests/bindings/python/bt2/test_stream.py @@ -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): diff --git a/tests/bindings/python/bt2/test_stream_class.py b/tests/bindings/python/bt2/test_stream_class.py index 3668fe86..635f8644 100644 --- a/tests/bindings/python/bt2/test_stream_class.py +++ b/tests/bindings/python/bt2/test_stream_class.py @@ -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( diff --git a/tests/bindings/python/bt2/test_trace.py b/tests/bindings/python/bt2/test_trace.py index 0ce6e135..c984f85a 100644 --- a/tests/bindings/python/bt2/test_trace.py +++ b/tests/bindings/python/bt2/test_trace.py @@ -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()) diff --git a/tests/bindings/python/bt2/test_trace_class.py b/tests/bindings/python/bt2/test_trace_class.py index fd5f8deb..a8120645 100644 --- a/tests/bindings/python/bt2/test_trace_class.py +++ b/tests/bindings/python/bt2/test_trace_class.py @@ -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): diff --git a/tests/bindings/python/bt2/utils.py b/tests/bindings/python/bt2/utils.py index 3a5fcb05..8d25dcfd 100644 --- a/tests/bindings/python/bt2/utils.py +++ b/tests/bindings/python/bt2/utils.py @@ -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() -- 2.34.1