Added a QProcess derived class with timeout and changed the pip interface to use that class. eric7

Sun, 15 Sep 2024 16:56:58 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 15 Sep 2024 16:56:58 +0200
branch
eric7
changeset 10919
4e4c8ee38c45
parent 10918
056bd087096f
child 10920
8a1d447323a2

Added a QProcess derived class with timeout and changed the pip interface to use that class.

eric7.epj file | annotate | diff | comparison | revisions
src/eric7/APIs/Python3/eric7.api file | annotate | diff | comparison | revisions
src/eric7/APIs/Python3/eric7.bas file | annotate | diff | comparison | revisions
src/eric7/Documentation/Help/source.qch file | annotate | diff | comparison | revisions
src/eric7/Documentation/Help/source.qhp file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.EricCore.EricProcess.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.PipInterface.Pip.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.PipInterface.PipPackagesWindow.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/index-eric7.EricCore.html file | annotate | diff | comparison | revisions
src/eric7/EricCore/EricProcess.py file | annotate | diff | comparison | revisions
src/eric7/PipInterface/Pip.py file | annotate | diff | comparison | revisions
src/eric7/PipInterface/PipPackagesWidget.py file | annotate | diff | comparison | revisions
src/eric7/PipInterface/PipPackagesWindow.py file | annotate | diff | comparison | revisions
src/eric7/UI/UserInterface.py file | annotate | diff | comparison | revisions
--- a/eric7.epj	Fri Sep 06 14:56:18 2024 +0200
+++ b/eric7.epj	Sun Sep 15 16:56:58 2024 +0200
@@ -1178,6 +1178,7 @@
       "src/eric7/DocumentationTools/TemplatesListsStyleCSS.py",
       "src/eric7/DocumentationTools/__init__.py",
       "src/eric7/EricCore/EricFileSystemWatcher.py",
+      "src/eric7/EricCore/EricProcess.py",
       "src/eric7/EricCore/EricStdRedirector.py",
       "src/eric7/EricCore/EricTreeSortFilterProxyModel.py",
       "src/eric7/EricCore/__init__.py",
--- a/src/eric7/APIs/Python3/eric7.api	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/APIs/Python3/eric7.api	Sun Sep 15 16:56:58 2024 +0200
@@ -1108,6 +1108,12 @@
 eric7.EricCore.EricFileSystemWatcher._EricFileSystemEventHandler?2(parent=None)
 eric7.EricCore.EricFileSystemWatcher._GlobalFileSystemWatcher?8
 eric7.EricCore.EricFileSystemWatcher.instance?4()
+eric7.EricCore.EricProcess.EricProcess.failed?7
+eric7.EricCore.EricProcess.EricProcess.succeeded?7
+eric7.EricCore.EricProcess.EricProcess.timedOut?4()
+eric7.EricCore.EricProcess.EricProcess.timeout?7
+eric7.EricCore.EricProcess.EricProcess.timeoutInterval?4()
+eric7.EricCore.EricProcess.EricProcess?1(timeout=30000, parent=None)
 eric7.EricCore.EricStdRedirector.EricStdRedirector.encoding?4()
 eric7.EricCore.EricStdRedirector.EricStdRedirector.flush?4()
 eric7.EricCore.EricStdRedirector.EricStdRedirector.isatty?4()
@@ -3777,6 +3783,7 @@
 eric7.PipInterface.Pip.Pip.repairPip?4(venvName)
 eric7.PipInterface.Pip.Pip.runProcess?4(args, interpreter)
 eric7.PipInterface.Pip.Pip.showCacheInfo?4(venvName)
+eric7.PipInterface.Pip.Pip.shutdown?4()
 eric7.PipInterface.Pip.Pip.uninstallPackages?4(packages, venvName)
 eric7.PipInterface.Pip.Pip.uninstallPyprojectDependencies?4(venvName)
 eric7.PipInterface.Pip.Pip.uninstallRequirements?4(venvName)
