From: Philippe Proulx Date: Tue, 6 Aug 2019 00:31:35 +0000 (-0400) Subject: lib, bt2: make query method receive custom data X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=7c14d64103ff43ddeb43aaa04df17beb107f1f78 lib, bt2: make query method receive custom data Just like a component class initialization method can receive custom user data (`init_method_data`) along with generic parameters, this patch makes this possible for a query operation. Library changes =============== On the library side, this patch introduces the new bt_query_executor_create_with_method_data() function which is like bt_query_executor_create(), but accepts a `void *` user data parameter. Internally, bt_query_executor_create() calls bt_query_executor_create_with_method_data() with `NULL` as the `method_data` parameter. The component class query method type is changed to: typedef bt_component_class_query_method_status (*bt_component_class_*_query_method)( bt_self_component_class_* *comp_class, bt_private_query_executor *query_executor, const char *object, const bt_value *params, void *method_data, const bt_value **result); The component class is guaranteed, for a given query executor, to always being passed the same `method_data` value to its query method. Python bindings changes ======================= QueryExecutor.__init__() accepts a new, optional `method_obj` parameter which defaults to `None`. `None` gets translated to `NULL` as the `method_data` parameter, and vice versa when a Python query method is called from the native part. QueryExecutor.__init__() validates that you can only pass a Python method object when the component class you query is a Python component class. Because you build the query executor and then make a query operation in two steps, a Python reference to the method object must exist as long as the query executor exists. This patch makes it reside within the Python query executor wrapper (`_method_obj` attribute) as there's no way currently to lose the Python wrapper and retrieve it through a library call. If this becomes possible in the future, then we can introduce query executor destruction listeners and add one from the Python bindings to put the `PyObject *` reference when the query executor is destroyed. A new test checks this (test_query_with_method_obj_del_ref()), deleting the test's reference between the query executor's construction and the actual query operation. I tried without making the query executor keep a strong reference and the test causes a segmentation fault, as expected, which shows that the test is valuable. Signed-off-by: Philippe Proulx Change-Id: I454cdad039fab5b7d46e46762243f212c200f114 Reviewed-on: https://review.lttng.org/c/babeltrace/+/1831 Tested-by: jenkins --- diff --git a/include/babeltrace2/graph/component-class-filter.h b/include/babeltrace2/graph/component-class-filter.h index 08c0ff48..046a43bb 100644 --- a/include/babeltrace2/graph/component-class-filter.h +++ b/include/babeltrace2/graph/component-class-filter.h @@ -84,7 +84,7 @@ typedef bt_component_class_query_method_status bt_self_component_class_filter *comp_class, bt_private_query_executor *query_executor, const char *object, const bt_value *params, - const bt_value **result); + void *method_data, const bt_value **result); typedef bt_component_class_port_connected_method_status (*bt_component_class_filter_input_port_connected_method)( diff --git a/include/babeltrace2/graph/component-class-sink.h b/include/babeltrace2/graph/component-class-sink.h index 044895cf..ef3233b7 100644 --- a/include/babeltrace2/graph/component-class-sink.h +++ b/include/babeltrace2/graph/component-class-sink.h @@ -50,7 +50,7 @@ typedef bt_component_class_query_method_status bt_self_component_class_sink *comp_class, bt_private_query_executor *query_executor, const char *object, const bt_value *params, - const bt_value **result); + void *method_data, const bt_value **result); typedef bt_component_class_port_connected_method_status (*bt_component_class_sink_input_port_connected_method)( diff --git a/include/babeltrace2/graph/component-class-source.h b/include/babeltrace2/graph/component-class-source.h index 54cc2330..8d67bcb8 100644 --- a/include/babeltrace2/graph/component-class-source.h +++ b/include/babeltrace2/graph/component-class-source.h @@ -84,7 +84,7 @@ typedef bt_component_class_query_method_status bt_self_component_class_source *comp_class, bt_private_query_executor *query_executor, const char *object, const bt_value *params, - const bt_value **result); + void *method_data, const bt_value **result); typedef bt_component_class_port_connected_method_status (*bt_component_class_source_output_port_connected_method)( diff --git a/include/babeltrace2/graph/query-executor.h b/include/babeltrace2/graph/query-executor.h index 4ffc4ec4..29068aaa 100644 --- a/include/babeltrace2/graph/query-executor.h +++ b/include/babeltrace2/graph/query-executor.h @@ -39,6 +39,11 @@ bt_query_executor *bt_query_executor_create( const bt_component_class *component_class, const char *object, const bt_value *params); +extern +bt_query_executor *bt_query_executor_create_with_method_data( + const bt_component_class *component_class, const char *object, + const bt_value *params, void *method_data); + typedef enum bt_query_executor_query_status { BT_QUERY_EXECUTOR_QUERY_STATUS_OK = __BT_FUNC_STATUS_OK, BT_QUERY_EXECUTOR_QUERY_STATUS_AGAIN = __BT_FUNC_STATUS_AGAIN, diff --git a/src/bindings/python/bt2/Makefile.am b/src/bindings/python/bt2/Makefile.am index ce1058d8..66696340 100644 --- a/src/bindings/python/bt2/Makefile.am +++ b/src/bindings/python/bt2/Makefile.am @@ -34,6 +34,7 @@ SWIG_INTERFACE_FILES = \ bt2/native_bt_plugin.i.h \ bt2/native_bt_port.i \ bt2/native_bt_query_exec.i \ + bt2/native_bt_query_exec.i.h \ bt2/native_bt_stream.i \ bt2/native_bt_stream_class.i \ bt2/native_bt_trace.i \ diff --git a/src/bindings/python/bt2/bt2/component.py b/src/bindings/python/bt2/bt2/component.py index 8052e8a4..72376ef9 100644 --- a/src/bindings/python/bt2/bt2/component.py +++ b/src/bindings/python/bt2/bt2/component.py @@ -573,7 +573,7 @@ class _UserComponentType(type): def addr(cls): return int(cls._bt_cc_ptr) - def _bt_query_from_native(cls, priv_query_exec_ptr, obj, params_ptr): + def _bt_query_from_native(cls, priv_query_exec_ptr, object, params_ptr, method_obj): # this can raise, in which case the native call to # bt_component_class_query() returns NULL if params_ptr is not None: @@ -585,7 +585,7 @@ class _UserComponentType(type): try: # this can raise, but the native side checks the exception - results = cls._user_query(priv_query_exec, obj, params) + results = cls._user_query(priv_query_exec, object, params, method_obj) finally: # the private query executor is a private view on the query # executor; it's not a shared object (the library does not @@ -607,7 +607,7 @@ class _UserComponentType(type): bt2_value._Value._get_ref(results_ptr) return int(results_ptr) - def _user_query(cls, priv_query_executor, obj, params): + def _user_query(cls, priv_query_executor, object, params, method_obj): raise bt2.UnknownObject def _bt_component_class_ptr(self): diff --git a/src/bindings/python/bt2/bt2/native_bt_component_class.i.h b/src/bindings/python/bt2/bt2/native_bt_component_class.i.h index 9b1e7d27..84c88f6d 100644 --- a/src/bindings/python/bt2/bt2/native_bt_component_class.i.h +++ b/src/bindings/python/bt2/bt2/native_bt_component_class.i.h @@ -214,14 +214,6 @@ bt_component_class_init_method_status component_class_init( BT_ASSERT(self_component_v); BT_ASSERT(self_comp_cls_type_swig_type); - /* - * If there's any `init_method_data`, assume this component is - * getting initialized from Python, so that `init_method_data` - * is a Python object to pass to the user's __init__() method. - */ - BT_ASSERT(!init_method_data || - bt_bt2_is_python_component_class(component_class)); - /* * Get the user-defined Python class which created this * component's class in the first place (borrowed @@ -593,7 +585,7 @@ bt_component_class_query_method_status component_class_query( const bt_component_class *component_class, bt_self_component_class *self_component_class, bt_private_query_executor *priv_query_executor, - const char *object, const bt_value *params, + const char *object, const bt_value *params, void *method_data, const bt_value **result) { PyObject *py_cls = NULL; @@ -609,6 +601,14 @@ bt_component_class_query_method_status component_class_query( bt_logging_level log_level = bt_query_executor_get_logging_level(query_exec); + /* + * If there's any `method_data`, assume this component class is + * getting queried from Python, so that `method_data` is a + * Python object to pass to the user's _user_query() method. + */ + BT_ASSERT(!method_data || + bt_bt2_is_python_component_class(component_class)); + py_cls = lookup_cc_ptr_to_py_cls(component_class); if (!py_cls) { BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, @@ -641,9 +641,17 @@ bt_component_class_query_method_status component_class_query( goto error; } + /* + * We don't take any reference on `method_data` which, if not + * `NULL`, is assumed to be a `PyObject *`: the user's + * _user_query() function will eventually take a reference if + * needed. If `method_data` is `NULL`, then we pass `Py_None` as + * the initialization's Python object. + */ py_results_addr = PyObject_CallMethod(py_cls, - "_bt_query_from_native", "(OOO)", py_priv_query_exec_ptr, - py_object, py_params_ptr); + "_bt_query_from_native", "(OOOO)", py_priv_query_exec_ptr, + py_object, py_params_ptr, + method_data ? method_data : Py_None); if (!py_results_addr) { BT_LOG_WRITE_CUR_LVL(BT_LOG_WARNING, log_level, BT_LOG_TAG, "Failed to call Python class's _bt_query_from_native() method: " @@ -680,7 +688,7 @@ static bt_component_class_query_method_status component_class_source_query( bt_self_component_class_source *self_component_class_source, bt_private_query_executor *priv_query_executor, - const char *object, const bt_value *params, + const char *object, const bt_value *params, void *method_data, const bt_value **result) { const bt_component_class_source *component_class_source = bt_self_component_class_source_as_component_class_source(self_component_class_source); @@ -688,14 +696,14 @@ bt_component_class_query_method_status component_class_source_query( bt_self_component_class *self_component_class = bt_self_component_class_source_as_self_component_class(self_component_class_source); return component_class_query(component_class, self_component_class, - priv_query_executor, object, params, result); + priv_query_executor, object, params, method_data, result); } static bt_component_class_query_method_status component_class_filter_query( bt_self_component_class_filter *self_component_class_filter, bt_private_query_executor *priv_query_executor, - const char *object, const bt_value *params, + const char *object, const bt_value *params, void *method_data, const bt_value **result) { const bt_component_class_filter *component_class_filter = bt_self_component_class_filter_as_component_class_filter(self_component_class_filter); @@ -703,14 +711,14 @@ bt_component_class_query_method_status component_class_filter_query( bt_self_component_class *self_component_class = bt_self_component_class_filter_as_self_component_class(self_component_class_filter); return component_class_query(component_class, self_component_class, - priv_query_executor, object, params, result); + priv_query_executor, object, params, method_data, result); } static bt_component_class_query_method_status component_class_sink_query( bt_self_component_class_sink *self_component_class_sink, bt_private_query_executor *priv_query_executor, - const char *object, const bt_value *params, + const char *object, const bt_value *params, void *method_data, const bt_value **result) { const bt_component_class_sink *component_class_sink = bt_self_component_class_sink_as_component_class_sink(self_component_class_sink); @@ -718,7 +726,7 @@ bt_component_class_query_method_status component_class_sink_query( bt_self_component_class *self_component_class = bt_self_component_class_sink_as_self_component_class(self_component_class_sink); return component_class_query(component_class, self_component_class, - priv_query_executor, object, params, result); + priv_query_executor, object, params, method_data, result); } static diff --git a/src/bindings/python/bt2/bt2/native_bt_query_exec.i b/src/bindings/python/bt2/bt2/native_bt_query_exec.i index a69d7a58..a422ecbb 100644 --- a/src/bindings/python/bt2/bt2/native_bt_query_exec.i +++ b/src/bindings/python/bt2/bt2/native_bt_query_exec.i @@ -25,3 +25,11 @@ %include %include %include + +%{ +#include "native_bt_query_exec.i.h" +%} + +bt_query_executor *bt_bt2_query_executor_create( + const bt_component_class *component_class, const char *object, + const bt_value *params, PyObject *py_obj); diff --git a/src/bindings/python/bt2/bt2/native_bt_query_exec.i.h b/src/bindings/python/bt2/bt2/native_bt_query_exec.i.h new file mode 100644 index 00000000..e19c69f2 --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_query_exec.i.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +static +bt_query_executor *bt_bt2_query_executor_create( + const bt_component_class *component_class, const char *object, + const bt_value *params, PyObject *py_obj) +{ + return bt_query_executor_create_with_method_data(component_class, + object, params, py_obj == Py_None ? NULL : py_obj); +} diff --git a/src/bindings/python/bt2/bt2/query_executor.py b/src/bindings/python/bt2/bt2/query_executor.py index 77b58574..45781919 100644 --- a/src/bindings/python/bt2/bt2/query_executor.py +++ b/src/bindings/python/bt2/bt2/query_executor.py @@ -50,7 +50,7 @@ class QueryExecutor(object._SharedObject, _QueryExecutorCommon): def _as_query_executor_ptr(self): return self._ptr - def __init__(self, component_class, object, params=None): + def __init__(self, component_class, object, params=None, method_obj=None): if not isinstance(component_class, bt2_component._ComponentClass): err = False @@ -74,13 +74,28 @@ class QueryExecutor(object._SharedObject, _QueryExecutorCommon): cc_ptr = component_class._bt_component_class_ptr() assert cc_ptr is not None - ptr = native_bt.query_executor_create(cc_ptr, object, params_ptr) + + if method_obj is not None and not native_bt.bt2_is_python_component_class( + cc_ptr + ): + raise ValueError( + 'cannot pass a Python object to a non-Python component class' + ) + + ptr = native_bt.bt2_query_executor_create( + cc_ptr, object, params_ptr, method_obj + ) if ptr is None: raise bt2._MemoryError('cannot create query executor object') super().__init__(ptr) + # Keep a reference of `method_obj` as the native query executor + # does not have any. This ensures that, when this object's + # query() method is called, the Python object still exists. + self._method_obj = method_obj + def add_interrupter(self, interrupter): utils._check_type(interrupter, bt2_interrupter.Interrupter) native_bt.query_executor_add_interrupter(self._ptr, interrupter._ptr) diff --git a/src/lib/graph/query-executor.c b/src/lib/graph/query-executor.c index ebc1991e..cf265fd3 100644 --- a/src/lib/graph/query-executor.c +++ b/src/lib/graph/query-executor.c @@ -68,9 +68,9 @@ void bt_query_executor_destroy(struct bt_object *obj) g_free(query_exec); } -struct bt_query_executor *bt_query_executor_create( +struct bt_query_executor *bt_query_executor_create_with_method_data( const bt_component_class *comp_cls, const char *object, - const bt_value *params) + const bt_value *params, void *method_data) { struct bt_query_executor *query_exec; @@ -119,6 +119,7 @@ struct bt_query_executor *bt_query_executor_create( } bt_object_get_no_null_check(query_exec->params); + query_exec->method_data = method_data; query_exec->log_level = BT_LOGGING_LEVEL_NONE; bt_query_executor_add_interrupter(query_exec, query_exec->default_interrupter); @@ -132,6 +133,14 @@ end: return (void *) query_exec; } +struct bt_query_executor *bt_query_executor_create( + const bt_component_class *comp_cls, const char *object, + const bt_value *params) +{ + return bt_query_executor_create_with_method_data(comp_cls, + object, params, NULL); +} + enum bt_query_executor_query_status bt_query_executor_query( struct bt_query_executor *query_exec, const struct bt_value **user_result) @@ -141,6 +150,7 @@ enum bt_query_executor_query_status bt_query_executor_query( void * /* private query executor */, const char * /* object */, const struct bt_value * /* parameters */, + void * /* method data */, const struct bt_value ** /* result */); enum bt_query_executor_query_status status; @@ -219,7 +229,7 @@ enum bt_query_executor_query_status bt_query_executor_query( *user_result = NULL; query_status = method((void *) query_exec->comp_cls, (void *) query_exec, query_exec->object->str, - query_exec->params, user_result); + query_exec->params, query_exec->method_data, user_result); BT_LIB_LOGD("User method returned: status=%s, %![res-]+v", bt_common_func_status_string(query_status), *user_result); BT_ASSERT_POST(query_status != BT_FUNC_STATUS_OK || *user_result, diff --git a/src/lib/graph/query-executor.h b/src/lib/graph/query-executor.h index 250bc1b8..c1f907aa 100644 --- a/src/lib/graph/query-executor.h +++ b/src/lib/graph/query-executor.h @@ -56,6 +56,7 @@ struct bt_query_executor { /* Owned by this */ const struct bt_value *params; + void *method_data; enum bt_logging_level log_level; }; diff --git a/src/plugins/ctf/fs-src/fs.c b/src/plugins/ctf/fs-src/fs.c index 8b6d547a..0f437dde 100644 --- a/src/plugins/ctf/fs-src/fs.c +++ b/src/plugins/ctf/fs-src/fs.c @@ -1991,6 +1991,7 @@ bt_component_class_query_method_status ctf_fs_query( bt_self_component_class_source *comp_class, bt_private_query_executor *priv_query_exec, const char *object, const bt_value *params, + __attribute__((unused)) void *method_data, const bt_value **result) { bt_component_class_query_method_status status = diff --git a/src/plugins/ctf/fs-src/fs.h b/src/plugins/ctf/fs-src/fs.h index 74432046..8968fcba 100644 --- a/src/plugins/ctf/fs-src/fs.h +++ b/src/plugins/ctf/fs-src/fs.h @@ -215,7 +215,7 @@ bt_component_class_query_method_status ctf_fs_query( bt_self_component_class_source *comp_class, bt_private_query_executor *priv_query_exec, const char *object, const bt_value *params, - const bt_value **result); + void *method_data, const bt_value **result); BT_HIDDEN bt_component_class_message_iterator_init_method_status ctf_fs_iterator_init( diff --git a/src/plugins/ctf/lttng-live/lttng-live.c b/src/plugins/ctf/lttng-live/lttng-live.c index f13a5eab..40d76b9d 100644 --- a/src/plugins/ctf/lttng-live/lttng-live.c +++ b/src/plugins/ctf/lttng-live/lttng-live.c @@ -1457,6 +1457,7 @@ bt_component_class_query_method_status lttng_live_query( bt_self_component_class_source *comp_class, bt_private_query_executor *priv_query_exec, const char *object, const bt_value *params, + __attribute__((unused)) void *method_data, const bt_value **result) { bt_component_class_query_method_status status = diff --git a/src/plugins/ctf/lttng-live/lttng-live.h b/src/plugins/ctf/lttng-live/lttng-live.h index e5d08613..7b72147f 100644 --- a/src/plugins/ctf/lttng-live/lttng-live.h +++ b/src/plugins/ctf/lttng-live/lttng-live.h @@ -266,7 +266,7 @@ bt_component_class_query_method_status lttng_live_query( bt_self_component_class_source *comp_class, bt_private_query_executor *priv_query_exec, const char *object, const bt_value *params, - const bt_value **result); + void *method_data, const bt_value **result); void lttng_live_component_finalize(bt_self_component_source *component); diff --git a/tests/bindings/python/bt2/test_component_class.py b/tests/bindings/python/bt2/test_component_class.py index 00a952c2..6664b7a7 100644 --- a/tests/bindings/python/bt2/test_component_class.py +++ b/tests/bindings/python/bt2/test_component_class.py @@ -205,7 +205,7 @@ class UserComponentClassTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): return ... with self.assertRaises(bt2._Error): @@ -217,7 +217,7 @@ class UserComponentClassTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal query_params query_params = params return None @@ -235,7 +235,7 @@ class UserComponentClassTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal query_log_level query_log_level = priv_query_exec.logging_level @@ -252,7 +252,7 @@ class UserComponentClassTestCase(unittest.TestCase): pass @staticmethod - def _user_query(priv_query_exec, obj, params): + def _user_query(priv_query_exec, obj, params, method_obj): return res = bt2.QueryExecutor(MySink, 'obj', None).query() @@ -264,7 +264,7 @@ class UserComponentClassTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal query_params query_params = params return 17.5 @@ -282,7 +282,7 @@ class UserComponentClassTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal query_params query_params = params return {'null': None, 'bt2': 'BT2'} @@ -320,7 +320,7 @@ class ComponentClassTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): return [obj, params, 23] self._py_comp_cls = MySink diff --git a/tests/bindings/python/bt2/test_error.py b/tests/bindings/python/bt2/test_error.py index 9c2a9e52..11328db7 100644 --- a/tests/bindings/python/bt2/test_error.py +++ b/tests/bindings/python/bt2/test_error.py @@ -70,7 +70,7 @@ class SinkWithFailingQuery(bt2._UserSinkComponent): pass @staticmethod - def _user_query(priv_executor, obj, params): + def _user_query(priv_executor, obj, params, method_obj): raise ValueError('Query is failing') diff --git a/tests/bindings/python/bt2/test_query_executor.py b/tests/bindings/python/bt2/test_query_executor.py index 453cf5fe..500ef9bd 100644 --- a/tests/bindings/python/bt2/test_query_executor.py +++ b/tests/bindings/python/bt2/test_query_executor.py @@ -20,6 +20,7 @@ from bt2 import value import unittest import copy import bt2 +import re class QueryExecutorTestCase(unittest.TestCase): @@ -29,7 +30,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal query_params query_params = params return {'null': None, 'bt2': 'BT2'} @@ -52,7 +53,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal query_params query_params = params @@ -67,7 +68,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal query_params query_params = params @@ -76,13 +77,79 @@ class QueryExecutorTestCase(unittest.TestCase): self.assertIs(query_params, None) del query_params + def test_query_with_method_obj(self): + class MySink(bt2._UserSinkComponent): + def _user_consume(self): + pass + + @classmethod + def _user_query(cls, priv_query_exec, obj, params, method_obj): + nonlocal query_method_obj + query_method_obj = method_obj + + query_method_obj = None + method_obj = object() + res = bt2.QueryExecutor(MySink, 'obj', method_obj=method_obj).query() + self.assertIs(query_method_obj, method_obj) + del query_method_obj + + def test_query_with_method_obj_del_ref(self): + class MySink(bt2._UserSinkComponent): + def _user_consume(self): + pass + + @classmethod + def _user_query(cls, priv_query_exec, obj, params, method_obj): + nonlocal query_method_obj + query_method_obj = method_obj + + class Custom: + pass + + query_method_obj = None + method_obj = Custom() + method_obj.hola = 'hello' + query_exec = bt2.QueryExecutor(MySink, 'obj', method_obj=method_obj) + del method_obj + query_exec.query() + self.assertIsInstance(query_method_obj, Custom) + self.assertEqual(query_method_obj.hola, 'hello') + del query_method_obj + + def test_query_with_none_method_obj(self): + class MySink(bt2._UserSinkComponent): + def _user_consume(self): + pass + + @classmethod + def _user_query(cls, priv_query_exec, obj, params, method_obj): + nonlocal query_method_obj + query_method_obj = method_obj + + query_method_obj = object() + res = bt2.QueryExecutor(MySink, 'obj').query() + self.assertIsNone(query_method_obj) + del query_method_obj + + def test_query_with_method_obj_non_python_comp_cls(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 + + with self.assertRaisesRegex( + ValueError, + re.escape(r'cannot pass a Python object to a non-Python component class'), + ): + bt2.QueryExecutor(cc, 'obj', method_obj=object()).query() + def test_query_logging_level(self): class MySink(bt2._UserSinkComponent): def _user_consume(self): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal query_log_level query_log_level = priv_query_exec.logging_level @@ -99,7 +166,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): raise ValueError with self.assertRaises(bt2._Error) as ctx: @@ -119,7 +186,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): raise bt2.UnknownObject with self.assertRaises(bt2.UnknownObject): @@ -131,7 +198,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): pass query_exec = bt2.QueryExecutor(MySink, 'obj', [17, 23]) @@ -145,7 +212,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): pass query_exec = bt2.QueryExecutor(MySink, 'obj', [17, 23]) @@ -159,7 +226,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): raise bt2.TryAgain with self.assertRaises(bt2.TryAgain): @@ -171,7 +238,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal interrupter2 test_self.assertFalse(query_exec.is_interrupted) interrupter2.set() @@ -193,7 +260,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): test_self.assertFalse(query_exec.is_interrupted) query_exec.interrupt() test_self.assertTrue(query_exec.is_interrupted) @@ -208,7 +275,7 @@ class QueryExecutorTestCase(unittest.TestCase): pass @classmethod - def _user_query(cls, priv_query_exec, obj, params): + def _user_query(cls, priv_query_exec, obj, params, method_obj): nonlocal test_priv_query_exec test_priv_query_exec = priv_query_exec diff --git a/tests/data/cli/convert/auto-source-discovery-grouping/bt_plugin_test.py b/tests/data/cli/convert/auto-source-discovery-grouping/bt_plugin_test.py index 3719ceb9..e40215d0 100644 --- a/tests/data/cli/convert/auto-source-discovery-grouping/bt_plugin_test.py +++ b/tests/data/cli/convert/auto-source-discovery-grouping/bt_plugin_test.py @@ -26,7 +26,7 @@ class TestSourceExt(Base, bt2._UserSourceComponent, message_iterator_class=TestI self._print_params(params) @staticmethod - def _user_query(priv_query_exec, obj, params): + def _user_query(priv_query_exec, obj, params, method_obj): if obj == 'babeltrace.support-info': if params['type'] == 'file': name = os.path.basename(str(params['input'])) @@ -64,7 +64,7 @@ class TestSourceSomeDir( self._print_params(params) @staticmethod - def _user_query(priv_query_exec, obj, params): + def _user_query(priv_query_exec, obj, params, method_obj): if obj == 'babeltrace.support-info': if params['type'] == 'directory': name = os.path.basename(str(params['input'])) @@ -83,7 +83,7 @@ class TestSourceABCDE(Base, bt2._UserSourceComponent, message_iterator_class=Tes self._print_params(params) @staticmethod - def _user_query(priv_query_exec, obj, params): + def _user_query(priv_query_exec, obj, params, method_obj): if obj == 'babeltrace.support-info': return ( 1.0 diff --git a/tests/data/cli/convert/auto-source-discovery-params-log-level/bt_plugin_test.py b/tests/data/cli/convert/auto-source-discovery-params-log-level/bt_plugin_test.py index 05e03071..dc7f4e69 100644 --- a/tests/data/cli/convert/auto-source-discovery-params-log-level/bt_plugin_test.py +++ b/tests/data/cli/convert/auto-source-discovery-params-log-level/bt_plugin_test.py @@ -39,7 +39,7 @@ class TestSourceA(Base, bt2._UserSourceComponent, message_iterator_class=TestIte self._print_info(params) @staticmethod - def _user_query(priv_query_exec, obj, params): + def _user_query(priv_query_exec, obj, params, method_obj): # Match files starting with 'aaa'. if obj == 'babeltrace.support-info': @@ -62,7 +62,7 @@ class TestSourceB(Base, bt2._UserSourceComponent, message_iterator_class=TestIte self._print_info(params) @staticmethod - def _user_query(priv_query_exec, obj, params): + def _user_query(priv_query_exec, obj, params, method_obj): # Match files starting with 'bbb'. if obj == 'babeltrace.support-info': diff --git a/tests/lib/test-plugin-plugins/sfs.c b/tests/lib/test-plugin-plugins/sfs.c index 3d9e74a5..93ca7110 100644 --- a/tests/lib/test-plugin-plugins/sfs.c +++ b/tests/lib/test-plugin-plugins/sfs.c @@ -60,6 +60,7 @@ static bt_component_class_query_method_status flt_query_method( bt_self_component_class_filter *component_class, bt_private_query_executor *priv_query_exec, const char *object, const bt_value *params, + __attribute__((unused)) void *method_data, const bt_value **result) { bt_value *res = bt_value_array_create();