From a01b452be2f3ec30264a06cb1e3da09a5fe124e9 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Sun, 14 Jul 2019 23:19:24 -0400 Subject: [PATCH] bt2: check for _graph_is_configured method in user sink classes Since a _graph_is_configured method is an essential method to implement in any useful sink, check for the presence of that method when instantiating a user sink component class in Python (that is, when the Python class is created). We already do that for the _consume method, and I think it greatly helps the user writing a sink by telling them what not to forget. Change-Id: Ic8c3741b121eccc2857afac809521dd7213aa679 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/1707 Tested-by: jenkins Reviewed-by: Philippe Proulx --- src/bindings/python/bt2/bt2/component.py | 3 + tests/bindings/python/bt2/test_component.py | 27 +++++++++ .../python/bt2/test_component_class.py | 57 +++++++++++++++++++ tests/bindings/python/bt2/test_connection.py | 9 +++ tests/bindings/python/bt2/test_graph.py | 33 +++++++++++ tests/bindings/python/bt2/test_port.py | 45 +++++++++++++++ .../python/bt2/test_query_executor.py | 30 ++++++++++ tests/bindings/python/bt2/utils.py | 3 + .../bt_plugin_test_python_plugin_provider.py | 3 + 9 files changed, 210 insertions(+) diff --git a/src/bindings/python/bt2/bt2/component.py b/src/bindings/python/bt2/bt2/component.py index 9834fa8c..18b502ac 100644 --- a/src/bindings/python/bt2/bt2/component.py +++ b/src/bindings/python/bt2/bt2/component.py @@ -443,6 +443,9 @@ class _UserComponentType(type): comp_cls_descr, comp_cls_help) elif _UserSinkComponent in bases: + if not hasattr(cls, '_graph_is_configured'): + raise bt2.IncompleteUserClass("cannot create component class '{}': missing a _graph_is_configured() method".format(class_name)) + if not hasattr(cls, '_consume'): raise bt2.IncompleteUserClass("cannot create component class '{}': missing a _consume() method".format(class_name)) diff --git a/tests/bindings/python/bt2/test_component.py b/tests/bindings/python/bt2/test_component.py index 4384c665..69e5617b 100644 --- a/tests/bindings/python/bt2/test_component.py +++ b/tests/bindings/python/bt2/test_component.py @@ -40,6 +40,9 @@ class UserComponentTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink, 'yaes') def test_logging_level(self): @@ -50,6 +53,9 @@ class UserComponentTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink, 'yaes', bt2.LoggingLevel.INFO) def test_class(self): @@ -60,6 +66,9 @@ class UserComponentTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._create_comp(MySink) def test_addr(self): @@ -71,6 +80,9 @@ class UserComponentTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._create_comp(MySink) def test_finalize(self): @@ -80,6 +92,9 @@ class UserComponentTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + def _finalize(comp_self): nonlocal finalized finalized = True @@ -107,6 +122,9 @@ class GenericComponentTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink, 'yaes') self.assertEqual(comp.name, 'yaes') @@ -115,6 +133,9 @@ class GenericComponentTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink, 'yaes', bt2.LoggingLevel.WARNING) self.assertEqual(comp.logging_level, bt2.LoggingLevel.WARNING) @@ -123,6 +144,9 @@ class GenericComponentTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) self.assertEqual(comp.cls, MySink) @@ -131,6 +155,9 @@ class GenericComponentTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) self.assertIsInstance(comp.addr, int) self.assertNotEqual(comp.addr, 0) diff --git a/tests/bindings/python/bt2/test_component_class.py b/tests/bindings/python/bt2/test_component_class.py index bc60606c..cece1a56 100644 --- a/tests/bindings/python/bt2/test_component_class.py +++ b/tests/bindings/python/bt2/test_component_class.py @@ -53,6 +53,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._test_no_init(MySink) def test_incomplete_source_no_msg_iter_cls(self): @@ -109,11 +112,17 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + def test_default_name(self): class MySink(bt2._UserSinkComponent): def _consume(self): pass + def _graph_is_configured(self): + pass + self.assertEqual(MySink.name, 'MySink') def test_custom_name(self): @@ -121,6 +130,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self.assertEqual(MySink.name, 'salut') def test_invalid_custom_name(self): @@ -129,6 +141,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + def test_description(self): class MySink(bt2._UserSinkComponent): """ @@ -144,6 +159,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self.assertEqual(MySink.description, 'The description.') def test_empty_description(self): @@ -154,6 +172,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self.assertIsNone(MySink.description) def test_help(self): @@ -169,6 +190,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self.assertEqual(MySink.help, 'The help\ntext is\nhere.') def test_addr(self): @@ -176,6 +200,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self.assertIsInstance(MySink.addr, int) self.assertNotEqual(MySink.addr, 0) @@ -184,6 +211,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + with self.assertRaises(bt2.Error): bt2.QueryExecutor().query(MySink, 'obj', 23) @@ -192,6 +222,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): raise ValueError @@ -204,6 +237,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): return ... @@ -216,6 +252,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): nonlocal query_params @@ -234,6 +273,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): nonlocal query_log_level @@ -250,6 +292,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @staticmethod def _query(query_exec, obj, params, log_level): return @@ -262,6 +307,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): nonlocal query_params @@ -280,6 +328,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): nonlocal query_params @@ -313,6 +364,9 @@ class UserComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self.assertEqual(MySink, MySink) @@ -327,6 +381,9 @@ class GenericComponentClassTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): return [obj, params, 23] diff --git a/tests/bindings/python/bt2/test_connection.py b/tests/bindings/python/bt2/test_connection.py index 22ce8804..7c1cbe57 100644 --- a/tests/bindings/python/bt2/test_connection.py +++ b/tests/bindings/python/bt2/test_connection.py @@ -38,6 +38,9 @@ class ConnectionTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + graph = bt2.Graph() src = graph.add_component(MySource, 'src') sink = graph.add_component(MySink, 'sink') @@ -62,6 +65,9 @@ class ConnectionTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + graph = bt2.Graph() src = graph.add_component(MySource, 'src') sink = graph.add_component(MySink, 'sink') @@ -86,6 +92,9 @@ class ConnectionTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + graph = bt2.Graph() src = graph.add_component(MySource, 'src') sink = graph.add_component(MySink, 'sink') diff --git a/tests/bindings/python/bt2/test_graph.py b/tests/bindings/python/bt2/test_graph.py index 852e3f01..cb447a5a 100644 --- a/tests/bindings/python/bt2/test_graph.py +++ b/tests/bindings/python/bt2/test_graph.py @@ -63,6 +63,8 @@ class GraphTestCase(unittest.TestCase): class MySink(bt2._UserSinkComponent): def _consume(self): pass + def _graph_is_configured(self): + pass comp = self._graph.add_component(MySink, 'salut') self.assertEqual(comp.name, 'salut') @@ -71,6 +73,8 @@ class GraphTestCase(unittest.TestCase): class MySink(bt2._UserSinkComponent): def _consume(self): pass + def _graph_is_configured(self): + pass comp = self._graph.add_component(MySink, 'salut') assert comp @@ -87,6 +91,8 @@ class GraphTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass params = {'hello': 23, 'path': '/path/to/stuff'} comp = self._graph.add_component(MySink, 'salut', params) @@ -101,6 +107,8 @@ class GraphTestCase(unittest.TestCase): class MySink(bt2._UserSinkComponent): def _consume(self): pass + def _graph_is_configured(self): + pass with self.assertRaises(TypeError): self._graph.add_component(MySink, 'salut', logging_level='yo') @@ -109,6 +117,8 @@ class GraphTestCase(unittest.TestCase): class MySink(bt2._UserSinkComponent): def _consume(self): pass + def _graph_is_configured(self): + pass with self.assertRaises(ValueError): self._graph.add_component(MySink, 'salut', logging_level=12345) @@ -117,6 +127,8 @@ class GraphTestCase(unittest.TestCase): class MySink(bt2._UserSinkComponent): def _consume(self): pass + def _graph_is_configured(self): + pass comp = self._graph.add_component(MySink, 'salut', logging_level=bt2.LoggingLevel.DEBUG) @@ -139,6 +151,9 @@ class GraphTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + src = self._graph.add_component(MySource, 'src') sink = self._graph.add_component(MySink, 'sink') @@ -166,6 +181,9 @@ class GraphTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + src = self._graph.add_component(MySource, 'src') sink = self._graph.add_component(MySink, 'sink') @@ -393,6 +411,9 @@ class GraphTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + def _port_connected(self, port, other_port): self._add_input_port('taste') @@ -457,6 +478,9 @@ class GraphTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + def _port_connected(self, port, other_port): self._add_input_port('taste') @@ -473,6 +497,9 @@ class GraphTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + graph = bt2.Graph() with self.assertRaises(bt2.Error): @@ -486,6 +513,9 @@ class GraphTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + def port_added_listener(component, port): raise ValueError('oh noes!') @@ -512,6 +542,9 @@ class GraphTestCase(unittest.TestCase): def _consume(self): raise bt2.Stop + def _graph_is_configured(self): + pass + def ports_connected_listener(upstream_component, upstream_port, downstream_component, downstream_port): raise ValueError('oh noes!') diff --git a/tests/bindings/python/bt2/test_port.py b/tests/bindings/python/bt2/test_port.py index 52bfc6a2..c94bb920 100644 --- a/tests/bindings/python/bt2/test_port.py +++ b/tests/bindings/python/bt2/test_port.py @@ -81,6 +81,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) self.assertEqual(len(comp.input_ports), 1) @@ -148,6 +151,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._create_comp(MySink) def test_user_src_output_ports_getitem_invalid_key(self): @@ -214,6 +220,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._create_comp(MySink) def test_user_src_output_ports_len(self): @@ -272,6 +281,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._create_comp(MySink) def test_user_src_output_ports_iter(self): @@ -370,6 +382,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._create_comp(MySink) def test_gen_src_output_ports_getitem(self): @@ -462,6 +477,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) self.assertEqual(port3.addr, comp.input_ports['insert'].addr) self.assertEqual(port2.addr, comp.input_ports['print'].addr) @@ -534,6 +552,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) with self.assertRaises(KeyError): @@ -594,6 +615,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) self.assertEqual(len(comp.input_ports), 3) @@ -711,6 +735,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) ports = [] @@ -735,6 +762,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) self.assertEqual(comp.input_ports['clear'].name, 'clear') @@ -746,6 +776,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) self.assertIsNone(comp.input_ports['clear'].connection) @@ -757,6 +790,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + comp = self._create_comp(MySink) self.assertFalse(comp.input_ports['clear'].is_connected) @@ -769,6 +805,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._create_comp(MySink) def test_self_connection_none(self): @@ -780,6 +819,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._create_comp(MySink) def test_self_is_connected_false(self): @@ -791,6 +833,9 @@ class PortTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + self._create_comp(MySink) def test_source_self_port_user_data(self): diff --git a/tests/bindings/python/bt2/test_query_executor.py b/tests/bindings/python/bt2/test_query_executor.py index 30e5a2c9..3c4ba62f 100644 --- a/tests/bindings/python/bt2/test_query_executor.py +++ b/tests/bindings/python/bt2/test_query_executor.py @@ -28,6 +28,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): nonlocal query_params @@ -61,6 +64,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): nonlocal query_params @@ -76,6 +82,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): nonlocal query_log_level @@ -92,6 +101,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): raise ValueError @@ -104,6 +116,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): raise bt2.InvalidObject @@ -116,6 +131,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): pass @@ -128,6 +146,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): pass @@ -140,6 +161,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): raise bt2.InvalidParams @@ -152,6 +176,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): raise bt2.TryAgain @@ -170,6 +197,9 @@ class QueryExecutorTestCase(unittest.TestCase): def _consume(self): pass + def _graph_is_configured(self): + pass + @classmethod def _query(cls, query_exec, obj, params, log_level): raise bt2.TryAgain diff --git a/tests/bindings/python/bt2/utils.py b/tests/bindings/python/bt2/utils.py index d52a474c..873a6514 100644 --- a/tests/bindings/python/bt2/utils.py +++ b/tests/bindings/python/bt2/utils.py @@ -32,6 +32,9 @@ def run_in_component_init(func): def _consume(self): pass + def _graph_is_configured(self): + pass + g = bt2.Graph() res_bound = None g.add_component(MySink, 'comp') diff --git a/tests/python-plugin-provider/bt_plugin_test_python_plugin_provider.py b/tests/python-plugin-provider/bt_plugin_test_python_plugin_provider.py index 5a0c893f..d5274ae4 100644 --- a/tests/python-plugin-provider/bt_plugin_test_python_plugin_provider.py +++ b/tests/python-plugin-provider/bt_plugin_test_python_plugin_provider.py @@ -40,6 +40,9 @@ class MySink(bt2._UserSinkComponent): def _consume(self): pass + def _graph_is_configured(self): + pass + bt2.register_plugin(__name__, 'sparkling', author='Philippe Proulx', description='A delicious plugin.', -- 2.34.1