Sun, 05 Jun 2022 17:17:44 +0200
Corrected the VCS tracing state of the recently merged files.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/DataViews/PyCoverageHtmlReportDialog.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to enter the parameters for a coverage HTML +report. +""" + +from PyQt6.QtCore import pyqtSlot +from PyQt6.QtWidgets import QDialog, QDialogButtonBox + +from EricWidgets.EricPathPicker import EricPathPickerModes + +from .Ui_PyCoverageHtmlReportDialog import Ui_PyCoverageHtmlReportDialog + + +class PyCoverageHtmlReportDialog(QDialog, Ui_PyCoverageHtmlReportDialog): + """ + Class implementing a dialog to enter the parameters for a coverage HTML + report. + """ + def __init__(self, defaultDirectory, parent=None): + """ + Constructor + + @param defaultDirectory default directory for selecting the output + directory + @type str + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.outputDirectoryPicker.setMode( + EricPathPickerModes.DIRECTORY_SHOW_FILES_MODE) + self.outputDirectoryPicker.setDefaultDirectory(defaultDirectory) + + self.extraCssPicker.setMode( + EricPathPickerModes.OPEN_FILE_MODE) + + self.buttonBox.button( + QDialogButtonBox.StandardButton.Ok).setEnabled(False) + + msh = self.minimumSizeHint() + self.resize(max(self.width(), msh.width()), msh.height()) + + @pyqtSlot(str) + def on_outputDirectoryPicker_textChanged(self, directory): + """ + Private slot handling a change of the output directory. + + @param directory current text of the directory picker + @type str + """ + self.buttonBox.button( + QDialogButtonBox.StandardButton.Ok).setEnabled(bool(directory)) + + def getData(self): + """ + Public method to get the entered data. + + @return tuple containing the report title, the output directory, the + path of a file containing extra CSS and a flag indicating to open + the generated report in a browser + + @rtype tuple of (str, str, str, bool) + """ + title = self.titleEdit.text() + return ( + title if bool(title) else None, + self.outputDirectoryPicker.currentText(), + self.extraCssPicker.currentText(), + self.openReportCheckBox.isChecked(), + )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/DataViews/PyCoverageHtmlReportDialog.ui Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,153 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PyCoverageHtmlReportDialog</class> + <widget class="QDialog" name="PyCoverageHtmlReportDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>154</height> + </rect> + </property> + <property name="windowTitle"> + <string>HTML Report</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Title:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="EricPathPicker" name="extraCssPicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string>Enter the path of a file containing additional CSS definitions</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Extra CSS:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="titleEdit"> + <property name="toolTip"> + <string>Enter the title for the HTML report</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Output Directory:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="EricPathPicker" name="outputDirectoryPicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string>Enter the path of the output directory</string> + </property> + </widget> + </item> + <item row="4" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="3" column="0" colspan="2"> + <widget class="QCheckBox" name="openReportCheckBox"> + <property name="toolTip"> + <string>Select to open the generated report</string> + </property> + <property name="text"> + <string>Open Report</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>EricPathPicker</class> + <extends>QWidget</extends> + <header>EricWidgets/EricPathPicker.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>titleEdit</tabstop> + <tabstop>outputDirectoryPicker</tabstop> + <tabstop>extraCssPicker</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>PyCoverageHtmlReportDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>PyCoverageHtmlReportDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/DataViews/PyCoverageJsonReportDialog.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to enter the parameters for a coverage JSON +report. +""" + +import os + +from PyQt6.QtCore import pyqtSlot +from PyQt6.QtWidgets import QDialog, QDialogButtonBox + +from EricWidgets.EricPathPicker import EricPathPickerModes + +from .Ui_PyCoverageJsonReportDialog import Ui_PyCoverageJsonReportDialog + + +class PyCoverageJsonReportDialog(QDialog, Ui_PyCoverageJsonReportDialog): + """ + Class implementing a dialog to enter the parameters for a coverage JSON + report. + """ + def __init__(self, defaultDirectory, parent=None): + """ + Constructor + + @param defaultDirectory default directory for selecting the output + directory + @type str + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.outputFilePicker.setMode( + EricPathPickerModes.SAVE_FILE_ENSURE_EXTENSION_MODE) + self.outputFilePicker.setDefaultDirectory(defaultDirectory) + self.outputFilePicker.setFilters( + self.tr("JSON Files (*.json);;All Files (*)")) + self.outputFilePicker.setText( + os.path.join(defaultDirectory, "coverage.json")) + + msh = self.minimumSizeHint() + self.resize(max(self.width(), msh.width()), msh.height()) + + @pyqtSlot(str) + def on_outputFilePicker_textChanged(self, filename): + """ + Private slot handling a change of the output file. + + @param filename current text of the file picker + @type str + """ + self.buttonBox.button( + QDialogButtonBox.StandardButton.Ok).setEnabled(bool(filename)) + + def getData(self): + """ + Public method to get the entered data. + + @return tuple containing the output file and a flag indicating the + creation of a compact JSON file + + @rtype tuple of (str, bool) + """ + return ( + self.outputFilePicker.currentText(), + self.compactCheckBox.isChecked(), + )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/DataViews/PyCoverageJsonReportDialog.ui Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PyCoverageJsonReportDialog</class> + <widget class="QDialog" name="PyCoverageJsonReportDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>98</height> + </rect> + </property> + <property name="windowTitle"> + <string>JSON Report</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0" colspan="2"> + <widget class="QCheckBox" name="compactCheckBox"> + <property name="toolTip"> + <string>Select to create the report using the compact format</string> + </property> + <property name="text"> + <string>Compact Format</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Output File:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="EricPathPicker" name="outputFilePicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string>Enter the path of the output file</string> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>EricPathPicker</class> + <extends>QWidget</extends> + <header>EricWidgets/EricPathPicker.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>outputFilePicker</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>PyCoverageJsonReportDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>PyCoverageJsonReportDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- a/eric7/DebugClients/Python/DCTestResult.py Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2003 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing a TestResult derivative for the eric debugger. -""" - -import select -from unittest import TestResult - - -class DCTestResult(TestResult): - """ - A TestResult derivative to work with eric's debug client. - - For more details see unittest.py of the standard python distribution. - """ - def __init__(self, dbgClient, failfast): - """ - Constructor - - @param dbgClient reference to the debug client - @type DebugClientBase - @param failfast flag indicating to stop at the first error - @type bool - """ - TestResult.__init__(self) - self.__dbgClient = dbgClient - self.failfast = failfast - - def addFailure(self, test, err): - """ - Public method called if a test failed. - - @param test Reference to the test object - @param err The error traceback - """ - TestResult.addFailure(self, test, err) - tracebackLines = self._exc_info_to_string(err, test) - self.__dbgClient.sendJsonCommand("ResponseUTTestFailed", { - "testname": str(test), - "traceback": tracebackLines, - "id": test.id(), - }) - - def addError(self, test, err): - """ - Public method called if a test errored. - - @param test Reference to the test object - @param err The error traceback - """ - TestResult.addError(self, test, err) - tracebackLines = self._exc_info_to_string(err, test) - self.__dbgClient.sendJsonCommand("ResponseUTTestErrored", { - "testname": str(test), - "traceback": tracebackLines, - "id": test.id(), - }) - - def addSubTest(self, test, subtest, err): - """ - Public method called for each subtest to record its result. - - @param test reference to the test object - @param subtest reference to the subtest object - @param err error traceback - """ - if err is not None: - TestResult.addSubTest(self, test, subtest, err) - tracebackLines = self._exc_info_to_string(err, test) - if issubclass(err[0], test.failureException): - self.__dbgClient.sendJsonCommand("ResponseUTTestFailed", { - "testname": str(subtest), - "traceback": tracebackLines, - "id": test.id(), - }) - else: - self.__dbgClient.sendJsonCommand("ResponseUTTestErrored", { - "testname": str(subtest), - "traceback": tracebackLines, - "id": test.id(), - }) - - def addSkip(self, test, reason): - """ - Public method called if a test was skipped. - - @param test reference to the test object - @param reason reason for skipping the test (string) - """ - TestResult.addSkip(self, test, reason) - self.__dbgClient.sendJsonCommand("ResponseUTTestSkipped", { - "testname": str(test), - "reason": reason, - "id": test.id(), - }) - - def addExpectedFailure(self, test, err): - """ - Public method called if a test failed expected. - - @param test reference to the test object - @param err error traceback - """ - TestResult.addExpectedFailure(self, test, err) - tracebackLines = self._exc_info_to_string(err, test) - self.__dbgClient.sendJsonCommand("ResponseUTTestFailedExpected", { - "testname": str(test), - "traceback": tracebackLines, - "id": test.id(), - }) - - def addUnexpectedSuccess(self, test): - """ - Public method called if a test succeeded expectedly. - - @param test reference to the test object - """ - TestResult.addUnexpectedSuccess(self, test) - self.__dbgClient.sendJsonCommand("ResponseUTTestSucceededUnexpected", { - "testname": str(test), - "id": test.id(), - }) - - def startTest(self, test): - """ - Public method called at the start of a test. - - @param test Reference to the test object - """ - TestResult.startTest(self, test) - self.__dbgClient.sendJsonCommand("ResponseUTStartTest", { - "testname": str(test), - "description": test.shortDescription(), - }) - - def stopTest(self, test): - """ - Public method called at the end of a test. - - @param test Reference to the test object - """ - TestResult.stopTest(self, test) - self.__dbgClient.sendJsonCommand("ResponseUTStopTest", {}) - - # ensure that pending input is processed - rrdy, wrdy, xrdy = select.select( - [self.__dbgClient.readstream], [], [], 0.01) - - if self.__dbgClient.readstream in rrdy: - self.__dbgClient.readReady(self.__dbgClient.readstream)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.DataViews.PyCoverageHtmlReportDialog.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,134 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.DataViews.PyCoverageHtmlReportDialog</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.DataViews.PyCoverageHtmlReportDialog</h1> + +<p> +Module implementing a dialog to enter the parameters for a coverage HTML +report. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#PyCoverageHtmlReportDialog">PyCoverageHtmlReportDialog</a></td> +<td>Class implementing a dialog to enter the parameters for a coverage HTML report.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="PyCoverageHtmlReportDialog" ID="PyCoverageHtmlReportDialog"></a> +<h2>PyCoverageHtmlReportDialog</h2> + +<p> + Class implementing a dialog to enter the parameters for a coverage HTML + report. +</p> +<h3>Derived from</h3> +QDialog, Ui_PyCoverageHtmlReportDialog +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#PyCoverageHtmlReportDialog.__init__">PyCoverageHtmlReportDialog</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#PyCoverageHtmlReportDialog.getData">getData</a></td> +<td>Public method to get the entered data.</td> +</tr> +<tr> +<td><a href="#PyCoverageHtmlReportDialog.on_outputDirectoryPicker_textChanged">on_outputDirectoryPicker_textChanged</a></td> +<td>Private slot handling a change of the output directory.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="PyCoverageHtmlReportDialog.__init__" ID="PyCoverageHtmlReportDialog.__init__"></a> +<h4>PyCoverageHtmlReportDialog (Constructor)</h4> +<b>PyCoverageHtmlReportDialog</b>(<i>defaultDirectory, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>defaultDirectory</i> (str)</dt> +<dd> +default directory for selecting the output + directory +</dd> +<dt><i>parent</i> (QWidget (optional))</dt> +<dd> +reference to the parent widget (defaults to None) +</dd> +</dl> +<a NAME="PyCoverageHtmlReportDialog.getData" ID="PyCoverageHtmlReportDialog.getData"></a> +<h4>PyCoverageHtmlReportDialog.getData</h4> +<b>getData</b>(<i></i>) + +<p> + Public method to get the entered data. +</p> +<dl> +<dt>Return:</dt> +<dd> +tuple containing the report title, the output directory, the + path of a file containing extra CSS and a flag indicating to open + the generated report in a browser +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +tuple of (str, str, str, bool) +</dd> +</dl> +<a NAME="PyCoverageHtmlReportDialog.on_outputDirectoryPicker_textChanged" ID="PyCoverageHtmlReportDialog.on_outputDirectoryPicker_textChanged"></a> +<h4>PyCoverageHtmlReportDialog.on_outputDirectoryPicker_textChanged</h4> +<b>on_outputDirectoryPicker_textChanged</b>(<i>directory</i>) + +<p> + Private slot handling a change of the output directory. +</p> +<dl> + +<dt><i>directory</i> (str)</dt> +<dd> +current text of the directory picker +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.DataViews.PyCoverageJsonReportDialog.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,133 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.DataViews.PyCoverageJsonReportDialog</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.DataViews.PyCoverageJsonReportDialog</h1> + +<p> +Module implementing a dialog to enter the parameters for a coverage JSON +report. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#PyCoverageJsonReportDialog">PyCoverageJsonReportDialog</a></td> +<td>Class implementing a dialog to enter the parameters for a coverage JSON report.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="PyCoverageJsonReportDialog" ID="PyCoverageJsonReportDialog"></a> +<h2>PyCoverageJsonReportDialog</h2> + +<p> + Class implementing a dialog to enter the parameters for a coverage JSON + report. +</p> +<h3>Derived from</h3> +QDialog, Ui_PyCoverageJsonReportDialog +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#PyCoverageJsonReportDialog.__init__">PyCoverageJsonReportDialog</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#PyCoverageJsonReportDialog.getData">getData</a></td> +<td>Public method to get the entered data.</td> +</tr> +<tr> +<td><a href="#PyCoverageJsonReportDialog.on_outputFilePicker_textChanged">on_outputFilePicker_textChanged</a></td> +<td>Private slot handling a change of the output file.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="PyCoverageJsonReportDialog.__init__" ID="PyCoverageJsonReportDialog.__init__"></a> +<h4>PyCoverageJsonReportDialog (Constructor)</h4> +<b>PyCoverageJsonReportDialog</b>(<i>defaultDirectory, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>defaultDirectory</i> (str)</dt> +<dd> +default directory for selecting the output + directory +</dd> +<dt><i>parent</i> (QWidget (optional))</dt> +<dd> +reference to the parent widget (defaults to None) +</dd> +</dl> +<a NAME="PyCoverageJsonReportDialog.getData" ID="PyCoverageJsonReportDialog.getData"></a> +<h4>PyCoverageJsonReportDialog.getData</h4> +<b>getData</b>(<i></i>) + +<p> + Public method to get the entered data. +</p> +<dl> +<dt>Return:</dt> +<dd> +tuple containing the output file and a flag indicating the + creation of a compact JSON file +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +tuple of (str, bool) +</dd> +</dl> +<a NAME="PyCoverageJsonReportDialog.on_outputFilePicker_textChanged" ID="PyCoverageJsonReportDialog.on_outputFilePicker_textChanged"></a> +<h4>PyCoverageJsonReportDialog.on_outputFilePicker_textChanged</h4> +<b>on_outputFilePicker_textChanged</b>(<i>filename</i>) + +<p> + Private slot handling a change of the output file. +</p> +<dl> + +<dt><i>filename</i> (str)</dt> +<dd> +current text of the file picker +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- a/eric7/Documentation/Source/eric7.DebugClients.Python.DCTestResult.html Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,259 +0,0 @@ -<!DOCTYPE html> -<html><head> -<title>eric7.DebugClients.Python.DCTestResult</title> -<meta charset="UTF-8"> -<link rel="stylesheet" href="styles.css"> -</head> -<body> -<a NAME="top" ID="top"></a> -<h1>eric7.DebugClients.Python.DCTestResult</h1> - -<p> -Module implementing a TestResult derivative for the eric debugger. -</p> -<h3>Global Attributes</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Classes</h3> - -<table> - -<tr> -<td><a href="#DCTestResult">DCTestResult</a></td> -<td>A TestResult derivative to work with eric's debug client.</td> -</tr> -</table> -<h3>Functions</h3> - -<table> -<tr><td>None</td></tr> -</table> -<hr /> -<hr /> -<a NAME="DCTestResult" ID="DCTestResult"></a> -<h2>DCTestResult</h2> - -<p> - A TestResult derivative to work with eric's debug client. -</p> -<p> - For more details see unittest.py of the standard python distribution. -</p> -<h3>Derived from</h3> -TestResult -<h3>Class Attributes</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Class Methods</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Methods</h3> - -<table> - -<tr> -<td><a href="#DCTestResult.__init__">DCTestResult</a></td> -<td>Constructor</td> -</tr> -<tr> -<td><a href="#DCTestResult.addError">addError</a></td> -<td>Public method called if a test errored.</td> -</tr> -<tr> -<td><a href="#DCTestResult.addExpectedFailure">addExpectedFailure</a></td> -<td>Public method called if a test failed expected.</td> -</tr> -<tr> -<td><a href="#DCTestResult.addFailure">addFailure</a></td> -<td>Public method called if a test failed.</td> -</tr> -<tr> -<td><a href="#DCTestResult.addSkip">addSkip</a></td> -<td>Public method called if a test was skipped.</td> -</tr> -<tr> -<td><a href="#DCTestResult.addSubTest">addSubTest</a></td> -<td>Public method called for each subtest to record its result.</td> -</tr> -<tr> -<td><a href="#DCTestResult.addUnexpectedSuccess">addUnexpectedSuccess</a></td> -<td>Public method called if a test succeeded expectedly.</td> -</tr> -<tr> -<td><a href="#DCTestResult.startTest">startTest</a></td> -<td>Public method called at the start of a test.</td> -</tr> -<tr> -<td><a href="#DCTestResult.stopTest">stopTest</a></td> -<td>Public method called at the end of a test.</td> -</tr> -</table> -<h3>Static Methods</h3> - -<table> -<tr><td>None</td></tr> -</table> - -<a NAME="DCTestResult.__init__" ID="DCTestResult.__init__"></a> -<h4>DCTestResult (Constructor)</h4> -<b>DCTestResult</b>(<i>dbgClient, failfast</i>) - -<p> - Constructor -</p> -<dl> - -<dt><i>dbgClient</i> (DebugClientBase)</dt> -<dd> -reference to the debug client -</dd> -<dt><i>failfast</i> (bool)</dt> -<dd> -flag indicating to stop at the first error -</dd> -</dl> -<a NAME="DCTestResult.addError" ID="DCTestResult.addError"></a> -<h4>DCTestResult.addError</h4> -<b>addError</b>(<i>test, err</i>) - -<p> - Public method called if a test errored. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -Reference to the test object -</dd> -<dt><i>err</i></dt> -<dd> -The error traceback -</dd> -</dl> -<a NAME="DCTestResult.addExpectedFailure" ID="DCTestResult.addExpectedFailure"></a> -<h4>DCTestResult.addExpectedFailure</h4> -<b>addExpectedFailure</b>(<i>test, err</i>) - -<p> - Public method called if a test failed expected. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -<dt><i>err</i></dt> -<dd> -error traceback -</dd> -</dl> -<a NAME="DCTestResult.addFailure" ID="DCTestResult.addFailure"></a> -<h4>DCTestResult.addFailure</h4> -<b>addFailure</b>(<i>test, err</i>) - -<p> - Public method called if a test failed. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -Reference to the test object -</dd> -<dt><i>err</i></dt> -<dd> -The error traceback -</dd> -</dl> -<a NAME="DCTestResult.addSkip" ID="DCTestResult.addSkip"></a> -<h4>DCTestResult.addSkip</h4> -<b>addSkip</b>(<i>test, reason</i>) - -<p> - Public method called if a test was skipped. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -<dt><i>reason</i></dt> -<dd> -reason for skipping the test (string) -</dd> -</dl> -<a NAME="DCTestResult.addSubTest" ID="DCTestResult.addSubTest"></a> -<h4>DCTestResult.addSubTest</h4> -<b>addSubTest</b>(<i>test, subtest, err</i>) - -<p> - Public method called for each subtest to record its result. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -<dt><i>subtest</i></dt> -<dd> -reference to the subtest object -</dd> -<dt><i>err</i></dt> -<dd> -error traceback -</dd> -</dl> -<a NAME="DCTestResult.addUnexpectedSuccess" ID="DCTestResult.addUnexpectedSuccess"></a> -<h4>DCTestResult.addUnexpectedSuccess</h4> -<b>addUnexpectedSuccess</b>(<i>test</i>) - -<p> - Public method called if a test succeeded expectedly. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -</dl> -<a NAME="DCTestResult.startTest" ID="DCTestResult.startTest"></a> -<h4>DCTestResult.startTest</h4> -<b>startTest</b>(<i>test</i>) - -<p> - Public method called at the start of a test. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -Reference to the test object -</dd> -</dl> -<a NAME="DCTestResult.stopTest" ID="DCTestResult.stopTest"></a> -<h4>DCTestResult.stopTest</h4> -<b>stopTest</b>(<i>test</i>) - -<p> - Public method called at the end of a test. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -Reference to the test object -</dd> -</dl> -<div align="right"><a href="#top">Up</a></div> -<hr /> -</body></html> \ No newline at end of file
--- a/eric7/Documentation/Source/eric7.DocumentationTools.TemplatesListsStyle.html Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -<!DOCTYPE html> -<html><head> -<title>eric7.DocumentationTools.TemplatesListsStyle</title> -<meta charset="UTF-8"> -<link rel="stylesheet" href="styles.css"> -</head> -<body> -<a NAME="top" ID="top"></a> -<h1>eric7.DocumentationTools.TemplatesListsStyle</h1> - -<p> -Module implementing templates for the documentation generator (lists style). -</p> -<h3>Global Attributes</h3> - -<table> -<tr><td>authorInfoTemplate</td></tr><tr><td>classTemplate</td></tr><tr><td>constructorTemplate</td></tr><tr><td>deprecatedTemplate</td></tr><tr><td>eventsListEntryTemplate</td></tr><tr><td>eventsListTemplate</td></tr><tr><td>exceptionsListEntryTemplate</td></tr><tr><td>exceptionsListTemplate</td></tr><tr><td>footerTemplate</td></tr><tr><td>functionTemplate</td></tr><tr><td>headerTemplate</td></tr><tr><td>indexBodyTemplate</td></tr><tr><td>indexListEntryTemplate</td></tr><tr><td>indexListModulesTemplate</td></tr><tr><td>indexListPackagesTemplate</td></tr><tr><td>listEntryDeprecatedTemplate</td></tr><tr><td>listEntryNoneTemplate</td></tr><tr><td>listEntrySimpleTemplate</td></tr><tr><td>listEntryTemplate</td></tr><tr><td>listTemplate</td></tr><tr><td>methodTemplate</td></tr><tr><td>moduleTemplate</td></tr><tr><td>paragraphTemplate</td></tr><tr><td>parameterTypesListEntryTemplate</td></tr><tr><td>parametersListEntryTemplate</td></tr><tr><td>parametersListTemplate</td></tr><tr><td>rbFileTemplate</td></tr><tr><td>rbModuleTemplate</td></tr><tr><td>rbModulesClassTemplate</td></tr><tr><td>returnTypesTemplate</td></tr><tr><td>returnsTemplate</td></tr><tr><td>seeLinkTemplate</td></tr><tr><td>seeListEntryTemplate</td></tr><tr><td>seeListTemplate</td></tr><tr><td>signalsListEntryTemplate</td></tr><tr><td>signalsListTemplate</td></tr><tr><td>sinceInfoTemplate</td></tr><tr><td>yieldTypesTemplate</td></tr><tr><td>yieldsTemplate</td></tr> -</table> -<h3>Classes</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Functions</h3> - -<table> -<tr><td>None</td></tr> -</table> -<hr /> -</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.EricNetwork.EricJsonStreamReader.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,183 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.EricNetwork.EricJsonStreamReader</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.EricNetwork.EricJsonStreamReader</h1> + +<p> +Module implementing a JSON based reader class. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#EricJsonReader">EricJsonReader</a></td> +<td>Class implementing a JSON based reader class.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="EricJsonReader" ID="EricJsonReader"></a> +<h2>EricJsonReader</h2> + +<p> + Class implementing a JSON based reader class. +</p> +<p> + The reader is responsible for opening a socket to listen for writer + connections. +</p> +<h3>Signals</h3> +<dl> + +<dt>dataReceived(object)</dt> +<dd> +emitted after a data object was received +</dd> +</dl> +<h3>Derived from</h3> +QTcpServer +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#EricJsonReader.__init__">EricJsonReader</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#EricJsonReader.__handleDisconnect">__handleDisconnect</a></td> +<td>Private slot handling a disconnect of the writer.</td> +</tr> +<tr> +<td><a href="#EricJsonReader.__receiveJson">__receiveJson</a></td> +<td>Private slot handling received data from the writer.</td> +</tr> +<tr> +<td><a href="#EricJsonReader.address">address</a></td> +<td>Public method to get the host address.</td> +</tr> +<tr> +<td><a href="#EricJsonReader.handleNewConnection">handleNewConnection</a></td> +<td>Public slot for new incoming connections from a writer.</td> +</tr> +<tr> +<td><a href="#EricJsonReader.port">port</a></td> +<td>Public method to get the port number to connect to.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="EricJsonReader.__init__" ID="EricJsonReader.__init__"></a> +<h4>EricJsonReader (Constructor)</h4> +<b>EricJsonReader</b>(<i>name="", ip=None, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>name</i> (str)</dt> +<dd> +name of the server (used for output only) +</dd> +<dt><i>ip</i> (str)</dt> +<dd> +IP address to listen at +</dd> +<dt><i>parent</i> (QObject)</dt> +<dd> +parent object +</dd> +</dl> +<a NAME="EricJsonReader.__handleDisconnect" ID="EricJsonReader.__handleDisconnect"></a> +<h4>EricJsonReader.__handleDisconnect</h4> +<b>__handleDisconnect</b>(<i></i>) + +<p> + Private slot handling a disconnect of the writer. +</p> +<a NAME="EricJsonReader.__receiveJson" ID="EricJsonReader.__receiveJson"></a> +<h4>EricJsonReader.__receiveJson</h4> +<b>__receiveJson</b>(<i></i>) + +<p> + Private slot handling received data from the writer. +</p> +<a NAME="EricJsonReader.address" ID="EricJsonReader.address"></a> +<h4>EricJsonReader.address</h4> +<b>address</b>(<i></i>) + +<p> + Public method to get the host address. +</p> +<dl> +<dt>Return:</dt> +<dd> +host address +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +str +</dd> +</dl> +<a NAME="EricJsonReader.handleNewConnection" ID="EricJsonReader.handleNewConnection"></a> +<h4>EricJsonReader.handleNewConnection</h4> +<b>handleNewConnection</b>(<i></i>) + +<p> + Public slot for new incoming connections from a writer. +</p> +<a NAME="EricJsonReader.port" ID="EricJsonReader.port"></a> +<h4>EricJsonReader.port</h4> +<b>port</b>(<i></i>) + +<p> + Public method to get the port number to connect to. +</p> +<dl> +<dt>Return:</dt> +<dd> +port number +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +int +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.EricNetwork.EricJsonStreamWriter.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,117 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.EricNetwork.EricJsonStreamWriter</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.EricNetwork.EricJsonStreamWriter</h1> + +<p> +Module implementing a JSON based writer class. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#EricJsonWriter">EricJsonWriter</a></td> +<td>Class implementing a JSON based writer class.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="EricJsonWriter" ID="EricJsonWriter"></a> +<h2>EricJsonWriter</h2> + +<p> + Class implementing a JSON based writer class. +</p> +<h3>Derived from</h3> +None +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#EricJsonWriter.__init__">EricJsonWriter</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#EricJsonWriter.close">close</a></td> +<td>Public method to close the stream.</td> +</tr> +<tr> +<td><a href="#EricJsonWriter.write">write</a></td> +<td>Public method to send JSON serializable data.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="EricJsonWriter.__init__" ID="EricJsonWriter.__init__"></a> +<h4>EricJsonWriter (Constructor)</h4> +<b>EricJsonWriter</b>(<i>host, port</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>host</i> (str)</dt> +<dd> +IP address the reader is listening on +</dd> +<dt><i>port</i> (int)</dt> +<dd> +port the reader is listening on +</dd> +</dl> +<a NAME="EricJsonWriter.close" ID="EricJsonWriter.close"></a> +<h4>EricJsonWriter.close</h4> +<b>close</b>(<i></i>) + +<p> + Public method to close the stream. +</p> +<a NAME="EricJsonWriter.write" ID="EricJsonWriter.write"></a> +<h4>EricJsonWriter.write</h4> +<b>write</b>(<i>data</i>) + +<p> + Public method to send JSON serializable data. +</p> +<dl> + +<dt><i>data</i> (object)</dt> +<dd> +JSON serializable object to be sent +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- a/eric7/Documentation/Source/eric7.PyUnit.UnittestDialog.html Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1236 +0,0 @@ -<!DOCTYPE html> -<html><head> -<title>eric7.PyUnit.UnittestDialog</title> -<meta charset="UTF-8"> -<link rel="stylesheet" href="styles.css"> -</head> -<body> -<a NAME="top" ID="top"></a> -<h1>eric7.PyUnit.UnittestDialog</h1> - -<p> -Module implementing the UI to the pyunit package. -</p> -<h3>Global Attributes</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Classes</h3> - -<table> - -<tr> -<td><a href="#QtTestResult">QtTestResult</a></td> -<td>A TestResult derivative to work with a graphical GUI.</td> -</tr> -<tr> -<td><a href="#UnittestDialog">UnittestDialog</a></td> -<td>Class implementing the UI to the pyunit package.</td> -</tr> -<tr> -<td><a href="#UnittestWindow">UnittestWindow</a></td> -<td>Main window class for the standalone dialog.</td> -</tr> -</table> -<h3>Functions</h3> - -<table> - -<tr> -<td><a href="#clearSavedHistories">clearSavedHistories</a></td> -<td>Function to clear the saved history lists.</td> -</tr> -</table> -<hr /> -<hr /> -<a NAME="QtTestResult" ID="QtTestResult"></a> -<h2>QtTestResult</h2> - -<p> - A TestResult derivative to work with a graphical GUI. -</p> -<p> - For more details see pyunit.py of the standard Python distribution. -</p> -<h3>Derived from</h3> -unittest.TestResult -<h3>Class Attributes</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Class Methods</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Methods</h3> - -<table> - -<tr> -<td><a href="#QtTestResult.__init__">QtTestResult</a></td> -<td>Constructor</td> -</tr> -<tr> -<td><a href="#QtTestResult.addError">addError</a></td> -<td>Public method called if a test errored.</td> -</tr> -<tr> -<td><a href="#QtTestResult.addExpectedFailure">addExpectedFailure</a></td> -<td>Public method called if a test failed expected.</td> -</tr> -<tr> -<td><a href="#QtTestResult.addFailure">addFailure</a></td> -<td>Public method called if a test failed.</td> -</tr> -<tr> -<td><a href="#QtTestResult.addSkip">addSkip</a></td> -<td>Public method called if a test was skipped.</td> -</tr> -<tr> -<td><a href="#QtTestResult.addSubTest">addSubTest</a></td> -<td>Public method called for each subtest to record its result.</td> -</tr> -<tr> -<td><a href="#QtTestResult.addUnexpectedSuccess">addUnexpectedSuccess</a></td> -<td>Public method called if a test succeeded expectedly.</td> -</tr> -<tr> -<td><a href="#QtTestResult.startTest">startTest</a></td> -<td>Public method called at the start of a test.</td> -</tr> -<tr> -<td><a href="#QtTestResult.stopTest">stopTest</a></td> -<td>Public method called at the end of a test.</td> -</tr> -</table> -<h3>Static Methods</h3> - -<table> -<tr><td>None</td></tr> -</table> - -<a NAME="QtTestResult.__init__" ID="QtTestResult.__init__"></a> -<h4>QtTestResult (Constructor)</h4> -<b>QtTestResult</b>(<i>parent, failfast</i>) - -<p> - Constructor -</p> -<dl> - -<dt><i>parent</i> (UnittestDialog)</dt> -<dd> -reference to the parent widget -</dd> -<dt><i>failfast</i> (bool)</dt> -<dd> -flag indicating to stop at the first error -</dd> -</dl> -<a NAME="QtTestResult.addError" ID="QtTestResult.addError"></a> -<h4>QtTestResult.addError</h4> -<b>addError</b>(<i>test, err</i>) - -<p> - Public method called if a test errored. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -<dt><i>err</i></dt> -<dd> -error traceback -</dd> -</dl> -<a NAME="QtTestResult.addExpectedFailure" ID="QtTestResult.addExpectedFailure"></a> -<h4>QtTestResult.addExpectedFailure</h4> -<b>addExpectedFailure</b>(<i>test, err</i>) - -<p> - Public method called if a test failed expected. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -<dt><i>err</i></dt> -<dd> -error traceback -</dd> -</dl> -<a NAME="QtTestResult.addFailure" ID="QtTestResult.addFailure"></a> -<h4>QtTestResult.addFailure</h4> -<b>addFailure</b>(<i>test, err</i>) - -<p> - Public method called if a test failed. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -<dt><i>err</i></dt> -<dd> -error traceback -</dd> -</dl> -<a NAME="QtTestResult.addSkip" ID="QtTestResult.addSkip"></a> -<h4>QtTestResult.addSkip</h4> -<b>addSkip</b>(<i>test, reason</i>) - -<p> - Public method called if a test was skipped. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -<dt><i>reason</i></dt> -<dd> -reason for skipping the test (string) -</dd> -</dl> -<a NAME="QtTestResult.addSubTest" ID="QtTestResult.addSubTest"></a> -<h4>QtTestResult.addSubTest</h4> -<b>addSubTest</b>(<i>test, subtest, err</i>) - -<p> - Public method called for each subtest to record its result. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -<dt><i>subtest</i></dt> -<dd> -reference to the subtest object -</dd> -<dt><i>err</i></dt> -<dd> -error traceback -</dd> -</dl> -<a NAME="QtTestResult.addUnexpectedSuccess" ID="QtTestResult.addUnexpectedSuccess"></a> -<h4>QtTestResult.addUnexpectedSuccess</h4> -<b>addUnexpectedSuccess</b>(<i>test</i>) - -<p> - Public method called if a test succeeded expectedly. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -reference to the test object -</dd> -</dl> -<a NAME="QtTestResult.startTest" ID="QtTestResult.startTest"></a> -<h4>QtTestResult.startTest</h4> -<b>startTest</b>(<i>test</i>) - -<p> - Public method called at the start of a test. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -Reference to the test object -</dd> -</dl> -<a NAME="QtTestResult.stopTest" ID="QtTestResult.stopTest"></a> -<h4>QtTestResult.stopTest</h4> -<b>stopTest</b>(<i>test</i>) - -<p> - Public method called at the end of a test. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -Reference to the test object -</dd> -</dl> -<div align="right"><a href="#top">Up</a></div> -<hr /> -<hr /> -<a NAME="UnittestDialog" ID="UnittestDialog"></a> -<h2>UnittestDialog</h2> - -<p> - Class implementing the UI to the pyunit package. -</p> -<h3>Signals</h3> -<dl> - -<dt>unittestFile(str, int, bool)</dt> -<dd> -emitted to show the source of a - unittest file -</dd> -<dt>unittestStopped()</dt> -<dd> -emitted after a unit test was run -</dd> -</dl> -<h3>Derived from</h3> -QWidget, Ui_UnittestDialog -<h3>Class Attributes</h3> - -<table> -<tr><td>ErrorsInfoRole</td></tr><tr><td>FailedExpectedColorDarkTheme</td></tr><tr><td>FailedExpectedColorLightTheme</td></tr><tr><td>SkippedColorDarkTheme</td></tr><tr><td>SkippedColorLightTheme</td></tr><tr><td>SucceededUnexpectedColorDarkTheme</td></tr><tr><td>SucceededUnexpectedColorLightTheme</td></tr><tr><td>TestCaseFileRole</td></tr><tr><td>TestCaseNameRole</td></tr> -</table> -<h3>Class Methods</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Methods</h3> - -<table> - -<tr> -<td><a href="#UnittestDialog.__init__">UnittestDialog</a></td> -<td>Constructor</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__UTDiscovered">__UTDiscovered</a></td> -<td>Private slot to handle the utDiscovered signal.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__UTPrepared">__UTPrepared</a></td> -<td>Private slot to handle the utPrepared signal.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__assembleTestCasesList">__assembleTestCasesList</a></td> -<td>Private method to assemble a list of test cases included in a test suite.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__discover">__discover</a></td> -<td>Private slot to discover unit test but don't run them.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__findDiscoveryItem">__findDiscoveryItem</a></td> -<td>Private method to find an item given the module path.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__loadRecent">__loadRecent</a></td> -<td>Private method to load the most recently used lists.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__openEditor">__openEditor</a></td> -<td>Private method to open an editor window for the given file.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__populateDiscoveryResults">__populateDiscoveryResults</a></td> -<td>Private method to populate the test discovery results list.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__populateVenvComboBox">__populateVenvComboBox</a></td> -<td>Private method to (re-)populate the virtual environments selector.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__saveRecent">__saveRecent</a></td> -<td>Private method to save the most recently used lists.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__selectedTestCases">__selectedTestCases</a></td> -<td>Private method to assemble the list of selected test cases and suites.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__setProgressColor">__setProgressColor</a></td> -<td>Private method to set the color of the progress color label.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__setRunningMode">__setRunningMode</a></td> -<td>Private method to set the GUI in running mode.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__setStoppedMode">__setStoppedMode</a></td> -<td>Private method to set the GUI in stopped mode.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__showSource">__showSource</a></td> -<td>Private slot to show the source of a traceback in an eric editor.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.__stopTests">__stopTests</a></td> -<td>Private slot to stop the test.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.clearRecent">clearRecent</a></td> -<td>Public slot to clear the recently used lists.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.closeEvent">closeEvent</a></td> -<td>Protected method to handle the close event.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.hasFailedTests">hasFailedTests</a></td> -<td>Public method to check, if there are failed tests from the last run.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.insertDiscovery">insertDiscovery</a></td> -<td>Public slot to insert the discovery start directory into the discoveryPicker object.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.insertProg">insertProg</a></td> -<td>Public slot to insert the filename prog into the testsuitePicker object.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.insertTestName">insertTestName</a></td> -<td>Public slot to insert a test name into the testComboBox object.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.keyPressEvent">keyPressEvent</a></td> -<td>Protected slot to handle key press events.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.on_buttonBox_clicked">on_buttonBox_clicked</a></td> -<td>Private slot called by a button of the button box clicked.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.on_discoverCheckBox_toggled">on_discoverCheckBox_toggled</a></td> -<td>Private slot handling state changes of the 'discover' checkbox.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.on_discoveryList_itemChanged">on_discoveryList_itemChanged</a></td> -<td>Private slot handling the user checking or unchecking an item.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.on_discoveryList_itemDoubleClicked">on_discoveryList_itemDoubleClicked</a></td> -<td>Private slot handling the user double clicking an item.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.on_errorsListWidget_currentTextChanged">on_errorsListWidget_currentTextChanged</a></td> -<td>Private slot to handle the highlighted signal.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.on_errorsListWidget_itemDoubleClicked">on_errorsListWidget_itemDoubleClicked</a></td> -<td>Private slot called by doubleclicking an errorlist entry.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.on_testsuitePicker_aboutToShowPathPickerDialog">on_testsuitePicker_aboutToShowPathPickerDialog</a></td> -<td>Private slot called before the test suite selection dialog is shown.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.on_testsuitePicker_editTextChanged">on_testsuitePicker_editTextChanged</a></td> -<td>Private slot handling changes of the test suite path.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.on_testsuitePicker_pathSelected">on_testsuitePicker_pathSelected</a></td> -<td>Private slot called after a test suite has been selected.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.setProjectMode">setProjectMode</a></td> -<td>Public method to set the project mode of the dialog.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.startTests">startTests</a></td> -<td>Public slot to start the test.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.testErrored">testErrored</a></td> -<td>Public method called if a test errors.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.testFailed">testFailed</a></td> -<td>Public method called if a test fails.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.testFailedExpected">testFailedExpected</a></td> -<td>Public method called if a test fails as expected.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.testFinished">testFinished</a></td> -<td>Public method called if a test has finished.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.testSkipped">testSkipped</a></td> -<td>Public method called if a test was skipped.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.testStarted">testStarted</a></td> -<td>Public method called if a test is about to be run.</td> -</tr> -<tr> -<td><a href="#UnittestDialog.testSucceededUnexpected">testSucceededUnexpected</a></td> -<td>Public method called if a test succeeds unexpectedly.</td> -</tr> -</table> -<h3>Static Methods</h3> - -<table> -<tr><td>None</td></tr> -</table> - -<a NAME="UnittestDialog.__init__" ID="UnittestDialog.__init__"></a> -<h4>UnittestDialog (Constructor)</h4> -<b>UnittestDialog</b>(<i>prog=None, dbs=None, ui=None, parent=None, name=None</i>) - -<p> - Constructor -</p> -<dl> - -<dt><i>prog</i> (str)</dt> -<dd> -filename of the program to open -</dd> -<dt><i>dbs</i> (DebugServer)</dt> -<dd> -reference to the debug server object. It is an indication - whether we were called from within the eric IDE. -</dd> -<dt><i>ui</i> (UserInterface)</dt> -<dd> -reference to the UI object -</dd> -<dt><i>parent</i> (QWidget)</dt> -<dd> -parent widget of this dialog -</dd> -<dt><i>name</i> (str)</dt> -<dd> -name of this dialog -</dd> -</dl> -<a NAME="UnittestDialog.__UTDiscovered" ID="UnittestDialog.__UTDiscovered"></a> -<h4>UnittestDialog.__UTDiscovered</h4> -<b>__UTDiscovered</b>(<i>testCases, exc_type, exc_value</i>) - -<p> - Private slot to handle the utDiscovered signal. -</p> -<p> - If the unittest suite was loaded successfully, we ask the - client to run the test suite. -</p> -<dl> - -<dt><i>testCases</i> (str)</dt> -<dd> -list of detected test cases -</dd> -<dt><i>exc_type</i> (str)</dt> -<dd> -exception type occured during discovery -</dd> -<dt><i>exc_value</i> (str)</dt> -<dd> -value of exception occured during discovery -</dd> -</dl> -<a NAME="UnittestDialog.__UTPrepared" ID="UnittestDialog.__UTPrepared"></a> -<h4>UnittestDialog.__UTPrepared</h4> -<b>__UTPrepared</b>(<i>nrTests, exc_type, exc_value</i>) - -<p> - Private slot to handle the utPrepared signal. -</p> -<p> - If the unittest suite was loaded successfully, we ask the - client to run the test suite. -</p> -<dl> - -<dt><i>nrTests</i></dt> -<dd> -number of tests contained in the test suite (integer) -</dd> -<dt><i>exc_type</i></dt> -<dd> -type of exception occured during preparation (string) -</dd> -<dt><i>exc_value</i></dt> -<dd> -value of exception occured during preparation (string) -</dd> -</dl> -<a NAME="UnittestDialog.__assembleTestCasesList" ID="UnittestDialog.__assembleTestCasesList"></a> -<h4>UnittestDialog.__assembleTestCasesList</h4> -<b>__assembleTestCasesList</b>(<i>suite, start</i>) - -<p> - Private method to assemble a list of test cases included in a test - suite. -</p> -<dl> - -<dt><i>suite</i> (unittest.TestSuite)</dt> -<dd> -test suite to be inspected -</dd> -<dt><i>start</i> (str)</dt> -<dd> -name of directory discovery was started at -</dd> -</dl> -<dl> -<dt>Return:</dt> -<dd> -list of tuples containing the test case ID, a short description - and the path of the test file name -</dd> -</dl> -<dl> -<dt>Return Type:</dt> -<dd> -list of tuples of (str, str, str) -</dd> -</dl> -<a NAME="UnittestDialog.__discover" ID="UnittestDialog.__discover"></a> -<h4>UnittestDialog.__discover</h4> -<b>__discover</b>(<i></i>) - -<p> - Private slot to discover unit test but don't run them. -</p> -<a NAME="UnittestDialog.__findDiscoveryItem" ID="UnittestDialog.__findDiscoveryItem"></a> -<h4>UnittestDialog.__findDiscoveryItem</h4> -<b>__findDiscoveryItem</b>(<i>modulePath</i>) - -<p> - Private method to find an item given the module path. -</p> -<dl> - -<dt><i>modulePath</i> (str)</dt> -<dd> -path of the module in dotted notation -</dd> -</dl> -<dl> -<dt>Return:</dt> -<dd> -reference to the item or None -</dd> -</dl> -<dl> -<dt>Return Type:</dt> -<dd> -QTreeWidgetItem or None -</dd> -</dl> -<a NAME="UnittestDialog.__loadRecent" ID="UnittestDialog.__loadRecent"></a> -<h4>UnittestDialog.__loadRecent</h4> -<b>__loadRecent</b>(<i></i>) - -<p> - Private method to load the most recently used lists. -</p> -<a NAME="UnittestDialog.__openEditor" ID="UnittestDialog.__openEditor"></a> -<h4>UnittestDialog.__openEditor</h4> -<b>__openEditor</b>(<i>filename, linenumber</i>) - -<p> - Private method to open an editor window for the given file. -</p> -<p> - Note: This method opens an editor window when the unittest dialog - is called as a standalone application. -</p> -<dl> - -<dt><i>filename</i> (str)</dt> -<dd> -path of the file to be opened -</dd> -<dt><i>linenumber</i> (int)</dt> -<dd> -line number to place the cursor at -</dd> -</dl> -<a NAME="UnittestDialog.__populateDiscoveryResults" ID="UnittestDialog.__populateDiscoveryResults"></a> -<h4>UnittestDialog.__populateDiscoveryResults</h4> -<b>__populateDiscoveryResults</b>(<i>tests</i>) - -<p> - Private method to populate the test discovery results list. -</p> -<dl> - -<dt><i>tests</i> (list of tuples of (str, str, str))</dt> -<dd> -list of tuples containing the discovery results -</dd> -</dl> -<a NAME="UnittestDialog.__populateVenvComboBox" ID="UnittestDialog.__populateVenvComboBox"></a> -<h4>UnittestDialog.__populateVenvComboBox</h4> -<b>__populateVenvComboBox</b>(<i></i>) - -<p> - Private method to (re-)populate the virtual environments selector. -</p> -<a NAME="UnittestDialog.__saveRecent" ID="UnittestDialog.__saveRecent"></a> -<h4>UnittestDialog.__saveRecent</h4> -<b>__saveRecent</b>(<i></i>) - -<p> - Private method to save the most recently used lists. -</p> -<a NAME="UnittestDialog.__selectedTestCases" ID="UnittestDialog.__selectedTestCases"></a> -<h4>UnittestDialog.__selectedTestCases</h4> -<b>__selectedTestCases</b>(<i>parent=None</i>) - -<p> - Private method to assemble the list of selected test cases and suites. -</p> -<dl> - -<dt><i>parent</i> (QTreeWidgetItem)</dt> -<dd> -reference to the parent item -</dd> -</dl> -<dl> -<dt>Return:</dt> -<dd> -list of selected test cases -</dd> -</dl> -<dl> -<dt>Return Type:</dt> -<dd> -list of str -</dd> -</dl> -<a NAME="UnittestDialog.__setProgressColor" ID="UnittestDialog.__setProgressColor"></a> -<h4>UnittestDialog.__setProgressColor</h4> -<b>__setProgressColor</b>(<i>color</i>) - -<p> - Private method to set the color of the progress color label. -</p> -<dl> - -<dt><i>color</i></dt> -<dd> -colour to be shown (string) -</dd> -</dl> -<a NAME="UnittestDialog.__setRunningMode" ID="UnittestDialog.__setRunningMode"></a> -<h4>UnittestDialog.__setRunningMode</h4> -<b>__setRunningMode</b>(<i></i>) - -<p> - Private method to set the GUI in running mode. -</p> -<a NAME="UnittestDialog.__setStoppedMode" ID="UnittestDialog.__setStoppedMode"></a> -<h4>UnittestDialog.__setStoppedMode</h4> -<b>__setStoppedMode</b>(<i></i>) - -<p> - Private method to set the GUI in stopped mode. -</p> -<a NAME="UnittestDialog.__showSource" ID="UnittestDialog.__showSource"></a> -<h4>UnittestDialog.__showSource</h4> -<b>__showSource</b>(<i></i>) - -<p> - Private slot to show the source of a traceback in an eric editor. -</p> -<a NAME="UnittestDialog.__stopTests" ID="UnittestDialog.__stopTests"></a> -<h4>UnittestDialog.__stopTests</h4> -<b>__stopTests</b>(<i></i>) - -<p> - Private slot to stop the test. -</p> -<a NAME="UnittestDialog.clearRecent" ID="UnittestDialog.clearRecent"></a> -<h4>UnittestDialog.clearRecent</h4> -<b>clearRecent</b>(<i></i>) - -<p> - Public slot to clear the recently used lists. -</p> -<a NAME="UnittestDialog.closeEvent" ID="UnittestDialog.closeEvent"></a> -<h4>UnittestDialog.closeEvent</h4> -<b>closeEvent</b>(<i>event</i>) - -<p> - Protected method to handle the close event. -</p> -<dl> - -<dt><i>event</i> (QCloseEvent)</dt> -<dd> -close event -</dd> -</dl> -<a NAME="UnittestDialog.hasFailedTests" ID="UnittestDialog.hasFailedTests"></a> -<h4>UnittestDialog.hasFailedTests</h4> -<b>hasFailedTests</b>(<i></i>) - -<p> - Public method to check, if there are failed tests from the last run. -</p> -<dl> -<dt>Return:</dt> -<dd> -flag indicating the presence of failed tests (boolean) -</dd> -</dl> -<a NAME="UnittestDialog.insertDiscovery" ID="UnittestDialog.insertDiscovery"></a> -<h4>UnittestDialog.insertDiscovery</h4> -<b>insertDiscovery</b>(<i>start</i>) - -<p> - Public slot to insert the discovery start directory into the - discoveryPicker object. -</p> -<dl> - -<dt><i>start</i> (str)</dt> -<dd> -start directory name to be inserted -</dd> -</dl> -<a NAME="UnittestDialog.insertProg" ID="UnittestDialog.insertProg"></a> -<h4>UnittestDialog.insertProg</h4> -<b>insertProg</b>(<i>prog</i>) - -<p> - Public slot to insert the filename prog into the testsuitePicker - object. -</p> -<dl> - -<dt><i>prog</i></dt> -<dd> -filename to be inserted (string) -</dd> -</dl> -<a NAME="UnittestDialog.insertTestName" ID="UnittestDialog.insertTestName"></a> -<h4>UnittestDialog.insertTestName</h4> -<b>insertTestName</b>(<i>testName</i>) - -<p> - Public slot to insert a test name into the testComboBox object. -</p> -<dl> - -<dt><i>testName</i></dt> -<dd> -name of the test to be inserted (string) -</dd> -</dl> -<a NAME="UnittestDialog.keyPressEvent" ID="UnittestDialog.keyPressEvent"></a> -<h4>UnittestDialog.keyPressEvent</h4> -<b>keyPressEvent</b>(<i>evt</i>) - -<p> - Protected slot to handle key press events. -</p> -<dl> - -<dt><i>evt</i></dt> -<dd> -key press event to handle (QKeyEvent) -</dd> -</dl> -<a NAME="UnittestDialog.on_buttonBox_clicked" ID="UnittestDialog.on_buttonBox_clicked"></a> -<h4>UnittestDialog.on_buttonBox_clicked</h4> -<b>on_buttonBox_clicked</b>(<i>button</i>) - -<p> - Private slot called by a button of the button box clicked. -</p> -<dl> - -<dt><i>button</i></dt> -<dd> -button that was clicked (QAbstractButton) -</dd> -</dl> -<a NAME="UnittestDialog.on_discoverCheckBox_toggled" ID="UnittestDialog.on_discoverCheckBox_toggled"></a> -<h4>UnittestDialog.on_discoverCheckBox_toggled</h4> -<b>on_discoverCheckBox_toggled</b>(<i>checked</i>) - -<p> - Private slot handling state changes of the 'discover' checkbox. -</p> -<dl> - -<dt><i>checked</i> (bool)</dt> -<dd> -state of the checkbox -</dd> -</dl> -<a NAME="UnittestDialog.on_discoveryList_itemChanged" ID="UnittestDialog.on_discoveryList_itemChanged"></a> -<h4>UnittestDialog.on_discoveryList_itemChanged</h4> -<b>on_discoveryList_itemChanged</b>(<i>item, column</i>) - -<p> - Private slot handling the user checking or unchecking an item. -</p> -<dl> - -<dt><i>item</i> (QTreeWidgetItem)</dt> -<dd> -reference to the item -</dd> -<dt><i>column</i> (int)</dt> -<dd> -changed column -</dd> -</dl> -<a NAME="UnittestDialog.on_discoveryList_itemDoubleClicked" ID="UnittestDialog.on_discoveryList_itemDoubleClicked"></a> -<h4>UnittestDialog.on_discoveryList_itemDoubleClicked</h4> -<b>on_discoveryList_itemDoubleClicked</b>(<i>item, column</i>) - -<p> - Private slot handling the user double clicking an item. -</p> -<dl> - -<dt><i>item</i> (QTreeWidgetItem)</dt> -<dd> -reference to the item -</dd> -<dt><i>column</i> (int)</dt> -<dd> -column of the double click -</dd> -</dl> -<a NAME="UnittestDialog.on_errorsListWidget_currentTextChanged" ID="UnittestDialog.on_errorsListWidget_currentTextChanged"></a> -<h4>UnittestDialog.on_errorsListWidget_currentTextChanged</h4> -<b>on_errorsListWidget_currentTextChanged</b>(<i>text</i>) - -<p> - Private slot to handle the highlighted signal. -</p> -<dl> - -<dt><i>text</i></dt> -<dd> -current text (string) -</dd> -</dl> -<a NAME="UnittestDialog.on_errorsListWidget_itemDoubleClicked" ID="UnittestDialog.on_errorsListWidget_itemDoubleClicked"></a> -<h4>UnittestDialog.on_errorsListWidget_itemDoubleClicked</h4> -<b>on_errorsListWidget_itemDoubleClicked</b>(<i>lbitem</i>) - -<p> - Private slot called by doubleclicking an errorlist entry. -</p> -<p> - It will popup a dialog showing the stacktrace. - If called from eric, an additional button is displayed - to show the python source in an eric source viewer (in - erics main window. -</p> -<dl> - -<dt><i>lbitem</i></dt> -<dd> -the listbox item that was double clicked -</dd> -</dl> -<a NAME="UnittestDialog.on_testsuitePicker_aboutToShowPathPickerDialog" ID="UnittestDialog.on_testsuitePicker_aboutToShowPathPickerDialog"></a> -<h4>UnittestDialog.on_testsuitePicker_aboutToShowPathPickerDialog</h4> -<b>on_testsuitePicker_aboutToShowPathPickerDialog</b>(<i></i>) - -<p> - Private slot called before the test suite selection dialog is shown. -</p> -<a NAME="UnittestDialog.on_testsuitePicker_editTextChanged" ID="UnittestDialog.on_testsuitePicker_editTextChanged"></a> -<h4>UnittestDialog.on_testsuitePicker_editTextChanged</h4> -<b>on_testsuitePicker_editTextChanged</b>(<i>path</i>) - -<p> - Private slot handling changes of the test suite path. -</p> -<dl> - -<dt><i>path</i> (str)</dt> -<dd> -path of the test suite file -</dd> -</dl> -<a NAME="UnittestDialog.on_testsuitePicker_pathSelected" ID="UnittestDialog.on_testsuitePicker_pathSelected"></a> -<h4>UnittestDialog.on_testsuitePicker_pathSelected</h4> -<b>on_testsuitePicker_pathSelected</b>(<i>suite</i>) - -<p> - Private slot called after a test suite has been selected. -</p> -<dl> - -<dt><i>suite</i> (str)</dt> -<dd> -file name of the test suite -</dd> -</dl> -<a NAME="UnittestDialog.setProjectMode" ID="UnittestDialog.setProjectMode"></a> -<h4>UnittestDialog.setProjectMode</h4> -<b>setProjectMode</b>(<i>forProject</i>) - -<p> - Public method to set the project mode of the dialog. -</p> -<dl> - -<dt><i>forProject</i> (bool)</dt> -<dd> -flag indicating to run for the open project -</dd> -</dl> -<a NAME="UnittestDialog.startTests" ID="UnittestDialog.startTests"></a> -<h4>UnittestDialog.startTests</h4> -<b>startTests</b>(<i>failedOnly=False</i>) - -<p> - Public slot to start the test. -</p> -<dl> - -<dt><i>failedOnly</i></dt> -<dd> -flag indicating to run only failed tests (boolean) -</dd> -</dl> -<a NAME="UnittestDialog.testErrored" ID="UnittestDialog.testErrored"></a> -<h4>UnittestDialog.testErrored</h4> -<b>testErrored</b>(<i>test, exc, testId</i>) - -<p> - Public method called if a test errors. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -name of the test (string) -</dd> -<dt><i>exc</i></dt> -<dd> -string representation of the exception (string) -</dd> -<dt><i>testId</i></dt> -<dd> -id of the test (string) -</dd> -</dl> -<a NAME="UnittestDialog.testFailed" ID="UnittestDialog.testFailed"></a> -<h4>UnittestDialog.testFailed</h4> -<b>testFailed</b>(<i>test, exc, testId</i>) - -<p> - Public method called if a test fails. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -name of the test (string) -</dd> -<dt><i>exc</i></dt> -<dd> -string representation of the exception (string) -</dd> -<dt><i>testId</i></dt> -<dd> -id of the test (string) -</dd> -</dl> -<a NAME="UnittestDialog.testFailedExpected" ID="UnittestDialog.testFailedExpected"></a> -<h4>UnittestDialog.testFailedExpected</h4> -<b>testFailedExpected</b>(<i>test, exc, testId</i>) - -<p> - Public method called if a test fails as expected. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -name of the test (string) -</dd> -<dt><i>exc</i></dt> -<dd> -string representation of the exception (string) -</dd> -<dt><i>testId</i></dt> -<dd> -id of the test (string) -</dd> -</dl> -<a NAME="UnittestDialog.testFinished" ID="UnittestDialog.testFinished"></a> -<h4>UnittestDialog.testFinished</h4> -<b>testFinished</b>(<i></i>) - -<p> - Public method called if a test has finished. -</p> -<p> - <b>Note</b>: It is also called if it has already failed or errored. -</p> -<a NAME="UnittestDialog.testSkipped" ID="UnittestDialog.testSkipped"></a> -<h4>UnittestDialog.testSkipped</h4> -<b>testSkipped</b>(<i>test, reason, testId</i>) - -<p> - Public method called if a test was skipped. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -name of the test (string) -</dd> -<dt><i>reason</i></dt> -<dd> -reason for skipping the test (string) -</dd> -<dt><i>testId</i></dt> -<dd> -id of the test (string) -</dd> -</dl> -<a NAME="UnittestDialog.testStarted" ID="UnittestDialog.testStarted"></a> -<h4>UnittestDialog.testStarted</h4> -<b>testStarted</b>(<i>test, doc</i>) - -<p> - Public method called if a test is about to be run. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -name of the started test (string) -</dd> -<dt><i>doc</i></dt> -<dd> -documentation of the started test (string) -</dd> -</dl> -<a NAME="UnittestDialog.testSucceededUnexpected" ID="UnittestDialog.testSucceededUnexpected"></a> -<h4>UnittestDialog.testSucceededUnexpected</h4> -<b>testSucceededUnexpected</b>(<i>test, testId</i>) - -<p> - Public method called if a test succeeds unexpectedly. -</p> -<dl> - -<dt><i>test</i></dt> -<dd> -name of the test (string) -</dd> -<dt><i>testId</i></dt> -<dd> -id of the test (string) -</dd> -</dl> -<div align="right"><a href="#top">Up</a></div> -<hr /> -<hr /> -<a NAME="UnittestWindow" ID="UnittestWindow"></a> -<h2>UnittestWindow</h2> - -<p> - Main window class for the standalone dialog. -</p> -<h3>Derived from</h3> -EricMainWindow -<h3>Class Attributes</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Class Methods</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Methods</h3> - -<table> - -<tr> -<td><a href="#UnittestWindow.__init__">UnittestWindow</a></td> -<td>Constructor</td> -</tr> -<tr> -<td><a href="#UnittestWindow.eventFilter">eventFilter</a></td> -<td>Public method to filter events.</td> -</tr> -</table> -<h3>Static Methods</h3> - -<table> -<tr><td>None</td></tr> -</table> - -<a NAME="UnittestWindow.__init__" ID="UnittestWindow.__init__"></a> -<h4>UnittestWindow (Constructor)</h4> -<b>UnittestWindow</b>(<i>prog=None, parent=None</i>) - -<p> - Constructor -</p> -<dl> - -<dt><i>prog</i></dt> -<dd> -filename of the program to open -</dd> -<dt><i>parent</i></dt> -<dd> -reference to the parent widget (QWidget) -</dd> -</dl> -<a NAME="UnittestWindow.eventFilter" ID="UnittestWindow.eventFilter"></a> -<h4>UnittestWindow.eventFilter</h4> -<b>eventFilter</b>(<i>obj, event</i>) - -<p> - Public method to filter events. -</p> -<dl> - -<dt><i>obj</i></dt> -<dd> -reference to the object the event is meant for (QObject) -</dd> -<dt><i>event</i></dt> -<dd> -reference to the event object (QEvent) -</dd> -</dl> -<dl> -<dt>Return:</dt> -<dd> -flag indicating, whether the event was handled (boolean) -</dd> -</dl> -<div align="right"><a href="#top">Up</a></div> -<hr /> -<hr /> -<a NAME="clearSavedHistories" ID="clearSavedHistories"></a> -<h2>clearSavedHistories</h2> -<b>clearSavedHistories</b>(<i>self</i>) - -<p> - Function to clear the saved history lists. -</p> -<div align="right"><a href="#top">Up</a></div> -<hr /> -</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.Testing.Interfaces.PytestExecutor.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,297 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.Interfaces.PytestExecutor</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.Testing.Interfaces.PytestExecutor</h1> + +<p> +Module implementing the executor for the 'pytest' framework. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#PytestExecutor">PytestExecutor</a></td> +<td>Class implementing the executor for the 'pytest' framework.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="PytestExecutor" ID="PytestExecutor"></a> +<h2>PytestExecutor</h2> + +<p> + Class implementing the executor for the 'pytest' framework. +</p> +<h3>Derived from</h3> +TestExecutorBase +<h3>Class Attributes</h3> + +<table> +<tr><td>module</td></tr><tr><td>name</td></tr><tr><td>runner</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#PytestExecutor.__init__">PytestExecutor</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#PytestExecutor.__nodeid2testname">__nodeid2testname</a></td> +<td>Private method to convert a nodeid to a test name.</td> +</tr> +<tr> +<td><a href="#PytestExecutor.__normalizeModuleName">__normalizeModuleName</a></td> +<td>Private method to convert a module name reported by pytest to Python conventions.</td> +</tr> +<tr> +<td><a href="#PytestExecutor.__processData">__processData</a></td> +<td>Private slot to process the received data.</td> +</tr> +<tr> +<td><a href="#PytestExecutor.createArguments">createArguments</a></td> +<td>Public method to create the arguments needed to start the test process.</td> +</tr> +<tr> +<td><a href="#PytestExecutor.finished">finished</a></td> +<td>Public method handling the unit test process been finished.</td> +</tr> +<tr> +<td><a href="#PytestExecutor.getVersions">getVersions</a></td> +<td>Public method to get the test framework version and version information of its installed plugins.</td> +</tr> +<tr> +<td><a href="#PytestExecutor.hasCoverage">hasCoverage</a></td> +<td>Public method to get the test framework version and version information of its installed plugins.</td> +</tr> +<tr> +<td><a href="#PytestExecutor.start">start</a></td> +<td>Public method to start the testing process.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="PytestExecutor.__init__" ID="PytestExecutor.__init__"></a> +<h4>PytestExecutor (Constructor)</h4> +<b>PytestExecutor</b>(<i>testWidget</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>testWidget</i> (TestingWidget)</dt> +<dd> +reference to the unit test widget +</dd> +</dl> +<a NAME="PytestExecutor.__nodeid2testname" ID="PytestExecutor.__nodeid2testname"></a> +<h4>PytestExecutor.__nodeid2testname</h4> +<b>__nodeid2testname</b>(<i>nodeid</i>) + +<p> + Private method to convert a nodeid to a test name. +</p> +<dl> + +<dt><i>nodeid</i> (str)</dt> +<dd> +nodeid to be converted +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +test name +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +str +</dd> +</dl> +<a NAME="PytestExecutor.__normalizeModuleName" ID="PytestExecutor.__normalizeModuleName"></a> +<h4>PytestExecutor.__normalizeModuleName</h4> +<b>__normalizeModuleName</b>(<i>name</i>) + +<p> + Private method to convert a module name reported by pytest to Python + conventions. +</p> +<p> + This method strips the extensions '.pyw' and '.py' first and replaces + '/' and '\' thereafter. +</p> +<dl> + +<dt><i>name</i> (str)</dt> +<dd> +module name reported by pytest +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +module name iaw. Python conventions +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +str +</dd> +</dl> +<a NAME="PytestExecutor.__processData" ID="PytestExecutor.__processData"></a> +<h4>PytestExecutor.__processData</h4> +<b>__processData</b>(<i>data</i>) + +<p> + Private slot to process the received data. +</p> +<dl> + +<dt><i>data</i> (dict)</dt> +<dd> +data object received +</dd> +</dl> +<a NAME="PytestExecutor.createArguments" ID="PytestExecutor.createArguments"></a> +<h4>PytestExecutor.createArguments</h4> +<b>createArguments</b>(<i>config</i>) + +<p> + Public method to create the arguments needed to start the test process. +</p> +<dl> + +<dt><i>config</i> (TestConfig)</dt> +<dd> +configuration for the test execution +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +list of process arguments +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of str +</dd> +</dl> +<a NAME="PytestExecutor.finished" ID="PytestExecutor.finished"></a> +<h4>PytestExecutor.finished</h4> +<b>finished</b>(<i></i>) + +<p> + Public method handling the unit test process been finished. +</p> +<p> + This method should read the results (if necessary) and emit the signal + testFinished. +</p> +<a NAME="PytestExecutor.getVersions" ID="PytestExecutor.getVersions"></a> +<h4>PytestExecutor.getVersions</h4> +<b>getVersions</b>(<i>interpreter</i>) + +<p> + Public method to get the test framework version and version information + of its installed plugins. +</p> +<dl> + +<dt><i>interpreter</i> (str)</dt> +<dd> +interpreter to be used for the test +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +dictionary containing the framework name and version and the + list of available plugins with name and version each +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +dict +</dd> +</dl> +<a NAME="PytestExecutor.hasCoverage" ID="PytestExecutor.hasCoverage"></a> +<h4>PytestExecutor.hasCoverage</h4> +<b>hasCoverage</b>(<i>interpreter</i>) + +<p> + Public method to get the test framework version and version information + of its installed plugins. +</p> +<dl> + +<dt><i>interpreter</i> (str)</dt> +<dd> +interpreter to be used for the test +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +flag indicating the availability of coverage functionality +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> +<a NAME="PytestExecutor.start" ID="PytestExecutor.start"></a> +<h4>PytestExecutor.start</h4> +<b>start</b>(<i>config, pythonpath</i>) + +<p> + Public method to start the testing process. +</p> +<dl> + +<dt><i>config</i> (TestConfig)</dt> +<dd> +configuration for the test execution +</dd> +<dt><i>pythonpath</i> (list of str)</dt> +<dd> +list of directories to be added to the Python path +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.Testing.Interfaces.PytestRunner.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,364 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.Interfaces.PytestRunner</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.Testing.Interfaces.PytestRunner</h1> + +<p> +Module implementing the test runner script for the 'pytest' framework. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#EricPlugin">EricPlugin</a></td> +<td>Class implementing a pytest plugin which reports the data in a format suitable for the PytestExecutor.</td> +</tr> +<tr> +<td><a href="#GetPluginVersionsPlugin">GetPluginVersionsPlugin</a></td> +<td>Class implementing a pytest plugin to extract the version info of all installed plugins.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> + +<tr> +<td><a href="#getVersions">getVersions</a></td> +<td>Function to determine the framework version and versions of all available plugins.</td> +</tr> +</table> +<hr /> +<hr /> +<a NAME="EricPlugin" ID="EricPlugin"></a> +<h2>EricPlugin</h2> + +<p> + Class implementing a pytest plugin which reports the data in a format + suitable for the PytestExecutor. +</p> +<h3>Derived from</h3> +None +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#EricPlugin.__init__">EricPlugin</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#EricPlugin.__initializeReportData">__initializeReportData</a></td> +<td>Private method to initialize attributes for data collection.</td> +</tr> +<tr> +<td><a href="#EricPlugin.pytest_collectreport">pytest_collectreport</a></td> +<td>Public method called by pytest after the tests have been collected.</td> +</tr> +<tr> +<td><a href="#EricPlugin.pytest_itemcollected">pytest_itemcollected</a></td> +<td>Public malled by pytest after a test item has been collected.</td> +</tr> +<tr> +<td><a href="#EricPlugin.pytest_report_header">pytest_report_header</a></td> +<td>Public method called by pytest before any reporting.</td> +</tr> +<tr> +<td><a href="#EricPlugin.pytest_runtest_logfinish">pytest_runtest_logfinish</a></td> +<td>Public method called by pytest after a test has been completed.</td> +</tr> +<tr> +<td><a href="#EricPlugin.pytest_runtest_logreport">pytest_runtest_logreport</a></td> +<td>Public method called by pytest when a test phase (setup, call and teardown) has been completed.</td> +</tr> +<tr> +<td><a href="#EricPlugin.pytest_runtest_logstart">pytest_runtest_logstart</a></td> +<td>Public method called by pytest before running a test.</td> +</tr> +<tr> +<td><a href="#EricPlugin.pytest_sessionfinish">pytest_sessionfinish</a></td> +<td>Public method called by pytest after the whole test run finished.</td> +</tr> +<tr> +<td><a href="#EricPlugin.pytest_sessionstart">pytest_sessionstart</a></td> +<td>Public method called by pytest before performing collection and entering the run test loop.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="EricPlugin.__init__" ID="EricPlugin.__init__"></a> +<h4>EricPlugin (Constructor)</h4> +<b>EricPlugin</b>(<i>writer</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>writer</i> (EricJsonWriter)</dt> +<dd> +reference to the object to write the results to +</dd> +</dl> +<a NAME="EricPlugin.__initializeReportData" ID="EricPlugin.__initializeReportData"></a> +<h4>EricPlugin.__initializeReportData</h4> +<b>__initializeReportData</b>(<i></i>) + +<p> + Private method to initialize attributes for data collection. +</p> +<a NAME="EricPlugin.pytest_collectreport" ID="EricPlugin.pytest_collectreport"></a> +<h4>EricPlugin.pytest_collectreport</h4> +<b>pytest_collectreport</b>(<i>report</i>) + +<p> + Public method called by pytest after the tests have been collected. +</p> +<dl> + +<dt><i>report</i> (CollectReport)</dt> +<dd> +reference to the report object +</dd> +</dl> +<a NAME="EricPlugin.pytest_itemcollected" ID="EricPlugin.pytest_itemcollected"></a> +<h4>EricPlugin.pytest_itemcollected</h4> +<b>pytest_itemcollected</b>(<i>item</i>) + +<p> + Public malled by pytest after a test item has been collected. +</p> +<dl> + +<dt><i>item</i> (Item)</dt> +<dd> +reference to the collected test item +</dd> +</dl> +<a NAME="EricPlugin.pytest_report_header" ID="EricPlugin.pytest_report_header"></a> +<h4>EricPlugin.pytest_report_header</h4> +<b>pytest_report_header</b>(<i>config, startdir</i>) + +<p> + Public method called by pytest before any reporting. +</p> +<dl> + +<dt><i>config</i> (Config)</dt> +<dd> +reference to the configuration object +</dd> +<dt><i>startdir</i> (LocalPath)</dt> +<dd> +starting directory +</dd> +</dl> +<a NAME="EricPlugin.pytest_runtest_logfinish" ID="EricPlugin.pytest_runtest_logfinish"></a> +<h4>EricPlugin.pytest_runtest_logfinish</h4> +<b>pytest_runtest_logfinish</b>(<i>nodeid, location</i>) + +<p> + Public method called by pytest after a test has been completed. +</p> +<dl> + +<dt><i>nodeid</i> (str)</dt> +<dd> +node id of the test item +</dd> +<dt><i>location</i> (tuple of (str, int, str))</dt> +<dd> +tuple containing the file name, the line number and + the test name +</dd> +</dl> +<a NAME="EricPlugin.pytest_runtest_logreport" ID="EricPlugin.pytest_runtest_logreport"></a> +<h4>EricPlugin.pytest_runtest_logreport</h4> +<b>pytest_runtest_logreport</b>(<i>report</i>) + +<p> + Public method called by pytest when a test phase (setup, call and + teardown) has been completed. +</p> +<dl> + +<dt><i>report</i> (TestReport)</dt> +<dd> +reference to the test report object +</dd> +</dl> +<a NAME="EricPlugin.pytest_runtest_logstart" ID="EricPlugin.pytest_runtest_logstart"></a> +<h4>EricPlugin.pytest_runtest_logstart</h4> +<b>pytest_runtest_logstart</b>(<i>nodeid, location</i>) + +<p> + Public method called by pytest before running a test. +</p> +<dl> + +<dt><i>nodeid</i> (str)</dt> +<dd> +node id of the test item +</dd> +<dt><i>location</i> (tuple of (str, int, str))</dt> +<dd> +tuple containing the file name, the line number and + the test name +</dd> +</dl> +<a NAME="EricPlugin.pytest_sessionfinish" ID="EricPlugin.pytest_sessionfinish"></a> +<h4>EricPlugin.pytest_sessionfinish</h4> +<b>pytest_sessionfinish</b>(<i>session, exitstatus</i>) + +<p> + Public method called by pytest after the whole test run finished. +</p> +<dl> + +<dt><i>session</i> (Session)</dt> +<dd> +reference to the session object +</dd> +<dt><i>exitstatus</i> (int or ExitCode)</dt> +<dd> +exit status +</dd> +</dl> +<a NAME="EricPlugin.pytest_sessionstart" ID="EricPlugin.pytest_sessionstart"></a> +<h4>EricPlugin.pytest_sessionstart</h4> +<b>pytest_sessionstart</b>(<i>session</i>) + +<p> + Public method called by pytest before performing collection and + entering the run test loop. +</p> +<dl> + +<dt><i>session</i> (Session)</dt> +<dd> +reference to the session object +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="GetPluginVersionsPlugin" ID="GetPluginVersionsPlugin"></a> +<h2>GetPluginVersionsPlugin</h2> + +<p> + Class implementing a pytest plugin to extract the version info of all + installed plugins. +</p> +<h3>Derived from</h3> +None +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#GetPluginVersionsPlugin.__init__">GetPluginVersionsPlugin</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#GetPluginVersionsPlugin.getVersions">getVersions</a></td> +<td>Public method to get the assembled list of plugin versions.</td> +</tr> +<tr> +<td><a href="#GetPluginVersionsPlugin.pytest_cmdline_main">pytest_cmdline_main</a></td> +<td>Public method called for performing the main command line action.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="GetPluginVersionsPlugin.__init__" ID="GetPluginVersionsPlugin.__init__"></a> +<h4>GetPluginVersionsPlugin (Constructor)</h4> +<b>GetPluginVersionsPlugin</b>(<i></i>) + +<p> + Constructor +</p> +<a NAME="GetPluginVersionsPlugin.getVersions" ID="GetPluginVersionsPlugin.getVersions"></a> +<h4>GetPluginVersionsPlugin.getVersions</h4> +<b>getVersions</b>(<i></i>) + +<p> + Public method to get the assembled list of plugin versions. +</p> +<dl> +<dt>Return:</dt> +<dd> +list of collected plugin versions +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of dict +</dd> +</dl> +<a NAME="GetPluginVersionsPlugin.pytest_cmdline_main" ID="GetPluginVersionsPlugin.pytest_cmdline_main"></a> +<h4>GetPluginVersionsPlugin.pytest_cmdline_main</h4> +<b>pytest_cmdline_main</b>(<i>config</i>) + +<p> + Public method called for performing the main command line action. +</p> +<dl> + +<dt><i>config</i> (Config)</dt> +<dd> +pytest config object +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="getVersions" ID="getVersions"></a> +<h2>getVersions</h2> +<b>getVersions</b>(<i></i>) + +<p> + Function to determine the framework version and versions of all available + plugins. +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.Testing.Interfaces.TestExecutorBase.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,520 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.Interfaces.TestExecutorBase</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.Testing.Interfaces.TestExecutorBase</h1> + +<p> +Module implementing the executor base class for the various testing frameworks +and supporting classes. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#TestConfig">TestConfig</a></td> +<td>Class containing the test run configuration.</td> +</tr> +<tr> +<td><a href="#TestExecutorBase">TestExecutorBase</a></td> +<td>Base class for test framework specific implementations.</td> +</tr> +<tr> +<td><a href="#TestResult">TestResult</a></td> +<td>Class containing the test result data.</td> +</tr> +<tr> +<td><a href="#TestResultCategory">TestResultCategory</a></td> +<td>Class defining the supported result categories.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="TestConfig" ID="TestConfig"></a> +<h2>TestConfig</h2> + +<p> + Class containing the test run configuration. +</p> +<h3>Derived from</h3> +None +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="TestExecutorBase" ID="TestExecutorBase"></a> +<h2>TestExecutorBase</h2> + +<p> + Base class for test framework specific implementations. +</p> +<h3>Signals</h3> +<dl> + +<dt>collectError(list of tuple of (str, str)</dt> +<dd> +) emitted when errors + are encountered during test collection. Tuple elements are the + test name and the error message. +</dd> +<dt>collected(list of tuple of (str, str, str)</dt> +<dd> +) emitted after all tests + have been collected. Tuple elements are the test id, the test name and + a short description of the test. +</dd> +<dt>coverageDataSaved(str)</dt> +<dd> +emitted after the coverage data was saved. + The element is the absolute path of the coverage data file. +</dd> +<dt>startTest(tuple of (str, str, str)</dt> +<dd> +emitted before tests are run. + Tuple elements are test id, test name and short description. +</dd> +<dt>stop()</dt> +<dd> +emitted when the test process is being stopped. +</dd> +<dt>testFinished(list, str)</dt> +<dd> +emitted when the test has finished. + The elements are the list of test results and the captured output + of the test worker (if any). +</dd> +<dt>testResult(TestResult)</dt> +<dd> +emitted when a test result is ready +</dd> +<dt>testRunAboutToBeStarted()</dt> +<dd> +emitted just before the test run will + be started. +</dd> +<dt>testRunFinished(int, float)</dt> +<dd> +emitted when the test run has finished. + The elements are the number of tests run and the duration in seconds +</dd> +</dl> +<h3>Derived from</h3> +QObject +<h3>Class Attributes</h3> + +<table> +<tr><td>module</td></tr><tr><td>name</td></tr><tr><td>runner</td></tr> +</table> +<h3>Class Methods</h3> + +<table> + +<tr> +<td><a href="#TestExecutorBase.isInstalled">isInstalled</a></td> +<td>Class method to check whether a test framework is installed.</td> +</tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#TestExecutorBase.__init__">TestExecutorBase</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#TestExecutorBase._prepareProcess">_prepareProcess</a></td> +<td>Protected method to prepare a process object to be started.</td> +</tr> +<tr> +<td><a href="#TestExecutorBase.createArguments">createArguments</a></td> +<td>Public method to create the arguments needed to start the test process.</td> +</tr> +<tr> +<td><a href="#TestExecutorBase.finished">finished</a></td> +<td>Public method handling the unit test process been finished.</td> +</tr> +<tr> +<td><a href="#TestExecutorBase.getVersions">getVersions</a></td> +<td>Public method to get the test framework version and version information of its installed plugins.</td> +</tr> +<tr> +<td><a href="#TestExecutorBase.hasCoverage">hasCoverage</a></td> +<td>Public method to get the test framework version and version information of its installed plugins.</td> +</tr> +<tr> +<td><a href="#TestExecutorBase.readAllOutput">readAllOutput</a></td> +<td>Public method to read all output of the test process.</td> +</tr> +<tr> +<td><a href="#TestExecutorBase.start">start</a></td> +<td>Public method to start the testing process.</td> +</tr> +<tr> +<td><a href="#TestExecutorBase.stopIfRunning">stopIfRunning</a></td> +<td>Public method to stop the testing process, if it is running.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="TestExecutorBase.isInstalled" ID="TestExecutorBase.isInstalled"></a> +<h4>TestExecutorBase.isInstalled (class method)</h4> +<b>isInstalled</b>(<i>interpreter</i>) + +<p> + Class method to check whether a test framework is installed. +</p> +<p> + The test is performed by checking, if a module loader can found. +</p> +<dl> + +<dt><i>interpreter</i> (str)</dt> +<dd> +interpreter to be used for the test +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +flag indicating the test framework module is installed +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> +<a NAME="TestExecutorBase.__init__" ID="TestExecutorBase.__init__"></a> +<h4>TestExecutorBase (Constructor)</h4> +<b>TestExecutorBase</b>(<i>testWidget</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>testWidget</i> (TestingWidget)</dt> +<dd> +reference to the unit test widget +</dd> +</dl> +<a NAME="TestExecutorBase._prepareProcess" ID="TestExecutorBase._prepareProcess"></a> +<h4>TestExecutorBase._prepareProcess</h4> +<b>_prepareProcess</b>(<i>workDir, pythonpath</i>) + +<p> + Protected method to prepare a process object to be started. +</p> +<dl> + +<dt><i>workDir</i> (str)</dt> +<dd> +working directory +</dd> +<dt><i>pythonpath</i> (list of str)</dt> +<dd> +list of directories to be added to the Python path +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +prepared process object +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +QProcess +</dd> +</dl> +<a NAME="TestExecutorBase.createArguments" ID="TestExecutorBase.createArguments"></a> +<h4>TestExecutorBase.createArguments</h4> +<b>createArguments</b>(<i>config</i>) + +<p> + Public method to create the arguments needed to start the test process. +</p> +<dl> + +<dt><i>config</i> (TestConfig)</dt> +<dd> +configuration for the test execution +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +list of process arguments +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of str +</dd> +</dl> +<dl> + +<dt>Raises <b>NotImplementedError</b>:</dt> +<dd> +this method needs to be implemented by + derived classes +</dd> +</dl> +<a NAME="TestExecutorBase.finished" ID="TestExecutorBase.finished"></a> +<h4>TestExecutorBase.finished</h4> +<b>finished</b>(<i></i>) + +<p> + Public method handling the unit test process been finished. +</p> +<p> + This method should read the results (if necessary) and emit the signal + testFinished. +</p> +<dl> + +<dt>Raises <b>NotImplementedError</b>:</dt> +<dd> +this method needs to be implemented by + derived classes +</dd> +</dl> +<a NAME="TestExecutorBase.getVersions" ID="TestExecutorBase.getVersions"></a> +<h4>TestExecutorBase.getVersions</h4> +<b>getVersions</b>(<i>interpreter</i>) + +<p> + Public method to get the test framework version and version information + of its installed plugins. +</p> +<dl> + +<dt><i>interpreter</i> (str)</dt> +<dd> +interpreter to be used for the test +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +dictionary containing the framework name and version and the + list of available plugins with name and version each +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +dict +</dd> +</dl> +<dl> + +<dt>Raises <b>NotImplementedError</b>:</dt> +<dd> +this method needs to be implemented by + derived classes +</dd> +</dl> +<a NAME="TestExecutorBase.hasCoverage" ID="TestExecutorBase.hasCoverage"></a> +<h4>TestExecutorBase.hasCoverage</h4> +<b>hasCoverage</b>(<i>interpreter</i>) + +<p> + Public method to get the test framework version and version information + of its installed plugins. +</p> +<dl> + +<dt><i>interpreter</i> (str)</dt> +<dd> +interpreter to be used for the test +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +flag indicating the availability of coverage functionality +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> +<dl> + +<dt>Raises <b>NotImplementedError</b>:</dt> +<dd> +this method needs to be implemented by + derived classes +</dd> +</dl> +<a NAME="TestExecutorBase.readAllOutput" ID="TestExecutorBase.readAllOutput"></a> +<h4>TestExecutorBase.readAllOutput</h4> +<b>readAllOutput</b>(<i>process=None</i>) + +<p> + Public method to read all output of the test process. +</p> +<dl> + +<dt><i>process</i> (QProcess)</dt> +<dd> +reference to the process object +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +test process output +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +str +</dd> +</dl> +<a NAME="TestExecutorBase.start" ID="TestExecutorBase.start"></a> +<h4>TestExecutorBase.start</h4> +<b>start</b>(<i>config, pythonpath</i>) + +<p> + Public method to start the testing process. +</p> +<dl> + +<dt><i>config</i> (TestConfig)</dt> +<dd> +configuration for the test execution +</dd> +<dt><i>pythonpath</i> (list of str)</dt> +<dd> +list of directories to be added to the Python path +</dd> +</dl> +<dl> + +<dt>Raises <b>RuntimeError</b>:</dt> +<dd> +raised if the the testing process did not start +</dd> +</dl> +<a NAME="TestExecutorBase.stopIfRunning" ID="TestExecutorBase.stopIfRunning"></a> +<h4>TestExecutorBase.stopIfRunning</h4> +<b>stopIfRunning</b>(<i></i>) + +<p> + Public method to stop the testing process, if it is running. +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="TestResult" ID="TestResult"></a> +<h2>TestResult</h2> + +<p> + Class containing the test result data. +</p> +<h3>Derived from</h3> +None +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="TestResultCategory" ID="TestResultCategory"></a> +<h2>TestResultCategory</h2> + +<p> + Class defining the supported result categories. +</p> +<h3>Derived from</h3> +IntEnum +<h3>Class Attributes</h3> + +<table> +<tr><td>FAIL</td></tr><tr><td>OK</td></tr><tr><td>PENDING</td></tr><tr><td>RUNNING</td></tr><tr><td>SKIP</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.Testing.Interfaces.TestFrameworkRegistry.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,166 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.Interfaces.TestFrameworkRegistry</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.Testing.Interfaces.TestFrameworkRegistry</h1> + +<p> +Module implementing a simple registry containing the available test framework +interfaces. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#TestFrameworkRegistry">TestFrameworkRegistry</a></td> +<td>Class implementing a simple registry of test framework interfaces.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="TestFrameworkRegistry" ID="TestFrameworkRegistry"></a> +<h2>TestFrameworkRegistry</h2> + +<p> + Class implementing a simple registry of test framework interfaces. +</p> +<p> + The test executor for a framework is responsible for running the tests, + receiving the results and preparing them for display. It must implement + the interface of TestExecutorBase. +</p> +<p> + Frameworks must first be registered using '.register()'. This registry + can then create the assoicated test executor when '.createExecutor()' is + called. +</p> +<h3>Derived from</h3> +None +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#TestFrameworkRegistry.__init__">TestFrameworkRegistry</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#TestFrameworkRegistry.createExecutor">createExecutor</a></td> +<td>Public method to create a test framework executor.</td> +</tr> +<tr> +<td><a href="#TestFrameworkRegistry.getFrameworks">getFrameworks</a></td> +<td>Public method to get a copy of the registered frameworks.</td> +</tr> +<tr> +<td><a href="#TestFrameworkRegistry.register">register</a></td> +<td>Public method to register a test framework executor.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="TestFrameworkRegistry.__init__" ID="TestFrameworkRegistry.__init__"></a> +<h4>TestFrameworkRegistry (Constructor)</h4> +<b>TestFrameworkRegistry</b>(<i></i>) + +<p> + Constructor +</p> +<a NAME="TestFrameworkRegistry.createExecutor" ID="TestFrameworkRegistry.createExecutor"></a> +<h4>TestFrameworkRegistry.createExecutor</h4> +<b>createExecutor</b>(<i>framework, widget</i>) + +<p> + Public method to create a test framework executor. +</p> +<p> + Note: The executor classes have to be registered first. +</p> +<dl> + +<dt><i>framework</i> (str)</dt> +<dd> +name of the test framework +</dd> +<dt><i>widget</i> (TestingWidget)</dt> +<dd> +reference to the unit test widget +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +test framework executor object +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +TestExecutorBase +</dd> +</dl> +<a NAME="TestFrameworkRegistry.getFrameworks" ID="TestFrameworkRegistry.getFrameworks"></a> +<h4>TestFrameworkRegistry.getFrameworks</h4> +<b>getFrameworks</b>(<i></i>) + +<p> + Public method to get a copy of the registered frameworks. +</p> +<dl> +<dt>Return:</dt> +<dd> +copy of the registered frameworks +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +dict +</dd> +</dl> +<a NAME="TestFrameworkRegistry.register" ID="TestFrameworkRegistry.register"></a> +<h4>TestFrameworkRegistry.register</h4> +<b>register</b>(<i>executorClass</i>) + +<p> + Public method to register a test framework executor. +</p> +<dl> + +<dt><i>executorClass</i> (TestExecutorBase)</dt> +<dd> +class implementing the test framework executor +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.Testing.Interfaces.UnittestExecutor.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,232 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.Interfaces.UnittestExecutor</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.Testing.Interfaces.UnittestExecutor</h1> + +<p> +Module implementing the executor for the standard 'unittest' framework. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#UnittestExecutor">UnittestExecutor</a></td> +<td>Class implementing the executor for the standard 'unittest' framework.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="UnittestExecutor" ID="UnittestExecutor"></a> +<h2>UnittestExecutor</h2> + +<p> + Class implementing the executor for the standard 'unittest' framework. +</p> +<h3>Derived from</h3> +TestExecutorBase +<h3>Class Attributes</h3> + +<table> +<tr><td>module</td></tr><tr><td>name</td></tr><tr><td>runner</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#UnittestExecutor.__init__">UnittestExecutor</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#UnittestExecutor.__processData">__processData</a></td> +<td>Private slot to process the received data.</td> +</tr> +<tr> +<td><a href="#UnittestExecutor.createArguments">createArguments</a></td> +<td>Public method to create the arguments needed to start the test process.</td> +</tr> +<tr> +<td><a href="#UnittestExecutor.finished">finished</a></td> +<td>Public method handling the unit test process been finished.</td> +</tr> +<tr> +<td><a href="#UnittestExecutor.getVersions">getVersions</a></td> +<td>Public method to get the test framework version and version information of its installed plugins.</td> +</tr> +<tr> +<td><a href="#UnittestExecutor.hasCoverage">hasCoverage</a></td> +<td>Public method to get the test framework version and version information of its installed plugins.</td> +</tr> +<tr> +<td><a href="#UnittestExecutor.start">start</a></td> +<td>Public method to start the testing process.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="UnittestExecutor.__init__" ID="UnittestExecutor.__init__"></a> +<h4>UnittestExecutor (Constructor)</h4> +<b>UnittestExecutor</b>(<i>testWidget</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>testWidget</i> (TestingWidget)</dt> +<dd> +reference to the unit test widget +</dd> +</dl> +<a NAME="UnittestExecutor.__processData" ID="UnittestExecutor.__processData"></a> +<h4>UnittestExecutor.__processData</h4> +<b>__processData</b>(<i>data</i>) + +<p> + Private slot to process the received data. +</p> +<dl> + +<dt><i>data</i> (dict)</dt> +<dd> +data object received +</dd> +</dl> +<a NAME="UnittestExecutor.createArguments" ID="UnittestExecutor.createArguments"></a> +<h4>UnittestExecutor.createArguments</h4> +<b>createArguments</b>(<i>config</i>) + +<p> + Public method to create the arguments needed to start the test process. +</p> +<dl> + +<dt><i>config</i> (TestConfig)</dt> +<dd> +configuration for the test execution +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +list of process arguments +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of str +</dd> +</dl> +<a NAME="UnittestExecutor.finished" ID="UnittestExecutor.finished"></a> +<h4>UnittestExecutor.finished</h4> +<b>finished</b>(<i></i>) + +<p> + Public method handling the unit test process been finished. +</p> +<p> + This method should read the results (if necessary) and emit the signal + testFinished. +</p> +<a NAME="UnittestExecutor.getVersions" ID="UnittestExecutor.getVersions"></a> +<h4>UnittestExecutor.getVersions</h4> +<b>getVersions</b>(<i>interpreter</i>) + +<p> + Public method to get the test framework version and version information + of its installed plugins. +</p> +<dl> + +<dt><i>interpreter</i> (str)</dt> +<dd> +interpreter to be used for the test +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +dictionary containing the framework name and version and the + list of available plugins with name and version each +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +dict +</dd> +</dl> +<a NAME="UnittestExecutor.hasCoverage" ID="UnittestExecutor.hasCoverage"></a> +<h4>UnittestExecutor.hasCoverage</h4> +<b>hasCoverage</b>(<i>interpreter</i>) + +<p> + Public method to get the test framework version and version information + of its installed plugins. +</p> +<dl> + +<dt><i>interpreter</i> (str)</dt> +<dd> +interpreter to be used for the test +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +flag indicating the availability of coverage functionality +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> +<a NAME="UnittestExecutor.start" ID="UnittestExecutor.start"></a> +<h4>UnittestExecutor.start</h4> +<b>start</b>(<i>config, pythonpath</i>) + +<p> + Public method to start the testing process. +</p> +<dl> + +<dt><i>config</i> (TestConfig)</dt> +<dd> +configuration for the test execution +</dd> +<dt><i>pythonpath</i> (list of str)</dt> +<dd> +list of directories to be added to the Python path +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.Testing.Interfaces.UnittestRunner.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,339 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.Interfaces.UnittestRunner</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.Testing.Interfaces.UnittestRunner</h1> + +<p> +Module implementing the test runner script for the 'unittest' framework. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#EricTestResult">EricTestResult</a></td> +<td>Class implementing a TestResult derivative to send the data via a network connection.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> + +<tr> +<td><a href="#_assembleTestCasesList">_assembleTestCasesList</a></td> +<td>Protected function to assemble a list of test cases included in a test suite.</td> +</tr> +<tr> +<td><a href="#runtest">runtest</a></td> +<td>Function to run the tests.</td> +</tr> +</table> +<hr /> +<hr /> +<a NAME="EricTestResult" ID="EricTestResult"></a> +<h2>EricTestResult</h2> + +<p> + Class implementing a TestResult derivative to send the data via a network + connection. +</p> +<h3>Derived from</h3> +unittest.TestResult +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#EricTestResult.__init__">EricTestResult</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#EricTestResult.addError">addError</a></td> +<td>Public method called if a test errored.</td> +</tr> +<tr> +<td><a href="#EricTestResult.addExpectedFailure">addExpectedFailure</a></td> +<td>Public method called if a test failed expected.</td> +</tr> +<tr> +<td><a href="#EricTestResult.addFailure">addFailure</a></td> +<td>Public method called if a test failed.</td> +</tr> +<tr> +<td><a href="#EricTestResult.addSkip">addSkip</a></td> +<td>Public method called if a test was skipped.</td> +</tr> +<tr> +<td><a href="#EricTestResult.addSubTest">addSubTest</a></td> +<td>Public method called for each subtest to record its result.</td> +</tr> +<tr> +<td><a href="#EricTestResult.addUnexpectedSuccess">addUnexpectedSuccess</a></td> +<td>Public method called if a test succeeded expectedly.</td> +</tr> +<tr> +<td><a href="#EricTestResult.startTest">startTest</a></td> +<td>Public method called at the start of a test.</td> +</tr> +<tr> +<td><a href="#EricTestResult.startTestRun">startTestRun</a></td> +<td>Public method called once before any tests are executed.</td> +</tr> +<tr> +<td><a href="#EricTestResult.stopTest">stopTest</a></td> +<td>Public method called at the end of a test.</td> +</tr> +<tr> +<td><a href="#EricTestResult.stopTestRun">stopTestRun</a></td> +<td>Public method called once after all tests are executed.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="EricTestResult.__init__" ID="EricTestResult.__init__"></a> +<h4>EricTestResult (Constructor)</h4> +<b>EricTestResult</b>(<i>writer, failfast</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>writer</i> (EricJsonWriter)</dt> +<dd> +reference to the object to write the results to +</dd> +<dt><i>failfast</i> (bool)</dt> +<dd> +flag indicating to stop at the first error +</dd> +</dl> +<a NAME="EricTestResult.addError" ID="EricTestResult.addError"></a> +<h4>EricTestResult.addError</h4> +<b>addError</b>(<i>test, err</i>) + +<p> + Public method called if a test errored. +</p> +<dl> + +<dt><i>test</i> (TestCase)</dt> +<dd> +reference to the test object +</dd> +<dt><i>err</i> (tuple)</dt> +<dd> +tuple containing the exception data like sys.exc_info + (exception type, exception instance, traceback) +</dd> +</dl> +<a NAME="EricTestResult.addExpectedFailure" ID="EricTestResult.addExpectedFailure"></a> +<h4>EricTestResult.addExpectedFailure</h4> +<b>addExpectedFailure</b>(<i>test, err</i>) + +<p> + Public method called if a test failed expected. +</p> +<dl> + +<dt><i>test</i> (TestCase)</dt> +<dd> +reference to the test object +</dd> +<dt><i>err</i> (tuple)</dt> +<dd> +tuple containing the exception data like sys.exc_info + (exception type, exception instance, traceback) +</dd> +</dl> +<a NAME="EricTestResult.addFailure" ID="EricTestResult.addFailure"></a> +<h4>EricTestResult.addFailure</h4> +<b>addFailure</b>(<i>test, err</i>) + +<p> + Public method called if a test failed. +</p> +<dl> + +<dt><i>test</i> (TestCase)</dt> +<dd> +reference to the test object +</dd> +<dt><i>err</i> (tuple)</dt> +<dd> +tuple containing the exception data like sys.exc_info + (exception type, exception instance, traceback) +</dd> +</dl> +<a NAME="EricTestResult.addSkip" ID="EricTestResult.addSkip"></a> +<h4>EricTestResult.addSkip</h4> +<b>addSkip</b>(<i>test, reason</i>) + +<p> + Public method called if a test was skipped. +</p> +<dl> + +<dt><i>test</i> (TestCase)</dt> +<dd> +reference to the test object +</dd> +<dt><i>reason</i> (str)</dt> +<dd> +reason for skipping the test +</dd> +</dl> +<a NAME="EricTestResult.addSubTest" ID="EricTestResult.addSubTest"></a> +<h4>EricTestResult.addSubTest</h4> +<b>addSubTest</b>(<i>test, subtest, err</i>) + +<p> + Public method called for each subtest to record its result. +</p> +<dl> + +<dt><i>test</i> (TestCase)</dt> +<dd> +reference to the test object +</dd> +<dt><i>subtest</i> (TestCase)</dt> +<dd> +reference to the subtest object +</dd> +<dt><i>err</i> (tuple)</dt> +<dd> +tuple containing the exception data like sys.exc_info + (exception type, exception instance, traceback) +</dd> +</dl> +<a NAME="EricTestResult.addUnexpectedSuccess" ID="EricTestResult.addUnexpectedSuccess"></a> +<h4>EricTestResult.addUnexpectedSuccess</h4> +<b>addUnexpectedSuccess</b>(<i>test</i>) + +<p> + Public method called if a test succeeded expectedly. +</p> +<dl> + +<dt><i>test</i> (TestCase)</dt> +<dd> +reference to the test object +</dd> +</dl> +<a NAME="EricTestResult.startTest" ID="EricTestResult.startTest"></a> +<h4>EricTestResult.startTest</h4> +<b>startTest</b>(<i>test</i>) + +<p> + Public method called at the start of a test. +</p> +<dl> + +<dt><i>test</i> (TestCase)</dt> +<dd> +reference to the test object +</dd> +</dl> +<a NAME="EricTestResult.startTestRun" ID="EricTestResult.startTestRun"></a> +<h4>EricTestResult.startTestRun</h4> +<b>startTestRun</b>(<i></i>) + +<p> + Public method called once before any tests are executed. +</p> +<a NAME="EricTestResult.stopTest" ID="EricTestResult.stopTest"></a> +<h4>EricTestResult.stopTest</h4> +<b>stopTest</b>(<i>test</i>) + +<p> + Public method called at the end of a test. +</p> +<dl> + +<dt><i>test</i> (TestCase)</dt> +<dd> +reference to the test object +</dd> +</dl> +<a NAME="EricTestResult.stopTestRun" ID="EricTestResult.stopTestRun"></a> +<h4>EricTestResult.stopTestRun</h4> +<b>stopTestRun</b>(<i></i>) + +<p> + Public method called once after all tests are executed. +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="_assembleTestCasesList" ID="_assembleTestCasesList"></a> +<h2>_assembleTestCasesList</h2> +<b>_assembleTestCasesList</b>(<i>suite</i>) + +<p> + Protected function to assemble a list of test cases included in a test + suite. +</p> +<dl> + +<dt><i>suite</i> (unittest.TestSuite)</dt> +<dd> +test suite to be inspected +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +list of tuples containing the test case ID, the string + representation and the short description +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of tuples of (str, str) +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="runtest" ID="runtest"></a> +<h2>runtest</h2> +<b>runtest</b>(<i>argv</i>) + +<p> + Function to run the tests. +</p> +<dl> + +<dt><i>argv</i> (list of str)</dt> +<dd> +list of command line parameters. +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.Testing.TestResultsTree.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,770 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.TestResultsTree</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.Testing.TestResultsTree</h1> + +<p> +Module implementing a tree view and associated model to show the test result +data. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>TopLevelId</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#TestResultsModel">TestResultsModel</a></td> +<td>Class implementing the item model containing the test data.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView">TestResultsTreeView</a></td> +<td>Class implementing a tree view to show the test result data.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="TestResultsModel" ID="TestResultsModel"></a> +<h2>TestResultsModel</h2> + +<p> + Class implementing the item model containing the test data. +</p> +<h3>Signals</h3> +<dl> + +<dt>summary(str)</dt> +<dd> +emitted whenever the model data changes. The element + is a summary of the test results of the model. +</dd> +</dl> +<h3>Derived from</h3> +QAbstractItemModel +<h3>Class Attributes</h3> + +<table> +<tr><td>DurationColumn</td></tr><tr><td>Headers</td></tr><tr><td>MessageColumn</td></tr><tr><td>NameColumn</td></tr><tr><td>StatusColumn</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#TestResultsModel.__init__">TestResultsModel</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#TestResultsModel.__summary">__summary</a></td> +<td>Private method to generate a test results summary text.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.addTestResults">addTestResults</a></td> +<td>Public method to add test results to the ones already managed by the model.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.clear">clear</a></td> +<td>Public method to clear the model data.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.columnCount">columnCount</a></td> +<td>Public method to get the number of columns.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.data">data</a></td> +<td>Public method to get the data for the various columns and roles.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.durationKey">durationKey</a></td> +<td>Function to generate a key for duration sorting</td> +</tr> +<tr> +<td><a href="#TestResultsModel.getFailedTests">getFailedTests</a></td> +<td>Public method to extract the test ids of all failed tests.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.getTestResults">getTestResults</a></td> +<td>Public method to get the list of test results managed by the model.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.headerData">headerData</a></td> +<td>Public method to get the header string for the various sections.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.index">index</a></td> +<td>Public method to generate an index for the given row and column to identify the item.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.parent">parent</a></td> +<td>Public method to get the parent of the item pointed to by index.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.rowCount">rowCount</a></td> +<td>Public method to get the number of row for a given parent index.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.setTestResults">setTestResults</a></td> +<td>Public method to set the list of test results of the model.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.sort">sort</a></td> +<td>Public method to sort the model data by column in order.</td> +</tr> +<tr> +<td><a href="#TestResultsModel.updateTestResults">updateTestResults</a></td> +<td>Public method to update the data of managed test result items.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="TestResultsModel.__init__" ID="TestResultsModel.__init__"></a> +<h4>TestResultsModel (Constructor)</h4> +<b>TestResultsModel</b>(<i>parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>parent</i> (QObject (optional))</dt> +<dd> +reference to the parent object (defaults to None) +</dd> +</dl> +<a NAME="TestResultsModel.__summary" ID="TestResultsModel.__summary"></a> +<h4>TestResultsModel.__summary</h4> +<b>__summary</b>(<i></i>) + +<p> + Private method to generate a test results summary text. +</p> +<dl> +<dt>Return:</dt> +<dd> +test results summary text +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +str +</dd> +</dl> +<a NAME="TestResultsModel.addTestResults" ID="TestResultsModel.addTestResults"></a> +<h4>TestResultsModel.addTestResults</h4> +<b>addTestResults</b>(<i>testResults</i>) + +<p> + Public method to add test results to the ones already managed by the + model. +</p> +<dl> + +<dt><i>testResults</i> (list of TestResult)</dt> +<dd> +test results to be added to the model +</dd> +</dl> +<a NAME="TestResultsModel.clear" ID="TestResultsModel.clear"></a> +<h4>TestResultsModel.clear</h4> +<b>clear</b>(<i></i>) + +<p> + Public method to clear the model data. +</p> +<a NAME="TestResultsModel.columnCount" ID="TestResultsModel.columnCount"></a> +<h4>TestResultsModel.columnCount</h4> +<b>columnCount</b>(<i>parent=QModelIndex()</i>) + +<p> + Public method to get the number of columns. +</p> +<dl> + +<dt><i>parent</i> (QModelIndex (optional))</dt> +<dd> +index of the parent item (defaults to QModelIndex()) +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +number of columns +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +int +</dd> +</dl> +<a NAME="TestResultsModel.data" ID="TestResultsModel.data"></a> +<h4>TestResultsModel.data</h4> +<b>data</b>(<i>index, role</i>) + +<p> + Public method to get the data for the various columns and roles. +</p> +<dl> + +<dt><i>index</i> (QModelIndex)</dt> +<dd> +index of the data to be returned +</dd> +<dt><i>role</i> (Qt.ItemDataRole)</dt> +<dd> +role designating the data to return +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +requested data item +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +Any +</dd> +</dl> +<a NAME="TestResultsModel.durationKey" ID="TestResultsModel.durationKey"></a> +<h4>TestResultsModel.durationKey</h4> +<b>durationKey</b>(<i></i>) + +<p> + Function to generate a key for duration sorting +</p> +<dl> + +<dt><i>result</i> (TestResult)</dt> +<dd> +result object +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +sort key +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +float +</dd> +</dl> +<a NAME="TestResultsModel.getFailedTests" ID="TestResultsModel.getFailedTests"></a> +<h4>TestResultsModel.getFailedTests</h4> +<b>getFailedTests</b>(<i></i>) + +<p> + Public method to extract the test ids of all failed tests. +</p> +<dl> +<dt>Return:</dt> +<dd> +test ids of all failed tests +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of str +</dd> +</dl> +<a NAME="TestResultsModel.getTestResults" ID="TestResultsModel.getTestResults"></a> +<h4>TestResultsModel.getTestResults</h4> +<b>getTestResults</b>(<i></i>) + +<p> + Public method to get the list of test results managed by the model. +</p> +<dl> +<dt>Return:</dt> +<dd> +list of test results managed by the model +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of TestResult +</dd> +</dl> +<a NAME="TestResultsModel.headerData" ID="TestResultsModel.headerData"></a> +<h4>TestResultsModel.headerData</h4> +<b>headerData</b>(<i>section, orientation, role=Qt.ItemDataRole.DisplayRole</i>) + +<p> + Public method to get the header string for the various sections. +</p> +<dl> + +<dt><i>section</i> (int)</dt> +<dd> +section number +</dd> +<dt><i>orientation</i> (Qt.Orientation)</dt> +<dd> +orientation of the header +</dd> +<dt><i>role</i> (Qt.ItemDataRole (optional))</dt> +<dd> +data role (defaults to Qt.ItemDataRole.DisplayRole) +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +header string of the section +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +str +</dd> +</dl> +<a NAME="TestResultsModel.index" ID="TestResultsModel.index"></a> +<h4>TestResultsModel.index</h4> +<b>index</b>(<i>row, column, parent=QModelIndex()</i>) + +<p> + Public method to generate an index for the given row and column to + identify the item. +</p> +<dl> + +<dt><i>row</i> (int)</dt> +<dd> +row for the index +</dd> +<dt><i>column</i> (int)</dt> +<dd> +column for the index +</dd> +<dt><i>parent</i> (QModelIndex (optional))</dt> +<dd> +index of the parent item (defaults to QModelIndex()) +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +index for the item +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +QModelIndex +</dd> +</dl> +<a NAME="TestResultsModel.parent" ID="TestResultsModel.parent"></a> +<h4>TestResultsModel.parent</h4> +<b>parent</b>(<i>index</i>) + +<p> + Public method to get the parent of the item pointed to by index. +</p> +<dl> + +<dt><i>index</i> (QModelIndex)</dt> +<dd> +index of the item +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +index of the parent item +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +QModelIndex +</dd> +</dl> +<a NAME="TestResultsModel.rowCount" ID="TestResultsModel.rowCount"></a> +<h4>TestResultsModel.rowCount</h4> +<b>rowCount</b>(<i>parent=QModelIndex()</i>) + +<p> + Public method to get the number of row for a given parent index. +</p> +<dl> + +<dt><i>parent</i> (QModelIndex (optional))</dt> +<dd> +index of the parent item (defaults to QModelIndex()) +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +number of rows +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +int +</dd> +</dl> +<a NAME="TestResultsModel.setTestResults" ID="TestResultsModel.setTestResults"></a> +<h4>TestResultsModel.setTestResults</h4> +<b>setTestResults</b>(<i>testResults</i>) + +<p> + Public method to set the list of test results of the model. +</p> +<dl> + +<dt><i>testResults</i> (list of TestResult)</dt> +<dd> +test results to be managed by the model +</dd> +</dl> +<a NAME="TestResultsModel.sort" ID="TestResultsModel.sort"></a> +<h4>TestResultsModel.sort</h4> +<b>sort</b>(<i>column, order</i>) + +<p> + Public method to sort the model data by column in order. +</p> +<dl> + +<dt><i>column</i> (int)</dt> +<dd> +sort column number +</dd> +<dt><i>order</i> (Qt.SortOrder)</dt> +<dd> +sort order +</dd> +</dl> +<a NAME="TestResultsModel.updateTestResults" ID="TestResultsModel.updateTestResults"></a> +<h4>TestResultsModel.updateTestResults</h4> +<b>updateTestResults</b>(<i>testResults</i>) + +<p> + Public method to update the data of managed test result items. +</p> +<dl> + +<dt><i>testResults</i> (list of TestResult)</dt> +<dd> +test results to be updated +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="TestResultsTreeView" ID="TestResultsTreeView"></a> +<h2>TestResultsTreeView</h2> + +<p> + Class implementing a tree view to show the test result data. +</p> +<h3>Signals</h3> +<dl> + +<dt>goto(str, int)</dt> +<dd> +emitted to go to the position given by file name + and line number +</dd> +</dl> +<h3>Derived from</h3> +QTreeView +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#TestResultsTreeView.__init__">TestResultsTreeView</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.__canonicalIndex">__canonicalIndex</a></td> +<td>Private method to create the canonical index for a given index.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.__createBackgroundContextMenu">__createBackgroundContextMenu</a></td> +<td>Private method to create a context menu for the background.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.__createContextMenu">__createContextMenu</a></td> +<td>Private method to create a context menu for the item pointed to by the given index.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.__gotoTestDefinition">__gotoTestDefinition</a></td> +<td>Private slot to show the test definition.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.__showContextMenu">__showContextMenu</a></td> +<td>Private slot to show the context menu.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.dataChanged">dataChanged</a></td> +<td>Public method called when the model data has changed.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.reset">reset</a></td> +<td>Public method to reset the internal state of the view.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.resizeColumns">resizeColumns</a></td> +<td>Public method to resize the columns to their contents.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.rowsInserted">rowsInserted</a></td> +<td>Public method called when rows are inserted.</td> +</tr> +<tr> +<td><a href="#TestResultsTreeView.spanFirstColumn">spanFirstColumn</a></td> +<td>Public method to make the first column span the row for second level items.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="TestResultsTreeView.__init__" ID="TestResultsTreeView.__init__"></a> +<h4>TestResultsTreeView (Constructor)</h4> +<b>TestResultsTreeView</b>(<i>parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>parent</i> (QWidget (optional))</dt> +<dd> +reference to the parent widget (defaults to None) +</dd> +</dl> +<a NAME="TestResultsTreeView.__canonicalIndex" ID="TestResultsTreeView.__canonicalIndex"></a> +<h4>TestResultsTreeView.__canonicalIndex</h4> +<b>__canonicalIndex</b>(<i>index</i>) + +<p> + Private method to create the canonical index for a given index. +</p> +<p> + The canonical index is the index of the first column of the test + result entry (i.e. the top-level item). If the index is invalid, + None is returned. +</p> +<dl> + +<dt><i>index</i> (QModelIndex)</dt> +<dd> +index to determine the canonical index for +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +index of the firt column of the associated top-level item index +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +QModelIndex +</dd> +</dl> +<a NAME="TestResultsTreeView.__createBackgroundContextMenu" ID="TestResultsTreeView.__createBackgroundContextMenu"></a> +<h4>TestResultsTreeView.__createBackgroundContextMenu</h4> +<b>__createBackgroundContextMenu</b>(<i></i>) + +<p> + Private method to create a context menu for the background. +</p> +<dl> +<dt>Return:</dt> +<dd> +created context menu +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +QMenu +</dd> +</dl> +<a NAME="TestResultsTreeView.__createContextMenu" ID="TestResultsTreeView.__createContextMenu"></a> +<h4>TestResultsTreeView.__createContextMenu</h4> +<b>__createContextMenu</b>(<i>index</i>) + +<p> + Private method to create a context menu for the item pointed to by the + given index. +</p> +<dl> + +<dt><i>index</i> (QModelIndex)</dt> +<dd> +index of the item +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +created context menu +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +QMenu +</dd> +</dl> +<a NAME="TestResultsTreeView.__gotoTestDefinition" ID="TestResultsTreeView.__gotoTestDefinition"></a> +<h4>TestResultsTreeView.__gotoTestDefinition</h4> +<b>__gotoTestDefinition</b>(<i>index</i>) + +<p> + Private slot to show the test definition. +</p> +<dl> + +<dt><i>index</i> (QModelIndex)</dt> +<dd> +index for the double-clicked item +</dd> +</dl> +<a NAME="TestResultsTreeView.__showContextMenu" ID="TestResultsTreeView.__showContextMenu"></a> +<h4>TestResultsTreeView.__showContextMenu</h4> +<b>__showContextMenu</b>(<i>pos</i>) + +<p> + Private slot to show the context menu. +</p> +<dl> + +<dt><i>pos</i> (QPoint)</dt> +<dd> +relative position for the context menu +</dd> +</dl> +<a NAME="TestResultsTreeView.dataChanged" ID="TestResultsTreeView.dataChanged"></a> +<h4>TestResultsTreeView.dataChanged</h4> +<b>dataChanged</b>(<i>topLeft, bottomRight, roles=[]</i>) + +<p> + Public method called when the model data has changed. +</p> +<dl> + +<dt><i>topLeft</i> (QModelIndex)</dt> +<dd> +index of the top left element +</dd> +<dt><i>bottomRight</i> (QModelIndex)</dt> +<dd> +index of the bottom right element +</dd> +<dt><i>roles</i> (list of Qt.ItemDataRole (optional))</dt> +<dd> +list of roles changed (defaults to []) +</dd> +</dl> +<a NAME="TestResultsTreeView.reset" ID="TestResultsTreeView.reset"></a> +<h4>TestResultsTreeView.reset</h4> +<b>reset</b>(<i></i>) + +<p> + Public method to reset the internal state of the view. +</p> +<a NAME="TestResultsTreeView.resizeColumns" ID="TestResultsTreeView.resizeColumns"></a> +<h4>TestResultsTreeView.resizeColumns</h4> +<b>resizeColumns</b>(<i></i>) + +<p> + Public method to resize the columns to their contents. +</p> +<a NAME="TestResultsTreeView.rowsInserted" ID="TestResultsTreeView.rowsInserted"></a> +<h4>TestResultsTreeView.rowsInserted</h4> +<b>rowsInserted</b>(<i>parent, startRow, endRow</i>) + +<p> + Public method called when rows are inserted. +</p> +<dl> + +<dt><i>parent</i> (QModelIndex)</dt> +<dd> +model index of the parent item +</dd> +<dt><i>startRow</i> (int)</dt> +<dd> +first row been inserted +</dd> +<dt><i>endRow</i> (int)</dt> +<dd> +last row been inserted +</dd> +</dl> +<a NAME="TestResultsTreeView.spanFirstColumn" ID="TestResultsTreeView.spanFirstColumn"></a> +<h4>TestResultsTreeView.spanFirstColumn</h4> +<b>spanFirstColumn</b>(<i>startRow, endRow</i>) + +<p> + Public method to make the first column span the row for second level + items. +</p> +<p> + These items contain the test results. +</p> +<dl> + +<dt><i>startRow</i> (QModelIndex)</dt> +<dd> +index of the first row to span +</dd> +<dt><i>endRow</i> (QModelIndex)</dt> +<dd> +index of the last row (including) to span +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.Testing.TestingWidget.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,970 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.TestingWidget</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.Testing.TestingWidget</h1> + +<p> +Module implementing a widget to orchestrate unit test execution. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#TestingWidget">TestingWidget</a></td> +<td>Class implementing a widget to orchestrate unit test execution.</td> +</tr> +<tr> +<td><a href="#TestingWidgetModes">TestingWidgetModes</a></td> +<td>Class defining the various modes of the testing widget.</td> +</tr> +<tr> +<td><a href="#TestingWindow">TestingWindow</a></td> +<td>Main window class for the standalone dialog.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> + +<tr> +<td><a href="#clearSavedHistories">clearSavedHistories</a></td> +<td>Function to clear the saved history lists.</td> +</tr> +</table> +<hr /> +<hr /> +<a NAME="TestingWidget" ID="TestingWidget"></a> +<h2>TestingWidget</h2> + +<p> + Class implementing a widget to orchestrate unit test execution. +</p> +<h3>Signals</h3> +<dl> + +<dt>testFile(str, int, bool)</dt> +<dd> +emitted to show the source of a + test file +</dd> +<dt>testRunStopped()</dt> +<dd> +emitted after a test run has finished +</dd> +</dl> +<h3>Derived from</h3> +QWidget, Ui_TestingWidget +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#TestingWidget.__init__">TestingWidget</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#TestingWidget.__adjustPendingState">__adjustPendingState</a></td> +<td>Private method to change the status indicator of all still pending tests to "not run".</td> +</tr> +<tr> +<td><a href="#TestingWidget.__coverageData">__coverageData</a></td> +<td>Private slot to handle the 'coverageData' signal of the executor.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__insertDiscovery">__insertDiscovery</a></td> +<td>Private slot to insert the discovery start directory into the discoveryPicker object.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__insertHistory">__insertHistory</a></td> +<td>Private slot to insert an item into a history object.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__insertTestFile">__insertTestFile</a></td> +<td>Private slot to insert a test file name into the testsuitePicker object.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__insertTestName">__insertTestName</a></td> +<td>Private slot to insert a test name into the testComboBox object.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__loadRecent">__loadRecent</a></td> +<td>Private method to load the most recently used lists.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__openEditor">__openEditor</a></td> +<td>Private method to open an editor window for the given file.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__populateTestFrameworkComboBox">__populateTestFrameworkComboBox</a></td> +<td>Private method to (re-)populate the test framework selector.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__populateVenvComboBox">__populateVenvComboBox</a></td> +<td>Private method to (re-)populate the virtual environments selector.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__processTestResult">__processTestResult</a></td> +<td>Private slot to handle the receipt of a test result object.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__projectClosed">__projectClosed</a></td> +<td>Private slot to handle a project being closed.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__projectOpened">__projectOpened</a></td> +<td>Private slot to handle a project being opened.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__resetResults">__resetResults</a></td> +<td>Private slot to reset the test results tab and data.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__saveRecent">__saveRecent</a></td> +<td>Private method to save the most recently used lists.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__setIdleMode">__setIdleMode</a></td> +<td>Private slot to switch the widget to idle mode.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__setRunningMode">__setRunningMode</a></td> +<td>Private slot to switch the widget to running mode.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__setStatusLabel">__setStatusLabel</a></td> +<td>Private slot to set the status label to the text sent by the model.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__setStoppedMode">__setStoppedMode</a></td> +<td>Private slot to switch the widget to stopped mode.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__showCoverageDialog">__showCoverageDialog</a></td> +<td>Private slot to show a code coverage dialog for the most recent test run.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__showLogOutput">__showLogOutput</a></td> +<td>Private slot to show the output of the most recent test run.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__showSource">__showSource</a></td> +<td>Private slot to show the source of a traceback in an editor.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__stopTests">__stopTests</a></td> +<td>Private slot to stop the current test run.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__testProcessFinished">__testProcessFinished</a></td> +<td>Private slot to handle the 'testFinished' signal of the executor.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__testRunAboutToBeStarted">__testRunAboutToBeStarted</a></td> +<td>Private slot to handle the 'testRunAboutToBeStarted' signal of the executor.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__testRunFinished">__testRunFinished</a></td> +<td>Private slot to handle the 'testRunFinished' signal of the executor.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__testStarted">__testStarted</a></td> +<td>Private slot handling the 'startTest' signal of the executor.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__testsCollectError">__testsCollectError</a></td> +<td>Private slot handling the 'collectError' signal of the executor.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__testsCollected">__testsCollected</a></td> +<td>Private slot handling the 'collected' signal of the executor.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__testsStopped">__testsStopped</a></td> +<td>Private slot to handle the 'stop' signal of the executor.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__updateButtonBoxButtons">__updateButtonBoxButtons</a></td> +<td>Private slot to update the state of the buttons of the button box.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__updateCoverage">__updateCoverage</a></td> +<td>Private slot to update the state of the coverage checkbox depending on the selected framework's capabilities.</td> +</tr> +<tr> +<td><a href="#TestingWidget.__updateProgress">__updateProgress</a></td> +<td>Private slot update the progress indicators.</td> +</tr> +<tr> +<td><a href="#TestingWidget.clearRecent">clearRecent</a></td> +<td>Public slot to clear the recently used lists.</td> +</tr> +<tr> +<td><a href="#TestingWidget.closeEvent">closeEvent</a></td> +<td>Protected method to handle the close event.</td> +</tr> +<tr> +<td><a href="#TestingWidget.getFailedTests">getFailedTests</a></td> +<td>Public method to get the list of failed tests (if any).</td> +</tr> +<tr> +<td><a href="#TestingWidget.getResultsModel">getResultsModel</a></td> +<td>Public method to get a reference to the model containing the test result data.</td> +</tr> +<tr> +<td><a href="#TestingWidget.hasFailedTests">hasFailedTests</a></td> +<td>Public method to check for failed tests.</td> +</tr> +<tr> +<td><a href="#TestingWidget.on_buttonBox_clicked">on_buttonBox_clicked</a></td> +<td>Private slot called by a button of the button box clicked.</td> +</tr> +<tr> +<td><a href="#TestingWidget.on_discoverCheckBox_toggled">on_discoverCheckBox_toggled</a></td> +<td>Private slot handling state changes of the 'discover' checkbox.</td> +</tr> +<tr> +<td><a href="#TestingWidget.on_frameworkComboBox_currentIndexChanged">on_frameworkComboBox_currentIndexChanged</a></td> +<td>Private slot handling the selection of a test framework.</td> +</tr> +<tr> +<td><a href="#TestingWidget.on_testsuitePicker_aboutToShowPathPickerDialog">on_testsuitePicker_aboutToShowPathPickerDialog</a></td> +<td>Private slot called before the test file selection dialog is shown.</td> +</tr> +<tr> +<td><a href="#TestingWidget.on_venvComboBox_currentIndexChanged">on_venvComboBox_currentIndexChanged</a></td> +<td>Private slot handling the selection of a virtual environment.</td> +</tr> +<tr> +<td><a href="#TestingWidget.on_versionsButton_clicked">on_versionsButton_clicked</a></td> +<td>Private slot to show the versions of available plugins.</td> +</tr> +<tr> +<td><a href="#TestingWidget.setTestFile">setTestFile</a></td> +<td>Public slot to set the given test file as the current one.</td> +</tr> +<tr> +<td><a href="#TestingWidget.startTests">startTests</a></td> +<td>Public slot to start the test run.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="TestingWidget.__init__" ID="TestingWidget.__init__"></a> +<h4>TestingWidget (Constructor)</h4> +<b>TestingWidget</b>(<i>testfile=None, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>testfile</i> (str)</dt> +<dd> +file name of the test to load +</dd> +<dt><i>parent</i> (QWidget (optional))</dt> +<dd> +reference to the parent widget (defaults to None) +</dd> +</dl> +<a NAME="TestingWidget.__adjustPendingState" ID="TestingWidget.__adjustPendingState"></a> +<h4>TestingWidget.__adjustPendingState</h4> +<b>__adjustPendingState</b>(<i></i>) + +<p> + Private method to change the status indicator of all still pending + tests to "not run". +</p> +<a NAME="TestingWidget.__coverageData" ID="TestingWidget.__coverageData"></a> +<h4>TestingWidget.__coverageData</h4> +<b>__coverageData</b>(<i>coverageFile</i>) + +<p> + Private slot to handle the 'coverageData' signal of the executor. +</p> +<dl> + +<dt><i>coverageFile</i> (str)</dt> +<dd> +file containing the coverage data +</dd> +</dl> +<a NAME="TestingWidget.__insertDiscovery" ID="TestingWidget.__insertDiscovery"></a> +<h4>TestingWidget.__insertDiscovery</h4> +<b>__insertDiscovery</b>(<i>start</i>) + +<p> + Private slot to insert the discovery start directory into the + discoveryPicker object. +</p> +<dl> + +<dt><i>start</i> (str)</dt> +<dd> +start directory name to be inserted +</dd> +</dl> +<a NAME="TestingWidget.__insertHistory" ID="TestingWidget.__insertHistory"></a> +<h4>TestingWidget.__insertHistory</h4> +<b>__insertHistory</b>(<i>widget, history, item</i>) + +<p> + Private slot to insert an item into a history object. +</p> +<dl> + +<dt><i>widget</i> (QComboBox or EricComboPathPicker)</dt> +<dd> +reference to the widget +</dd> +<dt><i>history</i> (list of str)</dt> +<dd> +array containing the history +</dd> +<dt><i>item</i> (str)</dt> +<dd> +item to be inserted +</dd> +</dl> +<a NAME="TestingWidget.__insertTestFile" ID="TestingWidget.__insertTestFile"></a> +<h4>TestingWidget.__insertTestFile</h4> +<b>__insertTestFile</b>(<i>prog</i>) + +<p> + Private slot to insert a test file name into the testsuitePicker + object. +</p> +<dl> + +<dt><i>prog</i> (str)</dt> +<dd> +test file name to be inserted +</dd> +</dl> +<a NAME="TestingWidget.__insertTestName" ID="TestingWidget.__insertTestName"></a> +<h4>TestingWidget.__insertTestName</h4> +<b>__insertTestName</b>(<i>testName</i>) + +<p> + Private slot to insert a test name into the testComboBox object. +</p> +<dl> + +<dt><i>testName</i> (str)</dt> +<dd> +name of the test to be inserted +</dd> +</dl> +<a NAME="TestingWidget.__loadRecent" ID="TestingWidget.__loadRecent"></a> +<h4>TestingWidget.__loadRecent</h4> +<b>__loadRecent</b>(<i></i>) + +<p> + Private method to load the most recently used lists. +</p> +<a NAME="TestingWidget.__openEditor" ID="TestingWidget.__openEditor"></a> +<h4>TestingWidget.__openEditor</h4> +<b>__openEditor</b>(<i>filename, linenumber=1</i>) + +<p> + Private method to open an editor window for the given file. +</p> +<p> + Note: This method opens an editor window when the testing dialog + is called as a standalone application. +</p> +<dl> + +<dt><i>filename</i> (str)</dt> +<dd> +path of the file to be opened +</dd> +<dt><i>linenumber</i> (int (optional))</dt> +<dd> +line number to place the cursor at (defaults to 1) +</dd> +</dl> +<a NAME="TestingWidget.__populateTestFrameworkComboBox" ID="TestingWidget.__populateTestFrameworkComboBox"></a> +<h4>TestingWidget.__populateTestFrameworkComboBox</h4> +<b>__populateTestFrameworkComboBox</b>(<i></i>) + +<p> + Private method to (re-)populate the test framework selector. +</p> +<a NAME="TestingWidget.__populateVenvComboBox" ID="TestingWidget.__populateVenvComboBox"></a> +<h4>TestingWidget.__populateVenvComboBox</h4> +<b>__populateVenvComboBox</b>(<i></i>) + +<p> + Private method to (re-)populate the virtual environments selector. +</p> +<a NAME="TestingWidget.__processTestResult" ID="TestingWidget.__processTestResult"></a> +<h4>TestingWidget.__processTestResult</h4> +<b>__processTestResult</b>(<i>result</i>) + +<p> + Private slot to handle the receipt of a test result object. +</p> +<dl> + +<dt><i>result</i> (TestResult)</dt> +<dd> +test result object +</dd> +</dl> +<a NAME="TestingWidget.__projectClosed" ID="TestingWidget.__projectClosed"></a> +<h4>TestingWidget.__projectClosed</h4> +<b>__projectClosed</b>(<i></i>) + +<p> + Private slot to handle a project being closed. +</p> +<a NAME="TestingWidget.__projectOpened" ID="TestingWidget.__projectOpened"></a> +<h4>TestingWidget.__projectOpened</h4> +<b>__projectOpened</b>(<i></i>) + +<p> + Private slot to handle a project being opened. +</p> +<a NAME="TestingWidget.__resetResults" ID="TestingWidget.__resetResults"></a> +<h4>TestingWidget.__resetResults</h4> +<b>__resetResults</b>(<i></i>) + +<p> + Private slot to reset the test results tab and data. +</p> +<a NAME="TestingWidget.__saveRecent" ID="TestingWidget.__saveRecent"></a> +<h4>TestingWidget.__saveRecent</h4> +<b>__saveRecent</b>(<i></i>) + +<p> + Private method to save the most recently used lists. +</p> +<a NAME="TestingWidget.__setIdleMode" ID="TestingWidget.__setIdleMode"></a> +<h4>TestingWidget.__setIdleMode</h4> +<b>__setIdleMode</b>(<i></i>) + +<p> + Private slot to switch the widget to idle mode. +</p> +<a NAME="TestingWidget.__setRunningMode" ID="TestingWidget.__setRunningMode"></a> +<h4>TestingWidget.__setRunningMode</h4> +<b>__setRunningMode</b>(<i></i>) + +<p> + Private slot to switch the widget to running mode. +</p> +<a NAME="TestingWidget.__setStatusLabel" ID="TestingWidget.__setStatusLabel"></a> +<h4>TestingWidget.__setStatusLabel</h4> +<b>__setStatusLabel</b>(<i>statusText</i>) + +<p> + Private slot to set the status label to the text sent by the model. +</p> +<dl> + +<dt><i>statusText</i> (str)</dt> +<dd> +text to be shown +</dd> +</dl> +<a NAME="TestingWidget.__setStoppedMode" ID="TestingWidget.__setStoppedMode"></a> +<h4>TestingWidget.__setStoppedMode</h4> +<b>__setStoppedMode</b>(<i></i>) + +<p> + Private slot to switch the widget to stopped mode. +</p> +<a NAME="TestingWidget.__showCoverageDialog" ID="TestingWidget.__showCoverageDialog"></a> +<h4>TestingWidget.__showCoverageDialog</h4> +<b>__showCoverageDialog</b>(<i></i>) + +<p> + Private slot to show a code coverage dialog for the most recent test + run. +</p> +<a NAME="TestingWidget.__showLogOutput" ID="TestingWidget.__showLogOutput"></a> +<h4>TestingWidget.__showLogOutput</h4> +<b>__showLogOutput</b>(<i></i>) + +<p> + Private slot to show the output of the most recent test run. +</p> +<a NAME="TestingWidget.__showSource" ID="TestingWidget.__showSource"></a> +<h4>TestingWidget.__showSource</h4> +<b>__showSource</b>(<i>filename, lineno</i>) + +<p> + Private slot to show the source of a traceback in an editor. +</p> +<dl> + +<dt><i>filename</i> (str)</dt> +<dd> +file name of the file to be shown +</dd> +<dt><i>lineno</i> (int)</dt> +<dd> +line number to go to in the file +</dd> +</dl> +<a NAME="TestingWidget.__stopTests" ID="TestingWidget.__stopTests"></a> +<h4>TestingWidget.__stopTests</h4> +<b>__stopTests</b>(<i></i>) + +<p> + Private slot to stop the current test run. +</p> +<a NAME="TestingWidget.__testProcessFinished" ID="TestingWidget.__testProcessFinished"></a> +<h4>TestingWidget.__testProcessFinished</h4> +<b>__testProcessFinished</b>(<i>results, output</i>) + +<p> + Private slot to handle the 'testFinished' signal of the executor. +</p> +<dl> + +<dt><i>results</i> (list of TestResult)</dt> +<dd> +list of test result objects (if not sent via the + 'testResult' signal +</dd> +<dt><i>output</i> (str)</dt> +<dd> +string containing the test process output (if any) +</dd> +</dl> +<a NAME="TestingWidget.__testRunAboutToBeStarted" ID="TestingWidget.__testRunAboutToBeStarted"></a> +<h4>TestingWidget.__testRunAboutToBeStarted</h4> +<b>__testRunAboutToBeStarted</b>(<i></i>) + +<p> + Private slot to handle the 'testRunAboutToBeStarted' signal of the + executor. +</p> +<a NAME="TestingWidget.__testRunFinished" ID="TestingWidget.__testRunFinished"></a> +<h4>TestingWidget.__testRunFinished</h4> +<b>__testRunFinished</b>(<i>noTests, duration</i>) + +<p> + Private slot to handle the 'testRunFinished' signal of the executor. +</p> +<dl> + +<dt><i>noTests</i> (int)</dt> +<dd> +number of tests run by the executor +</dd> +<dt><i>duration</i> (float)</dt> +<dd> +time needed in seconds to run the tests +</dd> +</dl> +<a NAME="TestingWidget.__testStarted" ID="TestingWidget.__testStarted"></a> +<h4>TestingWidget.__testStarted</h4> +<b>__testStarted</b>(<i>test</i>) + +<p> + Private slot handling the 'startTest' signal of the executor. +</p> +<dl> + +<dt><i>test</i> (tuple of (str, str, str))</dt> +<dd> +tuple containing the id, name and short description of the + tests about to be run +</dd> +</dl> +<a NAME="TestingWidget.__testsCollectError" ID="TestingWidget.__testsCollectError"></a> +<h4>TestingWidget.__testsCollectError</h4> +<b>__testsCollectError</b>(<i>errors</i>) + +<p> + Private slot handling the 'collectError' signal of the executor. +</p> +<dl> + +<dt><i>errors</i> (list of tuple of (str, str))</dt> +<dd> +list of tuples containing the test name and a description + of the error +</dd> +</dl> +<a NAME="TestingWidget.__testsCollected" ID="TestingWidget.__testsCollected"></a> +<h4>TestingWidget.__testsCollected</h4> +<b>__testsCollected</b>(<i>testNames</i>) + +<p> + Private slot handling the 'collected' signal of the executor. +</p> +<dl> + +<dt><i>testNames</i> (list of tuple of (str, str, str))</dt> +<dd> +list of tuples containing the test id, the test name + and a description of collected tests +</dd> +</dl> +<a NAME="TestingWidget.__testsStopped" ID="TestingWidget.__testsStopped"></a> +<h4>TestingWidget.__testsStopped</h4> +<b>__testsStopped</b>(<i></i>) + +<p> + Private slot to handle the 'stop' signal of the executor. +</p> +<a NAME="TestingWidget.__updateButtonBoxButtons" ID="TestingWidget.__updateButtonBoxButtons"></a> +<h4>TestingWidget.__updateButtonBoxButtons</h4> +<b>__updateButtonBoxButtons</b>(<i></i>) + +<p> + Private slot to update the state of the buttons of the button box. +</p> +<a NAME="TestingWidget.__updateCoverage" ID="TestingWidget.__updateCoverage"></a> +<h4>TestingWidget.__updateCoverage</h4> +<b>__updateCoverage</b>(<i></i>) + +<p> + Private slot to update the state of the coverage checkbox depending on + the selected framework's capabilities. +</p> +<a NAME="TestingWidget.__updateProgress" ID="TestingWidget.__updateProgress"></a> +<h4>TestingWidget.__updateProgress</h4> +<b>__updateProgress</b>(<i></i>) + +<p> + Private slot update the progress indicators. +</p> +<a NAME="TestingWidget.clearRecent" ID="TestingWidget.clearRecent"></a> +<h4>TestingWidget.clearRecent</h4> +<b>clearRecent</b>(<i></i>) + +<p> + Public slot to clear the recently used lists. +</p> +<a NAME="TestingWidget.closeEvent" ID="TestingWidget.closeEvent"></a> +<h4>TestingWidget.closeEvent</h4> +<b>closeEvent</b>(<i>event</i>) + +<p> + Protected method to handle the close event. +</p> +<dl> + +<dt><i>event</i> (QCloseEvent)</dt> +<dd> +close event +</dd> +</dl> +<a NAME="TestingWidget.getFailedTests" ID="TestingWidget.getFailedTests"></a> +<h4>TestingWidget.getFailedTests</h4> +<b>getFailedTests</b>(<i></i>) + +<p> + Public method to get the list of failed tests (if any). +</p> +<dl> +<dt>Return:</dt> +<dd> +list of IDs of failed tests +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of str +</dd> +</dl> +<a NAME="TestingWidget.getResultsModel" ID="TestingWidget.getResultsModel"></a> +<h4>TestingWidget.getResultsModel</h4> +<b>getResultsModel</b>(<i></i>) + +<p> + Public method to get a reference to the model containing the test + result data. +</p> +<dl> +<dt>Return:</dt> +<dd> +reference to the test results model +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +TestResultsModel +</dd> +</dl> +<a NAME="TestingWidget.hasFailedTests" ID="TestingWidget.hasFailedTests"></a> +<h4>TestingWidget.hasFailedTests</h4> +<b>hasFailedTests</b>(<i></i>) + +<p> + Public method to check for failed tests. +</p> +<dl> +<dt>Return:</dt> +<dd> +flag indicating the existence of failed tests +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> +<a NAME="TestingWidget.on_buttonBox_clicked" ID="TestingWidget.on_buttonBox_clicked"></a> +<h4>TestingWidget.on_buttonBox_clicked</h4> +<b>on_buttonBox_clicked</b>(<i>button</i>) + +<p> + Private slot called by a button of the button box clicked. +</p> +<dl> + +<dt><i>button</i> (QAbstractButton)</dt> +<dd> +button that was clicked +</dd> +</dl> +<a NAME="TestingWidget.on_discoverCheckBox_toggled" ID="TestingWidget.on_discoverCheckBox_toggled"></a> +<h4>TestingWidget.on_discoverCheckBox_toggled</h4> +<b>on_discoverCheckBox_toggled</b>(<i>checked</i>) + +<p> + Private slot handling state changes of the 'discover' checkbox. +</p> +<dl> + +<dt><i>checked</i> (bool)</dt> +<dd> +state of the checkbox +</dd> +</dl> +<a NAME="TestingWidget.on_frameworkComboBox_currentIndexChanged" ID="TestingWidget.on_frameworkComboBox_currentIndexChanged"></a> +<h4>TestingWidget.on_frameworkComboBox_currentIndexChanged</h4> +<b>on_frameworkComboBox_currentIndexChanged</b>(<i>index</i>) + +<p> + Private slot handling the selection of a test framework. +</p> +<dl> + +<dt><i>index</i> (int)</dt> +<dd> +index of the selected framework +</dd> +</dl> +<a NAME="TestingWidget.on_testsuitePicker_aboutToShowPathPickerDialog" ID="TestingWidget.on_testsuitePicker_aboutToShowPathPickerDialog"></a> +<h4>TestingWidget.on_testsuitePicker_aboutToShowPathPickerDialog</h4> +<b>on_testsuitePicker_aboutToShowPathPickerDialog</b>(<i></i>) + +<p> + Private slot called before the test file selection dialog is shown. +</p> +<a NAME="TestingWidget.on_venvComboBox_currentIndexChanged" ID="TestingWidget.on_venvComboBox_currentIndexChanged"></a> +<h4>TestingWidget.on_venvComboBox_currentIndexChanged</h4> +<b>on_venvComboBox_currentIndexChanged</b>(<i>index</i>) + +<p> + Private slot handling the selection of a virtual environment. +</p> +<dl> + +<dt><i>index</i> (int)</dt> +<dd> +index of the selected environment +</dd> +</dl> +<a NAME="TestingWidget.on_versionsButton_clicked" ID="TestingWidget.on_versionsButton_clicked"></a> +<h4>TestingWidget.on_versionsButton_clicked</h4> +<b>on_versionsButton_clicked</b>(<i></i>) + +<p> + Private slot to show the versions of available plugins. +</p> +<a NAME="TestingWidget.setTestFile" ID="TestingWidget.setTestFile"></a> +<h4>TestingWidget.setTestFile</h4> +<b>setTestFile</b>(<i>testFile, forProject=False</i>) + +<p> + Public slot to set the given test file as the current one. +</p> +<dl> + +<dt><i>testFile</i> (str)</dt> +<dd> +path of the test file +</dd> +<dt><i>forProject</i> (bool (optional))</dt> +<dd> +flag indicating that this call is for a project + (defaults to False) +</dd> +</dl> +<a NAME="TestingWidget.startTests" ID="TestingWidget.startTests"></a> +<h4>TestingWidget.startTests</h4> +<b>startTests</b>(<i>failedOnly=False</i>) + +<p> + Public slot to start the test run. +</p> +<dl> + +<dt><i>failedOnly</i> (bool)</dt> +<dd> +flag indicating to run only failed tests +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="TestingWidgetModes" ID="TestingWidgetModes"></a> +<h2>TestingWidgetModes</h2> + +<p> + Class defining the various modes of the testing widget. +</p> +<h3>Derived from</h3> +enum.Enum +<h3>Class Attributes</h3> + +<table> +<tr><td>IDLE</td></tr><tr><td>RUNNING</td></tr><tr><td>STOPPED</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="TestingWindow" ID="TestingWindow"></a> +<h2>TestingWindow</h2> + +<p> + Main window class for the standalone dialog. +</p> +<h3>Derived from</h3> +EricMainWindow +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#TestingWindow.__init__">TestingWindow</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#TestingWindow.eventFilter">eventFilter</a></td> +<td>Public method to filter events.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="TestingWindow.__init__" ID="TestingWindow.__init__"></a> +<h4>TestingWindow (Constructor)</h4> +<b>TestingWindow</b>(<i>testfile=None, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>testfile</i> (str)</dt> +<dd> +file name of the test script to open +</dd> +<dt><i>parent</i> (QWidget)</dt> +<dd> +reference to the parent widget +</dd> +</dl> +<a NAME="TestingWindow.eventFilter" ID="TestingWindow.eventFilter"></a> +<h4>TestingWindow.eventFilter</h4> +<b>eventFilter</b>(<i>obj, event</i>) + +<p> + Public method to filter events. +</p> +<dl> + +<dt><i>obj</i></dt> +<dd> +reference to the object the event is meant for (QObject) +</dd> +<dt><i>event</i></dt> +<dd> +reference to the event object (QEvent) +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +flag indicating, whether the event was handled (boolean) +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="clearSavedHistories" ID="clearSavedHistories"></a> +<h2>clearSavedHistories</h2> +<b>clearSavedHistories</b>(<i>self</i>) + +<p> + Function to clear the saved history lists. +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.Testing.__init__.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,91 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.__init__</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.Testing.__init__</h1> + +<p> +Package implementing testing functionality and interface to various test +frameworks. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Functions</h3> + +<table> + +<tr> +<td><a href="#isLanguageSupported">isLanguageSupported</a></td> +<td>Function to check, if the given programming language is supported by any testing framework.</td> +</tr> +<tr> +<td><a href="#supportedLanguages">supportedLanguages</a></td> +<td>Function to get a list of supported programming languages.</td> +</tr> +</table> +<hr /> +<hr /> +<a NAME="isLanguageSupported" ID="isLanguageSupported"></a> +<h2>isLanguageSupported</h2> +<b>isLanguageSupported</b>(<i>language</i>) + +<p> + Function to check, if the given programming language is supported by any + testing framework. +</p> +<dl> + +<dt><i>language</i> (str)</dt> +<dd> +programming language +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +flag indicating support +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="supportedLanguages" ID="supportedLanguages"></a> +<h2>supportedLanguages</h2> +<b>supportedLanguages</b>(<i></i>) + +<p> + Function to get a list of supported programming languages. +</p> +<dl> +<dt>Return:</dt> +<dd> +list of supported programming languages +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of str +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/eric7.eric7_testing.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,82 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.eric7_testing</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.eric7_testing</h1> + +<p> +eric testing. +</p> +<p> +This is the main Python script that performs the necessary initialization +of the testing module and starts the Qt event loop. This is a standalone +version of the integrated testing module. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Functions</h3> + +<table> + +<tr> +<td><a href="#createMainWidget">createMainWidget</a></td> +<td>Function to create the main widget.</td> +</tr> +<tr> +<td><a href="#main">main</a></td> +<td>Main entry point into the application.</td> +</tr> +</table> +<hr /> +<hr /> +<a NAME="createMainWidget" ID="createMainWidget"></a> +<h2>createMainWidget</h2> +<b>createMainWidget</b>(<i>argv</i>) + +<p> + Function to create the main widget. +</p> +<dl> + +<dt><i>argv</i> (list of str)</dt> +<dd> +list of commandline parameters +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +reference to the main widget +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +QWidget +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="main" ID="main"></a> +<h2>main</h2> +<b>main</b>(<i></i>) + +<p> + Main entry point into the application. +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- a/eric7/Documentation/Source/eric7.eric7_unittest.html Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -<!DOCTYPE html> -<html><head> -<title>eric7.eric7_unittest</title> -<meta charset="UTF-8"> -<link rel="stylesheet" href="styles.css"> -</head> -<body> -<a NAME="top" ID="top"></a> -<h1>eric7.eric7_unittest</h1> - -<p> -eric Unittest. -</p> -<p> -This is the main Python script that performs the necessary initialization -of the unittest module and starts the Qt event loop. This is a standalone -version of the integrated unittest module. -</p> -<h3>Global Attributes</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Classes</h3> - -<table> -<tr><td>None</td></tr> -</table> -<h3>Functions</h3> - -<table> - -<tr> -<td><a href="#createMainWidget">createMainWidget</a></td> -<td>Function to create the main widget.</td> -</tr> -<tr> -<td><a href="#main">main</a></td> -<td>Main entry point into the application.</td> -</tr> -</table> -<hr /> -<hr /> -<a NAME="createMainWidget" ID="createMainWidget"></a> -<h2>createMainWidget</h2> -<b>createMainWidget</b>(<i>argv</i>) - -<p> - Function to create the main widget. -</p> -<dl> - -<dt><i>argv</i></dt> -<dd> -list of commandline parameters (list of strings) -</dd> -</dl> -<dl> -<dt>Return:</dt> -<dd> -reference to the main widget (QWidget) -</dd> -</dl> -<div align="right"><a href="#top">Up</a></div> -<hr /> -<hr /> -<a NAME="main" ID="main"></a> -<h2>main</h2> -<b>main</b>(<i></i>) - -<p> - Main entry point into the application. -</p> -<div align="right"><a href="#top">Up</a></div> -<hr /> -</body></html> \ No newline at end of file
--- a/eric7/Documentation/Source/index-eric7.PyUnit.html Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -<!DOCTYPE html> -<html><head> -<title>eric7.PyUnit</title> -<meta charset="UTF-8"> -<link rel="stylesheet" href="styles.css"> -</head> -<body> -<h1>eric7.PyUnit</h1> - -<p> -Package implementing an interface to the pyunit unittest package. -</p> -<p> -The package consist of a single dialog, which may be called as a -standalone version using the eric7_unittest script or from within the eric -IDE. If it is called from within eric, it has the additional function to -open a source file that failed a test. -</p> - - -<h3>Modules</h3> -<table> - -<tr> -<td><a href="eric7.PyUnit.UnittestDialog.html">UnittestDialog</a></td> -<td>Module implementing the UI to the pyunit package.</td> -</tr> -</table> -</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/index-eric7.Testing.Interfaces.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing.Interfaces</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<h1>eric7.Testing.Interfaces</h1> + +<p> +Package containg the various test framework interfaces. +</p> + + +<h3>Modules</h3> +<table> + +<tr> +<td><a href="eric7.Testing.Interfaces.PytestExecutor.html">PytestExecutor</a></td> +<td>Module implementing the executor for the 'pytest' framework.</td> +</tr> +<tr> +<td><a href="eric7.Testing.Interfaces.PytestRunner.html">PytestRunner</a></td> +<td>Module implementing the test runner script for the 'pytest' framework.</td> +</tr> +<tr> +<td><a href="eric7.Testing.Interfaces.TestExecutorBase.html">TestExecutorBase</a></td> +<td>Module implementing the executor base class for the various testing frameworks and supporting classes.</td> +</tr> +<tr> +<td><a href="eric7.Testing.Interfaces.TestFrameworkRegistry.html">TestFrameworkRegistry</a></td> +<td>Module implementing a simple registry containing the available test framework interfaces.</td> +</tr> +<tr> +<td><a href="eric7.Testing.Interfaces.UnittestExecutor.html">UnittestExecutor</a></td> +<td>Module implementing the executor for the standard 'unittest' framework.</td> +</tr> +<tr> +<td><a href="eric7.Testing.Interfaces.UnittestRunner.html">UnittestRunner</a></td> +<td>Module implementing the test runner script for the 'unittest' framework.</td> +</tr> +</table> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Documentation/Source/index-eric7.Testing.html Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.Testing</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<h1>eric7.Testing</h1> + +<p> +Package implementing testing functionality and interface to various test +frameworks. +</p> + +<h3>Packages</h3> +<table> + +<tr> +<td><a href="index-eric7.Testing.Interfaces.html">Interfaces</a></td> +<td>Package containg the various test framework interfaces.</td> +</tr> +</table> + +<h3>Modules</h3> +<table> + +<tr> +<td><a href="eric7.Testing.TestResultsTree.html">TestResultsTree</a></td> +<td>Module implementing a tree view and associated model to show the test result data.</td> +</tr> +<tr> +<td><a href="eric7.Testing.TestingWidget.html">TestingWidget</a></td> +<td>Module implementing a widget to orchestrate unit test execution.</td> +</tr> +<tr> +<td><a href="eric7.Testing.__init__.html">Testing</a></td> +<td>Package implementing testing functionality and interface to various test frameworks.</td> +</tr> +</table> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/EricNetwork/EricJsonStreamReader.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a JSON based reader class. +""" + +import json + +from PyQt6.QtCore import pyqtSignal, pyqtSlot +from PyQt6.QtNetwork import QTcpServer, QHostAddress + +from EricWidgets import EricMessageBox + +import Preferences +import Utilities + + +class EricJsonReader(QTcpServer): + """ + Class implementing a JSON based reader class. + + The reader is responsible for opening a socket to listen for writer + connections. + + @signal dataReceived(object) emitted after a data object was received + """ + dataReceived = pyqtSignal(object) + + def __init__(self, name="", ip=None, parent=None): + """ + Constructor + + @param name name of the server (used for output only) + @type str + @param ip IP address to listen at + @type str + @param parent parent object + @type QObject + """ + super().__init__(parent) + + self.__name = name + self.__connection = None + + # setup the network interface + if ip is None: + networkInterface = Preferences.getDebugger("NetworkInterface") + if networkInterface == "all" or '.' in networkInterface: + # IPv4 + self.__hostAddress = '127.0.0.1' + else: + # IPv6 + self.__hostAddress = '::1' + else: + self.__hostAddress = ip + self.listen(QHostAddress(self.__hostAddress)) + + self.newConnection.connect(self.handleNewConnection) + + ## Note: Need the port if writer is started external in debugger. + print('JSON reader ({1}) listening on: {0:d}' # __IGNORE_WARNING__ + .format(self.serverPort(), self.__name)) + + def address(self): + """ + Public method to get the host address. + + @return host address + @rtype str + """ + return self.__hostAddress + + def port(self): + """ + Public method to get the port number to connect to. + + @return port number + @rtype int + """ + return self.serverPort() + + @pyqtSlot() + def handleNewConnection(self): + """ + Public slot for new incoming connections from a writer. + """ + connection = self.nextPendingConnection() + if not connection.isValid(): + return + + if self.__connection is not None: + self.__connection.close() + + self.__connection = connection + + connection.readyRead.connect(self.__receiveJson) + connection.disconnected.connect(self.__handleDisconnect) + + @pyqtSlot() + def __handleDisconnect(self): + """ + Private slot handling a disconnect of the writer. + """ + if self.__connection is not None: + self.__receiveJson() # read all buffered data first + self.__connection.close() + + self.__connection = None + + @pyqtSlot() + def __receiveJson(self): + """ + Private slot handling received data from the writer. + """ + while self.__connection and self.__connection.canReadLine(): + dataStr = self.__connection.readLine() + jsonLine = bytes(dataStr).decode("utf-8", 'backslashreplace') + + #- print("JSON Reader ({0}): {1}".format(self.__name, jsonLine)) + #- this is for debugging only + + try: + data = json.loads(jsonLine.strip()) + except (TypeError, ValueError) as err: + EricMessageBox.critical( + None, + self.tr("JSON Protocol Error"), + self.tr("""<p>The data received from the writer""" + """ could not be decoded. Please report""" + """ this issue with the received data to the""" + """ eric bugs email address.</p>""" + """<p>Error: {0}</p>""" + """<p>Data:<br/>{1}</p>""").format( + str(err), Utilities.html_encode(jsonLine.strip())), + EricMessageBox.Ok) + return + + self.dataReceived.emit(data)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/EricNetwork/EricJsonStreamWriter.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a JSON based writer class. +""" + +import json +import socket + + +class EricJsonWriter: + """ + Class implementing a JSON based writer class. + """ + def __init__(self, host, port): + """ + Constructor + + @param host IP address the reader is listening on + @type str + @param port port the reader is listening on + @type int + """ + self.__connection = socket.create_connection((host, port)) + + def write(self, data): + """ + Public method to send JSON serializable data. + + @param data JSON serializable object to be sent + @type object + """ + dataStr = json.dumps(data) + '\n' + self.__connection.sendall(dataStr.encode('utf8', 'backslashreplace')) + + def close(self): + """ + Public method to close the stream. + """ + self.__connection.close()
--- a/eric7/PyUnit/UnittestDialog.py Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1506 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2002 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing the UI to the pyunit package. -""" - -import unittest -import sys -import time -import re -import os -import contextlib - -from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QEvent, QFileInfo -from PyQt6.QtGui import QColor -from PyQt6.QtWidgets import ( - QWidget, QDialog, QApplication, QDialogButtonBox, QListWidgetItem, - QComboBox, QTreeWidgetItem -) - -from EricWidgets.EricApplication import ericApp -from EricWidgets import EricMessageBox -from EricWidgets.EricMainWindow import EricMainWindow -from EricWidgets.EricPathPicker import EricPathPickerModes - -from .Ui_UnittestDialog import Ui_UnittestDialog - -import UI.PixmapCache - -import Preferences - -from Globals import ( - recentNameUnittestDiscoverHistory, recentNameUnittestFileHistory, - recentNameUnittestTestnameHistory -) - - -class UnittestDialog(QWidget, Ui_UnittestDialog): - """ - Class implementing the UI to the pyunit package. - - @signal unittestFile(str, int, bool) emitted to show the source of a - unittest file - @signal unittestStopped() emitted after a unit test was run - """ - unittestFile = pyqtSignal(str, int, bool) - unittestStopped = pyqtSignal() - - TestCaseNameRole = Qt.ItemDataRole.UserRole - TestCaseFileRole = Qt.ItemDataRole.UserRole + 1 - - ErrorsInfoRole = Qt.ItemDataRole.UserRole - - SkippedColorDarkTheme = QColor("#00aaff") - FailedExpectedColorDarkTheme = QColor("#ccaaff") - SucceededUnexpectedColorDarkTheme = QColor("#ff99dd") - SkippedColorLightTheme = QColor("#0000ff") - FailedExpectedColorLightTheme = QColor("#7700bb") - SucceededUnexpectedColorLightTheme = QColor("#ff0000") - - def __init__(self, prog=None, dbs=None, ui=None, parent=None, name=None): - """ - Constructor - - @param prog filename of the program to open - @type str - @param dbs reference to the debug server object. It is an indication - whether we were called from within the eric IDE. - @type DebugServer - @param ui reference to the UI object - @type UserInterface - @param parent parent widget of this dialog - @type QWidget - @param name name of this dialog - @type str - """ - super().__init__(parent) - if name: - self.setObjectName(name) - self.setupUi(self) - - self.clearHistoriesButton.setIcon( - UI.PixmapCache.getIcon("clearPrivateData")) - - self.testsuitePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) - self.testsuitePicker.setInsertPolicy( - QComboBox.InsertPolicy.InsertAtTop) - self.testsuitePicker.setSizeAdjustPolicy( - QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon) - - self.discoveryPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) - self.discoveryPicker.setInsertPolicy( - QComboBox.InsertPolicy.InsertAtTop) - self.discoveryPicker.setSizeAdjustPolicy( - QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon) - - self.testComboBox.lineEdit().setClearButtonEnabled(True) - - self.discoverButton = self.buttonBox.addButton( - self.tr("Discover"), QDialogButtonBox.ButtonRole.ActionRole) - self.discoverButton.setToolTip(self.tr( - "Discover tests")) - self.discoverButton.setWhatsThis(self.tr( - """<b>Discover</b>""" - """<p>This button starts a discovery of available tests.</p>""")) - self.startButton = self.buttonBox.addButton( - self.tr("Start"), QDialogButtonBox.ButtonRole.ActionRole) - - self.startButton.setToolTip(self.tr( - "Start the selected testsuite")) - self.startButton.setWhatsThis(self.tr( - """<b>Start Test</b>""" - """<p>This button starts the selected testsuite.</p>""")) - - self.startFailedButton = self.buttonBox.addButton( - self.tr("Rerun Failed"), QDialogButtonBox.ButtonRole.ActionRole) - self.startFailedButton.setToolTip( - self.tr("Reruns failed tests of the selected testsuite")) - self.startFailedButton.setWhatsThis(self.tr( - """<b>Rerun Failed</b>""" - """<p>This button reruns all failed tests of the selected""" - """ testsuite.</p>""")) - - self.stopButton = self.buttonBox.addButton( - self.tr("Stop"), QDialogButtonBox.ButtonRole.ActionRole) - self.stopButton.setToolTip(self.tr("Stop the running unittest")) - self.stopButton.setWhatsThis(self.tr( - """<b>Stop Test</b>""" - """<p>This button stops a running unittest.</p>""")) - - self.discoverButton.setEnabled(False) - self.stopButton.setEnabled(False) - self.startButton.setDefault(True) - self.startFailedButton.setEnabled(False) - - self.__dbs = dbs - self.__forProject = False - - self.setWindowFlags( - self.windowFlags() | - Qt.WindowType.WindowContextHelpButtonHint - ) - self.setWindowIcon(UI.PixmapCache.getIcon("eric")) - self.setWindowTitle(self.tr("Unittest")) - if dbs: - self.ui = ui - - self.debuggerCheckBox.setChecked(True) - - # virtual environment manager is only used in the integrated - # variant - self.__venvManager = ericApp().getObject("VirtualEnvManager") - self.__populateVenvComboBox() - self.__venvManager.virtualEnvironmentAdded.connect( - self.__populateVenvComboBox) - self.__venvManager.virtualEnvironmentRemoved.connect( - self.__populateVenvComboBox) - self.__venvManager.virtualEnvironmentChanged.connect( - self.__populateVenvComboBox) - else: - self.__venvManager = None - self.debuggerCheckBox.setVisible(False) - self.venvComboBox.setVisible(bool(self.__venvManager)) - self.venvLabel.setVisible(bool(self.__venvManager)) - - self.__setProgressColor("green") - self.progressLed.setDarkFactor(150) - self.progressLed.off() - - self.discoverHistory = [] - self.fileHistory = [] - self.testNameHistory = [] - self.running = False - self.savedModulelist = None - self.savedSysPath = sys.path - self.savedCwd = os.getcwd() - - self.rxPatterns = [ - self.tr("^Failure: "), - self.tr("^Error: "), - # These are for untranslated/partially translated situations - "^Failure: ", - "^Error: ", - ] - - self.__failedTests = set() - - # now connect the debug server signals if called from the eric IDE - if self.__dbs: - self.__dbs.utDiscovered.connect(self.__UTDiscovered) - self.__dbs.utPrepared.connect(self.__UTPrepared) - self.__dbs.utFinished.connect(self.__setStoppedMode) - self.__dbs.utStartTest.connect(self.testStarted) - self.__dbs.utStopTest.connect(self.testFinished) - self.__dbs.utTestFailed.connect(self.testFailed) - self.__dbs.utTestErrored.connect(self.testErrored) - self.__dbs.utTestSkipped.connect(self.testSkipped) - self.__dbs.utTestFailedExpected.connect(self.testFailedExpected) - self.__dbs.utTestSucceededUnexpected.connect( - self.testSucceededUnexpected) - - self.__editors = [] - - self.__loadRecent() - - self.insertProg(prog) - self.insertTestName("") - - self.clearHistoriesButton.clicked.connect(self.clearRecent) - - def keyPressEvent(self, evt): - """ - Protected slot to handle key press events. - - @param evt key press event to handle (QKeyEvent) - """ - if evt.key() == Qt.Key.Key_Escape and self.__dbs: - self.close() - - def __populateVenvComboBox(self): - """ - Private method to (re-)populate the virtual environments selector. - """ - currentText = self.venvComboBox.currentText() - self.venvComboBox.clear() - self.venvComboBox.addItem("") - self.venvComboBox.addItems( - sorted(self.__venvManager.getVirtualenvNames())) - index = self.venvComboBox.findText(currentText) - if index < 0: - index = 0 - self.venvComboBox.setCurrentIndex(index) - - def __setProgressColor(self, color): - """ - Private method to set the color of the progress color label. - - @param color colour to be shown (string) - """ - self.progressLed.setColor(QColor(color)) - - def setProjectMode(self, forProject): - """ - Public method to set the project mode of the dialog. - - @param forProject flag indicating to run for the open project - @type bool - """ - self.__forProject = forProject - if forProject: - project = ericApp().getObject("Project") - if project.isOpen(): - self.insertDiscovery(project.getProjectPath()) - else: - self.insertDiscovery("") - else: - self.insertDiscovery("") - - self.discoveryList.clear() - self.tabWidget.setCurrentIndex(0) - - def insertDiscovery(self, start): - """ - Public slot to insert the discovery start directory into the - discoveryPicker object. - - @param start start directory name to be inserted - @type str - """ - current = self.discoveryPicker.currentText() - - # prepend the given directory to the discovery picker - if start is None: - start = "" - if start in self.discoverHistory: - self.discoverHistory.remove(start) - self.discoverHistory.insert(0, start) - self.discoveryPicker.clear() - self.discoveryPicker.addItems(self.discoverHistory) - - if current: - self.discoveryPicker.setText(current) - - def insertProg(self, prog): - """ - Public slot to insert the filename prog into the testsuitePicker - object. - - @param prog filename to be inserted (string) - """ - current = self.testsuitePicker.currentText() - - # prepend the selected file to the testsuite picker - if prog is None: - prog = "" - if prog in self.fileHistory: - self.fileHistory.remove(prog) - self.fileHistory.insert(0, prog) - self.testsuitePicker.clear() - self.testsuitePicker.addItems(self.fileHistory) - - if current: - self.testsuitePicker.setText(current) - - def insertTestName(self, testName): - """ - Public slot to insert a test name into the testComboBox object. - - @param testName name of the test to be inserted (string) - """ - current = self.testComboBox.currentText() - - # prepend the selected file to the testsuite combobox - if testName is None: - testName = "" - if testName in self.testNameHistory: - self.testNameHistory.remove(testName) - self.testNameHistory.insert(0, testName) - self.testComboBox.clear() - self.testComboBox.addItems(self.testNameHistory) - - if current: - self.testComboBox.setCurrentText(current) - - @pyqtSlot() - def on_testsuitePicker_aboutToShowPathPickerDialog(self): - """ - Private slot called before the test suite selection dialog is shown. - """ - if self.__dbs: - py3Extensions = ' '.join( - ["*{0}".format(ext) - for ext in self.__dbs.getExtensions('Python3')] - ) - fileFilter = self.tr( - "Python3 Files ({0});;All Files (*)" - ).format(py3Extensions) - else: - fileFilter = self.tr("Python Files (*.py);;All Files (*)") - self.testsuitePicker.setFilters(fileFilter) - - defaultDirectory = Preferences.getMultiProject("Workspace") - if not defaultDirectory: - defaultDirectory = os.path.expanduser("~") - if self.__dbs: - project = ericApp().getObject("Project") - if self.__forProject and project.isOpen(): - defaultDirectory = project.getProjectPath() - self.testsuitePicker.setDefaultDirectory(defaultDirectory) - - @pyqtSlot(str) - def on_testsuitePicker_pathSelected(self, suite): - """ - Private slot called after a test suite has been selected. - - @param suite file name of the test suite - @type str - """ - self.insertProg(suite) - - @pyqtSlot(str) - def on_testsuitePicker_editTextChanged(self, path): - """ - Private slot handling changes of the test suite path. - - @param path path of the test suite file - @type str - """ - self.startFailedButton.setEnabled(False) - - @pyqtSlot(bool) - def on_discoverCheckBox_toggled(self, checked): - """ - Private slot handling state changes of the 'discover' checkbox. - - @param checked state of the checkbox - @type bool - """ - self.discoverButton.setEnabled(checked) - self.discoveryList.clear() - - if not bool(self.discoveryPicker.currentText()): - if self.__forProject: - project = ericApp().getObject("Project") - if project.isOpen(): - self.insertDiscovery(project.getProjectPath()) - return - - self.insertDiscovery(Preferences.getMultiProject("Workspace")) - - def on_buttonBox_clicked(self, button): - """ - Private slot called by a button of the button box clicked. - - @param button button that was clicked (QAbstractButton) - """ - if button == self.discoverButton: - self.__discover() - self.__saveRecent() - elif button == self.startButton: - self.startTests() - self.__saveRecent() - elif button == self.stopButton: - self.__stopTests() - elif button == self.startFailedButton: - self.startTests(failedOnly=True) - - def __loadRecent(self): - """ - Private method to load the most recently used lists. - """ - Preferences.Prefs.rsettings.sync() - - # 1. discovery history - self.discoverHistory = [] - rs = Preferences.Prefs.rsettings.value( - recentNameUnittestDiscoverHistory) - if rs is not None: - recent = [f - for f in Preferences.toList(rs) - if QFileInfo(f).exists()] - self.discoverHistory = recent[ - :Preferences.getDebugger("RecentNumber")] - - # 2. test file history - self.fileHistory = [] - rs = Preferences.Prefs.rsettings.value( - recentNameUnittestFileHistory) - if rs is not None: - recent = [f - for f in Preferences.toList(rs) - if QFileInfo(f).exists()] - self.fileHistory = recent[ - :Preferences.getDebugger("RecentNumber")] - - # 3. test name history - self.testNameHistory = [] - rs = Preferences.Prefs.rsettings.value( - recentNameUnittestTestnameHistory) - if rs is not None: - recent = [n for n in Preferences.toList(rs) if n] - self.testNameHistory = recent[ - :Preferences.getDebugger("RecentNumber")] - - def __saveRecent(self): - """ - Private method to save the most recently used lists. - """ - Preferences.Prefs.rsettings.setValue( - recentNameUnittestDiscoverHistory, self.discoverHistory) - Preferences.Prefs.rsettings.setValue( - recentNameUnittestFileHistory, self.fileHistory) - Preferences.Prefs.rsettings.setValue( - recentNameUnittestTestnameHistory, self.testNameHistory) - - Preferences.Prefs.rsettings.sync() - - @pyqtSlot() - def clearRecent(self): - """ - Public slot to clear the recently used lists. - """ - # clear histories - self.discoverHistory = [] - self.fileHistory = [] - self.testNameHistory = [] - - # clear widgets with histories - self.discoveryPicker.clear() - self.testsuitePicker.clear() - self.testComboBox.clear() - - # sync histories - self.__saveRecent() - - @pyqtSlot() - def __discover(self): - """ - Private slot to discover unit test but don't run them. - """ - if self.running: - return - - self.discoveryList.clear() - - discoveryStart = self.discoveryPicker.currentText() - self.insertDiscovery(discoveryStart) - self.sbLabel.setText(self.tr("Discovering Tests")) - QApplication.processEvents() - - self.testName = self.tr("Unittest with auto-discovery") - if self.__dbs: - venvName = self.venvComboBox.currentText() - - # we are cooperating with the eric IDE - project = ericApp().getObject("Project") - if self.__forProject: - mainScript = project.getMainScript(True) - clientType = project.getProjectLanguage() - if mainScript: - workdir = os.path.dirname(os.path.abspath(mainScript)) - else: - workdir = project.getProjectPath() - sysPath = [workdir] - if not discoveryStart: - discoveryStart = workdir - else: - if not discoveryStart: - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr("You must enter a start directory for" - " auto-discovery.")) - return - - workdir = "" - clientType = "Python3" - sysPath = [] - self.__dbs.remoteUTDiscover(clientType, self.__forProject, - venvName, sysPath, workdir, - discoveryStart) - else: - # we are running as an application - if not discoveryStart: - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr("You must enter a start directory for" - " auto-discovery.")) - return - - if discoveryStart: - sys.path = ( - [os.path.abspath(discoveryStart)] + - self.savedSysPath - ) - - # clean up list of imported modules to force a reimport upon - # running the test - if self.savedModulelist: - for modname in list(sys.modules.keys()): - if modname not in self.savedModulelist: - # delete it - del(sys.modules[modname]) - self.savedModulelist = sys.modules.copy() - - # now try to discover the testsuite - os.chdir(discoveryStart) - try: - testLoader = unittest.TestLoader() - test = testLoader.discover(discoveryStart) - if hasattr(testLoader, "errors") and bool(testLoader.errors): - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr( - "<p>Unable to discover tests.</p>" - "<p>{0}</p>" - ).format("<br/>".join(testLoader.errors) - .replace("\n", "<br/>")) - ) - self.sbLabel.clear() - else: - testsList = self.__assembleTestCasesList( - test, discoveryStart) - self.__populateDiscoveryResults(testsList) - self.sbLabel.setText( - self.tr("Discovered %n Test(s)", "", - len(testsList))) - self.tabWidget.setCurrentIndex(0) - except Exception: - exc_type, exc_value, exc_tb = sys.exc_info() - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr( - "<p>Unable to discover tests.</p>" - "<p>{0}<br/>{1}</p>") - .format(str(exc_type), - str(exc_value).replace("\n", "<br/>")) - ) - self.sbLabel.clear() - - sys.path = self.savedSysPath - - def __assembleTestCasesList(self, suite, start): - """ - Private method to assemble a list of test cases included in a test - suite. - - @param suite test suite to be inspected - @type unittest.TestSuite - @param start name of directory discovery was started at - @type str - @return list of tuples containing the test case ID, a short description - and the path of the test file name - @rtype list of tuples of (str, str, str) - """ - testCases = [] - for test in suite: - if isinstance(test, unittest.TestSuite): - testCases.extend(self.__assembleTestCasesList(test, start)) - else: - testId = test.id() - if ( - "ModuleImportFailure" not in testId and - "LoadTestsFailure" not in testId and - "_FailedTest" not in testId - ): - filename = os.path.join( - start, - test.__module__.replace(".", os.sep) + ".py") - testCases.append( - (test.id(), test.shortDescription(), filename) - ) - return testCases - - def __findDiscoveryItem(self, modulePath): - """ - Private method to find an item given the module path. - - @param modulePath path of the module in dotted notation - @type str - @return reference to the item or None - @rtype QTreeWidgetItem or None - """ - itm = self.discoveryList.topLevelItem(0) - while itm is not None: - if itm.data(0, UnittestDialog.TestCaseNameRole) == modulePath: - return itm - itm = self.discoveryList.itemBelow(itm) - - return None - - def __populateDiscoveryResults(self, tests): - """ - Private method to populate the test discovery results list. - - @param tests list of tuples containing the discovery results - @type list of tuples of (str, str, str) - """ - for test, _testDescription, filename in tests: - testPath = test.split(".") - pitm = None - for index in range(1, len(testPath) + 1): - modulePath = ".".join(testPath[:index]) - itm = self.__findDiscoveryItem(modulePath) - if itm is not None: - pitm = itm - else: - if pitm is None: - itm = QTreeWidgetItem(self.discoveryList, - [testPath[index - 1]]) - else: - itm = QTreeWidgetItem(pitm, - [testPath[index - 1]]) - pitm.setExpanded(True) - itm.setFlags(Qt.ItemFlag.ItemIsUserCheckable | - Qt.ItemFlag.ItemIsEnabled) - itm.setCheckState(0, Qt.CheckState.Unchecked) - itm.setData(0, UnittestDialog.TestCaseNameRole, modulePath) - if ( - os.path.splitext(os.path.basename(filename))[0] == - itm.text(0) - ): - itm.setData(0, UnittestDialog.TestCaseFileRole, - filename) - elif pitm: - fn = pitm.data(0, UnittestDialog.TestCaseFileRole) - if fn: - itm.setData(0, UnittestDialog.TestCaseFileRole, fn) - pitm = itm - - def __selectedTestCases(self, parent=None): - """ - Private method to assemble the list of selected test cases and suites. - - @param parent reference to the parent item - @type QTreeWidgetItem - @return list of selected test cases - @rtype list of str - """ - selectedTests = [] - itemsList = [ - self.discoveryList.topLevelItem(index) - for index in range(self.discoveryList.topLevelItemCount()) - ] if parent is None else [ - parent.child(index) - for index in range(parent.childCount()) - ] - - for itm in itemsList: - if ( - itm.checkState(0) == Qt.CheckState.Checked and - itm.childCount() == 0 - ): - selectedTests.append( - itm.data(0, UnittestDialog.TestCaseNameRole)) - if itm.childCount(): - # recursively check children - selectedTests.extend(self.__selectedTestCases(itm)) - - return selectedTests - - def __UTDiscovered(self, testCases, exc_type, exc_value): - """ - Private slot to handle the utDiscovered signal. - - If the unittest suite was loaded successfully, we ask the - client to run the test suite. - - @param testCases list of detected test cases - @type str - @param exc_type exception type occured during discovery - @type str - @param exc_value value of exception occured during discovery - @type str - """ - if testCases: - self.__populateDiscoveryResults(testCases) - self.sbLabel.setText( - self.tr("Discovered %n Test(s)", "", - len(testCases))) - self.tabWidget.setCurrentIndex(0) - else: - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr("<p>Unable to discover tests.</p>" - "<p>{0}<br/>{1}</p>") - .format(exc_type, exc_value.replace("\n", "<br/>")) - ) - - @pyqtSlot(QTreeWidgetItem, int) - def on_discoveryList_itemChanged(self, item, column): - """ - Private slot handling the user checking or unchecking an item. - - @param item reference to the item - @type QTreeWidgetItem - @param column changed column - @type int - """ - if column == 0: - for index in range(item.childCount()): - item.child(index).setCheckState(0, item.checkState(0)) - - @pyqtSlot(QTreeWidgetItem, int) - def on_discoveryList_itemDoubleClicked(self, item, column): - """ - Private slot handling the user double clicking an item. - - @param item reference to the item - @type QTreeWidgetItem - @param column column of the double click - @type int - """ - if item: - filename = item.data(0, UnittestDialog.TestCaseFileRole) - if filename: - if self.__dbs: - # running as part of eric IDE - self.unittestFile.emit(filename, 1, False) - else: - self.__openEditor(filename, 1) - - @pyqtSlot() - def startTests(self, failedOnly=False): - """ - Public slot to start the test. - - @param failedOnly flag indicating to run only failed tests (boolean) - """ - if self.running: - return - - discover = self.discoverCheckBox.isChecked() - if discover: - discoveryStart = self.discoveryPicker.currentText() - testFileName = "" - testName = "" - - if discoveryStart: - self.insertDiscovery(discoveryStart) - else: - discoveryStart = "" - testFileName = self.testsuitePicker.currentText() - testName = self.testComboBox.currentText() - if testName: - self.insertTestName(testName) - if testFileName and not testName: - testName = "suite" - - if not discover and not testFileName and not testName: - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr("You must select auto-discovery or enter a test suite" - " file or a dotted test name.")) - return - - # prepend the selected file to the testsuite combobox - self.insertProg(testFileName) - self.sbLabel.setText(self.tr("Preparing Testsuite")) - QApplication.processEvents() - - if discover: - self.testName = self.tr("Unittest with auto-discovery") - else: - # build the module name from the filename without extension - if testFileName: - self.testName = os.path.splitext( - os.path.basename(testFileName))[0] - elif testName: - self.testName = testName - else: - self.testName = self.tr("<Unnamed Test>") - - if failedOnly: - testCases = [] - else: - testCases = self.__selectedTestCases() - - if not testCases and self.discoveryList.topLevelItemCount(): - ok = EricMessageBox.yesNo( - self, - self.tr("Unittest"), - self.tr("""No test case has been selected. Shall all""" - """ test cases be run?""")) - if not ok: - return - - if self.__dbs: - venvName = self.venvComboBox.currentText() - - # we are cooperating with the eric IDE - project = ericApp().getObject("Project") - if self.__forProject: - mainScript = project.getMainScript(True) - clientType = project.getProjectLanguage() - if mainScript: - workdir = os.path.dirname(os.path.abspath(mainScript)) - coverageFile = os.path.splitext(mainScript)[0] - else: - workdir = project.getProjectPath() - coverageFile = os.path.join(discoveryStart, "unittest") - sysPath = [workdir] - if discover and not discoveryStart: - discoveryStart = workdir - else: - if discover: - if not discoveryStart: - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr("You must enter a start directory for" - " auto-discovery.")) - return - - coverageFile = os.path.join(discoveryStart, "unittest") - workdir = "" - clientType = "Python3" - elif testFileName: - mainScript = os.path.abspath(testFileName) - workdir = os.path.dirname(mainScript) - clientType = "Python3" - coverageFile = os.path.splitext(mainScript)[0] - else: - coverageFile = os.path.abspath("unittest") - workdir = "" - clientType = "Python3" - sysPath = [] - if failedOnly and self.__failedTests: - failed = list(self.__failedTests) - if discover: - workdir = discoveryStart - discover = False - else: - failed = [] - self.__failedTests = set() - self.__dbs.remoteUTPrepare( - testFileName, self.testName, testName, failed, - self.coverageCheckBox.isChecked(), coverageFile, - self.coverageEraseCheckBox.isChecked(), clientType=clientType, - forProject=self.__forProject, workdir=workdir, - venvName=venvName, syspath=sysPath, - discover=discover, discoveryStart=discoveryStart, - testCases=testCases, debug=self.debuggerCheckBox.isChecked()) - else: - # we are running as an application - if discover and not discoveryStart: - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr("You must enter a start directory for" - " auto-discovery.")) - return - - if testFileName: - sys.path = ( - [os.path.dirname(os.path.abspath(testFileName))] + - self.savedSysPath - ) - elif discoveryStart: - sys.path = ( - [os.path.abspath(discoveryStart)] + - self.savedSysPath - ) - - # clean up list of imported modules to force a reimport upon - # running the test - if self.savedModulelist: - for modname in list(sys.modules.keys()): - if modname not in self.savedModulelist: - # delete it - del(sys.modules[modname]) - self.savedModulelist = sys.modules.copy() - - os.chdir(self.savedCwd) - - # now try to generate the testsuite - try: - testLoader = unittest.TestLoader() - if failedOnly and self.__failedTests: - failed = list(self.__failedTests) - if discover: - os.chdir(discoveryStart) - discover = False - else: - failed = [] - if discover: - if testCases: - test = testLoader.loadTestsFromNames(testCases) - else: - test = testLoader.discover(discoveryStart) - else: - if testFileName: - module = __import__(self.testName) - else: - module = None - if failedOnly and self.__failedTests: - if module: - failed = [t.split(".", 1)[1] - for t in self.__failedTests] - else: - failed = list(self.__failedTests) - test = testLoader.loadTestsFromNames( - failed, module) - else: - test = testLoader.loadTestsFromName( - testName, module) - except Exception: - exc_type, exc_value, exc_tb = sys.exc_info() - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr( - "<p>Unable to run test <b>{0}</b>.</p>" - "<p>{1}<br/>{2}</p>") - .format(self.testName, str(exc_type), - str(exc_value).replace("\n", "<br/>")) - ) - return - - # now set up the coverage stuff - if self.coverageCheckBox.isChecked(): - if discover: - covname = os.path.join(discoveryStart, "unittest") - elif testFileName: - covname = os.path.splitext( - os.path.abspath(testFileName))[0] - else: - covname = "unittest" - - from DebugClients.Python.coverage import coverage - cover = coverage(data_file="{0}.coverage".format(covname)) - if self.coverageEraseCheckBox.isChecked(): - cover.erase() - else: - cover = None - - self.testResult = QtTestResult( - self, self.failfastCheckBox.isChecked()) - self.totalTests = test.countTestCases() - if self.totalTests == 0: - EricMessageBox.warning( - self, - self.tr("Unittest"), - self.tr("""No unittest were found. Aborting...""")) - else: - self.__failedTests = set() - self.__setRunningMode() - if cover: - cover.start() - test.run(self.testResult) - if cover: - cover.stop() - cover.save() - self.__setStoppedMode() - sys.path = self.savedSysPath - - def __UTPrepared(self, nrTests, exc_type, exc_value): - """ - Private slot to handle the utPrepared signal. - - If the unittest suite was loaded successfully, we ask the - client to run the test suite. - - @param nrTests number of tests contained in the test suite (integer) - @param exc_type type of exception occured during preparation (string) - @param exc_value value of exception occured during preparation (string) - """ - if nrTests == 0: - EricMessageBox.critical( - self, - self.tr("Unittest"), - self.tr( - "<p>Unable to run test <b>{0}</b>.</p>" - "<p>{1}<br/>{2}</p>") - .format(self.testName, exc_type, - exc_value.replace("\n", "<br/>")) - ) - return - - self.totalTests = nrTests - self.__setRunningMode() - self.__dbs.remoteUTRun(debug=self.debuggerCheckBox.isChecked(), - failfast=self.failfastCheckBox.isChecked()) - - @pyqtSlot() - def __stopTests(self): - """ - Private slot to stop the test. - """ - if self.__dbs: - self.__dbs.remoteUTStop() - elif self.testResult: - self.testResult.stop() - - def on_errorsListWidget_currentTextChanged(self, text): - """ - Private slot to handle the highlighted signal. - - @param text current text (string) - """ - if text: - for pattern in self.rxPatterns: - text = re.sub(pattern, "", text) - - foundItems = self.testsListWidget.findItems( - text, Qt.MatchFlag.MatchExactly) - if len(foundItems) > 0: - itm = foundItems[0] - self.testsListWidget.setCurrentItem(itm) - self.testsListWidget.scrollToItem(itm) - - def __setRunningMode(self): - """ - Private method to set the GUI in running mode. - """ - self.running = True - self.tabWidget.setCurrentIndex(1) - - # reset counters and error infos - self.runCount = 0 - self.failCount = 0 - self.errorCount = 0 - self.skippedCount = 0 - self.expectedFailureCount = 0 - self.unexpectedSuccessCount = 0 - self.remainingCount = self.totalTests - - # reset the GUI - self.progressCounterRunCount.setText(str(self.runCount)) - self.progressCounterRemCount.setText(str(self.remainingCount)) - self.progressCounterFailureCount.setText(str(self.failCount)) - self.progressCounterErrorCount.setText(str(self.errorCount)) - self.progressCounterSkippedCount.setText(str(self.skippedCount)) - self.progressCounterExpectedFailureCount.setText( - str(self.expectedFailureCount)) - self.progressCounterUnexpectedSuccessCount.setText( - str(self.unexpectedSuccessCount)) - - self.errorsListWidget.clear() - self.testsListWidget.clear() - - self.progressProgressBar.setRange(0, self.totalTests) - self.__setProgressColor("green") - self.progressProgressBar.reset() - - self.stopButton.setEnabled(True) - self.startButton.setEnabled(False) - self.startFailedButton.setEnabled(False) - self.stopButton.setDefault(True) - - self.sbLabel.setText(self.tr("Running")) - self.progressLed.on() - QApplication.processEvents() - - self.startTime = time.time() - - def __setStoppedMode(self): - """ - Private method to set the GUI in stopped mode. - """ - self.stopTime = time.time() - self.timeTaken = float(self.stopTime - self.startTime) - self.running = False - - failedAvailable = bool(self.__failedTests) - self.startButton.setEnabled(True) - self.startFailedButton.setEnabled(failedAvailable) - self.stopButton.setEnabled(False) - if failedAvailable: - self.startFailedButton.setDefault(True) - self.startButton.setDefault(False) - else: - self.startFailedButton.setDefault(False) - self.startButton.setDefault(True) - self.sbLabel.setText( - self.tr("Ran %n test(s) in {0:.3f}s", "", self.runCount) - .format(self.timeTaken)) - self.progressLed.off() - - self.unittestStopped.emit() - - self.raise_() - self.activateWindow() - - def testFailed(self, test, exc, testId): - """ - Public method called if a test fails. - - @param test name of the test (string) - @param exc string representation of the exception (string) - @param testId id of the test (string) - """ - self.failCount += 1 - self.progressCounterFailureCount.setText(str(self.failCount)) - itm = QListWidgetItem(self.tr("Failure: {0}").format(test)) - itm.setData(UnittestDialog.ErrorsInfoRole, (test, exc)) - self.errorsListWidget.insertItem(0, itm) - self.__failedTests.add(testId) - - def testErrored(self, test, exc, testId): - """ - Public method called if a test errors. - - @param test name of the test (string) - @param exc string representation of the exception (string) - @param testId id of the test (string) - """ - self.errorCount += 1 - self.progressCounterErrorCount.setText(str(self.errorCount)) - itm = QListWidgetItem(self.tr("Error: {0}").format(test)) - itm.setData(UnittestDialog.ErrorsInfoRole, (test, exc)) - self.errorsListWidget.insertItem(0, itm) - self.__failedTests.add(testId) - - def testSkipped(self, test, reason, testId): - """ - Public method called if a test was skipped. - - @param test name of the test (string) - @param reason reason for skipping the test (string) - @param testId id of the test (string) - """ - self.skippedCount += 1 - self.progressCounterSkippedCount.setText(str(self.skippedCount)) - itm = QListWidgetItem(self.tr(" Skipped: {0}").format(reason)) - if ericApp().usesDarkPalette(): - itm.setForeground(self.SkippedColorDarkTheme) - else: - itm.setForeground(self.SkippedColorLightTheme) - self.testsListWidget.insertItem(1, itm) - - def testFailedExpected(self, test, exc, testId): - """ - Public method called if a test fails as expected. - - @param test name of the test (string) - @param exc string representation of the exception (string) - @param testId id of the test (string) - """ - self.expectedFailureCount += 1 - self.progressCounterExpectedFailureCount.setText( - str(self.expectedFailureCount)) - itm = QListWidgetItem(self.tr(" Expected Failure")) - if ericApp().usesDarkPalette(): - itm.setForeground(self.FailedExpectedColorDarkTheme) - else: - itm.setForeground(self.FailedExpectedColorLightTheme) - self.testsListWidget.insertItem(1, itm) - - def testSucceededUnexpected(self, test, testId): - """ - Public method called if a test succeeds unexpectedly. - - @param test name of the test (string) - @param testId id of the test (string) - """ - self.unexpectedSuccessCount += 1 - self.progressCounterUnexpectedSuccessCount.setText( - str(self.unexpectedSuccessCount)) - itm = QListWidgetItem(self.tr(" Unexpected Success")) - if ericApp().usesDarkPalette(): - itm.setForeground(self.SucceededUnexpectedColorDarkTheme) - else: - itm.setForeground(self.SucceededUnexpectedColorLightTheme) - self.testsListWidget.insertItem(1, itm) - - def testStarted(self, test, doc): - """ - Public method called if a test is about to be run. - - @param test name of the started test (string) - @param doc documentation of the started test (string) - """ - if doc: - self.testsListWidget.insertItem(0, " {0}".format(doc)) - self.testsListWidget.insertItem(0, test) - if self.__dbs is None: - QApplication.processEvents() - - def testFinished(self): - """ - Public method called if a test has finished. - - <b>Note</b>: It is also called if it has already failed or errored. - """ - # update the counters - self.remainingCount -= 1 - self.runCount += 1 - self.progressCounterRunCount.setText(str(self.runCount)) - self.progressCounterRemCount.setText(str(self.remainingCount)) - - # update the progressbar - if self.errorCount: - self.__setProgressColor("red") - elif self.failCount: - self.__setProgressColor("orange") - self.progressProgressBar.setValue(self.runCount) - - def on_errorsListWidget_itemDoubleClicked(self, lbitem): - """ - Private slot called by doubleclicking an errorlist entry. - - It will popup a dialog showing the stacktrace. - If called from eric, an additional button is displayed - to show the python source in an eric source viewer (in - erics main window. - - @param lbitem the listbox item that was double clicked - """ - self.errListIndex = self.errorsListWidget.row(lbitem) - text = lbitem.text() - self.on_errorsListWidget_currentTextChanged(text) - - # get the error info - test, tracebackText = lbitem.data(UnittestDialog.ErrorsInfoRole) - - # now build the dialog - from .Ui_UnittestStacktraceDialog import Ui_UnittestStacktraceDialog - self.dlg = QDialog(self) - ui = Ui_UnittestStacktraceDialog() - ui.setupUi(self.dlg) - self.dlg.traceback = ui.traceback - - ui.showButton = ui.buttonBox.addButton( - self.tr("Show Source"), QDialogButtonBox.ButtonRole.ActionRole) - ui.showButton.clicked.connect(self.__showSource) - - ui.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setDefault(True) - - self.dlg.setWindowTitle(text) - ui.testLabel.setText(test) - ui.traceback.setPlainText(tracebackText) - - # and now fire it up - self.dlg.show() - self.dlg.exec() - - def __showSource(self): - """ - Private slot to show the source of a traceback in an eric editor. - """ - # get the error info - tracebackLines = self.dlg.traceback.toPlainText().splitlines() - # find the last entry matching the pattern - for index in range(len(tracebackLines) - 1, -1, -1): - fmatch = re.search(r'File "(.*?)", line (\d*?),.*', - tracebackLines[index]) - if fmatch: - break - if fmatch: - fn, ln = fmatch.group(1, 2) - if self.__dbs: - # running as part of eric IDE - self.unittestFile.emit(fn, int(ln), True) - else: - self.__openEditor(fn, int(ln)) - - def hasFailedTests(self): - """ - Public method to check, if there are failed tests from the last run. - - @return flag indicating the presence of failed tests (boolean) - """ - return bool(self.__failedTests) - - def __openEditor(self, filename, linenumber): - """ - Private method to open an editor window for the given file. - - Note: This method opens an editor window when the unittest dialog - is called as a standalone application. - - @param filename path of the file to be opened - @type str - @param linenumber line number to place the cursor at - @type int - """ - from QScintilla.MiniEditor import MiniEditor - editor = MiniEditor(filename, "Python3", self) - editor.gotoLine(linenumber) - editor.show() - - self.__editors.append(editor) - - def closeEvent(self, event): - """ - Protected method to handle the close event. - - @param event close event - @type QCloseEvent - """ - event.accept() - - for editor in self.__editors: - with contextlib.suppress(Exception): - editor.close() - - -class QtTestResult(unittest.TestResult): - """ - A TestResult derivative to work with a graphical GUI. - - For more details see pyunit.py of the standard Python distribution. - """ - def __init__(self, parent, failfast): - """ - Constructor - - @param parent reference to the parent widget - @type UnittestDialog - @param failfast flag indicating to stop at the first error - @type bool - """ - super().__init__() - self.parent = parent - self.failfast = failfast - - def addFailure(self, test, err): - """ - Public method called if a test failed. - - @param test reference to the test object - @param err error traceback - """ - super().addFailure(test, err) - tracebackLines = self._exc_info_to_string(err, test) - self.parent.testFailed(str(test), tracebackLines, test.id()) - - def addError(self, test, err): - """ - Public method called if a test errored. - - @param test reference to the test object - @param err error traceback - """ - super().addError(test, err) - tracebackLines = self._exc_info_to_string(err, test) - self.parent.testErrored(str(test), tracebackLines, test.id()) - - def addSubTest(self, test, subtest, err): - """ - Public method called for each subtest to record its result. - - @param test reference to the test object - @param subtest reference to the subtest object - @param err error traceback - """ - if err is not None: - super().addSubTest(test, subtest, err) - tracebackLines = self._exc_info_to_string(err, test) - if issubclass(err[0], test.failureException): - self.parent.testFailed( - str(subtest), tracebackLines, test.id()) - else: - self.parent.testErrored( - str(subtest), tracebackLines, test.id()) - - def addSkip(self, test, reason): - """ - Public method called if a test was skipped. - - @param test reference to the test object - @param reason reason for skipping the test (string) - """ - super().addSkip(test, reason) - self.parent.testSkipped(str(test), reason, test.id()) - - def addExpectedFailure(self, test, err): - """ - Public method called if a test failed expected. - - @param test reference to the test object - @param err error traceback - """ - super().addExpectedFailure(test, err) - tracebackLines = self._exc_info_to_string(err, test) - self.parent.testFailedExpected(str(test), tracebackLines, test.id()) - - def addUnexpectedSuccess(self, test): - """ - Public method called if a test succeeded expectedly. - - @param test reference to the test object - """ - super().addUnexpectedSuccess(test) - self.parent.testSucceededUnexpected(str(test), test.id()) - - def startTest(self, test): - """ - Public method called at the start of a test. - - @param test Reference to the test object - """ - super().startTest(test) - self.parent.testStarted(str(test), test.shortDescription()) - - def stopTest(self, test): - """ - Public method called at the end of a test. - - @param test Reference to the test object - """ - super().stopTest(test) - self.parent.testFinished() - - -class UnittestWindow(EricMainWindow): - """ - Main window class for the standalone dialog. - """ - def __init__(self, prog=None, parent=None): - """ - Constructor - - @param prog filename of the program to open - @param parent reference to the parent widget (QWidget) - """ - super().__init__(parent) - self.cw = UnittestDialog(prog, parent=self) - self.cw.installEventFilter(self) - size = self.cw.size() - self.setCentralWidget(self.cw) - self.resize(size) - - self.setStyle(Preferences.getUI("Style"), - Preferences.getUI("StyleSheet")) - - self.cw.buttonBox.accepted.connect(self.close) - self.cw.buttonBox.rejected.connect(self.close) - - def eventFilter(self, obj, event): - """ - Public method to filter events. - - @param obj reference to the object the event is meant for (QObject) - @param event reference to the event object (QEvent) - @return flag indicating, whether the event was handled (boolean) - """ - if event.type() == QEvent.Type.Close: - QApplication.exit() - return True - - return False - - -def clearSavedHistories(self): - """ - Function to clear the saved history lists. - """ - Preferences.Prefs.rsettings.setValue( - recentNameUnittestDiscoverHistory, []) - Preferences.Prefs.rsettings.setValue( - recentNameUnittestFileHistory, []) - Preferences.Prefs.rsettings.setValue( - recentNameUnittestTestnameHistory, []) - - Preferences.Prefs.rsettings.sync()
--- a/eric7/PyUnit/UnittestDialog.ui Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,694 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>UnittestDialog</class> - <widget class="QWidget" name="UnittestDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>650</width> - <height>700</height> - </rect> - </property> - <property name="windowTitle"> - <string>Unittest</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_5"> - <item> - <widget class="QTabWidget" name="tabWidget"> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="parametersTab"> - <attribute name="title"> - <string>Parameters</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_6"> - <item> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Test Parameters</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QCheckBox" name="discoverCheckBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Select to discover tests automatically</string> - </property> - <property name="text"> - <string>&Discover tests (test modules must be importable)</string> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="clearHistoriesButton"> - <property name="toolTip"> - <string>Press to clear the various histories</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Discovery &Start:</string> - </property> - <property name="buddy"> - <cstring>discoveryPicker</cstring> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="EricComboPathPicker" name="discoveryPicker" native="true"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="focusPolicy"> - <enum>Qt::WheelFocus</enum> - </property> - <property name="toolTip"> - <string>Enter name of the directory at which to start the test file discovery</string> - </property> - <property name="whatsThis"> - <string><b>Discovery Start</b> -<p>Enter name of the directory at which to start the test file discovery. -Note that all test modules must be importable from this directory.</p></string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="testsuiteLabel"> - <property name="text"> - <string>Test &Filename:</string> - </property> - <property name="buddy"> - <cstring>testsuitePicker</cstring> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="EricComboPathPicker" name="testsuitePicker" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="focusPolicy"> - <enum>Qt::WheelFocus</enum> - </property> - <property name="toolTip"> - <string>Enter name of file defining the testsuite</string> - </property> - <property name="whatsThis"> - <string><b>Testsuite</b> -<p>Enter the name of the file defining the testsuite. -It should have a method with a name given below. If no name is given, the suite() method will be tried. If no such method can be -found, the module will be inspected for proper test -cases.</p></string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>&Test Name:</string> - </property> - <property name="buddy"> - <cstring>testComboBox</cstring> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QComboBox" name="testComboBox"> - <property name="toolTip"> - <string>Enter the test name. Leave empty to use the default name "suite".</string> - </property> - <property name="whatsThis"> - <string><b>Testname</b><p>Enter the name of the test to be performed. This name must follow the rules given by Python's unittest module. If this field is empty, the default name of "suite" will be used.</p></string> - </property> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="optionsGroup"> - <property name="title"> - <string>Run Parameters</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QLabel" name="venvLabel"> - <property name="text"> - <string>&Virtual Environment:</string> - </property> - <property name="buddy"> - <cstring>venvComboBox</cstring> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="venvComboBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Select the virtual environment to be used</string> - </property> - <property name="whatsThis"> - <string><b>Virtual Environment</b>\n<p>Enter the virtual environment to be used. Leave it empty to use the default environment, i.e. the one configured globally or per project.</p></string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QCheckBox" name="coverageCheckBox"> - <property name="toolTip"> - <string>Select whether coverage data should be collected</string> - </property> - <property name="text"> - <string>C&ollect coverage data</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QCheckBox" name="coverageEraseCheckBox"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="toolTip"> - <string>Select whether old coverage data should be erased</string> - </property> - <property name="text"> - <string>&Erase coverage data</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QCheckBox" name="failfastCheckBox"> - <property name="toolTip"> - <string>Select to stop the test run on the first error or failure</string> - </property> - <property name="text"> - <string>Stop on First Error or Failure</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QCheckBox" name="debuggerCheckBox"> - <property name="toolTip"> - <string>Select to run the unittest with debugger support enabled</string> - </property> - <property name="text"> - <string>Run with Debugger</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="discoveryGroup"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="title"> - <string>Discovery Results</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <widget class="QTreeWidget" name="discoveryList"> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <property name="sortingEnabled"> - <bool>true</bool> - </property> - <property name="headerHidden"> - <bool>true</bool> - </property> - <property name="expandsOnDoubleClick"> - <bool>false</bool> - </property> - <column> - <property name="text"> - <string notr="true">1</string> - </property> - </column> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="resultsTab"> - <attribute name="title"> - <string>Results</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <item> - <widget class="QGroupBox" name="progressGroupBox"> - <property name="title"> - <string>Progress</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="_8"> - <item> - <widget class="QLabel" name="progressTextLabel"> - <property name="text"> - <string>Progress:</string> - </property> - </widget> - </item> - <item> - <spacer> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>371</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="EricLed" name="progressLed"/> - </item> - </layout> - </item> - <item> - <widget class="QProgressBar" name="progressProgressBar"> - <property name="value"> - <number>0</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="format"> - <string>%v/%m Tests</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QLabel" name="progressCounterRunLabel"> - <property name="text"> - <string>Run:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterRunCount"> - <property name="toolTip"> - <string>Number of tests run</string> - </property> - <property name="text"> - <string notr="true">0</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterRemLabel"> - <property name="text"> - <string>Remaining:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterRemCount"> - <property name="toolTip"> - <string>Number of tests to be run</string> - </property> - <property name="text"> - <string notr="true">0</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLabel" name="progressCounterFailureLabel"> - <property name="text"> - <string>Failures:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterFailureCount"> - <property name="toolTip"> - <string>Number of test failures</string> - </property> - <property name="text"> - <string notr="true">0</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterErrorLabel"> - <property name="text"> - <string>Errors:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterErrorCount"> - <property name="toolTip"> - <string>Number of test errors</string> - </property> - <property name="text"> - <string notr="true">0</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterSkippedLabel"> - <property name="text"> - <string>Skipped:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterSkippedCount"> - <property name="toolTip"> - <string>Number of tests skipped</string> - </property> - <property name="text"> - <string notr="true">0</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterExpectedFailureLabel"> - <property name="text"> - <string>Expected Failures:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterExpectedFailureCount"> - <property name="toolTip"> - <string>Number of tests with expected failure</string> - </property> - <property name="text"> - <string notr="true">0</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterUnexpectedSuccessLabel"> - <property name="text"> - <string>Unexpected Successes:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="progressCounterUnexpectedSuccessCount"> - <property name="toolTip"> - <string>Number of tests with unexpected success</string> - </property> - <property name="text"> - <string notr="true">0</string> - </property> - </widget> - </item> - <item> - <spacer> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QLabel" name="textLabel1"> - <property name="text"> - <string>Tests performed:</string> - </property> - </widget> - </item> - <item> - <widget class="QListWidget" name="testsListWidget"/> - </item> - <item> - <widget class="QLabel" name="listboxLabel"> - <property name="text"> - <string>Failures and errors:</string> - </property> - </widget> - </item> - <item> - <widget class="QListWidget" name="errorsListWidget"> - <property name="toolTip"> - <string>Failures and Errors list</string> - </property> - <property name="whatsThis"> - <string><b>Failures and Errors list</b> -<p>This list shows all failed and errored tests. -Double clicking on an entry will show the respective traceback.</p></string> - </property> - </widget> - </item> - </layout> - </widget> - </widget> - </item> - <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Close</set> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="_3"> - <item> - <widget class="QLabel" name="sbLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Idle</string> - </property> - </widget> - </item> - <item> - <spacer> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>EricComboPathPicker</class> - <extends>QWidget</extends> - <header>EricWidgets/EricPathPicker.h</header> - <container>1</container> - </customwidget> - <customwidget> - <class>EricLed</class> - <extends>QFrame</extends> - <header>EricWidgets/EricLed.h</header> - <container>1</container> - </customwidget> - </customwidgets> - <tabstops> - <tabstop>tabWidget</tabstop> - <tabstop>discoverCheckBox</tabstop> - <tabstop>clearHistoriesButton</tabstop> - <tabstop>discoveryPicker</tabstop> - <tabstop>testsuitePicker</tabstop> - <tabstop>testComboBox</tabstop> - <tabstop>venvComboBox</tabstop> - <tabstop>coverageCheckBox</tabstop> - <tabstop>coverageEraseCheckBox</tabstop> - <tabstop>failfastCheckBox</tabstop> - <tabstop>debuggerCheckBox</tabstop> - <tabstop>discoveryList</tabstop> - <tabstop>testsListWidget</tabstop> - <tabstop>errorsListWidget</tabstop> - </tabstops> - <resources/> - <connections> - <connection> - <sender>coverageCheckBox</sender> - <signal>toggled(bool)</signal> - <receiver>coverageEraseCheckBox</receiver> - <slot>setEnabled(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>321</x> - <y>294</y> - </hint> - <hint type="destinationlabel"> - <x>616</x> - <y>294</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>UnittestDialog</receiver> - <slot>close()</slot> - <hints> - <hint type="sourcelabel"> - <x>67</x> - <y>662</y> - </hint> - <hint type="destinationlabel"> - <x>72</x> - <y>667</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>rejected()</signal> - <receiver>UnittestDialog</receiver> - <slot>close()</slot> - <hints> - <hint type="sourcelabel"> - <x>157</x> - <y>662</y> - </hint> - <hint type="destinationlabel"> - <x>148</x> - <y>668</y> - </hint> - </hints> - </connection> - <connection> - <sender>discoverCheckBox</sender> - <signal>toggled(bool)</signal> - <receiver>discoveryPicker</receiver> - <slot>setEnabled(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>209</x> - <y>93</y> - </hint> - <hint type="destinationlabel"> - <x>209</x> - <y>120</y> - </hint> - </hints> - </connection> - <connection> - <sender>discoverCheckBox</sender> - <signal>toggled(bool)</signal> - <receiver>testsuitePicker</receiver> - <slot>setDisabled(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>96</x> - <y>93</y> - </hint> - <hint type="destinationlabel"> - <x>150</x> - <y>143</y> - </hint> - </hints> - </connection> - <connection> - <sender>discoverCheckBox</sender> - <signal>toggled(bool)</signal> - <receiver>testComboBox</receiver> - <slot>setDisabled(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>321</x> - <y>97</y> - </hint> - <hint type="destinationlabel"> - <x>327</x> - <y>166</y> - </hint> - </hints> - </connection> - </connections> -</ui>
--- a/eric7/PyUnit/UnittestStacktraceDialog.ui Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -<ui version="4.0" > - <class>UnittestStacktraceDialog</class> - <widget class="QDialog" name="UnittestStacktraceDialog" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>600</width> - <height>250</height> - </rect> - </property> - <layout class="QVBoxLayout" > - <item> - <widget class="QLabel" name="testLabel" /> - </item> - <item> - <widget class="QTextEdit" name="traceback" > - <property name="readOnly" > - <bool>true</bool> - </property> - <property name="acceptRichText" > - <bool>false</bool> - </property> - </widget> - </item> - <item> - <widget class="QDialogButtonBox" name="buttonBox" > - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons" > - <set>QDialogButtonBox::Close</set> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>UnittestStacktraceDialog</receiver> - <slot>accept()</slot> - <hints> - <hint type="sourcelabel" > - <x>33</x> - <y>235</y> - </hint> - <hint type="destinationlabel" > - <x>33</x> - <y>249</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>rejected()</signal> - <receiver>UnittestStacktraceDialog</receiver> - <slot>reject()</slot> - <hints> - <hint type="sourcelabel" > - <x>94</x> - <y>226</y> - </hint> - <hint type="destinationlabel" > - <x>95</x> - <y>249</y> - </hint> - </hints> - </connection> - </connections> -</ui>
--- a/eric7/PyUnit/__init__.py Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2002 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Package implementing an interface to the pyunit unittest package. - -The package consist of a single dialog, which may be called as a -standalone version using the eric7_unittest script or from within the eric -IDE. If it is called from within eric, it has the additional function to -open a source file that failed a test. -"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/Interfaces/PytestExecutor.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,310 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the executor for the 'pytest' framework. +""" + +import contextlib +import json +import os + +from PyQt6.QtCore import pyqtSlot, QProcess + +from EricNetwork.EricJsonStreamReader import EricJsonReader + +from .TestExecutorBase import TestExecutorBase, TestResult, TestResultCategory + + +class PytestExecutor(TestExecutorBase): + """ + Class implementing the executor for the 'pytest' framework. + """ + module = "pytest" + name = "pytest" + + runner = os.path.join(os.path.dirname(__file__), "PytestRunner.py") + + def __init__(self, testWidget): + """ + Constructor + + @param testWidget reference to the unit test widget + @type TestingWidget + """ + super().__init__(testWidget) + + self.__statusDisplayMapping = { + "failed": self.tr("Failure"), + "skipped": self.tr("Skipped"), + "xfailed": self.tr("Expected Failure"), + "xpassed": self.tr("Unexpected Success"), + "passed": self.tr("Success"), + } + + self.__config = None + + def getVersions(self, interpreter): + """ + Public method to get the test framework version and version information + of its installed plugins. + + @param interpreter interpreter to be used for the test + @type str + @return dictionary containing the framework name and version and the + list of available plugins with name and version each + @rtype dict + """ + proc = QProcess() + proc.start(interpreter, [PytestExecutor.runner, "versions"]) + if proc.waitForFinished(3000): + exitCode = proc.exitCode() + if exitCode == 0: + outputLines = self.readAllOutput(proc).splitlines() + for line in outputLines: + if line.startswith("{") and line.endswith("}"): + with contextlib.suppress(json.JSONDecodeError): + return json.loads(line) + + return {} + + def hasCoverage(self, interpreter): + """ + Public method to get the test framework version and version information + of its installed plugins. + + @param interpreter interpreter to be used for the test + @type str + @return flag indicating the availability of coverage functionality + @rtype bool + """ + versions = self.getVersions(interpreter) + if "plugins" in versions: + return any(plugin["name"] == "pytest-cov" + for plugin in versions["plugins"]) + + return False + + def createArguments(self, config): + """ + Public method to create the arguments needed to start the test process. + + @param config configuration for the test execution + @type TestConfig + @return list of process arguments + @rtype list of str + """ + # + # collectCoverage: --cov= + --cov-report= to suppress report generation + # eraseCoverage: --cov-append if eraseCoverage is False + # coverageFile + args = [ + PytestExecutor.runner, + "runtest", + self.reader.address(), + str(self.reader.port()), + "--quiet", + ] + + if config.failFast: + args.append("--exitfirst") + + if config.failedOnly: + args.append("--last-failed") + else: + args.append("--cache-clear") + + if config.collectCoverage: + args.extend([ + "--cov=.", + "--cov-report=" + ]) + if not config.eraseCoverage: + args.append("--cov-append") + + if config.testFilename: + if config.testName: + args.append("{0}::{1}".format( + config.testFilename, + config.testName.replace(".", "::") + )) + else: + args.append(config.testFilename) + + return args + + def start(self, config, pythonpath): + """ + Public method to start the testing process. + + @param config configuration for the test execution + @type TestConfig + @param pythonpath list of directories to be added to the Python path + @type list of str + """ + self.reader = EricJsonReader(name="Unittest Reader", parent=self) + self.reader.dataReceived.connect(self.__processData) + + self.__config = config + + if config.discoveryStart: + pythonpath.insert(0, os.path.abspath(config.discoveryStart)) + elif config.testFilename: + pythonpath.insert( + 0, os.path.abspath(os.path.dirname(config.testFilename))) + + if config.discover: + self.__rootdir = config.discoveryStart + elif config.testFilename: + self.__rootdir = os.path.dirname(config.testFilename) + else: + self.__rootdir = "" + + super().start(config, pythonpath) + + def finished(self): + """ + Public method handling the unit test process been finished. + + This method should read the results (if necessary) and emit the signal + testFinished. + """ + if self.__config.collectCoverage: + self.coverageDataSaved.emit( + os.path.join(self.__rootdir, ".coverage")) + + self.__config = None + + self.reader.close() + + output = self.readAllOutput() + self.testFinished.emit([], output) + + @pyqtSlot(object) + def __processData(self, data): + """ + Private slot to process the received data. + + @param data data object received + @type dict + """ + # test configuration + if data["event"] == "config": + self.__rootdir = data["root"] + + # error collecting tests + elif data["event"] == "collecterror": + name = self.__normalizeModuleName(data["nodeid"]) + self.collectError.emit([(name, data["report"])]) + + # tests collected + elif data["event"] == "collected": + self.collected.emit([ + (data["nodeid"], + self.__nodeid2testname(data["nodeid"]), + "") + ]) + + # test started + elif data["event"] == "starttest": + self.startTest.emit( + (data["nodeid"], + self.__nodeid2testname(data["nodeid"]), + "") + ) + + # test result + elif data["event"] == "result": + if data["status"] in ("failed", "xpassed") or data["with_error"]: + category = TestResultCategory.FAIL + elif data["status"] in ("passed", "xfailed"): + category = TestResultCategory.OK + else: + category = TestResultCategory.SKIP + + status = ( + self.tr("Error") + if data["with_error"] else + self.__statusDisplayMapping[data["status"]] + ) + + message = data.get("message", "") + extraText = data.get("report", "") + reportPhase = data.get("report_phase") + if reportPhase in ("setup", "teardown"): + message = ( + self.tr("ERROR at {0}: {1}", "phase, message") + .format(reportPhase, message) + ) + extraText = ( + self.tr("ERROR at {0}: {1}", "phase, extra text") + .format(reportPhase, extraText) + ) + sections = data.get("sections", []) + if sections: + extraText += "\n" + for heading, text in sections: + extraText += "----- {0} -----\n{1}".format(heading, text) + + duration = data.get("duration_s", None) + if duration: + # convert to ms + duration *= 1000 + + filename = data["filename"] + if self.__rootdir: + filename = os.path.join(self.__rootdir, filename) + + self.testResult.emit(TestResult( + category=category, + status=status, + name=self.__nodeid2testname(data["nodeid"]), + id=data["nodeid"], + description="", + message=message, + extra=extraText.rstrip().splitlines(), + duration=duration, + filename=filename, + lineno=data.get("linenumber", 0) + 1, + # pytest reports 0-based line numbers + )) + + # test run finished + elif data["event"] == "finished": + self.testRunFinished.emit(data["tests"], data["duration_s"]) + + def __normalizeModuleName(self, name): + r""" + Private method to convert a module name reported by pytest to Python + conventions. + + This method strips the extensions '.pyw' and '.py' first and replaces + '/' and '\' thereafter. + + @param name module name reported by pytest + @type str + @return module name iaw. Python conventions + @rtype str + """ + return (name + .replace(".pyw", "") + .replace(".py", "") + .replace("/", ".") + .replace("\\", ".")) + + def __nodeid2testname(self, nodeid): + """ + Private method to convert a nodeid to a test name. + + @param nodeid nodeid to be converted + @type str + @return test name + @rtype str + """ + module, name = nodeid.split("::", 1) + module = self.__normalizeModuleName(module) + name = name.replace("::", ".") + testname, name = "{0}.{1}".format(module, name).rsplit(".", 1) + return "{0} ({1})".format(name, testname)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/Interfaces/PytestRunner.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,302 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the test runner script for the 'pytest' framework. +""" + +import json +import os +import sys +import time + +sys.path.insert( + 2, + os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +) + + +class GetPluginVersionsPlugin(): + """ + Class implementing a pytest plugin to extract the version info of all + installed plugins. + """ + def __init__(self): + """ + Constructor + """ + super().__init__() + + self.versions = [] + + def pytest_cmdline_main(self, config): + """ + Public method called for performing the main command line action. + + @param config pytest config object + @type Config + """ + pluginInfo = config.pluginmanager.list_plugin_distinfo() + if pluginInfo: + for _plugin, dist in pluginInfo: + self.versions.append({ + "name": dist.project_name, + "version": dist.version + }) + + def getVersions(self): + """ + Public method to get the assembled list of plugin versions. + + @return list of collected plugin versions + @rtype list of dict + """ + return self.versions + + +class EricPlugin(): + """ + Class implementing a pytest plugin which reports the data in a format + suitable for the PytestExecutor. + """ + def __init__(self, writer): + """ + Constructor + + @param writer reference to the object to write the results to + @type EricJsonWriter + """ + self.__writer = writer + + self.__testsRun = 0 + + def __initializeReportData(self): + """ + Private method to initialize attributes for data collection. + """ + self.__status = '---' + self.__duration = 0 + self.__report = [] + self.__reportPhase = "" + self.__sections = [] + self.__hadError = False + self.__wasSkipped = False + self.__wasXfail = False + + def pytest_report_header(self, config, startdir): + """ + Public method called by pytest before any reporting. + + @param config reference to the configuration object + @type Config + @param startdir starting directory + @type LocalPath + """ + self.__writer.write({ + "event": "config", + "root": str(config.rootdir) + }) + + def pytest_collectreport(self, report): + """ + Public method called by pytest after the tests have been collected. + + @param report reference to the report object + @type CollectReport + """ + if report.outcome == "failed": + self.__writer.write({ + "event": "collecterror", + "nodeid": report.nodeid, + "report": str(report.longrepr), + }) + + def pytest_itemcollected(self, item): + """ + Public malled by pytest after a test item has been collected. + + @param item reference to the collected test item + @type Item + """ + self.__writer.write({ + "event": "collected", + "nodeid": item.nodeid, + "name": item.name, + }) + + def pytest_runtest_logstart(self, nodeid, location): + """ + Public method called by pytest before running a test. + + @param nodeid node id of the test item + @type str + @param location tuple containing the file name, the line number and + the test name + @type tuple of (str, int, str) + """ + self.__testsRun += 1 + + self.__writer.write({ + "event": "starttest", + "nodeid": nodeid, + }) + + self.__initializeReportData() + + def pytest_runtest_logreport(self, report): + """ + Public method called by pytest when a test phase (setup, call and + teardown) has been completed. + + @param report reference to the test report object + @type TestReport + """ + if report.when == "call": + self.__status = report.outcome + self.__duration = report.duration + else: + if report.outcome == "failed": + self.__hadError = True + elif report.outcome == "skipped": + self.__wasSkipped = True + + if hasattr(report, "wasxfail"): + self.__wasXfail = True + self.__report.append(report.wasxfail) + self.__reportPhase = report.when + + self.__sections = report.sections + + if report.longrepr: + self.__reportPhase = report.when + if ( + hasattr(report.longrepr, "reprcrash") and + report.longrepr.reprcrash is not None + ): + self.__report.append( + report.longrepr.reprcrash.message) + if isinstance(report.longrepr, tuple): + self.__report.append(report.longrepr[2]) + elif isinstance(report.longrepr, str): + self.__report.append(report.longrepr) + else: + self.__report.append(str(report.longrepr)) + + def pytest_runtest_logfinish(self, nodeid, location): + """ + Public method called by pytest after a test has been completed. + + @param nodeid node id of the test item + @type str + @param location tuple containing the file name, the line number and + the test name + @type tuple of (str, int, str) + """ + if self.__wasXfail: + self.__status = ( + "xpassed" + if self.__status == "passed" else + "xfailed" + ) + elif self.__wasSkipped: + self.__status = "skipped" + + data = { + "event": "result", + "status": self.__status, + "with_error": self.__hadError, + "sections": self.__sections, + "duration_s": self.__duration, + "nodeid": nodeid, + "filename": location[0], + "linenumber": location[1], + "report_phase": self.__reportPhase, + } + if self.__report: + messageLines = self.__report[0].rstrip().splitlines() + data["message"] = messageLines[0] + data["report"] = "\n".join(self.__report) + + self.__writer.write(data) + + def pytest_sessionstart(self, session): + """ + Public method called by pytest before performing collection and + entering the run test loop. + + @param session reference to the session object + @type Session + """ + self.__totalStartTime = time.monotonic_ns() + self.__testsRun = 0 + + def pytest_sessionfinish(self, session, exitstatus): + """ + Public method called by pytest after the whole test run finished. + + @param session reference to the session object + @type Session + @param exitstatus exit status + @type int or ExitCode + """ + stopTime = time.monotonic_ns() + duration = (stopTime - self.__totalStartTime) / 1_000_000_000 # s + + self.__writer.write({ + "event": "finished", + "duration_s": duration, + "tests": self.__testsRun, + }) + + +def getVersions(): + """ + Function to determine the framework version and versions of all available + plugins. + """ + try: + import pytest + versions = { + "name": "pytest", + "version": pytest.__version__, + "plugins": [], + } + + # --capture=sys needed on Windows to avoid + # ValueError: saved filedescriptor not valid anymore + plugin = GetPluginVersionsPlugin() + pytest.main(['--version', '--capture=sys'], plugins=[plugin]) + versions["plugins"] = plugin.getVersions() + except ImportError: + versions = {} + + print(json.dumps(versions)) + sys.exit(0) + + +if __name__ == '__main__': + command = sys.argv[1] + if command == "installed": + try: + import pytest # __IGNORE_WARNING__ + sys.exit(0) + except ImportError: + sys.exit(1) + + elif command == "versions": + getVersions() + + elif command == "runtest": + import pytest + from EricNetwork.EricJsonStreamWriter import EricJsonWriter + writer = EricJsonWriter(sys.argv[2], int(sys.argv[3])) + pytest.main(sys.argv[4:], plugins=[EricPlugin(writer)]) + writer.close() + sys.exit(0) + + sys.exit(42) + +# +# eflag: noqa = M801
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/Interfaces/TestExecutorBase.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,279 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the executor base class for the various testing frameworks +and supporting classes. +""" + +import os +from dataclasses import dataclass +from enum import IntEnum + +from PyQt6.QtCore import pyqtSignal, QObject, QProcess, QProcessEnvironment + +import Preferences + + +class TestResultCategory(IntEnum): + """ + Class defining the supported result categories. + """ + RUNNING = 0 + FAIL = 1 + OK = 2 + SKIP = 3 + PENDING = 4 + + +@dataclass +class TestResult: + """ + Class containing the test result data. + """ + category: TestResultCategory # result category + status: str # test status + name: str # test name + id: str # test id + description: str = "" # short description of test + message: str = "" # short result message + extra: list = None # additional information text + duration: float = None # test duration + filename: str = None # file name of a failed test + lineno: int = None # line number of a failed test + subtestResult: bool = False # flag indicating the result of a subtest + + +@dataclass +class TestConfig: + """ + Class containing the test run configuration. + """ + interpreter: str # path of the Python interpreter + discover: bool # auto discovery flag + discoveryStart: str # start directory for auto discovery + testFilename: str # name of the test script + testName: str # name of the test function + failFast: bool # stop on first fail + failedOnly: bool # run failed tests only + collectCoverage: bool # coverage collection flag + eraseCoverage: bool # erase coverage data first + coverageFile: str # name of the coverage data file + + +class TestExecutorBase(QObject): + """ + Base class for test framework specific implementations. + + @signal collected(list of tuple of (str, str, str)) emitted after all tests + have been collected. Tuple elements are the test id, the test name and + a short description of the test. + @signal collectError(list of tuple of (str, str)) emitted when errors + are encountered during test collection. Tuple elements are the + test name and the error message. + @signal startTest(tuple of (str, str, str) emitted before tests are run. + Tuple elements are test id, test name and short description. + @signal testResult(TestResult) emitted when a test result is ready + @signal testFinished(list, str) emitted when the test has finished. + The elements are the list of test results and the captured output + of the test worker (if any). + @signal testRunAboutToBeStarted() emitted just before the test run will + be started. + @signal testRunFinished(int, float) emitted when the test run has finished. + The elements are the number of tests run and the duration in seconds + @signal stop() emitted when the test process is being stopped. + @signal coverageDataSaved(str) emitted after the coverage data was saved. + The element is the absolute path of the coverage data file. + """ + collected = pyqtSignal(list) + collectError = pyqtSignal(list) + startTest = pyqtSignal(tuple) + testResult = pyqtSignal(TestResult) + testFinished = pyqtSignal(list, str) + testRunAboutToBeStarted = pyqtSignal() + testRunFinished = pyqtSignal(int, float) + stop = pyqtSignal() + coverageDataSaved = pyqtSignal(str) + + module = "" + name = "" + runner = "" + + def __init__(self, testWidget): + """ + Constructor + + @param testWidget reference to the unit test widget + @type TestingWidget + """ + super().__init__(testWidget) + + self.__process = None + + @classmethod + def isInstalled(cls, interpreter): + """ + Class method to check whether a test framework is installed. + + The test is performed by checking, if a module loader can found. + + @param interpreter interpreter to be used for the test + @type str + @return flag indicating the test framework module is installed + @rtype bool + """ + if cls.runner: + proc = QProcess() + proc.start(interpreter, [cls.runner, "installed"]) + if proc.waitForFinished(3000): + exitCode = proc.exitCode() + return exitCode == 0 + + return False + + def getVersions(self, interpreter): + """ + Public method to get the test framework version and version information + of its installed plugins. + + @param interpreter interpreter to be used for the test + @type str + @return dictionary containing the framework name and version and the + list of available plugins with name and version each + @rtype dict + @exception NotImplementedError this method needs to be implemented by + derived classes + """ + raise NotImplementedError + + return {} + + def hasCoverage(self, interpreter): + """ + Public method to get the test framework version and version information + of its installed plugins. + + @param interpreter interpreter to be used for the test + @type str + @return flag indicating the availability of coverage functionality + @rtype bool + @exception NotImplementedError this method needs to be implemented by + derived classes + """ + raise NotImplementedError + + return False + + def createArguments(self, config): + """ + Public method to create the arguments needed to start the test process. + + @param config configuration for the test execution + @type TestConfig + @return list of process arguments + @rtype list of str + @exception NotImplementedError this method needs to be implemented by + derived classes + """ + raise NotImplementedError + + return [] + + def _prepareProcess(self, workDir, pythonpath): + """ + Protected method to prepare a process object to be started. + + @param workDir working directory + @type str + @param pythonpath list of directories to be added to the Python path + @type list of str + @return prepared process object + @rtype QProcess + """ + process = QProcess(self) + process.setProcessChannelMode( + QProcess.ProcessChannelMode.MergedChannels) + process.setWorkingDirectory(workDir) + process.finished.connect(self.finished) + if pythonpath: + env = QProcessEnvironment.systemEnvironment() + currentPythonPath = env.value('PYTHONPATH', None) + newPythonPath = os.pathsep.join(pythonpath) + if currentPythonPath: + newPythonPath += os.pathsep + currentPythonPath + env.insert('PYTHONPATH', newPythonPath) + process.setProcessEnvironment(env) + + return process + + def start(self, config, pythonpath): + """ + Public method to start the testing process. + + @param config configuration for the test execution + @type TestConfig + @param pythonpath list of directories to be added to the Python path + @type list of str + @exception RuntimeError raised if the the testing process did not start + """ + workDir = ( + config.discoveryStart + if config.discover else + os.path.dirname(config.testFilename) + ) + self.__process = self._prepareProcess(workDir, pythonpath) + testArgs = self.createArguments(config) + self.testRunAboutToBeStarted.emit() + self.__process.start(config.interpreter, testArgs) + running = self.__process.waitForStarted() + if not running: + raise RuntimeError + + def finished(self): + """ + Public method handling the unit test process been finished. + + This method should read the results (if necessary) and emit the signal + testFinished. + + @exception NotImplementedError this method needs to be implemented by + derived classes + """ + raise NotImplementedError + + def readAllOutput(self, process=None): + """ + Public method to read all output of the test process. + + @param process reference to the process object + @type QProcess + @return test process output + @rtype str + """ + if process is None: + process = self.__process + output = ( + str(process.readAllStandardOutput(), + Preferences.getSystem("IOEncoding"), + 'replace').strip() + if process else + "" + ) + return output + + def stopIfRunning(self): + """ + Public method to stop the testing process, if it is running. + """ + if ( + self.__process and + self.__process.state() == QProcess.ProcessState.Running + ): + self.__process.terminate() + self.__process.waitForFinished(2000) + self.__process.kill() + self.__process.waitForFinished(3000) + + self.stop.emit()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/Interfaces/TestFrameworkRegistry.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a simple registry containing the available test framework +interfaces. +""" + +import copy + + +class TestFrameworkRegistry(): + """ + Class implementing a simple registry of test framework interfaces. + + The test executor for a framework is responsible for running the tests, + receiving the results and preparing them for display. It must implement + the interface of TestExecutorBase. + + Frameworks must first be registered using '.register()'. This registry + can then create the assoicated test executor when '.createExecutor()' is + called. + """ + def __init__(self): + """ + Constructor + """ + self.__frameworks = {} + + def register(self, executorClass): + """ + Public method to register a test framework executor. + + @param executorClass class implementing the test framework executor + @type TestExecutorBase + """ + self.__frameworks[executorClass.name] = executorClass + + def createExecutor(self, framework, widget): + """ + Public method to create a test framework executor. + + Note: The executor classes have to be registered first. + + @param framework name of the test framework + @type str + @param widget reference to the unit test widget + @type TestingWidget + @return test framework executor object + @rtype TestExecutorBase + """ + cls = self.__frameworks[framework] + return cls(widget) + + def getFrameworks(self): + """ + Public method to get a copy of the registered frameworks. + + @return copy of the registered frameworks + @rtype dict + """ + return copy.copy(self.__frameworks)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/Interfaces/UnittestExecutor.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the executor for the standard 'unittest' framework. +""" + +import contextlib +import json +import os +import re + +from PyQt6.QtCore import pyqtSlot, QProcess + +from EricNetwork.EricJsonStreamReader import EricJsonReader + +from .TestExecutorBase import TestExecutorBase, TestResult, TestResultCategory + + +class UnittestExecutor(TestExecutorBase): + """ + Class implementing the executor for the standard 'unittest' framework. + """ + module = "unittest" + name = "unittest" + + runner = os.path.join(os.path.dirname(__file__), "UnittestRunner.py") + + def __init__(self, testWidget): + """ + Constructor + + @param testWidget reference to the unit test widget + @type TestingWidget + """ + super().__init__(testWidget) + + self.__statusCategoryMapping = { + "failure": TestResultCategory.FAIL, + "error": TestResultCategory.FAIL, + "skipped": TestResultCategory.SKIP, + "expected failure": TestResultCategory.OK, + "unexpected success": TestResultCategory.FAIL, + "success": TestResultCategory.OK, + } + + self.__statusDisplayMapping = { + "failure": self.tr("Failure"), + "error": self.tr("Error"), + "skipped": self.tr("Skipped"), + "expected failure": self.tr("Expected Failure"), + "unexpected success": self.tr("Unexpected Success"), + "success": self.tr("Success"), + } + + self.__testWidget = testWidget + + def getVersions(self, interpreter): + """ + Public method to get the test framework version and version information + of its installed plugins. + + @param interpreter interpreter to be used for the test + @type str + @return dictionary containing the framework name and version and the + list of available plugins with name and version each + @rtype dict + """ + proc = QProcess() + proc.start(interpreter, [UnittestExecutor.runner, "versions"]) + if proc.waitForFinished(3000): + exitCode = proc.exitCode() + if exitCode == 0: + versionsStr = self.readAllOutput(proc) + with contextlib.suppress(json.JSONDecodeError): + return json.loads(versionsStr) + + return {} + + def hasCoverage(self, interpreter): + """ + Public method to get the test framework version and version information + of its installed plugins. + + @param interpreter interpreter to be used for the test + @type str + @return flag indicating the availability of coverage functionality + @rtype bool + """ + return True + + def createArguments(self, config): + """ + Public method to create the arguments needed to start the test process. + + @param config configuration for the test execution + @type TestConfig + @return list of process arguments + @rtype list of str + """ + args = [ + UnittestExecutor.runner, + "runtest", + self.reader.address(), + str(self.reader.port()), + ] + + if config.discover: + args.extend([ + "discover", + "--start-directory", + config.discoveryStart, + ]) + + if config.failFast: + args.append("--failfast") + + if config.collectCoverage: + args.append("--cover") + if config.eraseCoverage: + args.append("--cover-erase") + if config.coverageFile: + args.append("--cover-file") + args.append(config.coverageFile) + + if config.failedOnly: + args.append("--failed-only") + if config.testFilename: + args.append(config.testFilename) + args.extend(self.__testWidget.getFailedTests()) + elif config.testFilename: + args.append(config.testFilename) + args.append(config.testName if config.testName else "suite") + + return args + + def start(self, config, pythonpath): + """ + Public method to start the testing process. + + @param config configuration for the test execution + @type TestConfig + @param pythonpath list of directories to be added to the Python path + @type list of str + """ + self.reader = EricJsonReader(name="Unittest Reader", parent=self) + self.reader.dataReceived.connect(self.__processData) + + super().start(config, pythonpath) + + def finished(self): + """ + Public method handling the unit test process been finished. + + This method should read the results (if necessary) and emit the signal + testFinished. + """ + self.reader.close() + + output = self.readAllOutput() + self.testFinished.emit([], output) + + @pyqtSlot(object) + def __processData(self, data): + """ + Private slot to process the received data. + + @param data data object received + @type dict + """ + # error collecting tests + if data["event"] == "collecterror": + self.collectError.emit([("", data["error"])]) + + # tests collected + elif data["event"] == "collected": + self.collected.emit([ + (t["id"], t["name"], t["description"]) for t in data["tests"] + ]) + + # test started + elif data["event"] == "started": + self.startTest.emit( + (data["id"], data["name"], data["description"]) + ) + + # test result + elif data["event"] == "result": + filename, lineno = None, None + tracebackLines = data.get("traceback", "").splitlines() + if tracebackLines: + # find the last entry matching the pattern + for index in range(len(tracebackLines) - 1, -1, -1): + fmatch = re.search(r'File "(.*?)", line (\d*?),.*', + tracebackLines[index]) + if fmatch: + break + if fmatch: + filename = fmatch.group(1) + lineno = int(fmatch.group(2)) + + message = data.get("shortmsg", "") + if not message and tracebackLines: + message = tracebackLines[-1].split(":", 1)[1].strip() + + self.testResult.emit(TestResult( + category=self.__statusCategoryMapping[data["status"]], + status=self.__statusDisplayMapping[data["status"]], + name=data["name"], + id=data["id"], + description=data["description"], + message=message, + extra=tracebackLines, + duration=data.get("duration_ms", None), + filename=filename, + lineno=lineno, + subtestResult=data.get("subtest", False) + )) + + # test run finished + elif data["event"] == "finished": + self.testRunFinished.emit(data["tests"], data["duration_s"]) + + # coverage data + elif data["event"] == "coverage": + self.coverageDataSaved.emit(data["file"])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/Interfaces/UnittestRunner.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,434 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the test runner script for the 'unittest' framework. +""" + +import json +import os +import sys +import time +import unittest + +sys.path.insert( + 2, + os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +) + + +class EricTestResult(unittest.TestResult): + """ + Class implementing a TestResult derivative to send the data via a network + connection. + """ + def __init__(self, writer, failfast): + """ + Constructor + + @param writer reference to the object to write the results to + @type EricJsonWriter + @param failfast flag indicating to stop at the first error + @type bool + """ + super().__init__() + self.__writer = writer + self.failfast = failfast + self.__testsRun = 0 + + self.__currentTestStatus = {} + + def addFailure(self, test, err): + """ + Public method called if a test failed. + + @param test reference to the test object + @type TestCase + @param err tuple containing the exception data like sys.exc_info + (exception type, exception instance, traceback) + @type tuple + """ + super().addFailure(test, err) + tracebackLines = self._exc_info_to_string(err, test) + + self.__currentTestStatus.update({ + "status": "failure", + "traceback": tracebackLines, + }) + + def addError(self, test, err): + """ + Public method called if a test errored. + + @param test reference to the test object + @type TestCase + @param err tuple containing the exception data like sys.exc_info + (exception type, exception instance, traceback) + @type tuple + """ + super().addError(test, err) + tracebackLines = self._exc_info_to_string(err, test) + + self.__currentTestStatus.update({ + "status": "error", + "traceback": tracebackLines, + }) + + def addSkip(self, test, reason): + """ + Public method called if a test was skipped. + + @param test reference to the test object + @type TestCase + @param reason reason for skipping the test + @type str + """ + super().addSkip(test, reason) + + self.__currentTestStatus.update({ + "status": "skipped", + "shortmsg": reason, + }) + + def addExpectedFailure(self, test, err): + """ + Public method called if a test failed expected. + + @param test reference to the test object + @type TestCase + @param err tuple containing the exception data like sys.exc_info + (exception type, exception instance, traceback) + @type tuple + """ + super().addExpectedFailure(test, err) + tracebackLines = self._exc_info_to_string(err, test) + + self.__currentTestStatus.update({ + "status": "expected failure", + "traceback": tracebackLines, + }) + + def addUnexpectedSuccess(self, test): + """ + Public method called if a test succeeded expectedly. + + @param test reference to the test object + @type TestCase + """ + super().addUnexpectedSuccess(test) + + self.__currentTestStatus["status"] = "unexpected success" + + def addSubTest(self, test, subtest, err): + """ + Public method called for each subtest to record its result. + + @param test reference to the test object + @type TestCase + @param subtest reference to the subtest object + @type TestCase + @param err tuple containing the exception data like sys.exc_info + (exception type, exception instance, traceback) + @type tuple + """ + if err is not None: + super().addSubTest(test, subtest, err) + tracebackLines = self._exc_info_to_string(err, test) + status = ( + "failure" + if issubclass(err[0], test.failureException) else + "error" + ) + + # record the last subtest fail status as the overall status + self.__currentTestStatus["status"] = status + + self.__writer.write({ + "event": "result", + "status": status, + "name": str(subtest), + "id": subtest.id(), + "description": subtest.shortDescription(), + "traceback": tracebackLines, + "subtest": True, + }) + + if self.failfast: + self.stop() + else: + self.__writer.write({ + "event": "result", + "status": "success", + "name": str(subtest), + "id": subtest.id(), + "description": subtest.shortDescription(), + "subtest": True, + }) + + def startTest(self, test): + """ + Public method called at the start of a test. + + @param test reference to the test object + @type TestCase + """ + super().startTest(test) + + self.__testsRun += 1 + self.__currentTestStatus = { + "event": "result", + "status": "success", + "name": str(test), + "id": test.id(), + "description": test.shortDescription(), + "subtest": False, + } + + self.__writer.write({ + "event": "started", + "name": str(test), + "id": test.id(), + "description": test.shortDescription(), + }) + + self.__startTime = time.monotonic_ns() + + def stopTest(self, test): + """ + Public method called at the end of a test. + + @param test reference to the test object + @type TestCase + """ + stopTime = time.monotonic_ns() + duration = (stopTime - self.__startTime) / 1_000_000 # ms + + super().stopTest(test) + + self.__currentTestStatus["duration_ms"] = duration + self.__writer.write(self.__currentTestStatus) + + def startTestRun(self): + """ + Public method called once before any tests are executed. + """ + self.__totalStartTime = time.monotonic_ns() + self.__testsRun = 0 + + def stopTestRun(self): + """ + Public method called once after all tests are executed. + """ + stopTime = time.monotonic_ns() + duration = (stopTime - self.__totalStartTime) / 1_000_000_000 # s + + self.__writer.write({ + "event": "finished", + "duration_s": duration, + "tests": self.__testsRun, + }) + + +def _assembleTestCasesList(suite): + """ + Protected function to assemble a list of test cases included in a test + suite. + + @param suite test suite to be inspected + @type unittest.TestSuite + @return list of tuples containing the test case ID, the string + representation and the short description + @rtype list of tuples of (str, str) + """ + testCases = [] + for test in suite: + if isinstance(test, unittest.TestSuite): + testCases.extend(_assembleTestCasesList(test)) + else: + testId = test.id() + if ( + "ModuleImportFailure" not in testId and + "LoadTestsFailure" not in testId and + "_FailedTest" not in testId + ): + testCases.append( + (testId, str(test), test.shortDescription()) + ) + return testCases + + +def runtest(argv): + """ + Function to run the tests. + + @param argv list of command line parameters. + @type list of str + """ + from EricNetwork.EricJsonStreamWriter import EricJsonWriter + writer = EricJsonWriter(argv[0], int(argv[1])) + del argv[:2] + + # process arguments + if argv[0] == "discover": + discover = True + argv.pop(0) + if argv[0] == "--start-directory": + discoveryStart = argv[1] + del argv[:2] + else: + discover = False + discoveryStart = "" + + failfast = "--failfast" in argv + if failfast: + argv.remove("--failfast") + + collectCoverage = "--cover" in argv + if collectCoverage: + argv.remove("--cover") + coverageErase = "--cover-erase" in argv + if coverageErase: + argv.remove("--cover-erase") + if "--cover-file" in argv: + index = argv.index("--cover-file") + covDataFile = argv[index + 1] + del argv[index:index + 2] + else: + covDataFile = "" + + if argv and argv[0] == "--failed-only": + if discover: + testFileName = "" + failed = argv[1:] + else: + testFileName = argv[1] + failed = argv[2:] + else: + failed = [] + if discover: + testFileName = testName = "" + else: + testFileName, testName = argv[:2] + del argv[:2] + + testCases = argv[:] + + if testFileName: + sys.path.insert(1, os.path.dirname(os.path.abspath(testFileName))) + elif discoveryStart: + sys.path.insert(1, os.path.abspath(discoveryStart)) + + # setup test coverage + if collectCoverage: + if not covDataFile: + if discover: + covname = os.path.join(discoveryStart, "test") + elif testFileName: + covname = os.path.splitext( + os.path.abspath(testFileName))[0] + else: + covname = "test" + covDataFile = "{0}.coverage".format(covname) + if not os.path.isabs(covDataFile): + covDataFile = os.path.abspath(covDataFile) + + sys.path.insert( + 2, + os.path.abspath(os.path.join( + os.path.dirname(__file__), "..", "..", "DebugClients", "Python" + )) + ) + from DebugClients.Python.coverage import Coverage + cover = Coverage(data_file=covDataFile) + if coverageErase: + cover.erase() + cover.start() + else: + cover = None + + try: + testLoader = unittest.TestLoader() + if discover and not failed: + if testCases: + test = testLoader.loadTestsFromNames(testCases) + else: + test = testLoader.discover(discoveryStart) + else: + if testFileName: + module = __import__(os.path.splitext( + os.path.basename(testFileName))[0]) + else: + module = None + if failed: + if module: + failed = [t.split(".", 1)[1] + for t in failed] + test = testLoader.loadTestsFromNames( + failed, module) + else: + test = testLoader.loadTestsFromName( + testName, module) + except Exception as err: + print("Exception:", str(err)) + writer.write({ + "event": "collecterror", + "error": str(err), + }) + sys.exit(1) + + collectedTests = { + "event": "collected", + "tests": [ + {"id": id, "name": name, "description": desc} + for id, name, desc in _assembleTestCasesList(test) + ] + } + writer.write(collectedTests) + + testResult = EricTestResult(writer, failfast) + startTestRun = getattr(testResult, 'startTestRun', None) + if startTestRun is not None: + startTestRun() + try: + test.run(testResult) + finally: + if cover: + cover.stop() + cover.save() + writer.write({ + "event": "coverage", + "file": covDataFile, + }) + stopTestRun = getattr(testResult, 'stopTestRun', None) + if stopTestRun is not None: + stopTestRun() + + writer.close() + sys.exit(0) + +if __name__ == '__main__': + if len(sys.argv) > 1: + command = sys.argv[1] + if command == "installed": + sys.exit(0) + + elif command == "versions": + import platform + versions = { + "name": "unittest", + "version": platform.python_version(), + "plugins": [], + } + print(json.dumps(versions)) + sys.exit(0) + + elif command == "runtest": + runtest(sys.argv[2:]) + sys.exit(0) + + sys.exit(42) + +# +# eflag: noqa = M801
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/Interfaces/__init__.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package containg the various test framework interfaces. +""" + +from .PytestExecutor import PytestExecutor +from .UnittestExecutor import UnittestExecutor + +Frameworks = ( + UnittestExecutor, + PytestExecutor, +) + +FrameworkNames = { + "MicroPython": ( + UnittestExecutor.name, + PytestExecutor.name, + ), + "Python3": ( + UnittestExecutor.name, + PytestExecutor.name, + ), +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/TestResultsTree.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,611 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a tree view and associated model to show the test result +data. +""" + +import contextlib +import copy +import locale + +from collections import Counter +from operator import attrgetter + +from PyQt6.QtCore import ( + pyqtSignal, pyqtSlot, Qt, QAbstractItemModel, QCoreApplication, + QModelIndex, QPoint +) +from PyQt6.QtGui import QBrush, QColor +from PyQt6.QtWidgets import QMenu, QTreeView + +from EricWidgets.EricApplication import ericApp + +import Preferences + +from .Interfaces.TestExecutorBase import TestResultCategory + +TopLevelId = 2 ** 32 - 1 + + +class TestResultsModel(QAbstractItemModel): + """ + Class implementing the item model containing the test data. + + @signal summary(str) emitted whenever the model data changes. The element + is a summary of the test results of the model. + """ + summary = pyqtSignal(str) + + Headers = [ + QCoreApplication.translate("TestResultsModel", "Status"), + QCoreApplication.translate("TestResultsModel", "Name"), + QCoreApplication.translate("TestResultsModel", "Message"), + QCoreApplication.translate("TestResultsModel", "Duration [ms]"), + ] + + StatusColumn = 0 + NameColumn = 1 + MessageColumn = 2 + DurationColumn = 3 + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object (defaults to None) + @type QObject (optional) + """ + super().__init__(parent) + + if ericApp().usesDarkPalette(): + self.__backgroundColors = { + TestResultCategory.RUNNING: None, + TestResultCategory.FAIL: QBrush(QColor("#880000")), + TestResultCategory.OK: QBrush(QColor("#005500")), + TestResultCategory.SKIP: QBrush(QColor("#3f3f3f")), + TestResultCategory.PENDING: QBrush(QColor("#004768")), + } + else: + self.__backgroundColors = { + TestResultCategory.RUNNING: None, + TestResultCategory.FAIL: QBrush(QColor("#ff8080")), + TestResultCategory.OK: QBrush(QColor("#c1ffba")), + TestResultCategory.SKIP: QBrush(QColor("#c5c5c5")), + TestResultCategory.PENDING: QBrush(QColor("#6fbaff")), + } + + self.__testResults = [] + + def index(self, row, column, parent=QModelIndex()): + """ + Public method to generate an index for the given row and column to + identify the item. + + @param row row for the index + @type int + @param column column for the index + @type int + @param parent index of the parent item (defaults to QModelIndex()) + @type QModelIndex (optional) + @return index for the item + @rtype QModelIndex + """ + if not self.hasIndex(row, column, parent): # check bounds etc. + return QModelIndex() + + if not parent.isValid(): + # top level item + return self.createIndex(row, column, TopLevelId) + else: + testResultIndex = parent.row() + return self.createIndex(row, column, testResultIndex) + + def data(self, index, role): + """ + Public method to get the data for the various columns and roles. + + @param index index of the data to be returned + @type QModelIndex + @param role role designating the data to return + @type Qt.ItemDataRole + @return requested data item + @rtype Any + """ + if not index.isValid(): + return None + + row = index.row() + column = index.column() + idx = index.internalId() + + if role == Qt.ItemDataRole.DisplayRole: + if idx != TopLevelId: + if bool(self.__testResults[idx].extra): + return self.__testResults[idx].extra[index.row()] + else: + return None + elif column == TestResultsModel.StatusColumn: + return self.__testResults[row].status + elif column == TestResultsModel.NameColumn: + return self.__testResults[row].name + elif column == TestResultsModel.MessageColumn: + return self.__testResults[row].message + elif column == TestResultsModel.DurationColumn: + duration = self.__testResults[row].duration + return ( + "" + if duration is None else + locale.format_string("%.2f", duration, grouping=True) + ) + elif role == Qt.ItemDataRole.ToolTipRole: + if idx == TopLevelId and column == TestResultsModel.NameColumn: + return self.__testResults[row].name + elif role == Qt.ItemDataRole.FontRole: + if idx != TopLevelId: + return Preferences.getEditorOtherFonts("MonospacedFont") + elif role == Qt.ItemDataRole.BackgroundRole: + if idx == TopLevelId: + testResult = self.__testResults[row] + with contextlib.suppress(KeyError): + return self.__backgroundColors[testResult.category] + elif role == Qt.ItemDataRole.TextAlignmentRole: + if idx == TopLevelId and column == TestResultsModel.DurationColumn: + return Qt.AlignmentFlag.AlignRight + elif role == Qt.ItemDataRole.UserRole: # __IGNORE_WARNING_Y102__ + if idx == TopLevelId: + testresult = self.__testResults[row] + return (testresult.filename, testresult.lineno) + + return None + + def headerData(self, section, orientation, + role=Qt.ItemDataRole.DisplayRole): + """ + Public method to get the header string for the various sections. + + @param section section number + @type int + @param orientation orientation of the header + @type Qt.Orientation + @param role data role (defaults to Qt.ItemDataRole.DisplayRole) + @type Qt.ItemDataRole (optional) + @return header string of the section + @rtype str + """ + if ( + orientation == Qt.Orientation.Horizontal and + role == Qt.ItemDataRole.DisplayRole + ): + return TestResultsModel.Headers[section] + else: + return None + + def parent(self, index): + """ + Public method to get the parent of the item pointed to by index. + + @param index index of the item + @type QModelIndex + @return index of the parent item + @rtype QModelIndex + """ + if not index.isValid(): + return QModelIndex() + + idx = index.internalId() + if idx == TopLevelId: + return QModelIndex() + else: + return self.index(idx, 0) + + def rowCount(self, parent=QModelIndex()): + """ + Public method to get the number of row for a given parent index. + + @param parent index of the parent item (defaults to QModelIndex()) + @type QModelIndex (optional) + @return number of rows + @rtype int + """ + if not parent.isValid(): + return len(self.__testResults) + + if ( + parent.internalId() == TopLevelId and + parent.column() == 0 and + self.__testResults[parent.row()].extra is not None + ): + return len(self.__testResults[parent.row()].extra) + + return 0 + + def columnCount(self, parent=QModelIndex()): + """ + Public method to get the number of columns. + + @param parent index of the parent item (defaults to QModelIndex()) + @type QModelIndex (optional) + @return number of columns + @rtype int + """ + if not parent.isValid(): + return len(TestResultsModel.Headers) + else: + return 1 + + def clear(self): + """ + Public method to clear the model data. + """ + self.beginResetModel() + self.__testResults.clear() + self.endResetModel() + + self.summary.emit("") + + def sort(self, column, order): + """ + Public method to sort the model data by column in order. + + @param column sort column number + @type int + @param order sort order + @type Qt.SortOrder + """ # __IGNORE_WARNING_D234r__ + def durationKey(result): + """ + Function to generate a key for duration sorting + + @param result result object + @type TestResult + @return sort key + @rtype float + """ + return result.duration or -1.0 + + self.beginResetModel() + reverse = order == Qt.SortOrder.DescendingOrder + if column == TestResultsModel.StatusColumn: + self.__testResults.sort(key=attrgetter('category', 'status'), + reverse=reverse) + elif column == TestResultsModel.NameColumn: + self.__testResults.sort(key=attrgetter('name'), reverse=reverse) + elif column == TestResultsModel.MessageColumn: + self.__testResults.sort(key=attrgetter('message'), reverse=reverse) + elif column == TestResultsModel.DurationColumn: + self.__testResults.sort(key=durationKey, reverse=reverse) + self.endResetModel() + + def getTestResults(self): + """ + Public method to get the list of test results managed by the model. + + @return list of test results managed by the model + @rtype list of TestResult + """ + return copy.deepcopy(self.__testResults) + + def setTestResults(self, testResults): + """ + Public method to set the list of test results of the model. + + @param testResults test results to be managed by the model + @type list of TestResult + """ + self.beginResetModel() + self.__testResults = copy.deepcopy(testResults) + self.endResetModel() + + self.summary.emit(self.__summary()) + + def addTestResults(self, testResults): + """ + Public method to add test results to the ones already managed by the + model. + + @param testResults test results to be added to the model + @type list of TestResult + """ + firstRow = len(self.__testResults) + lastRow = firstRow + len(testResults) - 1 + self.beginInsertRows(QModelIndex(), firstRow, lastRow) + self.__testResults.extend(testResults) + self.endInsertRows() + + self.summary.emit(self.__summary()) + + def updateTestResults(self, testResults): + """ + Public method to update the data of managed test result items. + + @param testResults test results to be updated + @type list of TestResult + """ + minIndex = None + maxIndex = None + + testResultsToBeAdded = [] + + for testResult in testResults: + for (index, currentResult) in enumerate(self.__testResults): + if currentResult.id == testResult.id: + self.__testResults[index] = testResult + if minIndex is None: + minIndex = index + maxIndex = index + else: + minIndex = min(minIndex, index) + maxIndex = max(maxIndex, index) + + break + else: + # Test result with given id was not found. + # Just add it to the list (could be a sub test) + testResultsToBeAdded.append(testResult) + + if minIndex is not None: + self.dataChanged.emit( + self.index(minIndex, 0), + self.index(maxIndex, len(TestResultsModel.Headers) - 1) + ) + + self.summary.emit(self.__summary()) + + if testResultsToBeAdded: + self.addTestResults(testResultsToBeAdded) + + def getFailedTests(self): + """ + Public method to extract the test ids of all failed tests. + + @return test ids of all failed tests + @rtype list of str + """ + failedIds = [ + res.id for res in self.__testResults if ( + res.category == TestResultCategory.FAIL and + not res.subtestResult + ) + ] + return failedIds + + def __summary(self): + """ + Private method to generate a test results summary text. + + @return test results summary text + @rtype str + """ + if len(self.__testResults) == 0: + return self.tr("No results to show") + + counts = Counter(res.category for res in self.__testResults) + if all( + counts[category] == 0 + for category in (TestResultCategory.FAIL, TestResultCategory.OK, + TestResultCategory.SKIP) + ): + return self.tr("Collected %n test(s)", "", len(self.__testResults)) + + return self.tr( + "%n test(s)/subtest(s) total, {0} failed, {1} passed," + " {2} skipped, {3} pending", + "", len(self.__testResults) + ).format( + counts[TestResultCategory.FAIL], + counts[TestResultCategory.OK], + counts[TestResultCategory.SKIP], + counts[TestResultCategory.PENDING] + ) + + +class TestResultsTreeView(QTreeView): + """ + Class implementing a tree view to show the test result data. + + @signal goto(str, int) emitted to go to the position given by file name + and line number + """ + goto = pyqtSignal(str, int) + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + + self.setItemsExpandable(True) + self.setExpandsOnDoubleClick(False) + self.setSortingEnabled(True) + + self.header().setDefaultAlignment(Qt.AlignmentFlag.AlignCenter) + self.header().setSortIndicatorShown(False) + + self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) + + # connect signals and slots + self.doubleClicked.connect(self.__gotoTestDefinition) + self.customContextMenuRequested.connect(self.__showContextMenu) + + self.header().sortIndicatorChanged.connect(self.sortByColumn) + self.header().sortIndicatorChanged.connect( + lambda column, order: self.header().setSortIndicatorShown(True)) + + def reset(self): + """ + Public method to reset the internal state of the view. + """ + super().reset() + + self.resizeColumns() + self.spanFirstColumn(0, self.model().rowCount() - 1) + + def rowsInserted(self, parent, startRow, endRow): + """ + Public method called when rows are inserted. + + @param parent model index of the parent item + @type QModelIndex + @param startRow first row been inserted + @type int + @param endRow last row been inserted + @type int + """ + super().rowsInserted(parent, startRow, endRow) + + self.resizeColumns() + self.spanFirstColumn(startRow, endRow) + + def dataChanged(self, topLeft, bottomRight, roles=[]): + """ + Public method called when the model data has changed. + + @param topLeft index of the top left element + @type QModelIndex + @param bottomRight index of the bottom right element + @type QModelIndex + @param roles list of roles changed (defaults to []) + @type list of Qt.ItemDataRole (optional) + """ + super().dataChanged(topLeft, bottomRight, roles) + + self.resizeColumns() + while topLeft.parent().isValid(): + topLeft = topLeft.parent() + while bottomRight.parent().isValid(): + bottomRight = bottomRight.parent() + self.spanFirstColumn(topLeft.row(), bottomRight.row()) + + def resizeColumns(self): + """ + Public method to resize the columns to their contents. + """ + for column in range(self.model().columnCount()): + self.resizeColumnToContents(column) + + def spanFirstColumn(self, startRow, endRow): + """ + Public method to make the first column span the row for second level + items. + + These items contain the test results. + + @param startRow index of the first row to span + @type QModelIndex + @param endRow index of the last row (including) to span + @type QModelIndex + """ + model = self.model() + for row in range(startRow, endRow + 1): + index = model.index(row, 0) + for i in range(model.rowCount(index)): + self.setFirstColumnSpanned(i, index, True) + + def __canonicalIndex(self, index): + """ + Private method to create the canonical index for a given index. + + The canonical index is the index of the first column of the test + result entry (i.e. the top-level item). If the index is invalid, + None is returned. + + @param index index to determine the canonical index for + @type QModelIndex + @return index of the firt column of the associated top-level item index + @rtype QModelIndex + """ + if not index.isValid(): + return None + + while index.parent().isValid(): # find the top-level node + index = index.parent() + index = index.sibling(index.row(), 0) # go to first column + return index + + @pyqtSlot(QModelIndex) + def __gotoTestDefinition(self, index): + """ + Private slot to show the test definition. + + @param index index for the double-clicked item + @type QModelIndex + """ + cindex = self.__canonicalIndex(index) + filename, lineno = self.model().data(cindex, Qt.ItemDataRole.UserRole) + if filename is not None: + if lineno is None: + lineno = 1 + self.goto.emit(filename, lineno) + + @pyqtSlot(QPoint) + def __showContextMenu(self, pos): + """ + Private slot to show the context menu. + + @param pos relative position for the context menu + @type QPoint + """ + index = self.indexAt(pos) + cindex = self.__canonicalIndex(index) + + contextMenu = ( + self.__createContextMenu(cindex) + if cindex else + self.__createBackgroundContextMenu() + ) + contextMenu.exec(self.mapToGlobal(pos)) + + def __createContextMenu(self, index): + """ + Private method to create a context menu for the item pointed to by the + given index. + + @param index index of the item + @type QModelIndex + @return created context menu + @rtype QMenu + """ + menu = QMenu(self) + if self.isExpanded(index): + menu.addAction(self.tr("Collapse"), + lambda: self.collapse(index)) + else: + act = menu.addAction(self.tr("Expand"), + lambda: self.expand(index)) + act.setEnabled(self.model().hasChildren(index)) + menu.addSeparator() + + act = menu.addAction(self.tr("Show Source"), + lambda: self.__gotoTestDefinition(index)) + act.setEnabled( + self.model().data(index, Qt.ItemDataRole.UserRole) is not None + ) + menu.addSeparator() + + menu.addAction(self.tr("Collapse All"), self.collapseAll) + menu.addAction(self.tr("Expand All"), self.expandAll) + + return menu + + def __createBackgroundContextMenu(self): + """ + Private method to create a context menu for the background. + + @return created context menu + @rtype QMenu + """ + menu = QMenu(self) + menu.addAction(self.tr("Collapse All"), self.collapseAll) + menu.addAction(self.tr("Expand All"), self.expandAll) + + return menu + +# +# eflag: noqa = M821, M822
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/TestingWidget.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,1162 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a widget to orchestrate unit test execution. +""" + +import contextlib +import enum +import locale +import os + +from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QEvent, QCoreApplication +from PyQt6.QtWidgets import ( + QAbstractButton, QComboBox, QDialogButtonBox, QWidget +) + +from EricWidgets import EricMessageBox +from EricWidgets.EricApplication import ericApp +from EricWidgets.EricMainWindow import EricMainWindow +from EricWidgets.EricPathPicker import EricPathPickerModes + +from .Ui_TestingWidget import Ui_TestingWidget + +from .TestResultsTree import TestResultsModel, TestResultsTreeView +from .Interfaces import Frameworks +from .Interfaces.TestExecutorBase import ( + TestConfig, TestResult, TestResultCategory +) +from .Interfaces.TestFrameworkRegistry import TestFrameworkRegistry + +import Preferences +import UI.PixmapCache + +from Globals import ( + recentNameTestDiscoverHistory, recentNameTestFileHistory, + recentNameTestNameHistory, recentNameTestFramework, + recentNameTestEnvironment +) + + +class TestingWidgetModes(enum.Enum): + """ + Class defining the various modes of the testing widget. + """ + IDLE = 0 # idle, no test were run yet + RUNNING = 1 # test run being performed + STOPPED = 2 # test run finished + + +class TestingWidget(QWidget, Ui_TestingWidget): + """ + Class implementing a widget to orchestrate unit test execution. + + @signal testFile(str, int, bool) emitted to show the source of a + test file + @signal testRunStopped() emitted after a test run has finished + """ + testFile = pyqtSignal(str, int, bool) + testRunStopped = pyqtSignal() + + def __init__(self, testfile=None, parent=None): + """ + Constructor + + @param testfile file name of the test to load + @type str + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.__resultsModel = TestResultsModel(self) + self.__resultsModel.summary.connect(self.__setStatusLabel) + self.__resultsTree = TestResultsTreeView(self) + self.__resultsTree.setModel(self.__resultsModel) + self.__resultsTree.goto.connect(self.__showSource) + self.resultsGroupBox.layout().addWidget(self.__resultsTree) + + self.versionsButton.setIcon( + UI.PixmapCache.getIcon("info")) + self.clearHistoriesButton.setIcon( + UI.PixmapCache.getIcon("clearPrivateData")) + + self.testsuitePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) + self.testsuitePicker.setInsertPolicy( + QComboBox.InsertPolicy.InsertAtTop) + self.testsuitePicker.setSizeAdjustPolicy( + QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon) + + self.discoveryPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) + self.discoveryPicker.setInsertPolicy( + QComboBox.InsertPolicy.InsertAtTop) + self.discoveryPicker.setSizeAdjustPolicy( + QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon) + + self.testComboBox.lineEdit().setClearButtonEnabled(True) + + # create some more dialog buttons for orchestration + self.__showLogButton = self.buttonBox.addButton( + self.tr("Show Output..."), + QDialogButtonBox.ButtonRole.ActionRole) + self.__showLogButton.setToolTip( + self.tr("Show the output of the test runner process")) + self.__showLogButton.setWhatsThis(self.tr( + """<b>Show Output...</b""" + """<p>This button opens a dialog containing the output of the""" + """ test runner process of the most recent run.</p>""")) + + self.__showCoverageButton = self.buttonBox.addButton( + self.tr("Show Coverage..."), + QDialogButtonBox.ButtonRole.ActionRole) + self.__showCoverageButton.setToolTip( + self.tr("Show code coverage in a new dialog")) + self.__showCoverageButton.setWhatsThis(self.tr( + """<b>Show Coverage...</b>""" + """<p>This button opens a dialog containing the collected code""" + """ coverage data.</p>""")) + + self.__startButton = self.buttonBox.addButton( + self.tr("Start"), QDialogButtonBox.ButtonRole.ActionRole) + + self.__startButton.setToolTip(self.tr( + "Start the selected testsuite")) + self.__startButton.setWhatsThis(self.tr( + """<b>Start Test</b>""" + """<p>This button starts the test run.</p>""")) + + self.__startFailedButton = self.buttonBox.addButton( + self.tr("Rerun Failed"), QDialogButtonBox.ButtonRole.ActionRole) + self.__startFailedButton.setToolTip( + self.tr("Reruns failed tests of the selected testsuite")) + self.__startFailedButton.setWhatsThis(self.tr( + """<b>Rerun Failed</b>""" + """<p>This button reruns all failed tests of the most recent""" + """ test run.</p>""")) + + self.__stopButton = self.buttonBox.addButton( + self.tr("Stop"), QDialogButtonBox.ButtonRole.ActionRole) + self.__stopButton.setToolTip(self.tr("Stop the running test")) + self.__stopButton.setWhatsThis(self.tr( + """<b>Stop Test</b>""" + """<p>This button stops a running test.</p>""")) + + self.setWindowFlags( + self.windowFlags() | + Qt.WindowType.WindowContextHelpButtonHint + ) + self.setWindowIcon(UI.PixmapCache.getIcon("eric")) + self.setWindowTitle(self.tr("Testing")) + + try: + # we are called from within the eric IDE + self.__venvManager = ericApp().getObject("VirtualEnvManager") + self.__project = ericApp().getObject("Project") + self.__project.projectOpened.connect(self.__projectOpened) + self.__project.projectClosed.connect(self.__projectClosed) + except KeyError: + # we were called as a standalone application + from VirtualEnv.VirtualenvManager import VirtualenvManager + self.__venvManager = VirtualenvManager(self) + self.__venvManager.virtualEnvironmentAdded.connect( + self.__populateVenvComboBox) + self.__venvManager.virtualEnvironmentRemoved.connect( + self.__populateVenvComboBox) + self.__venvManager.virtualEnvironmentChanged.connect( + self.__populateVenvComboBox) + ericApp().registerObject("VirtualEnvManager", self.__venvManager) + + self.__project = None + + self.__discoverHistory = [] + self.__fileHistory = [] + self.__testNameHistory = [] + self.__recentFramework = "" + self.__recentEnvironment = "" + self.__failedTests = [] + + self.__coverageFile = "" + self.__coverageDialog = None + + self.__editors = [] + self.__testExecutor = None + self.__recentLog = "" + + # connect some signals + self.discoveryPicker.editTextChanged.connect( + self.__resetResults) + self.testsuitePicker.editTextChanged.connect( + self.__resetResults) + self.testComboBox.editTextChanged.connect( + self.__resetResults) + + self.__frameworkRegistry = TestFrameworkRegistry() + for framework in Frameworks: + self.__frameworkRegistry.register(framework) + + self.__setIdleMode() + + self.__loadRecent() + self.__populateVenvComboBox() + + if self.__project and self.__project.isOpen(): + self.venvComboBox.setCurrentText(self.__project.getProjectVenv()) + self.frameworkComboBox.setCurrentText( + self.__project.getProjectTestingFramework()) + self.__insertDiscovery(self.__project.getProjectPath()) + else: + self.__insertDiscovery("") + + self.__insertTestFile(testfile) + self.__insertTestName("") + + self.clearHistoriesButton.clicked.connect(self.clearRecent) + + self.tabWidget.setCurrentIndex(0) + + def __populateVenvComboBox(self): + """ + Private method to (re-)populate the virtual environments selector. + """ + currentText = self.venvComboBox.currentText() + if not currentText: + currentText = self.__recentEnvironment + + self.venvComboBox.clear() + self.venvComboBox.addItem("") + self.venvComboBox.addItems( + sorted(self.__venvManager.getVirtualenvNames())) + self.venvComboBox.setCurrentText(currentText) + + def __populateTestFrameworkComboBox(self): + """ + Private method to (re-)populate the test framework selector. + """ + currentText = self.frameworkComboBox.currentText() + if not currentText: + currentText = self.__recentFramework + + self.frameworkComboBox.clear() + + if bool(self.venvComboBox.currentText()): + interpreter = self.__venvManager.getVirtualenvInterpreter( + self.venvComboBox.currentText()) + self.frameworkComboBox.addItem("") + for index, (name, executor) in enumerate( + sorted(self.__frameworkRegistry.getFrameworks().items()), + start=1 + ): + isInstalled = executor.isInstalled(interpreter) + entry = ( + name + if isInstalled else + self.tr("{0} (not available)").format(name) + ) + self.frameworkComboBox.addItem(entry) + self.frameworkComboBox.model().item(index).setEnabled( + isInstalled) + + self.frameworkComboBox.setCurrentText(self.__recentFramework) + + def getResultsModel(self): + """ + Public method to get a reference to the model containing the test + result data. + + @return reference to the test results model + @rtype TestResultsModel + """ + return self.__resultsModel + + def hasFailedTests(self): + """ + Public method to check for failed tests. + + @return flag indicating the existence of failed tests + @rtype bool + """ + return bool(self.__resultsModel.getFailedTests()) + + def getFailedTests(self): + """ + Public method to get the list of failed tests (if any). + + @return list of IDs of failed tests + @rtype list of str + """ + return self.__failedTests[:] + + @pyqtSlot(str) + def __insertHistory(self, widget, history, item): + """ + Private slot to insert an item into a history object. + + @param widget reference to the widget + @type QComboBox or EricComboPathPicker + @param history array containing the history + @type list of str + @param item item to be inserted + @type str + """ + # prepend the given directory to the discovery picker + if item is None: + item = "" + if item in history: + history.remove(item) + history.insert(0, item) + widget.clear() + widget.addItems(history) + widget.setEditText(item) + + @pyqtSlot(str) + def __insertDiscovery(self, start): + """ + Private slot to insert the discovery start directory into the + discoveryPicker object. + + @param start start directory name to be inserted + @type str + """ + self.__insertHistory(self.discoveryPicker, self.__discoverHistory, + start) + + @pyqtSlot(str) + def setTestFile(self, testFile, forProject=False): + """ + Public slot to set the given test file as the current one. + + @param testFile path of the test file + @type str + @param forProject flag indicating that this call is for a project + (defaults to False) + @type bool (optional) + """ + if testFile: + self.__insertTestFile(testFile) + + self.discoverCheckBox.setChecked(forProject or not bool(testFile)) + + if forProject: + self.__projectOpened() + + self.tabWidget.setCurrentIndex(0) + + @pyqtSlot(str) + def __insertTestFile(self, prog): + """ + Private slot to insert a test file name into the testsuitePicker + object. + + @param prog test file name to be inserted + @type str + """ + self.__insertHistory(self.testsuitePicker, self.__fileHistory, + prog) + + @pyqtSlot(str) + def __insertTestName(self, testName): + """ + Private slot to insert a test name into the testComboBox object. + + @param testName name of the test to be inserted + @type str + """ + self.__insertHistory(self.testComboBox, self.__testNameHistory, + testName) + + def __loadRecent(self): + """ + Private method to load the most recently used lists. + """ + Preferences.Prefs.rsettings.sync() + + # 1. recently selected test framework and virtual environment + self.__recentEnvironment = Preferences.Prefs.rsettings.value( + recentNameTestEnvironment, "") + self.__recentFramework = Preferences.Prefs.rsettings.value( + recentNameTestFramework, "") + + # 2. discovery history + self.__discoverHistory = [] + rs = Preferences.Prefs.rsettings.value( + recentNameTestDiscoverHistory) + if rs is not None: + recent = [f for f in Preferences.toList(rs) if os.path.exists(f)] + self.__discoverHistory = recent[ + :Preferences.getDebugger("RecentNumber")] + + # 3. test file history + self.__fileHistory = [] + rs = Preferences.Prefs.rsettings.value( + recentNameTestFileHistory) + if rs is not None: + recent = [f for f in Preferences.toList(rs) if os.path.exists(f)] + self.__fileHistory = recent[ + :Preferences.getDebugger("RecentNumber")] + + # 4. test name history + self.__testNameHistory = [] + rs = Preferences.Prefs.rsettings.value( + recentNameTestNameHistory) + if rs is not None: + recent = [n for n in Preferences.toList(rs) if n] + self.__testNameHistory = recent[ + :Preferences.getDebugger("RecentNumber")] + + def __saveRecent(self): + """ + Private method to save the most recently used lists. + """ + Preferences.Prefs.rsettings.setValue( + recentNameTestEnvironment, self.__recentEnvironment) + Preferences.Prefs.rsettings.setValue( + recentNameTestFramework, self.__recentFramework) + Preferences.Prefs.rsettings.setValue( + recentNameTestDiscoverHistory, self.__discoverHistory) + Preferences.Prefs.rsettings.setValue( + recentNameTestFileHistory, self.__fileHistory) + Preferences.Prefs.rsettings.setValue( + recentNameTestNameHistory, self.__testNameHistory) + + Preferences.Prefs.rsettings.sync() + + @pyqtSlot() + def clearRecent(self): + """ + Public slot to clear the recently used lists. + """ + # clear histories + self.__discoverHistory = [] + self.__fileHistory = [] + self.__testNameHistory = [] + + # clear widgets with histories + self.discoveryPicker.clear() + self.testsuitePicker.clear() + self.testComboBox.clear() + + # sync histories + self.__saveRecent() + + @pyqtSlot() + def __resetResults(self): + """ + Private slot to reset the test results tab and data. + """ + self.__totalCount = 0 + self.__runCount = 0 + + self.progressCounterRunCount.setText("0") + self.progressCounterRemCount.setText("0") + self.progressProgressBar.setMaximum(100) + self.progressProgressBar.setValue(0) + + self.statusLabel.clear() + + self.__resultsModel.clear() + self.__updateButtonBoxButtons() + + @pyqtSlot() + def __updateButtonBoxButtons(self): + """ + Private slot to update the state of the buttons of the button box. + """ + failedAvailable = bool(self.__resultsModel.getFailedTests()) + + # Start button + if self.__mode in ( + TestingWidgetModes.IDLE, TestingWidgetModes.STOPPED + ): + self.__startButton.setEnabled( + bool(self.venvComboBox.currentText()) and + bool(self.frameworkComboBox.currentText()) and + ( + (self.discoverCheckBox.isChecked() and + bool(self.discoveryPicker.currentText())) or + bool(self.testsuitePicker.currentText()) + ) + ) + self.__startButton.setDefault( + self.__mode == TestingWidgetModes.IDLE or + not failedAvailable + ) + else: + self.__startButton.setEnabled(False) + self.__startButton.setDefault(False) + + # Start Failed button + self.__startFailedButton.setEnabled( + self.__mode == TestingWidgetModes.STOPPED and + failedAvailable + ) + self.__startFailedButton.setDefault( + self.__mode == TestingWidgetModes.STOPPED and + failedAvailable + ) + + # Stop button + self.__stopButton.setEnabled( + self.__mode == TestingWidgetModes.RUNNING) + self.__stopButton.setDefault( + self.__mode == TestingWidgetModes.RUNNING) + + # Code coverage button + self.__showCoverageButton.setEnabled( + self.__mode == TestingWidgetModes.STOPPED and + bool(self.__coverageFile) and + ( + (self.discoverCheckBox.isChecked() and + bool(self.discoveryPicker.currentText())) or + bool(self.testsuitePicker.currentText()) + ) + ) + + # Log output button + self.__showLogButton.setEnabled(bool(self.__recentLog)) + + # Close button + self.buttonBox.button( + QDialogButtonBox.StandardButton.Close + ).setEnabled(self.__mode in ( + TestingWidgetModes.IDLE, TestingWidgetModes.STOPPED + )) + + @pyqtSlot() + def __updateProgress(self): + """ + Private slot update the progress indicators. + """ + self.progressCounterRunCount.setText( + str(self.__runCount)) + self.progressCounterRemCount.setText( + str(self.__totalCount - self.__runCount)) + self.progressProgressBar.setMaximum(self.__totalCount) + self.progressProgressBar.setValue(self.__runCount) + + @pyqtSlot() + def __setIdleMode(self): + """ + Private slot to switch the widget to idle mode. + """ + self.__mode = TestingWidgetModes.IDLE + self.__updateButtonBoxButtons() + self.progressGroupBox.hide() + self.tabWidget.setCurrentIndex(0) + + @pyqtSlot() + def __setRunningMode(self): + """ + Private slot to switch the widget to running mode. + """ + self.__mode = TestingWidgetModes.RUNNING + + self.__totalCount = 0 + self.__runCount = 0 + + self.__coverageFile = "" + + self.sbLabel.setText(self.tr("Running")) + self.tabWidget.setCurrentIndex(1) + self.__updateButtonBoxButtons() + self.__updateProgress() + + self.progressGroupBox.show() + + @pyqtSlot() + def __setStoppedMode(self): + """ + Private slot to switch the widget to stopped mode. + """ + self.__mode = TestingWidgetModes.STOPPED + if self.__totalCount == 0: + self.progressProgressBar.setMaximum(100) + + self.progressGroupBox.hide() + + self.__updateButtonBoxButtons() + + self.testRunStopped.emit() + + self.raise_() + self.activateWindow() + + @pyqtSlot(bool) + def on_discoverCheckBox_toggled(self, checked): + """ + Private slot handling state changes of the 'discover' checkbox. + + @param checked state of the checkbox + @type bool + """ + if not bool(self.discoveryPicker.currentText()): + if self.__project and self.__project.isOpen(): + self.__insertDiscovery(self.__project.getProjectPath()) + else: + self.__insertDiscovery( + Preferences.getMultiProject("Workspace")) + + self.__resetResults() + + @pyqtSlot() + def on_testsuitePicker_aboutToShowPathPickerDialog(self): + """ + Private slot called before the test file selection dialog is shown. + """ + if self.__project: + # we were called from within eric + py3Extensions = ' '.join([ + "*{0}".format(ext) + for ext in + ericApp().getObject("DebugServer").getExtensions('Python3') + ]) + fileFilter = self.tr( + "Python3 Files ({0});;All Files (*)" + ).format(py3Extensions) + else: + # standalone application + fileFilter = self.tr("Python Files (*.py);;All Files (*)") + self.testsuitePicker.setFilters(fileFilter) + + defaultDirectory = ( + self.__project.getProjectPath() + if self.__project and self.__project.isOpen() else + Preferences.getMultiProject("Workspace") + ) + if not defaultDirectory: + defaultDirectory = os.path.expanduser("~") + self.testsuitePicker.setDefaultDirectory(defaultDirectory) + + @pyqtSlot(QAbstractButton) + def on_buttonBox_clicked(self, button): + """ + Private slot called by a button of the button box clicked. + + @param button button that was clicked + @type QAbstractButton + """ + if button == self.__startButton: + self.startTests() + self.__saveRecent() + elif button == self.__stopButton: + self.__stopTests() + elif button == self.__startFailedButton: + self.startTests(failedOnly=True) + elif button == self.__showCoverageButton: + self.__showCoverageDialog() + elif button == self.__showLogButton: + self.__showLogOutput() + + @pyqtSlot(int) + def on_venvComboBox_currentIndexChanged(self, index): + """ + Private slot handling the selection of a virtual environment. + + @param index index of the selected environment + @type int + """ + self.__populateTestFrameworkComboBox() + self.__updateButtonBoxButtons() + + self.versionsButton.setEnabled(bool(self.venvComboBox.currentText())) + + self.__updateCoverage() + + @pyqtSlot(int) + def on_frameworkComboBox_currentIndexChanged(self, index): + """ + Private slot handling the selection of a test framework. + + @param index index of the selected framework + @type int + """ + self.__resetResults() + self.__updateCoverage() + + @pyqtSlot() + def __updateCoverage(self): + """ + Private slot to update the state of the coverage checkbox depending on + the selected framework's capabilities. + """ + hasCoverage = False + + venvName = self.venvComboBox.currentText() + if venvName: + framework = self.frameworkComboBox.currentText() + if framework: + interpreter = self.__venvManager.getVirtualenvInterpreter( + venvName) + executor = self.__frameworkRegistry.createExecutor( + framework, self) + hasCoverage = executor.hasCoverage(interpreter) + + self.coverageCheckBox.setEnabled(hasCoverage) + if not hasCoverage: + self.coverageCheckBox.setChecked(False) + + @pyqtSlot() + def on_versionsButton_clicked(self): + """ + Private slot to show the versions of available plugins. + """ + venvName = self.venvComboBox.currentText() + if venvName: + headerText = self.tr("<h3>Versions of Frameworks and their" + " Plugins</h3>") + versionsText = "" + interpreter = self.__venvManager.getVirtualenvInterpreter(venvName) + for framework in sorted( + self.__frameworkRegistry.getFrameworks().keys() + ): + executor = self.__frameworkRegistry.createExecutor( + framework, self) + versions = executor.getVersions(interpreter) + if versions: + txt = "<p><strong>{0} {1}</strong>".format( + versions["name"], versions["version"]) + + if versions["plugins"]: + txt += "<table>" + for pluginVersion in versions["plugins"]: + txt += self.tr( + "<tr><td>{0}</td><td>{1}</td></tr>" + ).format( + pluginVersion["name"], pluginVersion["version"] + ) + txt += "</table>" + txt += "</p>" + + versionsText += txt + + if not versionsText: + versionsText = self.tr("No version information available.") + + EricMessageBox.information( + self, + self.tr("Versions"), + headerText + versionsText + ) + + @pyqtSlot() + def startTests(self, failedOnly=False): + """ + Public slot to start the test run. + + @param failedOnly flag indicating to run only failed tests + @type bool + """ + if self.__mode == TestingWidgetModes.RUNNING: + return + + self.__recentLog = "" + + self.__recentEnvironment = self.venvComboBox.currentText() + self.__recentFramework = self.frameworkComboBox.currentText() + + self.__failedTests = ( + self.__resultsModel.getFailedTests() + if failedOnly else + [] + ) + discover = self.discoverCheckBox.isChecked() + if discover: + discoveryStart = self.discoveryPicker.currentText() + testFileName = "" + testName = "" + + if discoveryStart: + self.__insertDiscovery(discoveryStart) + else: + discoveryStart = "" + testFileName = self.testsuitePicker.currentText() + if testFileName: + self.__insertTestFile(testFileName) + testName = self.testComboBox.currentText() + if testName: + self.__insertTestName(testName) + + self.sbLabel.setText(self.tr("Preparing Testsuite")) + QCoreApplication.processEvents() + + if self.__project: + mainScript = self.__project.getMainScript(True) + coverageFile = ( + os.path.splitext(mainScript)[0] + ".coverage" + if mainScript else + "" + ) + else: + coverageFile = "" + interpreter = self.__venvManager.getVirtualenvInterpreter( + self.__recentEnvironment) + config = TestConfig( + interpreter=interpreter, + discover=discover, + discoveryStart=discoveryStart, + testFilename=testFileName, + testName=testName, + failFast=self.failfastCheckBox.isChecked(), + failedOnly=failedOnly, + collectCoverage=self.coverageCheckBox.isChecked(), + eraseCoverage=self.coverageEraseCheckBox.isChecked(), + coverageFile=coverageFile, + ) + + self.__testExecutor = self.__frameworkRegistry.createExecutor( + self.__recentFramework, self) + self.__testExecutor.collected.connect(self.__testsCollected) + self.__testExecutor.collectError.connect(self.__testsCollectError) + self.__testExecutor.startTest.connect(self.__testStarted) + self.__testExecutor.testResult.connect(self.__processTestResult) + self.__testExecutor.testFinished.connect(self.__testProcessFinished) + self.__testExecutor.testRunFinished.connect(self.__testRunFinished) + self.__testExecutor.stop.connect(self.__testsStopped) + self.__testExecutor.coverageDataSaved.connect(self.__coverageData) + self.__testExecutor.testRunAboutToBeStarted.connect( + self.__testRunAboutToBeStarted) + + self.__setRunningMode() + self.__testExecutor.start(config, []) + + @pyqtSlot() + def __stopTests(self): + """ + Private slot to stop the current test run. + """ + self.__testExecutor.stopIfRunning() + + @pyqtSlot(list) + def __testsCollected(self, testNames): + """ + Private slot handling the 'collected' signal of the executor. + + @param testNames list of tuples containing the test id, the test name + and a description of collected tests + @type list of tuple of (str, str, str) + """ + testResults = [ + TestResult( + category=TestResultCategory.PENDING, + status=self.tr("pending"), + name=name, + id=id, + message=desc, + ) for id, name, desc in testNames + ] + self.__resultsModel.addTestResults(testResults) + + self.__totalCount += len(testResults) + self.__updateProgress() + + @pyqtSlot(list) + def __testsCollectError(self, errors): + """ + Private slot handling the 'collectError' signal of the executor. + + @param errors list of tuples containing the test name and a description + of the error + @type list of tuple of (str, str) + """ + testResults = [] + + for testFile, error in errors: + if testFile: + testResults.append(TestResult( + category=TestResultCategory.FAIL, + status=self.tr("Failure"), + name=testFile, + id=testFile, + message=self.tr("Collection Error"), + extra=error.splitlines() + )) + else: + EricMessageBox.critical( + self, + self.tr("Collection Error"), + self.tr( + "<p>There was an error while collecting tests." + "</p><p>{0}</p>" + ).format("<br/>".join(error.splitlines())) + ) + + if testResults: + self.__resultsModel.addTestResults(testResults) + + @pyqtSlot(tuple) + def __testStarted(self, test): + """ + Private slot handling the 'startTest' signal of the executor. + + @param test tuple containing the id, name and short description of the + tests about to be run + @type tuple of (str, str, str) + """ + self.__resultsModel.updateTestResults([ + TestResult( + category=TestResultCategory.RUNNING, + status=self.tr("running"), + id=test[0], + name=test[1], + message="" if test[2] is None else test[2], + ) + ]) + + @pyqtSlot(TestResult) + def __processTestResult(self, result): + """ + Private slot to handle the receipt of a test result object. + + @param result test result object + @type TestResult + """ + if not result.subtestResult: + self.__runCount += 1 + self.__updateProgress() + + self.__resultsModel.updateTestResults([result]) + + @pyqtSlot(list, str) + def __testProcessFinished(self, results, output): + """ + Private slot to handle the 'testFinished' signal of the executor. + + @param results list of test result objects (if not sent via the + 'testResult' signal + @type list of TestResult + @param output string containing the test process output (if any) + @type str + """ + self.__recentLog = output + + self.__setStoppedMode() + self.__testExecutor = None + + self.__adjustPendingState() + + @pyqtSlot(int, float) + def __testRunFinished(self, noTests, duration): + """ + Private slot to handle the 'testRunFinished' signal of the executor. + + @param noTests number of tests run by the executor + @type int + @param duration time needed in seconds to run the tests + @type float + """ + self.sbLabel.setText( + self.tr("Ran %n test(s) in {0}s", "", noTests).format( + locale.format_string("%.3f", duration, grouping=True) + ) + ) + + self.__setStoppedMode() + + @pyqtSlot() + def __testsStopped(self): + """ + Private slot to handle the 'stop' signal of the executor. + """ + self.sbLabel.setText(self.tr("Ran %n test(s)", "", self.__runCount)) + + self.__setStoppedMode() + + @pyqtSlot() + def __testRunAboutToBeStarted(self): + """ + Private slot to handle the 'testRunAboutToBeStarted' signal of the + executor. + """ + self.__resultsModel.clear() + + def __adjustPendingState(self): + """ + Private method to change the status indicator of all still pending + tests to "not run". + """ + newResults = [] + for result in self.__resultsModel.getTestResults(): + if result.category == TestResultCategory.PENDING: + result.category = TestResultCategory.SKIP + result.status = self.tr("not run") + newResults.append(result) + + if newResults: + self.__resultsModel.updateTestResults(newResults) + + @pyqtSlot(str) + def __coverageData(self, coverageFile): + """ + Private slot to handle the 'coverageData' signal of the executor. + + @param coverageFile file containing the coverage data + @type str + """ + self.__coverageFile = coverageFile + + @pyqtSlot() + def __showCoverageDialog(self): + """ + Private slot to show a code coverage dialog for the most recent test + run. + """ + if self.__coverageDialog is None: + from DataViews.PyCoverageDialog import PyCoverageDialog + self.__coverageDialog = PyCoverageDialog(self) + self.__coverageDialog.openFile.connect(self.__openEditor) + + testDir = ( + self.discoveryPicker.currentText() + if self.discoverCheckBox.isChecked() else + os.path.dirname(self.testsuitePicker.currentText()) + ) + if testDir: + self.__coverageDialog.show() + self.__coverageDialog.start(self.__coverageFile, testDir) + + @pyqtSlot() + def __showLogOutput(self): + """ + Private slot to show the output of the most recent test run. + """ + from EricWidgets.EricPlainTextDialog import EricPlainTextDialog + dlg = EricPlainTextDialog( + title=self.tr("Test Run Output"), + text=self.__recentLog + ) + dlg.exec() + + @pyqtSlot(str) + def __setStatusLabel(self, statusText): + """ + Private slot to set the status label to the text sent by the model. + + @param statusText text to be shown + @type str + """ + self.statusLabel.setText(f"<b>{statusText}</b>") + + @pyqtSlot() + def __projectOpened(self): + """ + Private slot to handle a project being opened. + """ + self.venvComboBox.setCurrentText(self.__project.getProjectVenv()) + self.frameworkComboBox.setCurrentText( + self.__project.getProjectTestingFramework()) + self.__insertDiscovery(self.__project.getProjectPath()) + + @pyqtSlot() + def __projectClosed(self): + """ + Private slot to handle a project being closed. + """ + self.venvComboBox.setCurrentText("") + self.frameworkComboBox.setCurrentText("") + self.__insertDiscovery("") + + @pyqtSlot(str, int) + def __showSource(self, filename, lineno): + """ + Private slot to show the source of a traceback in an editor. + + @param filename file name of the file to be shown + @type str + @param lineno line number to go to in the file + @type int + """ + if self.__project: + # running as part of eric IDE + self.testFile.emit(filename, lineno, True) + else: + self.__openEditor(filename, lineno) + + def __openEditor(self, filename, linenumber=1): + """ + Private method to open an editor window for the given file. + + Note: This method opens an editor window when the testing dialog + is called as a standalone application. + + @param filename path of the file to be opened + @type str + @param linenumber line number to place the cursor at (defaults to 1) + @type int (optional) + """ + from QScintilla.MiniEditor import MiniEditor + editor = MiniEditor(filename, "Python3", self) + editor.gotoLine(linenumber) + editor.show() + + self.__editors.append(editor) + + def closeEvent(self, event): + """ + Protected method to handle the close event. + + @param event close event + @type QCloseEvent + """ + event.accept() + + for editor in self.__editors: + with contextlib.suppress(Exception): + editor.close() + + +class TestingWindow(EricMainWindow): + """ + Main window class for the standalone dialog. + """ + def __init__(self, testfile=None, parent=None): + """ + Constructor + + @param testfile file name of the test script to open + @type str + @param parent reference to the parent widget + @type QWidget + """ + super().__init__(parent) + self.__cw = TestingWidget(testfile=testfile, parent=self) + self.__cw.installEventFilter(self) + size = self.__cw.size() + self.setCentralWidget(self.__cw) + self.resize(size) + + self.setStyle(Preferences.getUI("Style"), + Preferences.getUI("StyleSheet")) + + self.__cw.buttonBox.accepted.connect(self.close) + self.__cw.buttonBox.rejected.connect(self.close) + + def eventFilter(self, obj, event): + """ + Public method to filter events. + + @param obj reference to the object the event is meant for (QObject) + @param event reference to the event object (QEvent) + @return flag indicating, whether the event was handled (boolean) + """ + if event.type() == QEvent.Type.Close: + QCoreApplication.exit(0) + return True + + return False + + +def clearSavedHistories(self): + """ + Function to clear the saved history lists. + """ + Preferences.Prefs.rsettings.setValue( + recentNameTestDiscoverHistory, []) + Preferences.Prefs.rsettings.setValue( + recentNameTestFileHistory, []) + Preferences.Prefs.rsettings.setValue( + recentNameTestNameHistory, []) + + Preferences.Prefs.rsettings.sync()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/TestingWidget.ui Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,543 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>TestingWidget</class> + <widget class="QWidget" name="TestingWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>850</width> + <height>700</height> + </rect> + </property> + <property name="windowTitle"> + <string>Testing</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="parametersTab"> + <attribute name="title"> + <string>Parameters</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <widget class="QLabel" name="venvLabel"> + <property name="text"> + <string>Virtual Environment:</string> + </property> + <property name="buddy"> + <cstring>venvComboBox</cstring> + </property> + </widget> + </item> + <item row="0" column="1" colspan="2"> + <widget class="QComboBox" name="venvComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Select the virtual environment to be used</string> + </property> + <property name="whatsThis"> + <string><b>Virtual Environment</b>\n<p>Enter the virtual environment to be used. Leave it empty to use the default environment, i.e. the one configured globally or per project.</p></string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Test Framework:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="frameworkComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Select the test framwork to be used</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QToolButton" name="versionsButton"> + <property name="toolTip"> + <string>Press to show the test framework versions</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Test Parameters</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0" colspan="2"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QCheckBox" name="discoverCheckBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Select to discover tests automatically</string> + </property> + <property name="text"> + <string>Discover tests (test modules must be importable)</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="clearHistoriesButton"> + <property name="toolTip"> + <string>Press to clear the various histories</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Discovery Start:</string> + </property> + <property name="buddy"> + <cstring>discoveryPicker</cstring> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="EricComboPathPicker" name="discoveryPicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::WheelFocus</enum> + </property> + <property name="toolTip"> + <string>Enter name of the directory at which to start the test file discovery</string> + </property> + <property name="whatsThis"> + <string><b>Discovery Start</b> +<p>Enter name of the directory at which to start the test file discovery. +Note that all test modules must be importable from this directory.</p></string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="testsuiteLabel"> + <property name="text"> + <string>Test Filename:</string> + </property> + <property name="buddy"> + <cstring>testsuitePicker</cstring> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="EricComboPathPicker" name="testsuitePicker" native="true"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::WheelFocus</enum> + </property> + <property name="toolTip"> + <string>Enter name of file defining the testsuite</string> + </property> + <property name="whatsThis"> + <string><b>Testsuite</b><p>Enter the name of the file defining the testsuite. It should contain a method with a name given below. If no name is given, the 'suite()' method will be tried. If no such method can be found, the module will be inspected for proper test cases.</p></string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Test Name:</string> + </property> + <property name="buddy"> + <cstring>testComboBox</cstring> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="testComboBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Enter the test name. Leave empty to use the default name "suite".</string> + </property> + <property name="whatsThis"> + <string><b>Testname</b><p>Enter the name of the test to be performed. This name must follow the rules given by selecte test framework. If this field is empty, the default name of "suite" will be used.</p></string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="optionsGroup"> + <property name="title"> + <string>Run Parameters</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QCheckBox" name="coverageCheckBox"> + <property name="toolTip"> + <string>Select whether coverage data should be collected</string> + </property> + <property name="text"> + <string>Collect coverage data</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="coverageEraseCheckBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Select whether old coverage data should be erased</string> + </property> + <property name="text"> + <string>Erase coverage data</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="failfastCheckBox"> + <property name="toolTip"> + <string>Select to stop the test run on the first error or failure</string> + </property> + <property name="text"> + <string>Stop on First Error or Failure</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>239</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="resultsTab"> + <attribute name="title"> + <string>Results</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <widget class="QGroupBox" name="progressGroupBox"> + <property name="title"> + <string>Progress</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QProgressBar" name="progressProgressBar"> + <property name="value"> + <number>0</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="format"> + <string>%v/%m Tests</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="progressCounterRunLabel"> + <property name="text"> + <string>Run:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="progressCounterRunCount"> + <property name="toolTip"> + <string>Number of tests run</string> + </property> + <property name="text"> + <string notr="true">0</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="progressCounterRemLabel"> + <property name="text"> + <string>Remaining:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="progressCounterRemCount"> + <property name="toolTip"> + <string>Number of tests to be run</string> + </property> + <property name="text"> + <string notr="true">0</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="resultsGroupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Results</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QLabel" name="statusLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="_4"> + <item> + <widget class="QLabel" name="sbLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Idle</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>EricComboPathPicker</class> + <extends>QWidget</extends> + <header>EricWidgets/EricPathPicker.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>tabWidget</tabstop> + <tabstop>venvComboBox</tabstop> + <tabstop>frameworkComboBox</tabstop> + <tabstop>versionsButton</tabstop> + <tabstop>discoverCheckBox</tabstop> + <tabstop>clearHistoriesButton</tabstop> + <tabstop>discoveryPicker</tabstop> + <tabstop>testsuitePicker</tabstop> + <tabstop>testComboBox</tabstop> + <tabstop>coverageCheckBox</tabstop> + <tabstop>coverageEraseCheckBox</tabstop> + <tabstop>failfastCheckBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>TestingWidget</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>31</x> + <y>648</y> + </hint> + <hint type="destinationlabel"> + <x>1</x> + <y>510</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>TestingWidget</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>80</x> + <y>649</y> + </hint> + <hint type="destinationlabel"> + <x>3</x> + <y>580</y> + </hint> + </hints> + </connection> + <connection> + <sender>discoverCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>discoveryPicker</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>168</x> + <y>164</y> + </hint> + <hint type="destinationlabel"> + <x>170</x> + <y>191</y> + </hint> + </hints> + </connection> + <connection> + <sender>discoverCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>testsuitePicker</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>222</x> + <y>162</y> + </hint> + <hint type="destinationlabel"> + <x>222</x> + <y>209</y> + </hint> + </hints> + </connection> + <connection> + <sender>discoverCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>testComboBox</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>301</x> + <y>163</y> + </hint> + <hint type="destinationlabel"> + <x>300</x> + <y>238</y> + </hint> + </hints> + </connection> + <connection> + <sender>coverageCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>coverageEraseCheckBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>160</x> + <y>320</y> + </hint> + <hint type="destinationlabel"> + <x>369</x> + <y>319</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/Testing/__init__.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing testing functionality and interface to various test +frameworks. +""" + +from .Interfaces import FrameworkNames + + +def supportedLanguages(): + """ + Function to get a list of supported programming languages. + + @return list of supported programming languages + @rtype list of str + """ + return list(FrameworkNames.keys()) + + +def isLanguageSupported(language): + """ + Function to check, if the given programming language is supported by any + testing framework. + + @param language programming language + @type str + @return flag indicating support + @rtype bool + """ + return language in FrameworkNames
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/eric7_testing.py Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (c) 2002 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +eric testing. + +This is the main Python script that performs the necessary initialization +of the testing module and starts the Qt event loop. This is a standalone +version of the integrated testing module. +""" + +import sys +import os + +sys.path.insert(1, os.path.dirname(__file__)) + +for arg in sys.argv[:]: + if arg.startswith("--config="): + import Globals + configDir = arg.replace("--config=", "") + Globals.setConfigDir(configDir) + sys.argv.remove(arg) + elif arg.startswith("--settings="): + from PyQt6.QtCore import QSettings + settingsDir = os.path.expanduser(arg.replace("--settings=", "")) + if not os.path.isdir(settingsDir): + os.makedirs(settingsDir) + QSettings.setPath( + QSettings.Format.IniFormat, QSettings.Scope.UserScope, settingsDir) + sys.argv.remove(arg) + +from Globals import AppInfo + +from Toolbox import Startup + + +def createMainWidget(argv): + """ + Function to create the main widget. + + @param argv list of commandline parameters + @type list of str + @return reference to the main widget + @rtype QWidget + """ + from Testing.TestingWidget import TestingWindow + try: + fn = argv[1] + except IndexError: + fn = None + return TestingWindow(fn) + + +def main(): + """ + Main entry point into the application. + """ + from PyQt6.QtGui import QGuiApplication + QGuiApplication.setDesktopFileName("eric7_testing.desktop") + + options = [ + ("--config=configDir", + "use the given directory as the one containing the config files"), + ("--settings=settingsDir", + "use the given directory to store the settings files"), + ] + appinfo = AppInfo.makeAppInfo(sys.argv, + "eric Testing", + "file", + "Graphical test application", + options) + res = Startup.simpleAppStartup(sys.argv, + appinfo, + createMainWidget) + sys.exit(res) + +if __name__ == '__main__': + main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/eric7_testing.pyw Sun Jun 05 17:17:44 2022 +0200 @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2011 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the Windows entry point. +""" + +from eric7_testing import main + +main()
--- a/eric7/eric7_unittest.py Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Copyright (c) 2002 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -eric Unittest. - -This is the main Python script that performs the necessary initialization -of the unittest module and starts the Qt event loop. This is a standalone -version of the integrated unittest module. -""" - -import sys -import os - -sys.path.insert(1, os.path.dirname(__file__)) - -for arg in sys.argv[:]: - if arg.startswith("--config="): - import Globals - configDir = arg.replace("--config=", "") - Globals.setConfigDir(configDir) - sys.argv.remove(arg) - elif arg.startswith("--settings="): - from PyQt6.QtCore import QSettings - settingsDir = os.path.expanduser(arg.replace("--settings=", "")) - if not os.path.isdir(settingsDir): - os.makedirs(settingsDir) - QSettings.setPath( - QSettings.Format.IniFormat, QSettings.Scope.UserScope, settingsDir) - sys.argv.remove(arg) - -from Globals import AppInfo - -from Toolbox import Startup - - -def createMainWidget(argv): - """ - Function to create the main widget. - - @param argv list of commandline parameters (list of strings) - @return reference to the main widget (QWidget) - """ - from PyUnit.UnittestDialog import UnittestWindow - try: - fn = argv[1] - except IndexError: - fn = None - return UnittestWindow(fn) - - -def main(): - """ - Main entry point into the application. - """ - from PyQt6.QtGui import QGuiApplication - QGuiApplication.setDesktopFileName("eric7_unittest.desktop") - - options = [ - ("--config=configDir", - "use the given directory as the one containing the config files"), - ("--settings=settingsDir", - "use the given directory to store the settings files"), - ] - appinfo = AppInfo.makeAppInfo(sys.argv, - "eric Unittest", - "file", - "Graphical unit test application", - options) - res = Startup.simpleAppStartup(sys.argv, - appinfo, - createMainWidget) - sys.exit(res) - -if __name__ == '__main__': - main()
--- a/eric7/eric7_unittest.pyw Wed Jun 01 13:49:13 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2011 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing the Windows entry point. -""" - -from eric7_unittest import main - -main()