testexecutor-ui 0.6.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. testexecutor/VERSION +1 -0
  2. testexecutor/__init__.py +6 -0
  3. testexecutor/control/TestListenerApi.py +56 -0
  4. testexecutor/control/TestSuiteListener.py +249 -0
  5. testexecutor/control/__init__.py +0 -0
  6. testexecutor/model/GenericListModel.py +63 -0
  7. testexecutor/model/InstructionsModel.py +351 -0
  8. testexecutor/model/KeyValueModel.py +177 -0
  9. testexecutor/model/MultiTestWindowModel.py +184 -0
  10. testexecutor/model/ResultModel.py +314 -0
  11. testexecutor/model/TestSuiteControlModel.py +139 -0
  12. testexecutor/model/TestSuiteGroup.py +105 -0
  13. testexecutor/model/TestSuiteModel.py +301 -0
  14. testexecutor/model/__init__.py +0 -0
  15. testexecutor/model/selector/FilterGroupModel.py +90 -0
  16. testexecutor/model/selector/FilterModel.py +251 -0
  17. testexecutor/model/selector/MultiSelectDetails.py +106 -0
  18. testexecutor/model/selector/MultiSelectListModel.py +48 -0
  19. testexecutor/model/selector/__init__.py +0 -0
  20. testexecutor/ui/IdentificationWidget.qml +40 -0
  21. testexecutor/ui/InputWidget.qml +74 -0
  22. testexecutor/ui/InstructionWidget.qml +185 -0
  23. testexecutor/ui/KeyValueItem.qml +194 -0
  24. testexecutor/ui/KeyValueItemConfig.qml +41 -0
  25. testexecutor/ui/KeyValueList.qml +49 -0
  26. testexecutor/ui/MultiTestWidget.qml +48 -0
  27. testexecutor/ui/MultiTestWindow.qml +88 -0
  28. testexecutor/ui/ResultItem.qml +199 -0
  29. testexecutor/ui/ResultItemConfig.qml +46 -0
  30. testexecutor/ui/ResultList.qml +58 -0
  31. testexecutor/ui/TestSuiteConfig.qml +95 -0
  32. testexecutor/ui/TestSuiteController.qml +54 -0
  33. testexecutor/ui/TestSuiteWidget.qml +350 -0
  34. testexecutor/ui/selector/FilterItem.qml +75 -0
  35. testexecutor/ui/selector/FilterItemConfig.qml +24 -0
  36. testexecutor/ui/selector/FilterMultiSelectorItem.qml +169 -0
  37. testexecutor/ui/selector/FilterMultiSelectorItemConfig.qml +22 -0
  38. testexecutor/ui/selector/FilterMultiSelectorList.qml +50 -0
  39. testexecutor/ui/selector/HeaderConfig.qml +24 -0
  40. testexecutor/ui/selector/SectionConfig.qml +24 -0
  41. testexecutor/ui/selector/SectionDelegate.qml +85 -0
  42. testexecutor/ui/selector/SelectorHeader.qml +43 -0
  43. testexecutor/ui/selector/SuiteList.qml +150 -0
  44. testexecutor/ui/selector/SuiteSelector.qml +71 -0
  45. testexecutor/ui/selector/SuiteSelectorConfig.qml +38 -0
  46. testexecutor/ui/selector/TestConfig.qml +22 -0
  47. testexecutor/ui/selector/TestDelegate.qml +75 -0
  48. testexecutor/ui/te-64x64.ico +0 -0
  49. testexecutor_ui-0.6.1.dist-info/LICENSE +204 -0
  50. testexecutor_ui-0.6.1.dist-info/METADATA +27 -0
  51. testexecutor_ui-0.6.1.dist-info/NOTICE +3 -0
  52. testexecutor_ui-0.6.1.dist-info/RECORD +54 -0
  53. testexecutor_ui-0.6.1.dist-info/WHEEL +5 -0
  54. testexecutor_ui-0.6.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,184 @@