@@ -3884,6 +3891,7 @@
 eric7.PipInterface.PipPackagesWidget.PypiSearchResultsParser.handle_endtag?4(_tag)
 eric7.PipInterface.PipPackagesWidget.PypiSearchResultsParser.handle_starttag?4(tag, attrs)
 eric7.PipInterface.PipPackagesWidget.PypiSearchResultsParser?1(data)
+eric7.PipInterface.PipPackagesWindow.PipPackagesWindow.closeEvent?4(evt)
 eric7.PipInterface.PipPackagesWindow.PipPackagesWindow?1(parent=None)
 eric7.PipInterface.PipVulnerabilityChecker.Package.name?7
 eric7.PipInterface.PipVulnerabilityChecker.Package.version?7
--- a/src/eric7/APIs/Python3/eric7.bas	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/APIs/Python3/eric7.bas	Sun Sep 15 16:56:58 2024 +0200
@@ -297,6 +297,7 @@
 EricPathPickerDialog QDialog
 EricPathPickerModes enum.Enum
 EricPlainTextDialog QDialog Ui_EricPlainTextDialog
+EricProcess QProcess
 EricProcessDialog QDialog Ui_EricProcessDialog
 EricProgressDialog QProgressDialog
 EricProxyStyle QProxyStyle
Binary file src/eric7/Documentation/Help/source.qch has changed
--- a/src/eric7/Documentation/Help/source.qhp	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/Documentation/Help/source.qhp	Sun Sep 15 16:56:58 2024 +0200
@@ -109,6 +109,7 @@
           </section>
           <section title="eric7.EricCore" ref="index-eric7.EricCore.html">
             <section title="eric7.EricCore.EricFileSystemWatcher" ref="eric7.EricCore.EricFileSystemWatcher.html" />
+            <section title="eric7.EricCore.EricProcess" ref="eric7.EricCore.EricProcess.html" />
             <section title="eric7.EricCore.EricStdRedirector" ref="eric7.EricCore.EricStdRedirector.html" />
             <section title="eric7.EricCore.EricTreeSortFilterProxyModel" ref="eric7.EricCore.EricTreeSortFilterProxyModel.html" />
           </section>
@@ -5993,6 +5994,14 @@
       <keyword name="EricPlugin.pytest_sessionfinish" id="EricPlugin.pytest_sessionfinish" ref="eric7.Testing.Interfaces.PytestRunner.html#EricPlugin.pytest_sessionfinish" />
       <keyword name="EricPlugin.pytest_sessionstart" id="EricPlugin.pytest_sessionstart" ref="eric7.Testing.Interfaces.PytestRunner.html#EricPlugin.pytest_sessionstart" />
       <keyword name="EricPluginWizard (Package)" id="EricPluginWizard (Package)" ref="index-eric7.Plugins.WizardPlugins.EricPluginWizard.html" />
+      <keyword name="EricProcess" id="EricProcess" ref="eric7.EricCore.EricProcess.html#EricProcess" />
+      <keyword name="EricProcess (Constructor)" id="EricProcess (Constructor)" ref="eric7.EricCore.EricProcess.html#EricProcess.__init__" />
+      <keyword name="EricProcess (Module)" id="EricProcess (Module)" ref="eric7.EricCore.EricProcess.html" />
+      <keyword name="EricProcess.__finished" id="EricProcess.__finished" ref="eric7.EricCore.EricProcess.html#EricProcess.__finished" />
+      <keyword name="EricProcess.__started" id="EricProcess.__started" ref="eric7.EricCore.EricProcess.html#EricProcess.__started" />
+      <keyword name="EricProcess.__timeout" id="EricProcess.__timeout" ref="eric7.EricCore.EricProcess.html#EricProcess.__timeout" />
+      <keyword name="EricProcess.timedOut" id="EricProcess.timedOut" ref="eric7.EricCore.EricProcess.html#EricProcess.timedOut" />
+      <keyword name="EricProcess.timeoutInterval" id="EricProcess.timeoutInterval" ref="eric7.EricCore.EricProcess.html#EricProcess.timeoutInterval" />
       <keyword name="EricProcessDialog" id="EricProcessDialog" ref="eric7.EricWidgets.EricProcessDialog.html#EricProcessDialog" />
       <keyword name="EricProcessDialog (Constructor)" id="EricProcessDialog (Constructor)" ref="eric7.EricWidgets.EricProcessDialog.html#EricProcessDialog.__init__" />
       <keyword name="EricProcessDialog (Module)" id="EricProcessDialog (Module)" ref="eric7.EricWidgets.EricProcessDialog.html" />
