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)(
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)(
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)(
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,
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 \
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:
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
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):
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
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;
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,
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: "
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);
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);
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);
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
%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);
--- /dev/null
+/*
+ * 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);
+}
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
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)
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;
}
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);
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)
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;
*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,
/* Owned by this */
const struct bt_value *params;
+ void *method_data;
enum bt_logging_level log_level;
};
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 =
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(
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 =
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);
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):
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
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
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()
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
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'}
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
pass
@staticmethod
- def _user_query(priv_executor, obj, params):
+ def _user_query(priv_executor, obj, params, method_obj):
raise ValueError('Query is failing')
import unittest
import copy
import bt2
+import re
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'}
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
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
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
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:
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):
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])
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])
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):
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()
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)
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
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']))
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']))
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
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':
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':
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();