1
+ # Copyright 2020 Direkt, Australia
2
+ # Copyright 2021 Direkt Embedded Pty Ltd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from PySide6.QtCore import QObject, QJsonDocument
17
+ from PySide6.QtCore import Signal, Property, Slot
18
+ from PySide6.QtWidgets import QApplication
19
+ from PySide6.QtCore import QUrl
20
+ from PySide6.QtCore import Qt
21
+ from PySide6.QtCore import QCoreApplication
22
+ from PySide6.QtGui import QIcon
23
+ from PySide6.QtQml import QQmlApplicationEngine
24
+
25
+ import os
26
+ import sys
27
+ import json
28
+
29
+ notice = """
30
+ <b>This software includes code from Test Executor ™</b><br/>
31
+ <i>Copyright © Direkt Embedded Pty Ltd<br/>
32
+ https://www.direktembedded.com</i>"""
33
+
34
+ class MultiTestWindowModel(QObject):
35
+
36
+ def __init__(self, suiteGroup=None, title="Test Executor", closeHeading="There Are Still Tests Running", closeText="Stop all suites if you want to quit"):
37
+ QObject.__init__(self)
38
+ self._title = title
39
+ self._visibility = "Maximized"
40
+ self._abortCallback = None
41
+ self._closeHeading = closeHeading
42
+ self._closeText = closeText
43
+ self._allowAbort = False
44
+ self._config = None
45
+ self._suiteGroup = suiteGroup
46
+ self._about = None
47
+ if suiteGroup is not None and suiteGroup.abortAll is not None:
48
+ self._abortCallback = suiteGroup.abortAll
49
+ self._allowAbort = True
50
+ self._closeText = "Do you want to abort all tests?"
51
+
52
+ def _settitle(self, title):
53
+ """ Setter for title Property """
54
+ if self._title != title:
55
+ self._title = title
56
+ self.title_changed.emit()
57
+
58
+ def _gettitle(self):
59
+ """ Getter for title Property """
60
+ return self._title
61
+
62
+ title_changed = Signal()
63
+ title = Property(str, _gettitle, _settitle, notify=title_changed)
64
+
65
+ def _setvisibility(self, visibility):
66
+ """ Setter for visibility Property """
67
+ if self._visibility != visibility:
68
+ self._visibility = visibility
69
+ self.visibility_changed.emit()
70
+
71
+ def _getvisibility(self):
72
+ """ Getter for visibility Property """
73
+ return self._visibility
74
+
75
+ visibility_changed = Signal()
76
+ visibility = Property(str, _getvisibility, _setvisibility, notify=visibility_changed)
77
+
78
+ def _setabout(self, about):
79
+ """ Setter for about Property. Expects html (or rich text subset there of) """
80
+ if self._about != about:
81
+ self._about = about
82
+ self.about_changed.emit()
83
+
84
+ def _getabout(self):
85
+ """ Getter for about Property """
86
+ return self._add_notice(self._about)
87
+
88
+ def _add_notice(self, about):
89
+ if about:
90
+ about = f"{about}<br/>{notice}"
91
+ else:
92
+ about = notice
93
+ return about
94
+
95
+ about_changed = Signal()
96
+ about = Property(str, _getabout, _setabout, notify=about_changed)
97
+
98
+ def _setcloseHeading(self, closeHeading):
99
+ """ Setter for closeHeading Property """
100
+ if self._closeHeading != closeHeading:
101
+ self._closeHeading = closeHeading
102
+ self.closeHeading_changed.emit()
103
+
104
+ def _getcloseHeading(self):
105
+ """ Getter for closeHeading Property """
106
+ return self._closeHeading
107
+
108
+ closeHeading_changed = Signal()
109
+ closeHeading = Property(str, _getcloseHeading, _setcloseHeading, notify=closeHeading_changed)
110
+
111
+ def _setcloseText(self, closeText):
112
+ """ Setter for closeText Property """
113
+ if self._closeText != closeText:
114
+ self._closeText = closeText
115
+ self.closeText_changed.emit()
116
+
117
+ def _getcloseText(self):
118
+ """ Getter for closeText Property """
119
+ return self._closeText
120
+
121
+ closeText_changed = Signal()
122
+ closeText = Property(str, _getcloseText, _setcloseText, notify=closeText_changed)
123
+
124
+ def _setallowAbort(self, allowAbort):
125
+ """ Setter for allowAbort Property """
126
+ if self._allowAbort != allowAbort:
127
+ self._allowAbort = allowAbort
128
+ self.allowAbort_changed.emit()
129
+
130
+ def _getallowAbort(self):
131
+ """ Getter for allowAbort Property """
132
+ return self._allowAbort
133
+
134
+ allowAbort_changed = Signal()
135
+ allowAbort = Property(bool, _getallowAbort, _setallowAbort, notify=allowAbort_changed)
136
+
137
+ def _setconfig(self, config):
138
+ """ Setter for config Property """
139
+ if self._config != config:
140
+ self._config = config
141
+ self.config_changed.emit()
142
+
143
+ def _getconfig(self):
144
+ """ Getter for config Property """
145
+ return self._config
146
+
147
+ config_changed = Signal()
148
+ config = Property(str, _getconfig, _setconfig, notify=config_changed)
149
+
150
+
151
+ @Slot(bool)
152
+ def abortAll(self, hard=False):
153
+ if self._abortCallback:
154
+ self._abortCallback(hard)
155
+
156
+ def exec(self, iconFile=None):
157
+ current_path = os.path.dirname(os.path.abspath(__file__))
158
+ relative_path = os.path.join(current_path, "..")
159
+ ui_path = os.path.join(relative_path, 'ui')
160
+ qml_file = os.path.join(ui_path, 'MultiTestWindow.qml')
161
+ url = QUrl.fromLocalFile(qml_file)
162
+ if not iconFile:
163
+ iconFile = os.path.join(ui_path, 'te-64x64.ico')
164
+
165
+ QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
166
+ QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
167
+ app = QApplication(sys.argv)
168
+
169
+ app.setWindowIcon(QIcon(iconFile))
170
+ if self.config:
171
+ check_json = json.loads(self.config)
172
+ engine = QQmlApplicationEngine()
173
+ engine.rootContext().setContextProperty("app_model", self)
174
+ if self.config:
175
+ engine.rootContext().setContextProperty("contextKeyValueItemConfig",
176
+ json.dumps(check_json["identification"]["item"]))
177
+ if "controller" in check_json:
178
+ engine.rootContext().setContextProperty("contextFilterSelectorItemConfig",
179
+ json.dumps(check_json["controller"]["filter"]["item"]))
180
+ engine.rootContext().setContextProperty("model_list", self._suiteGroup)
181
+
182
+ engine.load(url)
183
+
184
+ return app.exec_()
@@ -0,0 +1,314 @@
1
+ # Copyright 2020 Direkt, Australia
2
+ # Copyright 2021 Direkt Embedded Pty Ltd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # This Python file uses the following encoding: utf-8
17
+ import threading
18
+ from PySide6 import QtCore
19
+ from PySide6.QtCore import QAbstractListModel
20
+ from PySide6.QtCore import Qt
21
+ from PySide6.QtCore import QModelIndex
22
+ from PySide6.QtCore import Slot
23
+ from PySide6.QtCore import Signal
24
+ from PySide6.QtCore import Property
25
+ from PySide6.QtCore import QObject
26
+
27
+ class Result(QObject):
28
+
29
+ StateRunning = "Running"
30
+ StatePass = "Pass"
31
+ StateFail = "Fail"
32
+
33
+ def __init__(self, name, result=None, feedback=None):
34
+ QObject.__init__(self)
35
+ self.lock = threading.RLock()
36
+ self._name = name
37
+ self._feedback = feedback
38
+ self._result = result
39
+ self._duration = 0
40
+ self._progress = 0
41
+
42
+ def _setfeedback(self, feedback):
43
+ """ Setter for feedback Property """
44
+ changed = False
45
+ with self.lock:
46
+ if self._feedback != feedback:
47
+ self._feedback = feedback
48
+ changed = True
49
+ if changed:
50
+ self.feedback_changed.emit()
51
+
52
+ def _getfeedback(self):
53
+ """ Getter for feedback Property """
54
+ with self.lock:
55
+ fb = self._feedback
56
+ return fb
57
+
58
+ feedback_changed = Signal()
59
+ feedback = Property(str, _getfeedback, _setfeedback, notify=feedback_changed)
60
+
61
+ def _setresult(self, result):
62
+ """ Setter for result Property """
63
+ changed = False
64
+ with self.lock:
65
+ if self._result != result:
66
+ self._result = result
67
+ changed = True
68
+ if changed:
69
+ self.result_changed.emit()
70
+
71
+ def _getresult(self):
72
+ """ Getter for result Property """
73
+ with self.lock:
74
+ r = self._result
75
+ return r
76
+
77
+ result_changed = Signal()
78
+ result = Property(str, _getresult, _setresult, notify=result_changed)
79
+
80
+ def _setduration(self, duration):
81
+ """ Setter for duration Property """
82
+ changed = False
83
+ with self.lock:
84
+ if self._duration != duration:
85
+ self._duration = duration
86
+ changed = True
87
+ if changed:
88
+ self.duration_changed.emit()
89
+
90
+ def _getduration(self):
91
+ """ Getter for duration Property """
92
+ with self.lock:
93
+ dur = self._duration
94
+ return dur
95
+
96
+ duration_changed = Signal()
97
+ duration = Property(int, _getduration, _setduration, notify=duration_changed)
98
+
99
+ def _setname(self, name):
100
+ """ Setter for name Property """
101
+ changed = False
102
+ with self.lock:
103
+ if self._name != name:
104
+ self._name = name
105
+ changed = True
106
+ if changed:
107
+ self.name_changed.emit()
108
+
109
+ def _getname(self):
110
+ """ Getter for name Property """
111
+ with self.lock:
112
+ n = self._name
113
+ return n
114
+
115
+ name_changed = Signal()
116
+ name = Property(str, _getname, _setname, notify=name_changed)
117
+
118
+ def _setprogress(self, progress):
119
+ """ Setter for progress Property """
120
+ changed = False
121
+ with self.lock:
122
+ if self._progress != progress:
123
+ if progress > 1:
124
+ progress = 1
125
+ elif progress < 0:
126
+ progress = 0
127
+ self._progress = progress
128
+ changed = True
129
+ if changed:
130
+ self.progress_changed.emit()
131
+
132
+ def _getprogress(self):
133
+ """ Getter for progress Property """
134
+ return self._progress
135
+
136
+ progress_changed = Signal()
137
+ progress = Property(float, _getprogress, _setprogress, notify=progress_changed)
138
+
139
+
140
+ class ResultModel(QAbstractListModel):
141
+
142
+ TestRole = Qt.UserRole
143
+ TestKey = b"test"
144
+
145
+ def __init__(self, parent=None):
146
+ QAbstractListModel.__init__(self, parent)
147
+ self.lock = threading.RLock()
148
+ self._currentTestIndex = -1
149
+ self._data = []
150
+
151
+ def rowCount(self, parent=QModelIndex()):
152
+ return len(self._data)
153
+
154
+ def roleNames(self):
155
+ return {self.TestRole: self.TestKey}
156
+
157
+ def data(self, index, role=None):
158
+ i = index.row()
159
+ if len(self._data) > i:
160
+ d = self._data[i]
161
+ if role == self.TestRole:
162
+ return d[self.TestKey]
163
+ return None
164
+
165
+ def setData(self, index, value, role=None):
166
+ i = index.row()
167
+ if len(self._data) > i:
168
+ self._data[index.row()] = value
169
+ self.dataChanged.emit(index, index, self.roleNames())
170
+
171
+ def overallResult(self):
172
+ """
173
+ Return the test suite result status
174
+ :return: None: State is unknown. Either no test results or error occurred.
175
+ Result.StateRunning: A test is in progress
176
+ Result.StatePass: All test have been run and all passed
177
+ Result.StateFail: One state failed
178
+ """
179
+ overall_result = None
180
+ if self._data and len(self._data):
181
+ for item in self._data:
182
+ test = item[self.TestKey]
183
+ if test.result == Result.StateFail:
184
+ overall_result = test.result
185
+ break
186
+ elif test.result == Result.StateRunning:
187
+ overall_result = test.result
188
+ break
189
+ if not overall_result:
190
+ overall_result = Result.StatePass
191
+ return overall_result
192
+
193
+
194
+ @Slot(str, str)
195
+ def add(self, name, result, feedback=None):
196
+ rowCount = self.rowCount()
197
+ self.beginInsertRows(QModelIndex(), rowCount, rowCount)
198
+ test = {b'test': Result(name, result, feedback)}
199
+ self._data.append(test)
200
+ self.endInsertRows()
201
+ return test
202
+
203
+ @Slot(str)
204
+ def start(self, name):
205
+ """
206
+ Method called to either add a new test, or re-start an existing one.
207
+ If the name-d test is found its 'content' will be cleared and restarted.
208
+ If it is not found the test will be added to the list and executed.
209
+ :param name: unique name of the test
210
+ :return: None
211
+ """
212
+ existing = False
213
+ for row in range(len(self._data)):
214
+ test = self._data[row][self.TestKey]
215
+ if test.name == name:
216
+ test.result = Result.StateRunning
217
+ ix = self.index(row, 0)
218
+ self._setcurrentTestIndex(row)
219
+ self.dataChanged.emit(ix, ix, self.roleNames())
220
+ existing = True
221
+ break
222
+ if not existing:
223
+ self.add(name, Result.StateRunning)
224
+ self._setcurrentTestIndex(len(self._data) - 1)
225
+
226
+ @Slot(str, str)
227
+ def end(self, name, result):
228
+ """
229
+ Method called to end a test.
230
+ Only updated if test is found. If no tests with name exist, nothing is done.
231
+ :param name: unique name of the test
232
+ :param result: test result for the suite
233
+ :return: None
234
+ """
235
+ for row in range(len(self._data)):
236
+ test = self._data[row][self.TestKey]
237
+ if test.name == name:
238
+ test.result = result
239
+ test.progress = 1
240
+ ix = self.index(row, 0)
241
+ self.dataChanged.emit(ix, ix, self.roleNames())
242
+ break
243
+
244
+ @Slot(str, int)
245
+ def progress(self, name, progress):
246
+ """
247
+ Method called to end a test.
248
+ Only updated if test is found. If no tests with name exist, nothing is done.
249
+ :param name: unique name of the test
250
+ :param progress: 0 to 100 for percentage of test progress.
251
+ :return: None
252
+ """
253
+ for row in range(len(self._data)):
254
+ test = self._data[row][self.TestKey]
255
+ if test.name == name:
256
+ test.progress = progress / 100
257
+ ix = self.index(row, 0)
258
+ self.dataChanged.emit(ix, ix, self.roleNames())
259
+ break
260
+
261
+ @Slot(str, str)
262
+ def setFeedback(self, key, feedback):
263
+ existing = False
264
+ for row in range(len(self._data)):
265
+ test = self._data[row][self.TestKey]
266
+ if test.name == key:
267
+ test.feedback = feedback
268
+ ix = self.index(row, 0)
269
+ self.dataChanged.emit(ix, ix, self.roleNames())
270
+ existing = True
271
+ break
272
+ if not existing:
273
+ self.add(key, None, feedback)
274
+
275
+ @Slot()
276
+ def clear(self):
277
+ rowCount = self.rowCount(QModelIndex())
278
+ if rowCount:
279
+ self.beginRemoveRows(QModelIndex(), 0, rowCount - 1)
280
+ self._data.clear()
281
+ self.endRemoveRows()
282
+
283
+ @Slot(list, bool)
284
+ def populateTests(self, tests, clear):
285
+ if clear:
286
+ self.removeRows(0, self.rowCount(QModelIndex()))
287
+ if tests:
288
+ for test in tests:
289
+ self.add(test, None)
290
+
291
+ def removeRows(self, position, rows, parent=QtCore.QModelIndex()):
292
+ self.beginRemoveRows(parent, position, position + rows - 1)
293
+ del self._data[position:position + rows]
294
+ self.endRemoveRows()
295
+ return True
296
+
297
+ def _setcurrentTestIndex(self, currentTestIndex):
298
+ """ Setter for currentTestIndex Property """
299
+ changed = False
300
+ with self.lock:
301
+ if self._currentTestIndex != currentTestIndex:
302
+ self._currentTestIndex = currentTestIndex
303
+ changed = True
304
+ if changed:
305
+ self.currentTestIndex_changed.emit()
306
+
307
+ def _getcurrentTestIndex(self):
308
+ """ Getter for currentTestIndex Property """
309
+ with self.lock:
310
+ index = self._currentTestIndex
311
+ return index
312
+
313
+ currentTestIndex_changed = Signal()
314
+ currentTestIndex = Property(int, _getcurrentTestIndex, _setcurrentTestIndex, notify=currentTestIndex_changed)
@@ -0,0 +1,139 @@
1
+ # Copyright 2020 Direkt, Australia
2
+ # Copyright 2021 Direkt Embedded Pty Ltd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import threading
17
+ from PySide6.QtCore import QObject
18
+ from PySide6.QtCore import Signal, Property, Slot
19
+ from .selector.MultiSelectListModel import MultiSelectListModel
20
+ from testexecutor.model.selector.FilterGroupModel import FilterGroupModel
21
+
22
+
23
+ class TestSuiteControlModel(QObject):
24
+ """
25
+ A Test Suite Control is a model for selecting tests to be executed. The tests can be filtered.
26
+ """
27
+
28
+ def __init__(self, filtercallback=None, filters=None):
29
+ """
30
+ The suite control calls the supplied callback when a change occurs in the filters. The callback is to the
31
+ execution test system, and should return a list of suites and associated tests, as well as a new set of
32
+ allowed filters, given the new suites and tests.
33
+ These will be 'merged' with the current suite and tests in the test selector.
34
+ What the filters are and how the filters effect the list of tests is entirely up to the calling test system.
35
+ Once the user has filtered and/or selected the tests, the getTests() method can be used by the test system
36
+ to get the list of suites and tests to execute. If this model is used in conjunction with the TestSuiteModel
37
+ then the test run will be seen on that associated UI.
38
+ :param filtercallback: Callback executed when a filter item changes, including on first creation
39
+ :param filters: A list of filter groups to be displayed
40
+ """
41
+ QObject.__init__(self)
42
+ self.lock = threading.RLock()
43
+ self._testselector = MultiSelectListModel()
44
+ self._filterchangedcallback = filtercallback
45
+ self._errors = ""
46
+ if filters:
47
+ self._filter_changed_signal = Signal()
48
+ self._filters = FilterGroupModel(filters, onSelectedChanged=self.on_filters_changed)
49
+
50
+ @Slot(str, object)
51
+ def on_filters_changed(self, name, selected):
52
+ try:
53
+ self._filterchangedcallback(name, selected)
54
+ except Exception as err:
55
+ self.errors = str(err)
56
+
57
+ def _setfilters(self, filters):
58
+ """ Setter for filters Property """
59
+ changed = False
60
+ with self.lock:
61
+ if self._filters != filters:
62
+ self._filters = filters
63
+ changed = True
64
+ if changed:
65
+ self.filters_changed.emit()
66
+
67
+ def _getfilters(self):
68
+ """
69
+ Getter for filters Property
70
+ """
71
+ filters = None
72
+ with self.lock:
73
+ filters = self._filters
74
+ return filters
75
+
76
+ """
77
+ Filters is a list of possible filter controls that can be used to control the suite filtering.
78
+ Each filter is then another list of items which are the filtering 'fields'
79
+ """
80
+ filters_changed = Signal()
81
+ filters = Property(QObject, _getfilters, _setfilters, notify=filters_changed)
82
+
83
+
84
+ def _settestselector(self, testselector):
85
+ """ Setter for testselector Property """
86
+ changed = False
87
+ with self.lock:
88
+ if self._testselector != testselector:
89
+ self._testselector = testselector
90
+ changed = True
91
+ if changed:
92
+ self.testselector_changed.emit()
93
+
94
+ def _gettestselector(self):
95
+ """
96
+ Getter for testselector Property
97
+ """
98
+ testselector = None
99
+ with self.lock:
100
+ testselector = self._testselector
101
+ return testselector
102
+
103
+ """
104
+ testselector is a tree of suites and associated tests which can be selected to create a subset of tests
105
+ to be executed.
106
+ Should be of type TreeSelectorModel
107
+ """
108
+ testselector_changed = Signal()
109
+ testselector = Property(QObject, _gettestselector, _settestselector, notify=testselector_changed)
110
+
111
+ def _seterrors(self, errors):
112
+ """ Setter for errors Property """
113
+ changed = False
114
+ with self.lock:
115
+ if self._errors != errors:
116
+ self._errors = errors
117
+ changed = True
118
+ if changed:
119
+ self.errors_changed.emit()
120
+
121
+ def _geterrors(self):
122
+ """
123
+ Getter for errors Property
124
+ """
125
+ errors = None
126
+ with self.lock:
127
+ errors = self._errors
128
+ return errors
129
+
130
+ """
131
+ errors is a tree of suites and associated tests which can be selected to create a subset of tests
132
+ to be executed.
133
+ Should be of type TreeSelectorModel
134
+ """
135
+ errors_changed = Signal()
136
+ errors = Property(str, _geterrors, _seterrors, notify=errors_changed)
137
+
138
+ def selectedItems(self):
139
+ return self._testselector.selectedItems()