@@ -12904,6 +12913,7 @@
       <keyword name="Pip.repairPip" id="Pip.repairPip" ref="eric7.PipInterface.Pip.html#Pip.repairPip" />
       <keyword name="Pip.runProcess" id="Pip.runProcess" ref="eric7.PipInterface.Pip.html#Pip.runProcess" />
       <keyword name="Pip.showCacheInfo" id="Pip.showCacheInfo" ref="eric7.PipInterface.Pip.html#Pip.showCacheInfo" />
+      <keyword name="Pip.shutdown" id="Pip.shutdown" ref="eric7.PipInterface.Pip.html#Pip.shutdown" />
       <keyword name="Pip.uninstallPackages" id="Pip.uninstallPackages" ref="eric7.PipInterface.Pip.html#Pip.uninstallPackages" />
       <keyword name="Pip.uninstallPyprojectDependencies" id="Pip.uninstallPyprojectDependencies" ref="eric7.PipInterface.Pip.html#Pip.uninstallPyprojectDependencies" />
       <keyword name="Pip.uninstallRequirements" id="Pip.uninstallRequirements" ref="eric7.PipInterface.Pip.html#Pip.uninstallRequirements" />
@@ -13072,6 +13082,7 @@
       <keyword name="PipPackagesWindow" id="PipPackagesWindow" ref="eric7.PipInterface.PipPackagesWindow.html#PipPackagesWindow" />
       <keyword name="PipPackagesWindow (Constructor)" id="PipPackagesWindow (Constructor)" ref="eric7.PipInterface.PipPackagesWindow.html#PipPackagesWindow.__init__" />
       <keyword name="PipPackagesWindow (Module)" id="PipPackagesWindow (Module)" ref="eric7.PipInterface.PipPackagesWindow.html" />
+      <keyword name="PipPackagesWindow.closeEvent" id="PipPackagesWindow.closeEvent" ref="eric7.PipInterface.PipPackagesWindow.html#PipPackagesWindow.closeEvent" />
       <keyword name="PipPage" id="PipPage" ref="eric7.Preferences.ConfigurationPages.PipPage.html#PipPage" />
       <keyword name="PipPage (Constructor)" id="PipPage (Constructor)" ref="eric7.Preferences.ConfigurationPages.PipPage.html#PipPage.__init__" />
       <keyword name="PipPage (Module)" id="PipPage (Module)" ref="eric7.Preferences.ConfigurationPages.PipPage.html" />
@@ -21384,6 +21395,7 @@
       <file>eric7.DocumentationTools.QtHelpGenerator.html</file>
       <file>eric7.DocumentationTools.TemplatesListsStyleCSS.html</file>
       <file>eric7.EricCore.EricFileSystemWatcher.html</file>
+      <file>eric7.EricCore.EricProcess.html</file>
       <file>eric7.EricCore.EricStdRedirector.html</file>
       <file>eric7.EricCore.EricTreeSortFilterProxyModel.html</file>
       <file>eric7.EricGraphics.EricArrowItem.html</file>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.EricCore.EricProcess.html	Sun Sep 15 16:56:58 2024 +0200
