• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

int-brain-lab / iblrig / 9031936551

10 May 2024 12:05PM UTC coverage: 48.538% (+1.7%) from 46.79%
9031936551

Pull #643

github

53c3e3
web-flow
Merge 3c8214f78 into ec2d8e4fe
Pull Request #643: 8.19.0

377 of 1073 new or added lines in 38 files covered. (35.14%)

977 existing lines in 19 files now uncovered.

3253 of 6702 relevant lines covered (48.54%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

30.37
/iblrig/gui/validation.py
1
from PyQt5 import QtCore, QtWidgets
2✔
2
from PyQt5.QtCore import QThreadPool, pyqtSlot
2✔
3
from PyQt5.QtGui import QFont, QIcon, QStandardItem, QStandardItemModel
2✔
4
from PyQt5.QtWidgets import QHeaderView
2✔
5

6
from iblrig.gui.tools import Worker
2✔
7
from iblrig.gui.ui_validation import Ui_validation
2✔
8
from iblrig.hardware_validation import Result, Status, Validator, get_all_validators
2✔
9
from iblrig.pydantic_definitions import HardwareSettings, RigSettings
2✔
10

11
SECTION_FONT = QFont('', -1, QFont.Bold, False)
2✔
12
STATUS_ICON: dict[Status, QIcon] = {
2✔
13
    Status.PASS: QIcon(':/images/validation_pass'),
14
    Status.WARN: QIcon(':/images/validation_warn'),
15
    Status.FAIL: QIcon(':/images/validation_fail'),
16
    Status.INFO: QIcon(':/images/validation_info'),
17
    Status.SKIP: QIcon(':/images/validation_skip'),
18
    Status.PEND: QIcon(':/images/validation_pending'),
19
}
20

21

22
class StatusItem(QStandardItem):
2✔
23
    _status: Status
2✔
24

25
    def __init__(self, status: Status):
2✔
NEW
26
        super().__init__()
×
NEW
27
        self.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignRight)
×
NEW
28
        self.status = status
×
29

30
    @property
2✔
31
    def status(self):
2✔
NEW
32
        return self._status
×
33

34
    @status.setter
2✔
35
    def status(self, status: Status):
2✔
NEW
36
        self._status = status
×
NEW
37
        match status:
×
NEW
38
            case Status.PEND:
×
NEW
39
                self.setText('pending')
×
NEW
40
            case Status.PASS:
×
NEW
41
                self.setText('passed')
×
NEW
42
            case Status.WARN:
×
NEW
43
                self.setText('warning')
×
NEW
44
            case Status.FAIL:
×
NEW
45
                self.setText('failed')
×
NEW
46
            case Status.INFO:
×
NEW
47
                self.setText('')
×
NEW
48
            case Status.SKIP:
×
NEW
49
                self.setText('skipped')
×
50

51

52
class ValidatorItem(QStandardItem):
2✔
53
    validator: Validator
2✔
54
    _status: Status
2✔
55

56
    def __init__(self, validator: type[Validator], hardware_settings: HardwareSettings, rig_settings: RigSettings):
2✔
NEW
57
        super().__init__()
×
NEW
58
        self.status = Status.PEND
×
NEW
59
        self.validator = validator(hardware_settings=hardware_settings, iblrig_settings=rig_settings, interactive=True)
×
NEW
60
        self.setText(self.validator.name)
×
NEW
61
        self.setFont(SECTION_FONT)
×
62

63
    @property
2✔
64
    def status(self) -> Status:
2✔
NEW
65
        return self._status
×
66

67
    @status.setter
2✔
68
    def status(self, status: Status):
2✔
NEW
69
        self._status = status
×
NEW
70
        self.setIcon(QIcon(STATUS_ICON[status]))
×
71

72
    def clear(self):
2✔
NEW
73
        self.status = Status.PEND
×
NEW
74
        while self.hasChildren():
×
NEW
75
            self.removeRow(0)
×
76

77

78
class SystemValidationDialog(QtWidgets.QDialog, Ui_validation):
2✔
79
    validator_items: list[ValidatorItem] = []
2✔
80
    status_items: list[StatusItem] = []
2✔
81
    item_started = QtCore.pyqtSignal(int)
2✔
82
    item_result = QtCore.pyqtSignal(int, Result)
2✔
83
    item_finished = QtCore.pyqtSignal(int, Status)
2✔
84

85
    def __init__(self, *args, hardware_settings: HardwareSettings, rig_settings: RigSettings, **kwargs) -> None:
2✔
86
        """
87
        Dialog for system validation.
88

89
        Parameters
90
        ----------
91
        *args
92
            Arguments to pass to the QDialog constructor.
93
        hardware_settings : HardwareSettings
94
            Pydantic model with data parsed from hardware_settings.yaml
95
        rig_settings : RigSettings
96
            Pydantic model with data parsed from iblrig_settings.yaml
97
        **kwargs
98
            Keyword arguments to pass to the QDialog constructor.
99

100
        """
