13 import os |
13 import os |
14 |
14 |
15 from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QEvent, QCoreApplication |
15 from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QEvent, QCoreApplication |
16 from PyQt6.QtWidgets import QAbstractButton, QComboBox, QDialogButtonBox, QWidget |
16 from PyQt6.QtWidgets import QAbstractButton, QComboBox, QDialogButtonBox, QWidget |
17 |
17 |
18 from EricWidgets import EricMessageBox |
18 from eric7.EricWidgets import EricMessageBox |
19 from EricWidgets.EricApplication import ericApp |
19 from eric7.EricWidgets.EricApplication import ericApp |
20 from EricWidgets.EricMainWindow import EricMainWindow |
20 from eric7.EricWidgets.EricMainWindow import EricMainWindow |
21 from EricWidgets.EricPathPicker import EricPathPickerModes |
21 from eric7.EricWidgets.EricPathPicker import EricPathPickerModes |
22 |
22 |
23 from .Ui_TestingWidget import Ui_TestingWidget |
23 from .Ui_TestingWidget import Ui_TestingWidget |
24 |
24 |
25 from .TestResultsTree import TestResultsModel, TestResultsTreeView |
25 from .TestResultsTree import TestResultsModel, TestResultsTreeView |
26 from .Interfaces import Frameworks |
26 from .Interfaces import Frameworks |
27 from .Interfaces.TestExecutorBase import TestConfig, TestResult, TestResultCategory |
27 from .Interfaces.TestExecutorBase import TestConfig, TestResult, TestResultCategory |
28 from .Interfaces.TestFrameworkRegistry import TestFrameworkRegistry |
28 from .Interfaces.TestFrameworkRegistry import TestFrameworkRegistry |
29 |
29 |
30 import Preferences |
30 from eric7 import Preferences |
31 import UI.PixmapCache |
31 from eric7.EricGui import EricPixmapCache |
32 |
32 |
33 from Globals import ( |
33 from eric7.Globals import ( |
34 recentNameTestDiscoverHistory, |
34 recentNameTestDiscoverHistory, |
35 recentNameTestFileHistory, |
35 recentNameTestFileHistory, |
36 recentNameTestNameHistory, |
36 recentNameTestNameHistory, |
37 recentNameTestFramework, |
37 recentNameTestFramework, |
38 recentNameTestEnvironment, |
38 recentNameTestEnvironment, |
78 self.__resultsTree = TestResultsTreeView(self) |
78 self.__resultsTree = TestResultsTreeView(self) |
79 self.__resultsTree.setModel(self.__resultsModel) |
79 self.__resultsTree.setModel(self.__resultsModel) |
80 self.__resultsTree.goto.connect(self.__showSource) |
80 self.__resultsTree.goto.connect(self.__showSource) |
81 self.resultsGroupBox.layout().addWidget(self.__resultsTree) |
81 self.resultsGroupBox.layout().addWidget(self.__resultsTree) |
82 |
82 |
83 self.versionsButton.setIcon(UI.PixmapCache.getIcon("info")) |
83 self.versionsButton.setIcon(EricPixmapCache.getIcon("info")) |
84 self.clearHistoriesButton.setIcon(UI.PixmapCache.getIcon("clearPrivateData")) |
84 self.clearHistoriesButton.setIcon(EricPixmapCache.getIcon("clearPrivateData")) |
85 self.showMarkersButton.setIcon(UI.PixmapCache.getIcon("select")) |
85 self.showMarkersButton.setIcon(EricPixmapCache.getIcon("select")) |
86 |
86 |
87 self.testsuitePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) |
87 self.testsuitePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) |
88 self.testsuitePicker.setInsertPolicy(QComboBox.InsertPolicy.InsertAtTop) |
88 self.testsuitePicker.setInsertPolicy(QComboBox.InsertPolicy.InsertAtTop) |
89 self.testsuitePicker.setSizeAdjustPolicy( |
89 self.testsuitePicker.setSizeAdjustPolicy( |
90 QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon |
90 QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon |
163 ) |
163 ) |
164 |
164 |
165 self.setWindowFlags( |
165 self.setWindowFlags( |
166 self.windowFlags() | Qt.WindowType.WindowContextHelpButtonHint |
166 self.windowFlags() | Qt.WindowType.WindowContextHelpButtonHint |
167 ) |
167 ) |
168 self.setWindowIcon(UI.PixmapCache.getIcon("eric")) |
168 self.setWindowIcon(EricPixmapCache.getIcon("eric")) |
169 self.setWindowTitle(self.tr("Testing")) |
169 self.setWindowTitle(self.tr("Testing")) |
170 |
170 |
171 try: |
171 try: |
172 # we are called from within the eric IDE |
172 # we are called from within the eric IDE |
173 self.__venvManager = ericApp().getObject("VirtualEnvManager") |
173 self.__venvManager = ericApp().getObject("VirtualEnvManager") |
174 self.__project = ericApp().getObject("Project") |
174 self.__project = ericApp().getObject("Project") |
175 self.__project.projectOpened.connect(self.__projectOpened) |
175 self.__project.projectOpened.connect(self.__projectOpened) |
176 self.__project.projectClosed.connect(self.__projectClosed) |
176 self.__project.projectClosed.connect(self.__projectClosed) |
|
177 self.__projectEnvironmentMarker = self.tr("<project>") |
177 except KeyError: |
178 except KeyError: |
178 # we were called as a standalone application |
179 # we were called as a standalone application |
179 from VirtualEnv.VirtualenvManager import VirtualenvManager |
180 from eric7.VirtualEnv.VirtualenvManager import VirtualenvManager |
180 |
181 |
181 self.__venvManager = VirtualenvManager(self) |
182 self.__venvManager = VirtualenvManager(self) |
182 self.__venvManager.virtualEnvironmentAdded.connect( |
183 self.__venvManager.virtualEnvironmentAdded.connect( |
183 self.__populateVenvComboBox |
184 self.__populateVenvComboBox |
184 ) |
185 ) |
189 self.__populateVenvComboBox |
190 self.__populateVenvComboBox |
190 ) |
191 ) |
191 ericApp().registerObject("VirtualEnvManager", self.__venvManager) |
192 ericApp().registerObject("VirtualEnvManager", self.__venvManager) |
192 |
193 |
193 self.__project = None |
194 self.__project = None |
|
195 self.__projectEnvironmentMarker = "" |
194 |
196 |
195 self.__discoverHistory = [] |
197 self.__discoverHistory = [] |
196 self.__fileHistory = [] |
198 self.__fileHistory = [] |
197 self.__testNameHistory = [] |
199 self.__testNameHistory = [] |
198 self.__recentFramework = "" |
200 self.__recentFramework = "" |
236 |
238 |
237 self.clearHistoriesButton.clicked.connect(self.clearRecent) |
239 self.clearHistoriesButton.clicked.connect(self.clearRecent) |
238 |
240 |
239 self.tabWidget.setCurrentIndex(0) |
241 self.tabWidget.setCurrentIndex(0) |
240 |
242 |
|
243 def __determineInterpreter(self, venvName): |
|
244 """ |
|
245 Private method to determine the interpreter to be used. |
|
246 |
|
247 @param venvName name of the virtual environment |
|
248 @type str |
|
249 @return path of the interpreter executable |
|
250 @rtype str |
|
251 """ |
|
252 if self.__project and venvName == self.__projectEnvironmentMarker: |
|
253 return self.__project.getProjectInterpreter() |
|
254 else: |
|
255 return self.__venvManager.getVirtualenvInterpreter(venvName) |
|
256 |
241 def __populateVenvComboBox(self): |
257 def __populateVenvComboBox(self): |
242 """ |
258 """ |
243 Private method to (re-)populate the virtual environments selector. |
259 Private method to (re-)populate the virtual environments selector. |
244 """ |
260 """ |
245 currentText = self.venvComboBox.currentText() |
261 currentText = self.venvComboBox.currentText() |
246 if not currentText: |
262 if not currentText: |
247 currentText = self.__recentEnvironment |
263 currentText = self.__recentEnvironment |
248 |
264 |
249 self.venvComboBox.clear() |
265 self.venvComboBox.clear() |
250 self.venvComboBox.addItem("") |
266 self.venvComboBox.addItem("") |
|
267 if self.__project and self.__project.isOpen(): |
|
268 self.venvComboBox.addItem(self.__projectEnvironmentMarker) |
251 self.venvComboBox.addItems(sorted(self.__venvManager.getVirtualenvNames())) |
269 self.venvComboBox.addItems(sorted(self.__venvManager.getVirtualenvNames())) |
252 self.venvComboBox.setCurrentText(currentText) |
270 self.venvComboBox.setCurrentText(currentText) |
253 |
271 |
254 def __populateTestFrameworkComboBox(self): |
272 def __populateTestFrameworkComboBox(self): |
255 """ |
273 """ |
260 currentText = self.__recentFramework |
278 currentText = self.__recentFramework |
261 |
279 |
262 self.frameworkComboBox.clear() |
280 self.frameworkComboBox.clear() |
263 |
281 |
264 if bool(self.venvComboBox.currentText()): |
282 if bool(self.venvComboBox.currentText()): |
265 interpreter = self.__venvManager.getVirtualenvInterpreter( |
283 interpreter = self.__determineInterpreter(self.venvComboBox.currentText()) |
266 self.venvComboBox.currentText() |
|
267 ) |
|
268 self.frameworkComboBox.addItem("") |
284 self.frameworkComboBox.addItem("") |
269 for index, (name, executor) in enumerate( |
285 for index, (name, executor) in enumerate( |
270 sorted(self.__frameworkRegistry.getFrameworks().items()), start=1 |
286 sorted(self.__frameworkRegistry.getFrameworks().items()), start=1 |
271 ): |
287 ): |
272 isInstalled = executor.isInstalled(interpreter) |
288 isInstalled = executor.isInstalled(interpreter) |
697 |
713 |
698 venvName = self.venvComboBox.currentText() |
714 venvName = self.venvComboBox.currentText() |
699 if venvName: |
715 if venvName: |
700 framework = self.frameworkComboBox.currentText() |
716 framework = self.frameworkComboBox.currentText() |
701 if framework: |
717 if framework: |
702 interpreter = self.__venvManager.getVirtualenvInterpreter(venvName) |
718 interpreter = self.__determineInterpreter(venvName) |
703 executor = self.__frameworkRegistry.createExecutor(framework, self) |
719 executor = self.__frameworkRegistry.createExecutor(framework, self) |
704 hasCoverage = executor.hasCoverage(interpreter) |
720 hasCoverage = executor.hasCoverage(interpreter) |
705 |
721 |
706 self.coverageCheckBox.setEnabled(hasCoverage) |
722 self.coverageCheckBox.setEnabled(hasCoverage) |
707 if not hasCoverage: |
723 if not hasCoverage: |
717 |
733 |
718 venvName = self.venvComboBox.currentText() |
734 venvName = self.venvComboBox.currentText() |
719 if venvName: |
735 if venvName: |
720 framework = self.frameworkComboBox.currentText() |
736 framework = self.frameworkComboBox.currentText() |
721 if framework: |
737 if framework: |
722 interpreter = self.__venvManager.getVirtualenvInterpreter(venvName) |
738 interpreter = self.__determineInterpreter(venvName) |
723 executor = self.__frameworkRegistry.createExecutor(framework, self) |
739 executor = self.__frameworkRegistry.createExecutor(framework, self) |
724 supportsMarkers = executor.supportsMarkers(interpreter) |
740 supportsMarkers = executor.supportsMarkers(interpreter) |
725 |
741 |
726 # 1. marker expression line edit |
742 # 1. marker expression line edit |
727 self.markerExpressionEdit.setEnabled(supportsMarkers) |
743 self.markerExpressionEdit.setEnabled(supportsMarkers) |
747 elif self.testsuitePicker.currentText(): |
763 elif self.testsuitePicker.currentText(): |
748 workdir = os.path.dirname(self.testsuitePicker.currentText()) |
764 workdir = os.path.dirname(self.testsuitePicker.currentText()) |
749 else: |
765 else: |
750 workdir = "" |
766 workdir = "" |
751 |
767 |
752 interpreter = self.__venvManager.getVirtualenvInterpreter(venvName) |
768 interpreter = self.__determineInterpreter(venvName) |
753 executor = self.__frameworkRegistry.createExecutor(framework, self) |
769 executor = self.__frameworkRegistry.createExecutor(framework, self) |
754 markers = executor.getMarkers(interpreter, workdir) |
770 markers = executor.getMarkers(interpreter, workdir) |
755 |
771 |
756 if self.__markersWindow is None: |
772 if self.__markersWindow is None: |
757 from .MarkersWindow import MarkersWindow |
773 from .MarkersWindow import MarkersWindow |
769 |
785 |
770 venvName = self.venvComboBox.currentText() |
786 venvName = self.venvComboBox.currentText() |
771 if venvName: |
787 if venvName: |
772 framework = self.frameworkComboBox.currentText() |
788 framework = self.frameworkComboBox.currentText() |
773 if framework: |
789 if framework: |
774 interpreter = self.__venvManager.getVirtualenvInterpreter(venvName) |
790 interpreter = self.__determineInterpreter(venvName) |
775 executor = self.__frameworkRegistry.createExecutor(framework, self) |
791 executor = self.__frameworkRegistry.createExecutor(framework, self) |
776 supportsPatterns = executor.supportsPatterns(interpreter) |
792 supportsPatterns = executor.supportsPatterns(interpreter) |
777 |
793 |
778 self.testNamePatternEdit.setEnabled(supportsPatterns) |
794 self.testNamePatternEdit.setEnabled(supportsPatterns) |
779 self.testNamePatternEdit.clear() |
795 self.testNamePatternEdit.clear() |
785 """ |
801 """ |
786 venvName = self.venvComboBox.currentText() |
802 venvName = self.venvComboBox.currentText() |
787 if venvName: |
803 if venvName: |
788 headerText = self.tr("<h3>Versions of Frameworks and their" " Plugins</h3>") |
804 headerText = self.tr("<h3>Versions of Frameworks and their" " Plugins</h3>") |
789 versionsText = "" |
805 versionsText = "" |
790 interpreter = self.__venvManager.getVirtualenvInterpreter(venvName) |
806 interpreter = self.__determineInterpreter(venvName) |
791 for framework in sorted(self.__frameworkRegistry.getFrameworks().keys()): |
807 for framework in sorted(self.__frameworkRegistry.getFrameworks().keys()): |
792 executor = self.__frameworkRegistry.createExecutor(framework, self) |
808 executor = self.__frameworkRegistry.createExecutor(framework, self) |
793 versions = executor.getVersions(interpreter) |
809 versions = executor.getVersions(interpreter) |
794 if versions: |
810 if versions: |
795 txt = "<p><strong>{0} {1}</strong>".format( |
811 txt = "<p><strong>{0} {1}</strong>".format( |
856 coverageFile = ( |
872 coverageFile = ( |
857 os.path.splitext(mainScript)[0] + ".coverage" if mainScript else "" |
873 os.path.splitext(mainScript)[0] + ".coverage" if mainScript else "" |
858 ) |
874 ) |
859 else: |
875 else: |
860 coverageFile = "" |
876 coverageFile = "" |
861 interpreter = self.__venvManager.getVirtualenvInterpreter( |
877 interpreter = self.__determineInterpreter(self.__recentEnvironment) |
862 self.__recentEnvironment |
|
863 ) |
|
864 config = TestConfig( |
878 config = TestConfig( |
865 interpreter=interpreter, |
879 interpreter=interpreter, |
866 discover=discover, |
880 discover=discover, |
867 discoveryStart=discoveryStart, |
881 discoveryStart=discoveryStart, |
868 testFilename=testFileName, |
882 testFilename=testFileName, |
1078 """ |
1092 """ |
1079 Private slot to show a code coverage dialog for the most recent test |
1093 Private slot to show a code coverage dialog for the most recent test |
1080 run. |
1094 run. |
1081 """ |
1095 """ |
1082 if self.__coverageDialog is None: |
1096 if self.__coverageDialog is None: |
1083 from DataViews.PyCoverageDialog import PyCoverageDialog |
1097 from eric7.DataViews.PyCoverageDialog import PyCoverageDialog |
1084 |
1098 |
1085 self.__coverageDialog = PyCoverageDialog(self) |
1099 self.__coverageDialog = PyCoverageDialog(self) |
1086 self.__coverageDialog.openFile.connect(self.__openEditor) |
1100 self.__coverageDialog.openFile.connect(self.__openEditor) |
1087 |
1101 |
1088 testDir = ( |
1102 testDir = ( |
1097 @pyqtSlot() |
1111 @pyqtSlot() |
1098 def __showLogOutput(self): |
1112 def __showLogOutput(self): |
1099 """ |
1113 """ |
1100 Private slot to show the output of the most recent test run. |
1114 Private slot to show the output of the most recent test run. |
1101 """ |
1115 """ |
1102 from EricWidgets.EricPlainTextDialog import EricPlainTextDialog |
1116 from eric7.EricWidgets.EricPlainTextDialog import EricPlainTextDialog |
1103 |
1117 |
1104 dlg = EricPlainTextDialog( |
1118 dlg = EricPlainTextDialog( |
1105 title=self.tr("Test Run Output"), text=self.__recentLog |
1119 title=self.tr("Test Run Output"), text=self.__recentLog |
1106 ) |
1120 ) |
1107 dlg.exec() |
1121 dlg.exec() |
1119 @pyqtSlot() |
1133 @pyqtSlot() |
1120 def __projectOpened(self): |
1134 def __projectOpened(self): |
1121 """ |
1135 """ |
1122 Private slot to handle a project being opened. |
1136 Private slot to handle a project being opened. |
1123 """ |
1137 """ |
1124 self.venvComboBox.setCurrentText(self.__project.getProjectVenv()) |
1138 self.venvComboBox.insertItem(1, self.__projectEnvironmentMarker) |
|
1139 self.venvComboBox.setCurrentIndex(1) |
1125 self.frameworkComboBox.setCurrentText( |
1140 self.frameworkComboBox.setCurrentText( |
1126 self.__project.getProjectTestingFramework() |
1141 self.__project.getProjectTestingFramework() |
1127 ) |
1142 ) |
1128 self.__insertDiscovery(self.__project.getProjectPath()) |
1143 self.__insertDiscovery(self.__project.getProjectPath()) |
1129 |
1144 |
1130 @pyqtSlot() |
1145 @pyqtSlot() |
1131 def __projectClosed(self): |
1146 def __projectClosed(self): |
1132 """ |
1147 """ |
1133 Private slot to handle a project being closed. |
1148 Private slot to handle a project being closed. |
1134 """ |
1149 """ |
|
1150 self.venvComboBox.removeItem(1) # <project> is always at index 1 |
1135 self.venvComboBox.setCurrentText("") |
1151 self.venvComboBox.setCurrentText("") |
1136 self.frameworkComboBox.setCurrentText("") |
1152 self.frameworkComboBox.setCurrentText("") |
1137 self.__insertDiscovery("") |
1153 self.__insertDiscovery("") |
1138 |
1154 |
1139 @pyqtSlot(str, int) |
1155 @pyqtSlot(str, int) |
1162 @param filename path of the file to be opened |
1178 @param filename path of the file to be opened |
1163 @type str |
1179 @type str |
1164 @param linenumber line number to place the cursor at (defaults to 1) |
1180 @param linenumber line number to place the cursor at (defaults to 1) |
1165 @type int (optional) |
1181 @type int (optional) |
1166 """ |
1182 """ |
1167 from QScintilla.MiniEditor import MiniEditor |
1183 from eric7.QScintilla.MiniEditor import MiniEditor |
1168 |
1184 |
1169 editor = MiniEditor(filename, "Python3", self) |
1185 editor = MiniEditor(filename, "Python3", self) |
1170 editor.gotoLine(linenumber) |
1186 editor.gotoLine(linenumber) |
1171 editor.show() |
1187 editor.show() |
1172 |
1188 |