@@ -0,0 +1,194 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.EricCore.EricProcess</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.EricCore.EricProcess</h1>
+<p>
+Module implementing a QProcess derived class with a timeout and convenience signals.
+</p>
+
+<h3>Global Attributes</h3>
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<h3>Classes</h3>
+<table>
+<tr>
+<td><a href="#EricProcess">EricProcess</a></td>
+<td>Class implementing a QProcess derived class with a timeout and convenience signals succeeded and failed.</td>
+</tr>
+</table>
+
+<h3>Functions</h3>
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<hr />
+<hr />
+<a NAME="EricProcess" ID="EricProcess"></a>
+<h2>EricProcess</h2>
+<p>
+    Class implementing a QProcess derived class with a timeout and convenience signals
+    succeeded and failed.
+</p>
+
+<h3>Signals</h3>
+<dl>
+
+<dt>failed()</dt>
+<dd>
+emitted to indicate a process failure
+</dd>
+<dt>succeeded()</dt>
+<dd>
+emitted to indicate that the process finished successfully
+</dd>
+<dt>timeout()</dt>
+<dd>
+emitted to indicate the expiry of the configured timeout value
+</dd>
+</dl>
+<h3>Derived from</h3>
+QProcess
+<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="#EricProcess.__init__">EricProcess</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#EricProcess.__finished">__finished</a></td>
+<td>Private slot handling the end of the process.</td>
+</tr>
+<tr>
+<td><a href="#EricProcess.__started">__started</a></td>
+<td>Private slot handling the process start.</td>
+</tr>
+<tr>
+<td><a href="#EricProcess.__timeout">__timeout</a></td>
+<td>Private slot to handle the timer interval exoiration.</td>
+</tr>
+<tr>
+<td><a href="#EricProcess.timedOut">timedOut</a></td>
+<td>Public method to test, if the process timed out.</td>
+</tr>
+<tr>
+<td><a href="#EricProcess.timeoutInterval">timeoutInterval</a></td>
+<td>Public method to get the process timeout interval.</td>
+</tr>
+</table>
+
+<h3>Static Methods</h3>
+<table>
+<tr><td>None</td></tr>
+</table>
+
+
+<a NAME="EricProcess.__init__" ID="EricProcess.__init__"></a>
+<h4>EricProcess (Constructor)</h4>
+<b>EricProcess</b>(<i>timeout=30000, parent=None</i>)
+<p>
+        Constructor
+</p>
+
+<dl>
+
+<dt><i>timeout</i> (int (optional))</dt>
+<dd>
+timeout value in milliseconds. If the process does not finish
+            within this interval, it is killed. (defaults to 30000)
+</dd>
+<dt><i>parent</i> (QObject (optional))</dt>
+<dd>
+reference to the parent object (defaults to None)
+</dd>
+</dl>
+<a NAME="EricProcess.__finished" ID="EricProcess.__finished"></a>
+<h4>EricProcess.__finished</h4>
+<b>__finished</b>(<i>exitCode, exitStatus</i>)
+<p>
+        Private slot handling the end of the process.
+</p>
+
+<dl>
+
+<dt><i>exitCode</i> (int)</dt>
+<dd>
+exit code of the process (0 = success)
+</dd>
+<dt><i>exitStatus</i> (QProcess.ExitStatus)</dt>
+<dd>
+exit status of the process
+</dd>
+</dl>
+<a NAME="EricProcess.__started" ID="EricProcess.__started"></a>
+<h4>EricProcess.__started</h4>
+<b>__started</b>(<i></i>)
+<p>
+        Private slot handling the process start.
+</p>
+
+<a NAME="EricProcess.__timeout" ID="EricProcess.__timeout"></a>
+<h4>EricProcess.__timeout</h4>
+<b>__timeout</b>(<i></i>)
+<p>
+        Private slot to handle the timer interval exoiration.
+</p>
+
+<a NAME="EricProcess.timedOut" ID="EricProcess.timedOut"></a>
+<h4>EricProcess.timedOut</h4>
+<b>timedOut</b>(<i></i>)
+<p>
+        Public method to test, if the process timed out.
+</p>
+
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a timeout
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="EricProcess.timeoutInterval" ID="EricProcess.timeoutInterval"></a>
+<h4>EricProcess.timeoutInterval</h4>
+<b>timeoutInterval</b>(<i></i>)
+<p>
+        Public method to get the process timeout interval.
+</p>
+
+<dl>
+<dt>Return:</dt>
+<dd>
+process timeout interval in milliseconds
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+int
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
--- a/src/eric7/Documentation/Source/eric7.PipInterface.Pip.html	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/Documentation/Source/eric7.PipInterface.Pip.html	Sun Sep 15 16:56:58 2024 +0200
@@ -195,6 +195,10 @@
 <td>Public method to show some information about the pip cache.</td>
 </tr>
 <tr>
