From 40910fbb32dca4f294744894d04cda81d8eea104 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 7 Feb 2017 20:12:39 -0500 Subject: [PATCH] bt2: add support for comp. class help MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Jérémie Galarneau --- bindings/python/bt2/component.py | 53 ++++++++++++++++++- bindings/python/bt2/native_btcomponentclass.i | 31 +++++++---- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/bindings/python/bt2/component.py b/bindings/python/bt2/component.py index 77576c52..beab3cd9 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 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) diff --git a/bindings/python/bt2/native_btcomponentclass.i b/bindings/python/bt2/native_btcomponentclass.i index a7df3a7a..53652b9a 100644 --- a/bindings/python/bt2/native_btcomponentclass.i +++ b/bindings/python/bt2/native_btcomponentclass.i @@ -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); -- 2.34.1