From f865c2aa246e2bd94037b02b7f3b23e4f59985f6 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Sat, 10 Aug 2019 14:53:32 -0400 Subject: [PATCH] bt2: add `ComponentDescriptor` class and test The goal of a `ComponentDescriptor` object is to eventually be used within an array of descriptors passed to a function which computes an effective message interchange protocol version with the help of version support component class methods. I choose not to wrap the `bt_component_descriptor_set` API as this is so simple and will be used at a single location. Signed-off-by: Philippe Proulx Change-Id: Ifef9b4fb0a7cf0278dbf8bed2d18d0b47934a272 Reviewed-on: https://review.lttng.org/c/babeltrace/+/1873 Tested-by: jenkins Reviewed-by: Simon Marchi --- src/bindings/python/bt2/Makefile.am | 1 + src/bindings/python/bt2/bt2/__init__.py | 1 + .../python/bt2/bt2/component_descriptor.py | 90 +++++++++++++++++++ .../python/bt2/test_component_descriptor.py | 68 ++++++++++++++ tests/bindings/python/bt2/test_package.py | 3 + 5 files changed, 163 insertions(+) create mode 100644 src/bindings/python/bt2/bt2/component_descriptor.py create mode 100644 tests/bindings/python/bt2/test_component_descriptor.py diff --git a/src/bindings/python/bt2/Makefile.am b/src/bindings/python/bt2/Makefile.am index a0eb73a9..75a65689 100644 --- a/src/bindings/python/bt2/Makefile.am +++ b/src/bindings/python/bt2/Makefile.am @@ -57,6 +57,7 @@ STATIC_BINDINGS_DEPS = \ bt2/clock_class.py \ bt2/clock_snapshot.py \ bt2/component.py \ + bt2/component_descriptor.py \ bt2/connection.py \ bt2/error.py \ bt2/event.py \ diff --git a/src/bindings/python/bt2/bt2/__init__.py b/src/bindings/python/bt2/bt2/__init__.py index 0bead489..9dd9f2e1 100644 --- a/src/bindings/python/bt2/bt2/__init__.py +++ b/src/bindings/python/bt2/bt2/__init__.py @@ -33,6 +33,7 @@ from bt2.component import _SinkComponent from bt2.component import _UserSourceComponent from bt2.component import _UserFilterComponent from bt2.component import _UserSinkComponent +from bt2.component_descriptor import ComponentDescriptor from bt2.error import ComponentClassType from bt2.error import _ErrorCause from bt2.error import _ComponentErrorCause diff --git a/src/bindings/python/bt2/bt2/component_descriptor.py b/src/bindings/python/bt2/bt2/component_descriptor.py new file mode 100644 index 00000000..f86928d2 --- /dev/null +++ b/src/bindings/python/bt2/bt2/component_descriptor.py @@ -0,0 +1,90 @@ +# The MIT License (MIT) +# +# Copyright (c) 2017 Philippe Proulx +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from bt2 import native_bt, object, utils +from bt2 import component as bt2_component +import bt2 + + +def _is_source_comp_cls(comp_cls): + if isinstance(comp_cls, bt2_component._SourceComponentClass): + return True + + try: + return issubclass(comp_cls, bt2_component._UserSourceComponent) + except: + return False + + +def _is_filter_comp_cls(comp_cls): + if isinstance(comp_cls, bt2_component._FilterComponentClass): + return True + + try: + return issubclass(comp_cls, bt2_component._UserFilterComponent) + except: + return False + + +def _is_sink_comp_cls(comp_cls): + if isinstance(comp_cls, bt2_component._SinkComponentClass): + return True + + try: + return issubclass(comp_cls, bt2_component._UserSinkComponent) + except: + return False + + +class ComponentDescriptor: + def __init__(self, component_class, params=None, obj=None): + if ( + not _is_source_comp_cls(component_class) + and not _is_filter_comp_cls(component_class) + and not _is_sink_comp_cls(component_class) + ): + raise TypeError( + "'{}' is not a component class".format( + component_class.__class__.__name__ + ) + ) + + base_cc_ptr = component_class._bt_component_class_ptr() + + if obj is not None and not native_bt.bt2_is_python_component_class(base_cc_ptr): + raise ValueError('cannot pass a Python object to a non-Python component') + + self._comp_cls = component_class + self._params = bt2.create_value(params) + self._obj = obj + + @property + def component_class(self): + return self._comp_cls + + @property + def params(self): + return self._params + + @property + def obj(self): + return self._obj diff --git a/tests/bindings/python/bt2/test_component_descriptor.py b/tests/bindings/python/bt2/test_component_descriptor.py new file mode 100644 index 00000000..1dfec54e --- /dev/null +++ b/tests/bindings/python/bt2/test_component_descriptor.py @@ -0,0 +1,68 @@ +# +# Copyright (C) 2019 EfficiOS Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; only version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +import unittest +import bt2 + + +class _DummySink(bt2._UserSinkComponent): + def _user_consume(self): + pass + + +class ComponentDescriptorTestCase(unittest.TestCase): + def setUp(self): + self._obj = object() + self._comp_descr = bt2.ComponentDescriptor(_DummySink, {'zoom': -23}, self._obj) + + def _get_comp_cls_from_plugin(self): + plugin = bt2.find_plugin('text', find_in_user_dir=False, find_in_sys_dir=False) + assert plugin is not None + cc = plugin.source_component_classes['dmesg'] + assert cc is not None + return cc + + def test_init_invalid_cls_type(self): + with self.assertRaises(TypeError): + bt2.ComponentDescriptor(int) + + def test_init_invalid_params_type(self): + with self.assertRaises(TypeError): + bt2.ComponentDescriptor(_DummySink, object()) + + def test_init_invalid_obj_non_python_comp_cls(self): + cc = self._get_comp_cls_from_plugin() + + with self.assertRaises(ValueError): + bt2.ComponentDescriptor(cc, obj=57) + + def test_init_with_user_comp_cls(self): + bt2.ComponentDescriptor(_DummySink) + + def test_init_with_gen_comp_cls(self): + cc = self._get_comp_cls_from_plugin() + bt2.ComponentDescriptor(cc) + + def test_attr_component_class(self): + self.assertIs(self._comp_descr.component_class, _DummySink) + + def test_attr_params(self): + self.assertEqual(self._comp_descr.params, {'zoom': -23}) + + def test_attr_obj(self): + self.assertIs(self._comp_descr.obj, self._obj) diff --git a/tests/bindings/python/bt2/test_package.py b/tests/bindings/python/bt2/test_package.py index 32c4791f..d118462b 100644 --- a/tests/bindings/python/bt2/test_package.py +++ b/tests/bindings/python/bt2/test_package.py @@ -183,6 +183,9 @@ class PackageTestCase(unittest.TestCase): def test_has__CurrentArrayElementFieldPathItem(self): self._assert_in_bt2('_CurrentArrayElementFieldPathItem') + def test_has_ComponentDescriptor(self): + self._assert_in_bt2('ComponentDescriptor') + def test_has_Graph(self): self._assert_in_bt2('Graph') -- 2.34.1