+<td><a href="#Pip.shutdown">shutdown</a></td>
+<td>Public method to perform shutdown actions.</td>
+</tr>
+<tr>
 <td><a href="#Pip.uninstallPackages">uninstallPackages</a></td>
 <td>Public method to uninstall the given list of packages.</td>
 </tr>
@@ -1090,6 +1094,13 @@
 name of the virtual environment to be used
 </dd>
 </dl>
+<a NAME="Pip.shutdown" ID="Pip.shutdown"></a>
+<h4>Pip.shutdown</h4>
+<b>shutdown</b>(<i></i>)
+<p>
+        Public method to perform shutdown actions.
+</p>
+
 <a NAME="Pip.uninstallPackages" ID="Pip.uninstallPackages"></a>
 <h4>Pip.uninstallPackages</h4>
 <b>uninstallPackages</b>(<i>packages, venvName</i>)
--- a/src/eric7/Documentation/Source/eric7.PipInterface.PipPackagesWindow.html	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/Documentation/Source/eric7.PipInterface.PipPackagesWindow.html	Sun Sep 15 16:56:58 2024 +0200
@@ -55,6 +55,10 @@
 <td><a href="#PipPackagesWindow.__init__">PipPackagesWindow</a></td>
 <td>Constructor</td>
 </tr>
+<tr>
+<td><a href="#PipPackagesWindow.closeEvent">closeEvent</a></td>
+<td>Protected method handling a close event.</td>
+</tr>
 </table>
 
 <h3>Static Methods</h3>
@@ -77,6 +81,20 @@
 reference to the parent widget
 </dd>
 </dl>
+<a NAME="PipPackagesWindow.closeEvent" ID="PipPackagesWindow.closeEvent"></a>
+<h4>PipPackagesWindow.closeEvent</h4>
+<b>closeEvent</b>(<i>evt</i>)
+<p>
+        Protected method handling a close event.
+</p>
+
+<dl>
+
+<dt><i>evt</i> (QCloseEvent)</dt>
+<dd>
+reference to the close event object
+</dd>
+</dl>
 <div align="right"><a href="#top">Up</a></div>
 <hr />
 </body></html>
--- a/src/eric7/Documentation/Source/index-eric7.EricCore.html	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/Documentation/Source/index-eric7.EricCore.html	Sun Sep 15 16:56:58 2024 +0200
@@ -23,6 +23,10 @@
 <td>Module implementing a QFileSystemWatcher replacement based on the 'watchdog' package.</td>
 </tr>
 <tr>
