From 8d99efe64b53dbcf1272be9b10e264fbd2eb6abb Mon Sep 17 00:00:00 2001 From: Francis Deslauriers Date: Thu, 3 Oct 2019 08:30:05 -0400 Subject: [PATCH] bt2: add `IntegerRangeSet` const classes Outside of simple rename and splitting, this commit changes the `__eq__` methods so that it's possible to compare const and non-const objects together. I also renamed the `_range_type` to `_range_pycls` to follow what is done in other files and `_borrow_range_by_index_ptr` to `_borrow_range_ptr_by_index` to increase readability. Signed-off-by: Francis Deslauriers Change-Id: I04b4027d297d088c6531be04681598653601579d Reviewed-on: https://review.lttng.org/c/babeltrace/+/2118 Reviewed-by: Philippe Proulx Tested-by: jenkins --- src/bindings/python/bt2/bt2/__init__.py | 4 + src/bindings/python/bt2/bt2/field_class.py | 12 +-- .../python/bt2/bt2/integer_range_set.py | 90 ++++++++++++------- tests/bindings/python/bt2/test_field_class.py | 10 +++ .../python/bt2/test_integer_range_set.py | 89 ++++++++++++++++++ tests/bindings/python/bt2/test_package.py | 12 +++ 6 files changed, 178 insertions(+), 39 deletions(-) diff --git a/src/bindings/python/bt2/bt2/__init__.py b/src/bindings/python/bt2/bt2/__init__.py index 3d102e66..e53f0aca 100644 --- a/src/bindings/python/bt2/bt2/__init__.py +++ b/src/bindings/python/bt2/bt2/__init__.py @@ -129,6 +129,10 @@ from bt2.integer_range_set import SignedIntegerRange from bt2.integer_range_set import UnsignedIntegerRange from bt2.integer_range_set import SignedIntegerRangeSet from bt2.integer_range_set import UnsignedIntegerRangeSet +from bt2.integer_range_set import _SignedIntegerRangeConst +from bt2.integer_range_set import _UnsignedIntegerRangeConst +from bt2.integer_range_set import _SignedIntegerRangeSetConst +from bt2.integer_range_set import _UnsignedIntegerRangeSetConst from bt2.interrupter import Interrupter from bt2.logging import LoggingLevel from bt2.logging import get_minimal_logging_level diff --git a/src/bindings/python/bt2/bt2/field_class.py b/src/bindings/python/bt2/bt2/field_class.py index 5aa72a0a..12ecced0 100644 --- a/src/bindings/python/bt2/bt2/field_class.py +++ b/src/bindings/python/bt2/bt2/field_class.py @@ -218,7 +218,7 @@ class _EnumerationFieldClassMapping: class _UnsignedEnumerationFieldClassMappingConst(_EnumerationFieldClassMapping): - _range_set_pycls = bt2_integer_range_set.UnsignedIntegerRangeSet + _range_set_pycls = bt2_integer_range_set._UnsignedIntegerRangeSetConst _as_enumeration_field_class_mapping_ptr = staticmethod( native_bt.field_class_enumeration_unsigned_mapping_as_mapping_const ) @@ -228,7 +228,7 @@ class _UnsignedEnumerationFieldClassMappingConst(_EnumerationFieldClassMapping): class _SignedEnumerationFieldClassMappingConst(_EnumerationFieldClassMapping): - _range_set_pycls = bt2_integer_range_set.SignedIntegerRangeSet + _range_set_pycls = bt2_integer_range_set._SignedIntegerRangeSetConst _as_enumeration_field_class_mapping_ptr = staticmethod( native_bt.field_class_enumeration_signed_mapping_as_mapping_const ) @@ -291,7 +291,6 @@ class _UnsignedEnumerationFieldClassConst( _EnumerationFieldClassConst, _UnsignedIntegerFieldClassConst ): _NAME = 'Const unsigned enumeration' - _range_set_pycls = bt2_integer_range_set.UnsignedIntegerRangeSet _borrow_mapping_ptr_by_label = staticmethod( native_bt.field_class_enumeration_unsigned_borrow_mapping_by_label_const ) @@ -311,6 +310,7 @@ class _UnsignedEnumerationFieldClass( _UnsignedIntegerFieldClass, ): _NAME = 'Unsigned enumeration' + _range_set_pycls = bt2_integer_range_set.UnsignedIntegerRangeSet _add_mapping = staticmethod(native_bt.field_class_enumeration_unsigned_add_mapping) @@ -318,7 +318,6 @@ class _SignedEnumerationFieldClassConst( _EnumerationFieldClassConst, _SignedIntegerFieldClassConst ): _NAME = 'Const signed enumeration' - _range_set_pycls = bt2_integer_range_set.SignedIntegerRangeSet _borrow_mapping_ptr_by_label = staticmethod( native_bt.field_class_enumeration_signed_borrow_mapping_by_label_const ) @@ -336,6 +335,7 @@ class _SignedEnumerationFieldClass( _SignedEnumerationFieldClassConst, _EnumerationFieldClass, _SignedIntegerFieldClass ): _NAME = 'Signed enumeration' + _range_set_pycls = bt2_integer_range_set.SignedIntegerRangeSet _add_mapping = staticmethod(native_bt.field_class_enumeration_signed_add_mapping) @@ -621,7 +621,7 @@ class _VariantFieldClassWithSignedSelectorOptionConst( _borrow_ranges_ptr = staticmethod( native_bt.field_class_variant_with_selector_signed_option_borrow_ranges_const ) - _range_set_pycls = bt2_integer_range_set.SignedIntegerRangeSet + _range_set_pycls = bt2_integer_range_set._SignedIntegerRangeSetConst class _VariantFieldClassWithSignedSelectorOption( @@ -640,7 +640,7 @@ class _VariantFieldClassWithUnsignedSelectorOptionConst( _borrow_ranges_ptr = staticmethod( native_bt.field_class_variant_with_selector_unsigned_option_borrow_ranges_const ) - _range_set_pycls = bt2_integer_range_set.UnsignedIntegerRangeSet + _range_set_pycls = bt2_integer_range_set._UnsignedIntegerRangeSetConst class _VariantFieldClassWithUnsignedSelectorOption( diff --git a/src/bindings/python/bt2/bt2/integer_range_set.py b/src/bindings/python/bt2/bt2/integer_range_set.py index 09d7b08f..44f08ed4 100644 --- a/src/bindings/python/bt2/bt2/integer_range_set.py +++ b/src/bindings/python/bt2/bt2/integer_range_set.py @@ -25,7 +25,7 @@ import collections.abc import bt2 -class _IntegerRange: +class _IntegerRangeConst: def __init__(self, lower, upper=None): self._check_type(lower) @@ -57,36 +57,36 @@ class _IntegerRange: return value >= self._lower and value <= self._upper def __eq__(self, other): - if type(other) is not type(self): + if not isinstance(other, _IntegerRangeConst): return False return self.lower == other.lower and self.upper == other.upper -class SignedIntegerRange(_IntegerRange): +class _IntegerRange(_IntegerRangeConst): + def __init__(self, lower, upper=None): + super().__init__(lower, upper) + + +class _SignedIntegerRangeConst(_IntegerRangeConst): _is_type = staticmethod(utils._is_int64) _check_type = staticmethod(utils._check_int64) -class UnsignedIntegerRange(_IntegerRange): - _is_type = staticmethod(utils._is_uint64) - _check_type = staticmethod(utils._check_uint64) +class SignedIntegerRange(_SignedIntegerRangeConst, _IntegerRange): + pass -class _IntegerRangeSet(object._SharedObject, collections.abc.MutableSet): - def __init__(self, ranges=None): - ptr = self._create_range_set() +class _UnsignedIntegerRangeConst(_IntegerRangeConst): + _is_type = staticmethod(utils._is_uint64) + _check_type = staticmethod(utils._check_uint64) - if ptr is None: - raise bt2._MemoryError('cannot create range set object') - super().__init__(ptr) +class UnsignedIntegerRange(_UnsignedIntegerRangeConst, _IntegerRange): + pass - if ranges is not None: - # will raise if not iterable - for rg in ranges: - self.add(rg) +class _IntegerRangeSetConst(object._SharedObject, collections.abc.Set): def __len__(self): range_set_ptr = self._as_range_set_ptr(self._ptr) count = native_bt.integer_range_set_get_range_count(range_set_ptr) @@ -102,14 +102,15 @@ class _IntegerRangeSet(object._SharedObject, collections.abc.MutableSet): def __iter__(self): for idx in range(len(self)): - rg_ptr = self._borrow_range_by_index_ptr(self._ptr, idx) + rg_ptr = self._borrow_range_ptr_by_index(self._ptr, idx) assert rg_ptr is not None lower = self._range_get_lower(rg_ptr) upper = self._range_get_upper(rg_ptr) - yield self._range_type(lower, upper) + yield self._range_pycls(lower, upper) def __eq__(self, other): - if type(other) is not type(self): + + if not isinstance(other, _IntegerRangeSetConst): return False return self._compare(self._ptr, other._ptr) @@ -121,13 +122,28 @@ class _IntegerRangeSet(object._SharedObject, collections.abc.MutableSet): return False + +class _IntegerRangeSet(_IntegerRangeSetConst, collections.abc.MutableSet): + def __init__(self, ranges=None): + ptr = self._create_range_set() + + if ptr is None: + raise bt2._MemoryError('cannot create range set object') + + super().__init__(ptr) + + if ranges is not None: + # will raise if not iterable + for rg in ranges: + self.add(rg) + def add(self, rg): - if type(rg) is not self._range_type: - if self._range_type._is_type(rg): - rg = self._range_type(rg) + if type(rg) is not self._range_pycls: + if self._range_pycls._is_type(rg): + rg = self._range_pycls(rg) else: # assume it's a simple pair (will raise if it's not) - rg = self._range_type(rg[0], rg[1]) + rg = self._range_pycls(rg[0], rg[1]) status = self._add_range(self._ptr, rg.lower, rg.upper) utils._handle_func_status(status, 'cannot add range to range set object') @@ -136,35 +152,43 @@ class _IntegerRangeSet(object._SharedObject, collections.abc.MutableSet): raise NotImplementedError -class SignedIntegerRangeSet(_IntegerRangeSet): +class _SignedIntegerRangeSetConst(_IntegerRangeSetConst): _get_ref = staticmethod(native_bt.integer_range_set_signed_get_ref) _put_ref = staticmethod(native_bt.integer_range_set_signed_put_ref) _as_range_set_ptr = staticmethod( native_bt.integer_range_set_signed_as_range_set_const ) - _create_range_set = staticmethod(native_bt.integer_range_set_signed_create) - _borrow_range_by_index_ptr = staticmethod( + _borrow_range_ptr_by_index = staticmethod( native_bt.integer_range_set_signed_borrow_range_by_index_const ) _range_get_lower = staticmethod(native_bt.integer_range_signed_get_lower) _range_get_upper = staticmethod(native_bt.integer_range_signed_get_upper) - _add_range = staticmethod(native_bt.integer_range_set_signed_add_range) _compare = staticmethod(native_bt.integer_range_set_signed_compare) - _range_type = SignedIntegerRange + _range_pycls = _SignedIntegerRangeConst -class UnsignedIntegerRangeSet(_IntegerRangeSet): +class SignedIntegerRangeSet(_SignedIntegerRangeSetConst, _IntegerRangeSet): + _create_range_set = staticmethod(native_bt.integer_range_set_signed_create) + _add_range = staticmethod(native_bt.integer_range_set_signed_add_range) + _range_pycls = SignedIntegerRange + + +class _UnsignedIntegerRangeSetConst(_IntegerRangeSetConst): _get_ref = staticmethod(native_bt.integer_range_set_unsigned_get_ref) _put_ref = staticmethod(native_bt.integer_range_set_unsigned_put_ref) _as_range_set_ptr = staticmethod( native_bt.integer_range_set_unsigned_as_range_set_const ) - _create_range_set = staticmethod(native_bt.integer_range_set_unsigned_create) - _borrow_range_by_index_ptr = staticmethod( + _borrow_range_ptr_by_index = staticmethod( native_bt.integer_range_set_unsigned_borrow_range_by_index_const ) _range_get_lower = staticmethod(native_bt.integer_range_unsigned_get_lower) _range_get_upper = staticmethod(native_bt.integer_range_unsigned_get_upper) - _add_range = staticmethod(native_bt.integer_range_set_unsigned_add_range) _compare = staticmethod(native_bt.integer_range_set_unsigned_compare) - _range_type = UnsignedIntegerRange + _range_pycls = _UnsignedIntegerRangeConst + + +class UnsignedIntegerRangeSet(_UnsignedIntegerRangeSetConst, _IntegerRangeSet): + _create_range_set = staticmethod(native_bt.integer_range_set_unsigned_create) + _add_range = staticmethod(native_bt.integer_range_set_unsigned_add_range) + _range_pycls = UnsignedIntegerRange diff --git a/tests/bindings/python/bt2/test_field_class.py b/tests/bindings/python/bt2/test_field_class.py index b59cc72f..ef0f5647 100644 --- a/tests/bindings/python/bt2/test_field_class.py +++ b/tests/bindings/python/bt2/test_field_class.py @@ -374,6 +374,8 @@ class _EnumerationFieldClassTestCase(_TestIntegerFieldClassProps): mapping = self._fc['a'] self.assertEqual(mapping.label, 'a') self.assertEqual(mapping.ranges, self._ranges1) + self.assertIs(type(mapping), self._MAPPING_CLASS) + self.assertIs(type(mapping.ranges), self._CONST_RANGE_SET_CLASS) def test_getitem_nonexistent(self): with self.assertRaises(KeyError): @@ -402,6 +404,10 @@ class _EnumerationFieldClassTestCase(_TestIntegerFieldClassProps): class UnsignedEnumerationFieldClassTestCase( _EnumerationFieldClassTestCase, _TestFieldClass, unittest.TestCase ): + _MAPPING_CLASS = bt2_field_class._UnsignedEnumerationFieldClassMappingConst + _RANGE_SET_CLASS = bt2.UnsignedIntegerRangeSet + _CONST_RANGE_SET_CLASS = bt2._UnsignedIntegerRangeSetConst + def _spec_set_up(self): self._ranges1 = bt2.UnsignedIntegerRangeSet([(1, 4), (18, 47)]) self._ranges2 = bt2.UnsignedIntegerRangeSet([(5, 5)]) @@ -428,6 +434,10 @@ class UnsignedEnumerationFieldClassTestCase( class SignedEnumerationFieldClassTestCase( _EnumerationFieldClassTestCase, _TestFieldClass, unittest.TestCase ): + _MAPPING_CLASS = bt2_field_class._SignedEnumerationFieldClassMappingConst + _RANGE_SET_CLASS = bt2.SignedIntegerRangeSet + _CONST_RANGE_SET_CLASS = bt2._SignedIntegerRangeSetConst + def _spec_set_up(self): self._ranges1 = bt2.SignedIntegerRangeSet([(-10, -4), (18, 47)]) self._ranges2 = bt2.SignedIntegerRangeSet([(-3, -3)]) diff --git a/tests/bindings/python/bt2/test_integer_range_set.py b/tests/bindings/python/bt2/test_integer_range_set.py index bc57526e..2d502fdb 100644 --- a/tests/bindings/python/bt2/test_integer_range_set.py +++ b/tests/bindings/python/bt2/test_integer_range_set.py @@ -19,14 +19,51 @@ import bt2 import unittest +from utils import ( + get_default_trace_class, + TestOutputPortMessageIterator, + create_const_field, +) + + +def get_const_signed_integer_range(int_ranges): + def range_setter(field): + field.value = 12 + + tc = get_default_trace_class() + fc = tc.create_signed_enumeration_field_class(32) + fc.add_mapping('something', bt2.SignedIntegerRangeSet(int_ranges)) + + return create_const_field(tc, fc, range_setter).cls['something'].ranges + + +def get_const_unsigned_integer_range(int_ranges): + def range_setter(field): + field.value = 12 + + tc = get_default_trace_class() + fc = tc.create_unsigned_enumeration_field_class(32) + fc.add_mapping('something', bt2.UnsignedIntegerRangeSet(int_ranges)) + + return create_const_field(tc, fc, range_setter).cls['something'].ranges + class _IntegerRangeTestCase: def setUp(self): self._rg = self._CLS(self._def_lower, self._def_upper) + self._const_rg = list( + self._GET_CONST_RANGE_SET([(self._def_lower, self._def_upper)]) + )[0] def test_create(self): self.assertEqual(self._rg.lower, self._def_lower) self.assertEqual(self._rg.upper, self._def_upper) + self.assertIs(type(self._rg), self._CLS) + + def test_const_create(self): + self.assertEqual(self._const_rg.lower, self._def_lower) + self.assertEqual(self._const_rg.upper, self._def_upper) + self.assertIs(type(self._const_rg), self._CONST_CLS) def test_create_same(self): rg = self._CLS(self._def_lower, self._def_lower) @@ -80,16 +117,31 @@ class _IntegerRangeTestCase: rg = self._CLS(self._def_lower, self._def_upper) self.assertEqual(rg, self._rg) + def test_const_eq(self): + rg = list(self._GET_CONST_RANGE_SET([(self._def_lower, self._def_upper)]))[0] + self.assertEqual(rg, self._const_rg) + + def test_const_nonconst_eq(self): + self.assertEqual(self._rg, self._const_rg) + def test_ne(self): rg = self._CLS(self._def_lower, self._def_upper - 1) self.assertNotEqual(rg, self._rg) + def test_const_ne(self): + rg = list(self._GET_CONST_RANGE_SET([(self._def_lower, self._def_upper - 1)]))[ + 0 + ] + self.assertNotEqual(rg, self._const_rg) + def test_ne_other_type(self): self.assertNotEqual(self._rg, 48) class UnsignedIntegerRangeTestCase(_IntegerRangeTestCase, unittest.TestCase): _CLS = bt2.UnsignedIntegerRange + _CONST_CLS = bt2._UnsignedIntegerRangeConst + _GET_CONST_RANGE_SET = staticmethod(get_const_unsigned_integer_range) _def_lower = 23 _def_upper = 18293 _oob_lower = -1 @@ -98,6 +150,8 @@ class UnsignedIntegerRangeTestCase(_IntegerRangeTestCase, unittest.TestCase): class SignedIntegerRangeTestCase(_IntegerRangeTestCase, unittest.TestCase): _CLS = bt2.SignedIntegerRange + _CONST_CLS = bt2._SignedIntegerRangeConst + _GET_CONST_RANGE_SET = staticmethod(get_const_signed_integer_range) _def_lower = -184 _def_upper = 11547 _oob_lower = -(1 << 63) - 1 @@ -107,12 +161,23 @@ class SignedIntegerRangeTestCase(_IntegerRangeTestCase, unittest.TestCase): class _IntegerRangeSetTestCase: def setUp(self): self._rs = self._CLS((self._range1, self._range2, self._range3)) + self._const_rs = self._GET_CONST_RANGE_SET( + [self._range1, self._range2, self._range3] + ) def test_create(self): self.assertEqual(len(self._rs), 3) self.assertIn(self._range1, self._rs) self.assertIn(self._range2, self._rs) self.assertIn(self._range3, self._rs) + self.assertIs(type(self._range1), self._RANGE_CLS) + + def test_const_create(self): + self.assertEqual(len(self._const_rs), 3) + self.assertIn(self._range1, self._const_rs) + self.assertIn(self._range2, self._const_rs) + self.assertIn(self._range3, self._const_rs) + self.assertIs(type(self._range1), self._RANGE_CLS) def test_create_tuples(self): rs = self._CLS( @@ -165,6 +230,18 @@ class _IntegerRangeSetTestCase: self.assertIn(self._range2, range_list) self.assertIn(self._range3, range_list) + for rg in range_list: + self.assertIs(type(rg), self._RANGE_CLS) + + def test_const_iter(self): + range_list = list(self._const_rs) + self.assertIn(self._range1, range_list) + self.assertIn(self._range2, range_list) + self.assertIn(self._range3, range_list) + + for rg in range_list: + self.assertIs(type(rg), self._CONST_RANGE_CLS) + def test_empty(self): rs = self._CLS() self.assertEqual(len(rs), 0) @@ -177,6 +254,10 @@ class _IntegerRangeSetTestCase: self.assertEqual(len(rs), 2) self.assertIn(self._range2, rs) + def test_const_add_range_obj(self): + with self.assertRaises(AttributeError): + self._const_rs.add((12, 4434)) + def test_discard_not_implemented(self): with self.assertRaises(NotImplementedError): self._rs.discard(self._range2) @@ -207,6 +288,10 @@ class _IntegerRangeSetTestCase: class UnsignedIntegerRangeSetTestCase(_IntegerRangeSetTestCase, unittest.TestCase): _CLS = bt2.UnsignedIntegerRangeSet + _CONST_CLS = bt2._UnsignedIntegerRangeSetConst + _RANGE_CLS = bt2.UnsignedIntegerRange + _CONST_RANGE_CLS = bt2._UnsignedIntegerRangeConst + _GET_CONST_RANGE_SET = staticmethod(get_const_unsigned_integer_range) def setUp(self): self._range1 = bt2.UnsignedIntegerRange(4, 192) @@ -218,6 +303,10 @@ class UnsignedIntegerRangeSetTestCase(_IntegerRangeSetTestCase, unittest.TestCas class SignedIntegerRangeSetTestCase(_IntegerRangeSetTestCase, unittest.TestCase): _CLS = bt2.SignedIntegerRangeSet + _CONST_CLS = bt2._SignedIntegerRangeSetConst + _RANGE_CLS = bt2.SignedIntegerRange + _CONST_RANGE_CLS = bt2._SignedIntegerRangeConst + _GET_CONST_RANGE_SET = staticmethod(get_const_signed_integer_range) def setUp(self): self._range1 = bt2.SignedIntegerRange(-1484, -17) diff --git a/tests/bindings/python/bt2/test_package.py b/tests/bindings/python/bt2/test_package.py index c3295c8a..b2d91592 100644 --- a/tests/bindings/python/bt2/test_package.py +++ b/tests/bindings/python/bt2/test_package.py @@ -342,6 +342,18 @@ class PackageTestCase(unittest.TestCase): def test_has_UnsignedIntegerRangeSet(self): self._assert_in_bt2('UnsignedIntegerRangeSet') + def test_has__SignedIntegerRangeConst(self): + self._assert_in_bt2('_SignedIntegerRangeConst') + + def test_has__UnsignedIntegerRangeConst(self): + self._assert_in_bt2('_UnsignedIntegerRangeConst') + + def test_has__SignedIntegerRangeSetConst(self): + self._assert_in_bt2('_SignedIntegerRangeSetConst') + + def test_has__UnsignedIntegerRangeSetConst(self): + self._assert_in_bt2('_UnsignedIntegerRangeSetConst') + def test_has_Interrupter(self): self._assert_in_bt2('Interrupter') -- 2.34.1