From a10e6f7820309d590e832f2bca44ca1db8ef72a1 Mon Sep 17 00:00:00 2001 From: David Perl Date: Wed, 21 May 2025 15:00:24 +0200 Subject: [PATCH] fix: make generate plugin robust to multiline init instead of str.find, use multiline regex with whitespace --- bec_widgets/utils/generate_designer_plugin.py | 31 ++++++------------- tests/unit_tests/test_generate_plugin.py | 12 ++++++- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/bec_widgets/utils/generate_designer_plugin.py b/bec_widgets/utils/generate_designer_plugin.py index 482de765..3e37fbb0 100644 --- a/bec_widgets/utils/generate_designer_plugin.py +++ b/bec_widgets/utils/generate_designer_plugin.py @@ -8,6 +8,9 @@ from qtpy.QtCore import QObject from bec_widgets.utils.name_utils import pascal_to_snake EXCLUDED_PLUGINS = ["BECConnector", "BECDockArea", "BECDock", "BECFigure"] +_PARENT_ARG_REGEX = r".__init__\(\s*(?:parent\)|parent=parent,?|parent,?)" +_SELF_PARENT_ARG_REGEX = r".__init__\(\s*self,\s*(?:parent\)|parent=parent,?|parent,?)" +SUPER_INIT_REGEX = re.compile(r"super\(\)" + _PARENT_ARG_REGEX, re.MULTILINE) class PluginFilenames(NamedTuple): @@ -90,34 +93,20 @@ class DesignerPluginGenerator: # Check if the widget class calls the super constructor with parent argument init_source = inspect.getsource(self.widget.__init__) - cls_init_found = ( - bool(init_source.find(f"{base_cls[0].__name__}.__init__(self, parent=parent") > 0) - or bool(init_source.find(f"{base_cls[0].__name__}.__init__(self, parent)") > 0) - or bool(init_source.find(f"{base_cls[0].__name__}.__init__(self, parent,") > 0) - ) - super_init_found = ( - bool( - init_source.find(f"super({base_cls[0].__name__}, self).__init__(parent=parent") > 0 - ) - or bool(init_source.find(f"super({base_cls[0].__name__}, self).__init__(parent,") > 0) - or bool(init_source.find(f"super({base_cls[0].__name__}, self).__init__(parent)") > 0) + class_re = re.compile(base_cls[0].__name__ + _SELF_PARENT_ARG_REGEX, re.MULTILINE) + cls_init_found = class_re.search(init_source) is not None + super_self_re = re.compile( + rf"super\({base_cls[0].__name__}, self\)" + _PARENT_ARG_REGEX, re.MULTILINE ) + super_init_found = super_self_re.search(init_source) is not None if issubclass(self.widget.__bases__[0], QObject) and not super_init_found: - super_init_found = ( - bool(init_source.find("super().__init__(parent=parent") > 0) - or bool(init_source.find("super().__init__(parent,") > 0) - or bool(init_source.find("super().__init__(parent)") > 0) - ) + super_init_found = SUPER_INIT_REGEX.search(init_source) is not None # for the new style classes, we only have one super call. We can therefore check if the # number of __init__ calls is 2 (the class itself and the super class) num_inits = re.findall(r"__init__", init_source) if len(num_inits) == 2 and not super_init_found: - super_init_found = bool( - init_source.find("super().__init__(parent=parent") > 0 - or init_source.find("super().__init__(parent,") > 0 - or init_source.find("super().__init__(parent)") > 0 - ) + super_init_found = SUPER_INIT_REGEX.search(init_source) is not None if not cls_init_found and not super_init_found: raise ValueError( diff --git a/tests/unit_tests/test_generate_plugin.py b/tests/unit_tests/test_generate_plugin.py index 8b55ed00..a5b395ca 100644 --- a/tests/unit_tests/test_generate_plugin.py +++ b/tests/unit_tests/test_generate_plugin.py @@ -48,12 +48,22 @@ class MyWidget(QWidget): from qtpy.QtWidgets import QWidget class MyWidget(QWidget): def __init__(self, parent=None): - super(QWidget, self).__init__(parent)""" + super(QWidget, self).__init__(parent) +""", """ from qtpy.QtWidgets import QWidget class MyWidget(QWidget): def __init__(self, parent=None): super(QWidget, self).__init__(parent=parent) +""", + """ +from qtpy.QtWidgets import QWidget +class MyWidget(QWidget): + def __init__(self, parent=None): + super(QWidget, self).__init__( + parent=parent, + other=arguments, + ) """, ] )