+<td><a href="eric7.EricCore.EricProcess.html">EricProcess</a></td>
+<td>Module implementing a QProcess derived class with a timeout and convenience signals.</td>
+</tr>
+<tr>
 <td><a href="eric7.EricCore.EricStdRedirector.html">EricStdRedirector</a></td>
 <td>Module implementing a redirector for stderr and stdout to be able to send data written to these streams via Qt signals.</td>
 </tr>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/EricCore/EricProcess.py	Sun Sep 15 16:56:58 2024 +0200
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2024 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a QProcess derived class with a timeout and convenience signals.
+"""
+
+from PyQt6.QtCore import QProcess, QTimer, pyqtSignal, pyqtSlot
+
+
+class EricProcess(QProcess):
+    """
+    Class implementing a QProcess derived class with a timeout and convenience signals
+    succeeded and failed.
+
+    @signal failed() emitted to indicate a process failure
+    @signal succeeded() emitted to indicate that the process finished successfully
+    @signal timeout() emitted to indicate the expiry of the configured timeout value
+    """
+
+    failed = pyqtSignal()
+    succeeded = pyqtSignal()
+    timeout = pyqtSignal()
+
+    def __init__(self, timeout=30000, parent=None):
+        """
+        Constructor
+
+        @param timeout timeout value in milliseconds. If the process does not finish
+            within this interval, it is killed. (defaults to 30000)
+        @type int (optional)
+        @param parent reference to the parent object (defaults to None)
+        @type QObject (optional)
+        """
+        super().__init__(parent=parent)
+
+        self.started.connect(self.__started)
+        self.finished.connect(self.__finished)
+
+        self.__timeoutTimer = QTimer(self)
+        self.__timeoutTimer.setInterval(timeout)
+        self.__timeoutTimer.timeout.connect(self.__timeout)
+
+        self.__timedOut = False
+
+    def timedOut(self):
+        """
+        Public method to test, if the process timed out.
+
+        @return flag indicating a timeout
+        @rtype bool
+        """
+        return self.__timedOut
+
+    def timeoutInterval(self):
+        """
+        Public method to get the process timeout interval.
+        
+        @return process timeout interval in milliseconds
+        @rtype int
+        """
+        return self.__timeoutTimer.interval()
+
+    @pyqtSlot()
+    def __timeout(self):
+        """
+        Private slot to handle the timer interval exoiration.
+        """
+        self.__timeoutTimer.stop()
+        self.__timedOut = True
+        self.kill()
+
+        self.timeout.emit()
+
+    @pyqtSlot()
+    def __started(self):
+        """
+        Private slot handling the process start.
+        """
+        self.__timedOut = False
+        self.__timeoutTimer.start()
+
+    @pyqtSlot(int, QProcess.ExitStatus)
+    def __finished(self, exitCode, exitStatus):
+        """
+        Private slot handling the end of the process.
+
+        @param exitCode exit code of the process (0 = success)
+        @type int
+        @param exitStatus exit status of the process
+        @type QProcess.ExitStatus
+        """
+        self.__timeoutTimer.stop()
+
+        if exitStatus == QProcess.ExitStatus.CrashExit or exitCode != 0:
+            self.failed.emit()
+        else:
+            self.succeeded.emit()
--- a/src/eric7/PipInterface/Pip.py	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/PipInterface/Pip.py	Sun Sep 15 16:56:58 2024 +0200
@@ -26,6 +26,7 @@
 from PyQt6.QtWidgets import QDialog, QInputDialog, QLineEdit
 
 from eric7 import Preferences
+from eric7.EricCore.EricProcess import EricProcess
 from eric7.EricNetwork.EricNetworkProxyFactory import (
     EricNetworkProxyFactory,
     proxyAuthenticationRequired,
@@ -86,6 +87,8 @@
             )
         self.__replies = []
 
+        self.__outdatedProc = None
+
         self.__vulnerabilityChecker = PipVulnerabilityChecker(self, self)
 
     def getNetworkAccessManager(self):
@@ -106,6 +109,14 @@
         """
         return self.__vulnerabilityChecker
 
