PyInstallerInterface/PyInstallerExecDialog.py

branch
eric7
changeset 38
fc9ef9dcd51a
parent 35
d9b3cadaf707
child 43
01ce3d6f7a07
equal deleted inserted replaced
37:9ecfea29a47c 38:fc9ef9dcd51a
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2018 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show the output of the pyinstaller/pyi-makespec
8 process.
9 """
10
11 import os
12
13 from PyQt6.QtCore import pyqtSlot, QProcess, QTimer
14 from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QAbstractButton
15
16 from EricWidgets import EricMessageBox
17
18 from .Ui_PyInstallerExecDialog import Ui_PyInstallerExecDialog
19
20 import Preferences
21
22
23 class PyInstallerExecDialog(QDialog, Ui_PyInstallerExecDialog):
24 """
25 Class implementing a dialog to show the output of the
26 pyinstaller/pyi-makespec process.
27
28 This class starts a QProcess and displays a dialog that
29 shows the output of the packager command process.
30 """
31 def __init__(self, cmdname, parent=None):
32 """
33 Constructor
34
35 @param cmdname name of the packager
36 @type str
37 @param parent reference to the parent widget
38 @type QWidget
39 """
40 super().__init__(parent)
41 self.setupUi(self)
42
43 self.buttonBox.button(
44 QDialogButtonBox.StandardButton.Close).setEnabled(False)
45 self.buttonBox.button(
46 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
47
48 self.__process = None
49 self.__cmdname = cmdname # used for several outputs
50
51 def start(self, args, parms, project, script):
52 """
53 Public slot to start the packager command.
54
55 @param args command line arguments for packager program
56 @type list of str
57 @param parms parameters got from the config dialog
58 @type dict
59 @param project reference to the project object
60 @type Project
61 @param script script or spec file name to be processed by by the
62 packager
63 @type str
64 @return flag indicating the successful start of the process
65 @rtype bool
66 """
67 self.__project = project
68
69 if not os.path.isabs(script):
70 # assume relative paths are relative to the project directory
71 script = os.path.join(self.__project.getProjectPath(), script)
72 dname = os.path.dirname(script)
73 self.__script = os.path.basename(script)
74
75 self.contents.clear()
76
77 args.append(self.__script)
78
79 self.__process = QProcess()
80 self.__process.setWorkingDirectory(dname)
81
82 self.__process.readyReadStandardOutput.connect(self.__readStdout)
83 self.__process.readyReadStandardError.connect(self.__readStderr)
84 self.__process.finished.connect(self.__finishedProcess)
85
86 self.setWindowTitle(self.tr('{0} - {1}').format(
87 self.__cmdname, script))
88 self.contents.insertPlainText("{0} {1}\n\n".format(
89 ' '.join(args), os.path.join(dname, self.__script)))
90 self.contents.ensureCursorVisible()
91
92 program = args.pop(0)
93 self.__process.start(program, args)
94 procStarted = self.__process.waitForStarted()
95 if not procStarted:
96 EricMessageBox.critical(
97 self,
98 self.tr('Process Generation Error'),
99 self.tr(
100 'The process {0} could not be started. '
101 'Ensure, that it is in the search path.'
102 ).format(program))
103 return procStarted
104
105 @pyqtSlot(QAbstractButton)
106 def on_buttonBox_clicked(self, button):
107 """
108 Private slot called by a button of the button box clicked.
109
110 @param button button that was clicked
111 @type QAbstractButton
112 """
113 if button == self.buttonBox.button(
114 QDialogButtonBox.StandardButton.Close
115 ):
116 self.accept()
117 elif button == self.buttonBox.button(
118 QDialogButtonBox.StandardButton.Cancel
119 ):
120 self.__finish()
121
122 def __finish(self):
123 """
124 Private slot called when the process was canceled by the user.
125
126 It is called when the process finished or
127 the user pressed the cancel button.
128 """
129 if self.__process is not None:
130 self.__process.disconnect(self.__finishedProcess)
131 self.__process.terminate()
132 QTimer.singleShot(2000, self.__process.kill)
133 self.__process.waitForFinished(3000)
134 self.__process = None
135
136 self.contents.insertPlainText(
137 self.tr('\n{0} aborted.\n').format(self.__cmdname))
138
139 self.__enableButtons()
140
141 def __finishedProcess(self):
142 """
143 Private slot called when the process finished.
144
145 It is called when the process finished or
146 the user pressed the cancel button.
147 """
148 if self.__process.exitStatus() == QProcess.ExitStatus.NormalExit:
149 # add the spec file to the project
150 self.__project.addToOthers(
151 os.path.splitext(self.__script)[0] + ".spec")
152
153 self.__process = None
154
155 self.contents.insertPlainText(
156 self.tr('\n{0} finished.\n').format(self.__cmdname))
157
158 self.__enableButtons()
159
160 def __enableButtons(self):
161 """
162 Private slot called when all processes finished.
163
164 It is called when the process finished or
165 the user pressed the cancel button.
166 """
167 self.buttonBox.button(
168 QDialogButtonBox.StandardButton.Close).setEnabled(True)
169 self.buttonBox.button(
170 QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
171 self.buttonBox.button(
172 QDialogButtonBox.StandardButton.Close).setDefault(True)
173 self.contents.ensureCursorVisible()
174
175 def __readStdout(self):
176 """
177 Private slot to handle the readyReadStandardOutput signal.
178
179 It reads the output of the process, formats it and inserts it into
180 the contents pane.
181 """
182 self.__process.setReadChannel(QProcess.ProcessChannel.StandardOutput)
183
184 while self.__process.canReadLine():
185 s = str(self.__process.readAllStandardOutput(),
186 Preferences.getSystem("IOEncoding"),
187 'replace')
188 self.contents.insertPlainText(s)
189 self.contents.ensureCursorVisible()
190
191 def __readStderr(self):
192 """
193 Private slot to handle the readyReadStandardError signal.
194
195 It reads the error output of the process and inserts it into the
196 error pane.
197 """
198 self.__process.setReadChannel(QProcess.ProcessChannel.StandardError)
199
200 while self.__process.canReadLine():
201 s = str(self.__process.readAllStandardError(),
202 Preferences.getSystem("IOEncoding"),
203 'replace')
204 self.contents.insertPlainText(s)
205 self.contents.ensureCursorVisible()

eric ide

mercurial