lib, bt2: make query method receive custom data
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 6 Aug 2019 00:31:35 +0000 (20:31 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 6 Aug 2019 20:17:46 +0000 (16:17 -0400)
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 <eeppeliteloop@gmail.com>
Change-Id: I454cdad039fab5b7d46e46762243f212c200f114
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1831
Tested-by: jenkins <jenkins@lttng.org>
22 files changed:
include/babeltrace2/graph/component-class-filter.h
include/babeltrace2/graph/component-class-sink.h
include/babeltrace2/graph/component-class-source.h
include/babeltrace2/graph/query-executor.h
src/bindings/python/bt2/Makefile.am
src/bindings/python/bt2/bt2/component.py
src/bindings/python/bt2/bt2/native_bt_component_class.i.h
src/bindings/python/bt2/bt2/native_bt_query_exec.i
src/bindings/python/bt2/bt2/native_bt_query_exec.i.h [new file with mode: 0644]
src/bindings/python/bt2/bt2/query_executor.py
src/lib/graph/query-executor.c
src/lib/graph/query-executor.h
src/plugins/ctf/fs-src/fs.c
src/plugins/ctf/fs-src/fs.h
src/plugins/ctf/lttng-live/lttng-live.c
src/plugins/ctf/lttng-live/lttng-live.h
tests/bindings/python/bt2/test_component_class.py
tests/bindings/python/bt2/test_error.py
tests/bindings/python/bt2/test_query_executor.py
tests/data/cli/convert/auto-source-discovery-grouping/bt_plugin_test.py
tests/data/cli/convert/auto-source-discovery-params-log-level/bt_plugin_test.py
tests/lib/test-plugin-plugins/sfs.c

index 08c0ff48c2dddf7be00b598f742d359e7203ab82..046a43bb5bfa5ad3959d3cac2f1baa27f87e24d0 100644 (file)
@@ -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)(
index 044895cfae03609c9d855322b4f5d7ea59ee23bd..ef3233b76135bb40f6d5fc815fb440fc2c1e2ba2 100644 (file)
@@ -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)(
index 54cc2330580dbe4f9b3011be892f1f658a1a336f..8d67bcb8c8c1115518f91039910ed66456794d9c 100644 (file)
@@ -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)(
index 4ffc4ec42977246b51cff2c6991eae0dd4c67be0..29068aaa9b9851eccfd43f13cfbf93201bca0586 100644 (file)
@@ -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,
index ce1058d802d516dfd856be89c013e7ef7b35209c..666963404fa305a9d50f4839421418ffc18908f0 100644 (file)
@@ -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                           \
index 8052e8a4b0c5ac35af07dbd32387d75f9ec870fe..72376ef97a5445f33b577594e2d36860f40b6dc3 100644 (file)
@@ -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):
index 9b1e7d279292564fd9935a1ee79ab00ce9cda876..84c88f6db54724368e989b6c70dbe4ec4a355768 100644 (file)
@@ -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
index a69d7a586197f26d248522e6079274f2758662d0..a422ecbb6d8b55e0c00d8bf38601ce7d7a29bfb0 100644 (file)
 %include <babeltrace2/graph/private-query-executor.h>
 %include <babeltrace2/graph/query-executor-const.h>
 %include <babeltrace2/graph/query-executor.h>
+
+%{
+#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 (file)
index 0000000..e19c69f
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * 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);
+}
index 77b5857496fbae9b2143892734f5bb94c01df541..4578191972b13fd015078241bd20ea9e82d4c179 100644 (file)
@@ -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)
index ebc1991ebfe659301449994e85c4620808cbacc5..cf265fd3a8e74a8e3ce6dbe43ed9f018a5d0a303 100644 (file)
@@ -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,
index 250bc1b835a18d96b848c991b3f137b55549b7d0..c1f907aafceca770b8af74890821eae4f0b51550 100644 (file)
@@ -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;
 };
 
index 8b6d547a6f24bae5b70c4bffa392712b5fa0087e..0f437ddea9c14cf31159f216dc41b3246df8cccd 100644 (file)
@@ -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 =
index 74432046d0d3fbefab048aaf95902da3612e6215..8968fcba88412a3bc71408de7b686ff54e16d713 100644 (file)
@@ -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(
index f13a5eabc301f9ac60a0f331c11b6e32af0ee269..40d76b9d2ad5d6f08e8aaf47480df20d56827585 100644 (file)
@@ -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 =
index e5d08613d560192bfb2584684521a0dfcaa9a3fe..7b72147f9aabc7fcc1461d3ccba3161992fee742 100644 (file)
@@ -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);
 
index 00a952c2b35d2a02c83809d4e9e90bfeec69990f..6664b7a7020ef2c1afc5ccd793a54688ac3a670c 100644 (file)
@@ -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
index 9c2a9e52df3a04887323786cb1798da0589ae4d3..11328db7b1814e427dd56b3123028e4baa866866 100644 (file)
@@ -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')
 
 
index 453cf5fe14feff33305dec1ec8c6d2f1aab928a0..500ef9bdb90669b1c4bee423b1c9e008f658982e 100644 (file)
@@ -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
 
index 3719ceb9fcfc3ad8b4eaea34a9bd268bf990e709..e40215d0b162d239034431cb2b0c64016174486e 100644 (file)
@@ -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
index 05e03071a97da8c8717e1a803e6fafca6ed61d9f..dc7f4e69940a953a117bb5d1d37d2cc35030aea6 100644 (file)
@@ -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':
index 3d9e74a5c4e28be6067f306e273fd8b56420957f..93ca71101762b170bec16fc3eb406be56fe9e0b8 100644 (file)
@@ -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();
This page took 0.039695 seconds and 4 git commands to generate.