bt2: add support for comp. class help
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 8 Feb 2017 01:12:39 +0000 (20:12 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:37 +0000 (12:57 -0400)
The description of a user component class is the first line of the
class's docstring; the help is everything else starting at line 3:

class MySink(bt2.UserSinkComponent):
    '''This is the description.

    This is the help.

    This too:

        * And this.
        * And also that.

    Voilà.
    '''

    def _consume(self):
        # ...

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
bindings/python/bt2/component.py
bindings/python/bt2/native_btcomponentclass.i

index 77576c5208a8cdd5b5f4ee69f49ffc1e08263974..beab3cd9a1c57c9ca472f2291d371942f524b825 100644 (file)
@@ -23,6 +23,7 @@
 from bt2 import native_bt, object, utils
 import bt2.notification_iterator
 import collections.abc
+import sys
 import bt2
 
 
@@ -39,6 +40,10 @@ 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 __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 +173,31 @@ 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)
+
+
 # Metaclass for component classes defined by Python code.
 #
 # The Python user can create a standard Python class which inherits one
@@ -246,7 +276,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 +297,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 +305,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 +313,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,6 +397,10 @@ 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)
index a7df3a7a3e1ba5394339ad477962b87bdb0fe0e7..53652b9acb7510b46e888635589f9eec56899f21 100644 (file)
@@ -49,6 +49,8 @@ const char *bt_component_class_get_name(
                struct bt_component_class *component_class);
 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);
 enum bt_component_class_type bt_component_class_get_type(
                struct bt_component_class *component_class);
 
@@ -884,7 +886,7 @@ end:
 /* Component class creation functions (called from Python module) */
 
 static int bt_py3_cc_set_optional_attrs_methods(struct bt_component_class *cc,
-               const char *description)
+               const char *description, const char *help)
 {
        int ret = 0;
 
@@ -895,6 +897,13 @@ static int bt_py3_cc_set_optional_attrs_methods(struct bt_component_class *cc,
                }
        }
 
+       if (help) {
+               ret = bt_component_class_set_help(cc, help);
+               if (ret) {
+                       goto end;
+               }
+       }
+
        ret = bt_component_class_set_init_method(cc, bt_py3_cc_init);
        if (ret) {
                goto end;
@@ -943,7 +952,7 @@ end:
 
 static struct bt_component_class *bt_py3_component_class_source_create(
                PyObject *py_cls, const char *name, const char *description,
-               bool has_seek_time)
+               const char *help, bool has_seek_time)
 {
        struct bt_component_class *cc;
        int ret;
@@ -956,7 +965,7 @@ static struct bt_component_class *bt_py3_component_class_source_create(
                goto end;
        }
 
-       ret = bt_py3_cc_set_optional_attrs_methods(cc, description);
+       ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help);
        if (ret) {
                BT_PUT(cc);
                goto end;
@@ -980,7 +989,7 @@ end:
 
 static struct bt_component_class *bt_py3_component_class_filter_create(
                PyObject *py_cls, const char *name, const char *description,
-               bool has_seek_time)
+               const char *help, bool has_seek_time)
 {
        struct bt_component_class *cc;
        int ret;
@@ -993,7 +1002,7 @@ static struct bt_component_class *bt_py3_component_class_filter_create(
                goto end;
        }
 
-       ret = bt_py3_cc_set_optional_attrs_methods(cc, description);
+       ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help);
        if (ret) {
                BT_PUT(cc);
                goto end;
@@ -1023,7 +1032,8 @@ end:
 }
 
 static struct bt_component_class *bt_py3_component_class_sink_create(
-               PyObject *py_cls, const char *name, const char *description)
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help)
 {
        struct bt_component_class *cc;
        int ret;
@@ -1034,7 +1044,7 @@ static struct bt_component_class *bt_py3_component_class_sink_create(
                goto end;
        }
 
-       ret = bt_py3_cc_set_optional_attrs_methods(cc, description);
+       ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help);
        if (ret) {
                BT_PUT(cc);
                goto end;
@@ -1107,12 +1117,13 @@ static void bt_py3_component_on_del(PyObject *py_comp)
 
 struct bt_component_class *bt_py3_component_class_source_create(
                PyObject *py_cls, const char *name, const char *description,
-               bool has_seek_time);
+               const char *help, bool has_seek_time);
 struct bt_component_class *bt_py3_component_class_filter_create(
                PyObject *py_cls, const char *name, const char *description,
-               bool has_seek_time);
+               const char *help, bool has_seek_time);
 struct bt_component_class *bt_py3_component_class_sink_create(
-               PyObject *py_cls, const char *name, const char *description);
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help);
 void bt_py3_component_create(
                struct bt_component_class *comp_class, PyObject *py_self,
                const char *name);
This page took 0.029307 seconds and 4 git commands to generate.