NEW
101
        super().__init__(*args, **kwargs)
×
NEW
102
        self.setupUi(self)
×
NEW
103
        self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowType.WindowContextHelpButtonHint)
×
104

NEW
105
        self.worker = Worker(self.run_subprocess)
×
NEW
106
        self.worker.setAutoDelete(False)
×
NEW
107
        self.worker.signals.finished.connect(lambda: self.pushButtonRerun.setEnabled(True))
×
NEW
108
        self.worker.signals.finished.connect(lambda: self.pushButtonOK.setEnabled(True))
×
109

NEW
110
        self.treeModel = QStandardItemModel()
×
NEW
111
        self.treeModel.setColumnCount(2)
×
112

NEW
113
        for validator in get_all_validators():
×
NEW
114
            self.validator_items.append(ValidatorItem(validator, hardware_settings, rig_settings))
×
NEW
115
            self.status_items.append(StatusItem(Status.PEND))
×
NEW
116
            self.status_items[-1].setFont(SECTION_FONT)
×
NEW
117
            self.treeModel.appendRow([self.validator_items[-1], self.status_items[-1]])
×
118

NEW
119
        self.treeView.setModel(self.treeModel)
×
NEW
120
        self.treeView.header().setSectionResizeMode(0, QHeaderView.Stretch)
×
NEW
121
        self.treeView.header().setSectionResizeMode(1, QHeaderView.Fixed)
×
NEW
122
        self.treeView.header().resizeSection(1, 60)
×
123

NEW
124
        self.pushButtonOK.clicked.connect(self.close)
×
NEW
125
        self.pushButtonRerun.clicked.connect(self.run)
×
NEW
126
        self.item_started.connect(self.on_item_started)
×
NEW
127
        self.item_result.connect(self.on_item_result)
×
NEW
128
        self.item_finished.connect(self.on_item_finished)
×
129

NEW
130
        self.show()
×
NEW
131
        self.run()
×
132

133
    def run(self):
2✔
134
        """
135
        Prepare GUI and start worker thread for running validators
136
        """
NEW
137
        self.pushButtonOK.setEnabled(False)
×
NEW
138
        self.pushButtonRerun.setEnabled(False)
×
NEW
139
        self.treeView.expandAll()
×
NEW
140
        for idx, _ in enumerate(self.validator_items):
×
NEW
141
            self.validator_items[idx].clear()
×
NEW
142
            self.status_items[idx].status = Status.PEND
×
NEW
143
            self.treeView.scrollToTop()
×
NEW
144
        self.update()
×
NEW
145
        QThreadPool.globalInstance().tryStart(self.worker)
×
146

147
    def run_subprocess(self):
2✔
148
        """
149
        Run all validators in a subprocess
150
        """
NEW
151
        for idx, validator_item in enumerate(self.validator_items):
×
NEW
152
            self.item_started.emit(idx)
×
NEW
153
            results = []
×
NEW
154
            for result in validator_item.validator.run():
×
NEW
155
                results.append(result)
×
NEW
156
                self.item_result.emit(idx, result)
×
157

NEW
158
            statuses = [r.status for r in results]
×
NEW
159
            if Status.SKIP in statuses:
×
NEW
160
                status = Status.SKIP
×
NEW
161
            elif Status.FAIL in statuses:
×
NEW
162
                status = Status.FAIL
×
NEW
163
            elif Status.WARN in statuses:
×
NEW
164
                status = Status.WARN
×
165
            else:
NEW
166
                status = Status.PASS
×
NEW
167
            self.item_finished.emit(idx, status)
×
168

169
    @pyqtSlot(int)
2✔
170
    def on_item_started(self, idx: int):
2✔
NEW
171
        self.status_items[idx].setText('running')
×
172

173
    @pyqtSlot(int, Result)
2✔
174
    def on_item_result(self, idx: int, result: Result):
2✔
NEW
175
        result_item = QStandardItem(result.message)
×
NEW
176
        result_item.setToolTip(result.message)
×
NEW
177
        result_item.setIcon(STATUS_ICON[result.status])
×
NEW
178
        self.validator_items[idx].appendRow([result_item, QStandardItem('')])
×
NEW
179
        if result.solution is not None and len(result.solution) > 0:
×
NEW
180
            solution_item = QStandardItem(f'Suggestion: {result.solution}')
×
NEW
181
            solution_item.setIcon(QIcon(':/images/validation_suggestion'))
×
NEW
182
            self.validator_items[idx].appendRow(solution_item)
×
NEW
183
        self.update()
×
184

185
    @pyqtSlot(int, Status)
2✔
186
    def on_item_finished(self, idx: int, status: Status):
2✔
NEW
187
        self.validator_items[idx].status = status
×
NEW
188
        self.status_items[idx].status = status
×
NEW
189
        if status == Status.PASS:
×
NEW
190
            self.treeView.collapse(self.validator_items[idx].index())
×
NEW
191
        self.treeView.scrollToBottom()
×
NEW
192
        self.update()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc