source: sasview/src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py @ 0595bb7

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 0595bb7 was 0595bb7, checked in by Piotr Rozyczko <rozyczko@…>, 6 years ago

Constraint validator - initial implementation + tests. SASVIEW-844

  • Property mode set to 100644
File size: 3.9 KB
Line 
1"""
2Widget for parameter constraints.
3"""
4from numpy import *
5
6from PyQt5 import QtCore
7from PyQt5 import QtGui
8from PyQt5 import QtWidgets
9
10import sas.qtgui.Utilities.GuiUtils as GuiUtils
11
12# Local UI
13from sas.qtgui.Perspectives.Fitting.UI.MultiConstraintUI import Ui_MultiConstraintUI
14
15class MultiConstraint(QtWidgets.QDialog, Ui_MultiConstraintUI):
16    def __init__(self, parent=None, params=None):
17        super(MultiConstraint, self).__init__()
18
19        self.setupUi(self)
20        self.setFixedSize(self.minimumSizeHint())
21        self.setModal(True)
22        self.params = params
23
24        self.setupLabels()
25        self.setupTooltip()
26
27        # Set param text control to the second parameter passed
28        self.txtConstraint.setText(self.params[1])
29
30        self.cmdOK.clicked.connect(self.accept)
31        self.cmdRevert.clicked.connect(self.revert)
32        self.txtConstraint.editingFinished.connect(self.validateFormula)
33
34    def revert(self):
35        """
36        switch M1 <-> M2
37        """
38        self.params[1], self.params[0] = self.params[0], self.params[1]
39        self.setupLabels()
40        self.setupTooltip()
41
42    def setupLabels(self):
43        """
44        Setup labels based on current parameters
45        """
46        l1 = self.params[0]
47        l2 = self.params[1]
48        self.txtParam1.setText(l1)
49        self.txtParam1_2.setText(l1)
50        self.txtParam2.setText(l2)
51
52    def setupTooltip(self):
53        """
54        Tooltip for txtConstraint
55        """
56        tooltip = "E.g.\n%s = 2.0 * (%s)\n" %(self.params[0], self.params[1])
57        tooltip += "%s = sqrt(%s) + 5"%(self.params[0], self.params[1])
58        self.txtConstraint.setToolTip(tooltip)
59
60    def validateFormula(self):
61        """
62        Add visual cues when formula is incorrect
63        """
64        formula_is_valid = False
65        formula_is_valid = self.validateConstraint(self.txtConstraint.text())
66        if not formula_is_valid:
67            self.cmdOK.setEnabled(False)
68            self.txtConstraint.setStyleSheet("QLineEdit {background-color: red;}")
69        else:
70            self.cmdOK.setEnabled(True)
71            self.txtConstraint.setStyleSheet("QLineEdit {background-color: white;}")
72
73    def validateConstraint(self, constraint_text):
74        """
75        Ensure the constraint has proper form
76        """
77        # 0. none or empty
78        if not constraint_text or not isinstance(constraint_text, str):
79            return False
80
81        param_str = str(self.params[1])
82        constraint_text = constraint_text.strip()
83
84        # 1. just the parameter
85        if param_str == constraint_text:
86            return True
87
88        # 2. ensure the text contains parameter name
89        parameter_string_start = constraint_text.find(param_str)
90        has_parameter_name = (parameter_string_start > -1)
91        if not has_parameter_name:
92            return False
93        parameter_string_end = parameter_string_start + len(param_str)
94
95        # 3. parameter name should be a separate word, but can have "()[]*+-/" around
96        valid_neighbours = "()[]*+-/ "
97        has_only_parameter = False
98        start_loc = parameter_string_start -1
99        end_loc = parameter_string_end
100        if not any([constraint_text[start_loc] == char for char in valid_neighbours]):
101            return False
102        if end_loc < len(constraint_text):
103            if not any([constraint_text[end_loc] == char for char in valid_neighbours]):
104                return False
105
106        # 4. replace parameter name with "1" and try to evaluate the expression
107        try:
108            expression_to_evaluate = constraint_text.replace(param_str, "1.0")
109            eval(expression_to_evaluate)
110        except Exception:
111            # Too many cases to cover individually, just a blanket
112            # Exception should be sufficient
113            # Note that in current numpy things like sqrt(-1) don't
114            # raise but just return warnings
115            return False
116
117        return True
118
119
120
Note: See TracBrowser for help on using the repository browser.