PyInstaller/PyInstallerExecDialog.py

branch
eric7
changeset 38
fc9ef9dcd51a
parent 37
9ecfea29a47c
child 39
5b34af15d930
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 PyQt5.QtCore import pyqtSlot, QProcess, QTimer
14 from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QAbstractButton
15
16 from E5Gui import E5MessageBox
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(QDialogButtonBox.Close).setEnabled(False)
44 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
45
46 self.__process = None
47 self.__cmdname = cmdname # used for several outputs
48
49 def start(self, args, parms, project, script):
50 """
51 Public slot to start the packager command.
52
53 @param args command line arguments for packager program
54 @type list of str
55 @param parms parameters got from the config dialog
56 @type dict
57 @param project reference to the project object
58 @type Project
59 @param script script or spec file name to be processed by by the
60 packager
61 @type str
62 @return flag indicating the successful start of the process
63 @rtype bool
64 """
65 self.__project = project
66
67 if not os.path.isabs(script):
68 # assume relative paths are relative to the project directory
69 script = os.path.join(self.__project.getProjectPath(), script)
70 dname = os.path.dirname(script)
71 self.__script = os.path.basename(script)
72
73 self.contents.clear()
74
75 args.append(self.__script)
76
77 self.__process = QProcess()
78 self.__process.setWorkingDirectory(dname)
79
80 self.__process.readyReadStandardOutput.connect(self.__readStdout)
81 self.__process.readyReadStandardError.connect(self.__readStderr)
82 self.__process.finished.connect(self.__finishedProcess)
83
84 self.setWindowTitle(self.tr('{0} - {1}').format(
85 self.__cmdname, script))
86 self.contents.insertPlainText("{0} {1}\n\n".format(
87 ' '.join(args), os.path.join(dname, self.__script)))
88 self.contents.ensureCursorVisible()
89
90 program = args.pop(0)
91 self.__process.start(program, args)
92 procStarted = self.__process.waitForStarted()
93 if not procStarted:
94 E5MessageBox.critical(
95 self,
96 self.tr('Process Generation Error'),
97 self.tr(
98 'The process {0} could not be started. '
99 'Ensure, that it is in the search path.'
100 ).format(program))
101 return procStarted
102
103 @pyqtSlot(QAbstractButton)
104 def on_buttonBox_clicked(self, button):
105 """
106 Private slot called by a button of the button box clicked.
107
108 @param button button that was clicked
109 @type QAbstractButton
110 """
111 if button == self.buttonBox.button(QDialogButtonBox.Close):
112 self.accept()
113 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
114 self.__finish()
115
116 def __finish(self):
117 """
118 Private slot called when the process was canceled by the user.
119
120 It is called when the process finished or
121 the user pressed the cancel button.
122 """
123 if self.__process is not None:
124 self.__process.disconnect(self.__finishedProcess)
125 self.__process.terminate()
126 QTimer.singleShot(2000, self.__process.kill)
127 self.__process.waitForFinished(3000)
128 self.__process = None
129
130 self.contents.insertPlainText(
131 self.tr('\n{0} aborted.\n').format(self.__cmdname))
132
133 self.__enableButtons()
134
135 def __finishedProcess(self):
136 """
137 Private slot called when the process finished.
138
139 It is called when the process finished or
140 the user pressed the cancel button.
141 """
142 if self.__process.exitStatus() == QProcess.NormalExit:
143 # add the spec file to the project
144 self.__project.addToOthers(
145 os.path.splitext(self.__script)[0] + ".spec")
146
147 self.__process = None
148
149 self.contents.insertPlainText(
150 self.tr('\n{0} finished.\n').format(self.__cmdname))
151
152 self.__enableButtons()
153
154 def __enableButtons(self):
155 """
156 Private slot called when all processes finished.
157
158 It is called when the process finished or
159 the user pressed the cancel button.
160 """
161 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
162 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
163 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
164 self.contents.ensureCursorVisible()
165
166 def __readStdout(self):
167 """
168 Private slot to handle the readyReadStandardOutput signal.
169
170 It reads the output of the process, formats it and inserts it into
171 the contents pane.
172 """
173 self.__process.setReadChannel(QProcess.StandardOutput)
174
175 while self.__process.canReadLine():
176 s = str(self.__process.readAllStandardOutput(),
177 Preferences.getSystem("IOEncoding"),
178 'replace')
179 self.contents.insertPlainText(s)
180 self.contents.ensureCursorVisible()
181
182 def __readStderr(self):
183 """
184 Private slot to handle the readyReadStandardError signal.
185
186 It reads the error output of the process and inserts it into the
187 error pane.
188 """
189 self.__process.setReadChannel(QProcess.StandardError)
190
191 while self.__process.canReadLine():
192 s = str(self.__process.readAllStandardError(),
193 Preferences.getSystem("IOEncoding"),
194 'replace')
195 self.contents.insertPlainText(s)
196 self.contents.ensureCursorVisible()

eric ide

mercurial