lib/plugin/plugin.c: do not use G_MODULE_BIND_LOCAL for Python plugin provider
[babeltrace.git] / bindings / python / bt2 / component.py
index 77576c5208a8cdd5b5f4ee69f49ffc1e08263974..6ee1a145a9bc708263352500f3ed50a31fdde819 100644 (file)
@@ -23,6 +23,8 @@
 from bt2 import native_bt, object, utils
 import bt2.notification_iterator
 import collections.abc
+import bt2.values
+import sys
 import bt2
 
 
@@ -39,6 +41,13 @@ class _GenericComponentClass(object._Object):
     def description(self):
         return native_bt.component_class_get_description(self._ptr)
 
+    @property
+    def help(self):
+        return native_bt.component_class_get_help(self._ptr)
+
+    def query(self, obj, params=None):
+        return _query(self._ptr, obj, 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,
@@ -168,6 +177,52 @@ def _create_generic_component_class_from_ptr(ptr):
     return _COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_CLS[comp_cls_type]._create_from_ptr(ptr)
 
 
+def _trim_docstring(docstring):
+    lines = docstring.expandtabs().splitlines()
+    indent = sys.maxsize
+
+    for line in lines[1:]:
+        stripped = line.lstrip()
+
+        if stripped:
+            indent = min(indent, len(line) - len(stripped))
+
+    trimmed = [lines[0].strip()]
+
+    if indent < sys.maxsize:
+        for line in lines[1:]:
+            trimmed.append(line[indent:].rstrip())
+
+    while trimmed and not trimmed[-1]:
+        trimmed.pop()
+
+    while trimmed and not trimmed[0]:
+        trimmed.pop(0)
+
+    return '\n'.join(trimmed)
+
+
+def _query(comp_cls_ptr, obj, params):
+    utils._check_str(obj)
+
+    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(comp_cls_ptr, obj,
+                                                       params_ptr)
+
+    if results_ptr is None:
+        raise bt2.Error('cannot query info with object "{}"'.format(obj))
+
+    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
@@ -246,7 +301,19 @@ class _UserComponentType(type):
             return
 
         comp_cls_name = kwargs.get('name', class_name)
-        comp_cls_descr = getattr(cls, '__doc__', None)
+        comp_cls_descr = None
+        comp_cls_help = None
+
+        if hasattr(cls, '__doc__') and cls.__doc__ is not None:
+            docstring = _trim_docstring(cls.__doc__)
+            lines = docstring.splitlines()
+
+            if len(lines) >= 1:
+                comp_cls_descr = lines[0]
+
+            if len(lines) >= 3:
+                comp_cls_help = '\n'.join(lines[2:])
+
         iter_cls = kwargs.get('notification_iterator_class')
 
         if UserSourceComponent in bases:
@@ -255,6 +322,7 @@ class _UserComponentType(type):
             cc_ptr = native_bt.py3_component_class_source_create(cls,
                                                                  comp_cls_name,
                                                                  comp_cls_descr,
+                                                                 comp_cls_help,
                                                                  has_seek_time)
         elif UserFilterComponent in bases:
             _UserComponentType._set_iterator_class(cls, iter_cls)
@@ -262,6 +330,7 @@ class _UserComponentType(type):
             cc_ptr = native_bt.py3_component_class_filter_create(cls,
                                                                  comp_cls_name,
                                                                  comp_cls_descr,
+                                                                 comp_cls_help,
                                                                  has_seek_time)
         elif UserSinkComponent in bases:
             if not hasattr(cls, '_consume'):
@@ -269,7 +338,8 @@ class _UserComponentType(type):
 
             cc_ptr = native_bt.py3_component_class_sink_create(cls,
                                                                comp_cls_name,
-                                                               comp_cls_descr)
+                                                               comp_cls_descr,
+                                                               comp_cls_help)
         else:
             raise bt2.IncompleteUserClassError("cannot find a known component class base in the bases of '{}'".format(class_name))
 
@@ -352,10 +422,37 @@ class _UserComponentType(type):
     def description(cls):
         return native_bt.component_class_get_description(cls._cc_ptr)
 
+    @property
+    def help(cls):
+        return native_bt.component_class_get_help(cls._cc_ptr)
+
     @property
     def addr(cls):
         return int(cls._cc_ptr)
 
+    def query(cls, action, params=None):
+        return _query(cls._cc_ptr, action, params)
+
+    def _query_from_bt(cls, action, params):
+        # this can raise, in which case the native call to
+        # bt_component_class_query() returns NULL
+        results = cls._query(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(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)
This page took 0.043668 seconds and 4 git commands to generate.