From 911dec0860545c08f347bf8dc291f94494cd4da5 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Sat, 11 Feb 2017 13:27:06 -0500 Subject: [PATCH] bt2: add support for the "query info" API MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Any user-defined component class can now define a _query_info() static method which accepts an action name and parameters (value object, or None) and returns a bt2.create_value()-compatible object: class MySink(bt2.UserSinkComponent): def _consume(self): pass @staticmethod def _query_info(action, params): if action == 'get-stuff': return { 'stuff': get_stuff(), 'id': get_id() } elif action == 'get-thing': return the_thing() This static method can raise any exception: the caller of bt_component_class_query_info() gets NULL. On the Python side, either with a user-defined component class or with a component class wrapper: results = comp_class.query_info('get-stuff', {'name': 'wrerzvr'}) Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- bindings/python/bt2/component.py | 48 ++++++++++++ bindings/python/bt2/native_btcomponentclass.i | 76 ++++++++++++++++++- 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/bindings/python/bt2/component.py b/bindings/python/bt2/component.py index beab3cd9..ebfe1262 100644 --- a/bindings/python/bt2/component.py +++ b/bindings/python/bt2/component.py @@ -23,6 +23,7 @@ from bt2 import native_bt, object, utils import bt2.notification_iterator import collections.abc +import bt2.values import sys import bt2 @@ -44,6 +45,9 @@ class _GenericComponentClass(object._Object): def help(self): return native_bt.component_class_get_help(self._ptr) + def query_info(self, action, params=None): + return _query_info(self._ptr, action, params) + def __call__(self, params=None, name=None): params = bt2.create_value(params) comp_ptr = native_bt.component_create_with_init_method_data(self._ptr, @@ -198,6 +202,27 @@ def _trim_docstring(docstring): return '\n'.join(trimmed) +def _query_info(comp_cls_ptr, action, params): + utils._check_str(action) + + if params is None: + params_ptr = native_bt.value_null + else: + params = bt2.create_value(params) + params_ptr = params._ptr + + results_ptr = native_bt.component_class_query_info(comp_cls_ptr, action, + params_ptr) + + if results_ptr is None: + raise bt2.Error('cannot query info with action "{}"'.format(action)) + + if results_ptr == native_bt.value_null: + return + + return bt2.values._create_from_ptr(results_ptr) + + # Metaclass for component classes defined by Python code. # # The Python user can create a standard Python class which inherits one @@ -405,6 +430,29 @@ class _UserComponentType(type): def addr(cls): return int(cls._cc_ptr) + def query_info(cls, action, params=None): + return _query_info(cls._cc_ptr, action, params) + + def _query_info_from_bt(cls, action, params): + # this can raise, in which case the native call to + # bt_component_class_query_info() returns NULL + results = cls._query_info(action, params) + results = bt2.create_value(results) + + if results is None: + results_addr = int(native_bt.value_null) + else: + # steal the underlying native value object for the caller + results_addr = int(results._ptr) + results._ptr = None + + return results_addr + + @staticmethod + def _query_info(action, params): + # BT catches this and returns NULL to the user + raise NotImplementedError + def __del__(cls): if hasattr(cls, '_cc_ptr'): native_bt.put(cls._cc_ptr) diff --git a/bindings/python/bt2/native_btcomponentclass.i b/bindings/python/bt2/native_btcomponentclass.i index 53652b9a..6acfdb6e 100644 --- a/bindings/python/bt2/native_btcomponentclass.i +++ b/bindings/python/bt2/native_btcomponentclass.i @@ -51,6 +51,9 @@ const char *bt_component_class_get_description( struct bt_component_class *component_class); const char *bt_component_class_get_help( struct bt_component_class *component_class); +struct bt_value *bt_component_class_query_info( + struct bt_component_class *component_class, + const char *action, struct bt_value *params); enum bt_component_class_type bt_component_class_get_type( struct bt_component_class *component_class); @@ -560,6 +563,70 @@ static void bt_py3_cc_destroy(struct bt_component *component) } } +static struct bt_value *bt_py3_cc_query_info( + struct bt_component_class *component_class, + const char *action, struct bt_value *params) +{ + PyObject *py_cls = NULL; + PyObject *py_params = NULL; + PyObject *py_query_info_func = NULL; + PyObject *py_action = NULL; + PyObject *py_results_addr = NULL; + struct bt_value *results = NULL; + + py_cls = lookup_cc_ptr_to_py_cls(component_class); + if (!py_cls) { + goto error; + } + + py_params = bt_py3_bt_value_from_ptr(params); + if (!py_params) { + goto error; + } + + py_action = SWIG_FromCharPtr(action); + if (!py_action) { + goto error; + } + + py_results_addr = PyObject_CallMethod(py_cls, + "_query_info_from_bt", "(OO)", py_action, py_params); + if (!py_results_addr) { + goto error; + } + + /* + * The returned object, on success, is an integer object + * (PyLong) containing the address of a BT value object + * (which is now ours). + */ + results = (struct bt_value *) PyLong_AsUnsignedLongLong( + py_results_addr); + + /* Clear potential overflow error; should never happen */ + if (PyErr_Occurred()) { + results = NULL; + goto error; + } + + if (!results) { + goto error; + } + + goto end; + +error: + BT_PUT(results); + PyErr_Clear(); + +end: + Py_XDECREF(py_params); + Py_XDECREF(py_query_info_func); + Py_XDECREF(py_action); + Py_XDECREF(py_results_addr); + return results; +} + static enum bt_notification_iterator_status bt_py3_exc_to_notif_iter_status(void) { enum bt_notification_iterator_status status = @@ -728,13 +795,14 @@ static struct bt_notification *bt_py3_cc_notification_iterator_get( /* * The returned object, on success, is an integer object * (PyLong) containing the address of a BT notification - * object (which is not ours). + * object (which is now ours). */ notif = (struct bt_notification *) PyLong_AsUnsignedLongLong( py_get_method_result); /* Clear potential overflow error; should never happen */ if (PyErr_Occurred()) { + notif = NULL; goto error; } @@ -914,6 +982,12 @@ static int bt_py3_cc_set_optional_attrs_methods(struct bt_component_class *cc, goto end; } + ret = bt_component_class_set_query_info_method(cc, + bt_py3_cc_query_info); + if (ret) { + goto end; + } + end: return ret; } -- 2.34.1