+    def shutdown(self):
+        """
+        Public method to perform shutdown actions.
+        """
+        if self.__outdatedProc is not None:
+            self.__outdatedProc.kill()  # end the process forcefully
+            self.__outdatedProc = None
+
     ##########################################################################
     ## Methods below implement some utility functions
     ##########################################################################
@@ -925,8 +936,12 @@
                     indexUrl = Preferences.getPip("PipSearchIndex") + "/simple"
                     args += ["--index-url", indexUrl]
 
-                proc = QProcess()
                 if callback:
+                    if self.__outdatedProc is not None:
+                        self.__outdatedProc.kill()  # end the process forcefully
+                        self.__outdatedProc = None
+
+                    proc = EricProcess(timeout=30000)
                     self.__outdatedProc = proc
                     proc.finished.connect(
                         functools.partial(self.__outdatedFinished, callback, proc)
@@ -934,6 +949,7 @@
                     proc.start(interpreter, args)
                     return None
 
+                proc = QProcess()
                 proc.start(interpreter, args)
                 if proc.waitForStarted(15000) and proc.waitForFinished(30000):
                     packages = self.__extractOutdatedPackages(proc)
@@ -989,7 +1005,11 @@
         """
         packages = (
             self.__extractOutdatedPackages(proc)
-            if exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0
+            if (
+                not proc.timedOut()
+                and exitStatus == QProcess.ExitStatus.NormalExit
+                and exitCode == 0
+            )
             else {}
         )
         callback(packages)
--- a/src/eric7/PipInterface/PipPackagesWidget.py	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/PipInterface/PipPackagesWidget.py	Sun Sep 15 16:56:58 2024 +0200
@@ -19,7 +19,6 @@
 from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest
 from PyQt6.QtWidgets import (
     QAbstractItemView,
-    QApplication,
     QDialog,
     QHeaderView,
     QMenu,
@@ -470,7 +469,6 @@
                     self.packagesList.resizeColumnToContents(
                         PipPackagesWidget.InstalledVersionColumn
                     )
-                    QApplication.processEvents()
 
                     # 2. update with vulnerability information
                     if self.vulnerabilityCheckBox.isChecked():
@@ -479,7 +477,6 @@
                             PipPackagesWidget.VulnerabilityColumn
                         )
                     self.statusLabel.setText(self.tr("Getting outdated packages..."))
-                    QApplication.processEvents()
 
                     # 3. update with update information
                     self.__pip.getOutdatedPackages(
@@ -514,13 +511,14 @@
         self.packagesList.resizeColumnToContents(
             PipPackagesWidget.AvailableVersionColumn
         )
-        self.statusLabel.hide()
 
         self.__updateActionButtons()
         self.__updateSearchActionButtons()
         self.__updateSearchButton()
         self.__updateSearchMoreButton(False)
 
+        self.statusLabel.hide()
+
     @pyqtSlot(str)
     def on_environmentsComboBox_currentTextChanged(self, name):
         """
--- a/src/eric7/PipInterface/PipPackagesWindow.py	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/PipInterface/PipPackagesWindow.py	Sun Sep 15 16:56:58 2024 +0200
@@ -57,3 +57,12 @@
 
         self.__buttonBox.accepted.connect(self.close)
         self.__buttonBox.rejected.connect(self.close)
+
+    def closeEvent(self, evt):
+        """
+        Protected method handling a close event.
+
+        @param evt reference to the close event object
+        @type QCloseEvent
+        """
+        self.__pip.shutdown()
--- a/src/eric7/UI/UserInterface.py	Fri Sep 06 14:56:18 2024 +0200
+++ b/src/eric7/UI/UserInterface.py	Sun Sep 15 16:56:58 2024 +0200
@@ -8474,6 +8474,8 @@
         if self.microPythonWidget is not None:
             self.microPythonWidget.shutdown()
 
+        self.pipInterface.shutdown()
+
         self.pluginManager.doShutdown()
 
         if self.SAServer is not None:

eric ide

mercurial