Tue, 06 Dec 2022 17:35:41 +0100
Corrected some 'wrong' string quotes caused by the Black line merging.
# -*- coding: utf-8 -*- # Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the virtualenv upgrade execution dialog. """ import os from PyQt6.QtCore import QProcess, QTimer from PyQt6.QtWidgets import QDialog, QDialogButtonBox from eric7 import Preferences from eric7.Globals import getPythonExecutable from .Ui_VirtualenvExecDialog import Ui_VirtualenvExecDialog class VirtualenvUpgradeExecDialog(QDialog, Ui_VirtualenvExecDialog): """ Class implementing the virtualenv upgrade execution dialog. """ def __init__(self, venvName, interpreter, createLog, venvManager, parent=None): """ Constructor @param venvName name of the virtual environment to be upgraded @type str @param interpreter interpreter to be used for the upgrade @type str @param createLog flag indicating to create a log file for the upgrade @type bool @param venvManager reference to the virtual environment manager @type VirtualenvManager @param parent reference to the parent widget @type QWidget """ super().__init__(parent) self.setupUi(self) self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False) self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True) self.__process = None self.__cmd = "" self.__progs = [] if interpreter: self.__progs.append(interpreter) self.__progs.extend( [ getPythonExecutable(), "python3", "python", ] ) self.__callIndex = 0 self.__callArgs = [] self.__venvName = venvName self.__venvDirectory = "" self.__createLog = createLog self.__manager = venvManager def start(self, arguments): """ Public slot to start the virtualenv command. @param arguments commandline arguments for virtualenv/pyvenv program (list of strings) """ if self.__callIndex == 0: # first attempt, add a given python interpreter and do # some other setup self.errorGroup.hide() self.contents.clear() self.errors.clear() self.__process = QProcess() self.__process.readyReadStandardOutput.connect(self.__readStdout) self.__process.readyReadStandardError.connect(self.__readStderr) self.__process.finished.connect(self.__finish) self.__callArgs = arguments self.__venvDirectory = arguments[-1] prog = self.__progs[self.__callIndex] self.__cmd = "{0} {1}".format(prog, " ".join(arguments)) self.__logOutput(self.tr("Executing: {0}\n").format(self.__cmd)) self.__process.start(prog, arguments) procStarted = self.__process.waitForStarted(5000) if not procStarted: self.__logOutput(self.tr("Failed\n\n")) self.__nextAttempt() 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.buttonBox.button(QDialogButtonBox.StandardButton.Close): self.accept() elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel): self.__finish(0, 0, giveUp=True) def __finish(self, exitCode, exitStatus, giveUp=False): """ Private slot called when the process finished. It is called when the process finished or the user pressed the button. @param exitCode exit code of the process (integer) @param exitStatus exit status of the process (QProcess.ExitStatus) @param giveUp flag indicating to not start another attempt (boolean) """ if ( self.__process is not None and self.__process.state() != QProcess.ProcessState.NotRunning ): self.__process.terminate() QTimer.singleShot(2000, self.__process.kill) self.__process.waitForFinished(3000) self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) if not giveUp: if exitCode != 0: self.__logOutput(self.tr("Failed\n\n")) if len(self.errors.toPlainText().splitlines()) == 1: self.errors.clear() self.errorGroup.hide() self.__nextAttempt() return self.__process = None self.__logOutput(self.tr("\npyvenv finished.\n")) if self.__createLog: self.__writeLogFile() self.__changeVirtualEnvironmentInterpreter() def __nextAttempt(self): """ Private method to start another attempt. """ self.__callIndex += 1 if self.__callIndex < len(self.__progs): self.start(self.__callArgs) else: self.__logError(self.tr("No suitable pyvenv program could be started.\n")) self.__cmd = "" self.__finish(0, 0, giveUp=True) def __readStdout(self): """ Private slot to handle the readyReadStandardOutput signal. It reads the output of the process, formats it and inserts it into the contents pane. """ self.__process.setReadChannel(QProcess.ProcessChannel.StandardOutput) while self.__process.canReadLine(): s = str( self.__process.readLine(), Preferences.getSystem("IOEncoding"), "replace", ) self.__logOutput(s) def __readStderr(self): """ Private slot to handle the readyReadStandardError signal. It reads the error output of the process and inserts it into the error pane. """ self.__process.setReadChannel(QProcess.ProcessChannel.StandardError) while self.__process.canReadLine(): s = str( self.__process.readLine(), Preferences.getSystem("IOEncoding"), "replace", ) self.__logError(s) def __logOutput(self, s): """ Private method to log some output. @param s output string to log (string) """ self.contents.insertPlainText(s) self.contents.ensureCursorVisible() def __logError(self, s): """ Private method to log an error. @param s error string to log (string) """ self.errorGroup.show() self.errors.insertPlainText(s) self.errors.ensureCursorVisible() def __writeLogFile(self): """ Private method to write a log file to the virtualenv directory. """ outtxt = self.contents.toPlainText() logFile = os.path.join(self.__venvDirectory, "pyvenv_upgrade.log") self.__logOutput(self.tr("\nWriting log file '{0}'.\n").format(logFile)) try: with open(logFile, "w", encoding="utf-8") as f: f.write(self.tr("Output:\n")) f.write(outtxt) errtxt = self.errors.toPlainText() if errtxt: f.write("\n") f.write(self.tr("Errors:\n")) f.write(errtxt) except OSError as err: self.__logError( self.tr( """The logfile '{0}' could not be written.\nReason: {1}\n""" ).format(logFile, str(err)) ) self.__logOutput(self.tr("Done.\n")) def __changeVirtualEnvironmentInterpreter(self): """ Private method to change the interpreter of the upgraded virtual environment. """ from .VirtualenvInterpreterSelectionDialog import ( VirtualenvInterpreterSelectionDialog, ) venvInterpreter = "" dlg = VirtualenvInterpreterSelectionDialog( self.__venvName, self.__venvDirectory ) if dlg.exec() == QDialog.DialogCode.Accepted: venvInterpreter = dlg.getData() if venvInterpreter: self.__manager.setVirtualEnvInterpreter(self.__venvName, venvInterpreter)