PyInstallerInterface/PyInstallerConfigDialog.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 PyInstallerConfigDialog.
8 """
9
10 import copy
11
12 from PyQt6.QtCore import pyqtSlot
13 from PyQt6.QtWidgets import QDialog, QDialogButtonBox
14
15 from EricWidgets.EricPathPicker import EricPathPickerModes
16
17 from .Ui_PyInstallerConfigDialog import Ui_PyInstallerConfigDialog
18
19 import Globals
20
21
22 class PyInstallerConfigDialog(QDialog, Ui_PyInstallerConfigDialog):
23 """
24 Class implementing a dialog to enter the parameters for pyinstaller
25 and pyi-makespec.
26 """
27 def __init__(self, project, executables, params=None, mode="installer",
28 parent=None):
29 """
30 Constructor
31
32 @param project reference to the project object
33 @type Project.Project
34 @param executables names of the pyinstaller executables
35 @type list of str
36 @param params parameters to set in the dialog
37 @type dict
38 @param mode mode of the dialog
39 @type str (one of 'installer' or 'spec')
40 @param parent reference to the parent widget
41 @type QWidget
42 """
43 super().__init__(parent)
44 self.setupUi(self)
45
46 self.__project = project
47 self.__mode = mode
48
49 self.inputFilePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
50 self.inputFilePicker.setDefaultDirectory(
51 self.__project.getProjectPath())
52 if self.__mode == "installer":
53 self.inputFilePicker.setFilters(self.tr(
54 "Python Files (*.py *.py3);;"
55 "Python GUI Files (*.pyw *.pyw3);;"
56 "Spec Files (*.spec);;"
57 "All Files (*)"
58 ))
59 elif self.__mode == "spec":
60 self.inputFilePicker.setFilters(self.tr(
61 "Python Files (*.py *.py3);;"
62 "Python GUI Files (*.pyw *.pyw3);;"
63 "All Files (*)"
64 ))
65
66 self.executableCombo.addItems(executables)
67
68 if not bool(project.getMainScript()):
69 # no main script defined
70 self.selectedScriptButton.setChecked(True)
71 self.mainScriptButton.setEnabled(False)
72
73 self.iconFilePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
74 self.iconFilePicker.setDefaultDirectory(
75 self.__project.getProjectPath())
76 if Globals.isMacPlatform():
77 self.iconFilePicker.setFilters(self.tr(
78 "Icon Files (*.icns);;"
79 "All Files (*)"
80 ))
81 elif Globals.isWindowsPlatform():
82 self.iconFilePicker.setFilters(self.tr(
83 "Icon Files (*.ico);;"
84 "Executable Files (*.exe);;"
85 "All Files (*)"
86 ))
87
88 # disable platform specific tabs
89 self.tabWidget.setTabEnabled(
90 self.tabWidget.indexOf(self.windowsMacTab),
91 Globals.isMacPlatform() or Globals.isWindowsPlatform())
92 self.tabWidget.setTabEnabled(
93 self.tabWidget.indexOf(self.macTab),
94 Globals.isMacPlatform())
95
96 self.__initializeDefaults()
97
98 # get a copy of the defaults to store the user settings
99 self.__parameters = copy.deepcopy(self.__defaults)
100
101 # combine it with the values of params
102 if params is not None:
103 self.__parameters.update(params)
104
105 # initialize general tab
106 if mode == "installer" and bool(self.__parameters["pyinstaller"]):
107 self.executableCombo.setCurrentIndex(
108 self.executableCombo.findText(
109 self.__parameters["pyinstaller"]))
110 elif mode == "spec" and bool(self.__parameters["pyi-makespec"]):
111 self.executableCombo.setCurrentIndex(
112 self.executableCombo.findText(
113 self.__parameters["pyi-makespec"]))
114 if self.__parameters["mainscript"]:
115 self.mainScriptButton.setChecked(True)
116 else:
117 self.selectedScriptButton.setChecked(True)
118 self.inputFilePicker.setText(self.__parameters["inputFile"])
119 if self.__parameters["oneDirectory"]:
120 self.oneDirButton.setChecked(True)
121 else:
122 self.oneFileButton.setChecked(True)
123 self.nameEdit.setText(self.__parameters["name"])
124 self.keyEdit.setText(self.__parameters["encryptionKey"])
125 self.cleanCheckBox.setChecked(self.__parameters["cleanBeforeBuilding"])
126
127 # initialize Windows and macOS tab
128 if self.__parameters["consoleApplication"]:
129 self.consoleButton.setChecked(True)
130 else:
131 self.windowedButton.setChecked(True)
132 self.iconFilePicker.setText(self.__parameters["iconFile"])
133 self.iconIdEdit.setText(self.__parameters["iconId"])
134
135 # initialize maxOS specific tab
136 self.bundleIdentifierEdit.setText(
137 self.__parameters["bundleIdentifier"])
138
139 self.__updateOkButton()
140
141 msh = self.minimumSizeHint()
142 self.resize(max(self.width(), msh.width()), msh.height())
143
144 def __initializeDefaults(self):
145 """
146 Private method to set the default values.
147
148 These are needed later on to generate the command line parameters.
149 """
150 self.__defaults = {
151 # general options
152 "pyinstaller": "",
153 "pyi-makespec": "",
154 "mainscript": bool(self.__project.getMainScript()),
155 "inputFile": "",
156 "oneDirectory": True,
157 "name": "",
158 "encryptionKey": "",
159 "cleanBeforeBuilding": False,
160
161 # Windows and macOS options
162 "consoleApplication": True,
163 "iconFile": "",
164 "iconId": "",
165
166 # macOS specific options
167 "bundleIdentifier": "",
168 }
169
170 def generateParameters(self):
171 """
172 Public method that generates the command line parameters.
173
174 It generates a list of strings to be used to set the QProcess arguments
175 for the pyinstaller/pyi-makespec call and a list containing the non
176 default parameters. The second list can be passed back upon object
177 generation to overwrite the default settings.
178
179 @return a tuple of the command line parameters, non default parameters
180 and the script path
181 @rtype tuple of (list of str, dict, str)
182 """
183 parms = {}
184 args = []
185
186 # 1. the program name
187 if self.__mode == "installer":
188 args.append(self.__parameters["pyinstaller"])
189 parms["pyinstaller"] = self.__parameters["pyinstaller"]
190 elif self.__mode == "spec":
191 args.append(self.__parameters["pyi-makespec"])
192 parms["pyi-makespec"] = self.__parameters["pyi-makespec"]
193
194 # 2. the commandline options
195 # 2.1 general options, input
196 if not self.__parameters["mainscript"]:
197 parms["mainscript"] = False
198 parms["inputFile"] = self.__parameters["inputFile"]
199
200 runWithSpec = self.__parameters["inputFile"].endswith(".spec")
201 if not runWithSpec:
202 # 2.2 general options, part 1
203 if not self.__parameters["oneDirectory"]:
204 parms["oneDirectory"] = self.__parameters["oneDirectory"]
205 args.append("--onefile")
206 if self.__parameters["name"] != self.__defaults["name"]:
207 parms["name"] = self.__parameters["name"]
208 args.append("--name")
209 args.append(self.__parameters["name"])
210 if (
211 self.__parameters["encryptionKey"] !=
212 self.__defaults["encryptionKey"]
213 ):
214 parms["encryptionKey"] = self.__parameters["encryptionKey"]
215 args.append("--key")
216 args.append(self.__parameters["encryptionKey"])
217
218 # 2.3 Windows and macOS options
219 if (
220 self.__parameters["consoleApplication"] !=
221 self.__defaults["consoleApplication"]
222 ):
223 parms["consoleApplication"] = (
224 self.__parameters["consoleApplication"]
225 )
226 args.append("--windowed")
227 if self.__parameters["iconFile"] != self.__defaults["iconFile"]:
228 parms["iconFile"] = self.__parameters["iconFile"]
229 parms["iconId"] = self.__parameters["iconId"]
230 args.append("--icon")
231 if self.__parameters["iconFile"].endswith(".exe"):
232 if bool(self.__parameters["iconId"]):
233 iconId = self.__parameters["iconId"]
234 else:
235 iconId = "0"
236 args.append("{0},{1}".format(
237 self.__parameters["iconFile"], iconId))
238 else:
239 args.append(self.__parameters["iconFile"])
240
241 # 2.4 macOS specific options
242 if (
243 self.__parameters["bundleIdentifier"] !=
244 self.__defaults["bundleIdentifier"]
245 ):
246 parms["bundleIdentifier"] = (
247 self.__parameters["bundleIdentifier"]
248 )
249 args.append("--osx-bundle-identifier")
250 args.append(self.__parameters["bundleIdentifier"])
251
252 # 2.5 general options, part 2
253 if (
254 self.__parameters["cleanBeforeBuilding"] !=
255 self.__defaults["cleanBeforeBuilding"]
256 ):
257 parms["cleanBeforeBuilding"] = (
258 self.__parameters["cleanBeforeBuilding"]
259 )
260 args.append("--clean")
261
262 # 3. always add these arguments
263 if self.__mode == "installer":
264 args.append("--noconfirm") # don't ask the user
265
266 # determine the script to be processed
267 script = (
268 self.__project.getMainScript()
269 if self.__parameters["mainscript"] else
270 self.__parameters["inputFile"]
271 )
272
273 return args, parms, script
274
275 def accept(self):
276 """
277 Public method called by the Ok button.
278
279 It saves the values in the parameters dictionary.
280 """
281 # get data of general tab
282 if self.__mode == "installer":
283 self.__parameters["pyinstaller"] = (
284 self.executableCombo.currentText()
285 )
286 elif self.__mode == "spec":
287 self.__parameters["pyi-makespec"] = (
288 self.executableCombo.currentText()
289 )
290 self.__parameters["mainscript"] = self.mainScriptButton.isChecked()
291 self.__parameters["inputFile"] = self.inputFilePicker.text()
292 self.__parameters["oneDirectory"] = self.oneDirButton.isChecked()
293 self.__parameters["name"] = self.nameEdit.text()
294 self.__parameters["encryptionKey"] = self.keyEdit.text()
295 self.__parameters["cleanBeforeBuilding"] = (
296 self.cleanCheckBox.isChecked()
297 )
298
299 # get data of Windows and macOS tab
300 self.__parameters["consoleApplication"] = (
301 self.consoleButton.isChecked()
302 )
303 self.__parameters["iconFile"] = self.iconFilePicker.text()
304 self.__parameters["iconId"] = self.iconIdEdit.text()
305
306 # get data of macOS specific tab
307 self.__parameters["bundleIdentifier"] = (
308 self.bundleIdentifierEdit.text()
309 )
310
311 # call the accept slot of the base class
312 super().accept()
313
314 def __updateOkButton(self):
315 """
316 Private method to update the enabled state of the OK button.
317 """
318 enable = True
319
320 # If not to be run with the project main script, a script or
321 # spec file must be selected.
322 if (
323 self.selectedScriptButton.isChecked() and
324 not bool(self.inputFilePicker.text())
325 ):
326 enable = False
327
328 # If the icon shall be picked from a .exe file, an icon ID
329 # must be entered (Windows only).
330 if (
331 self.iconFilePicker.text().endswith(".exe") and
332 not bool(self.iconIdEdit.text())
333 ):
334 enable = False
335
336 self.buttonBox.button(
337 QDialogButtonBox.StandardButton.Ok).setEnabled(enable)
338
339 @pyqtSlot(bool)
340 def on_selectedScriptButton_toggled(self, checked):
341 """
342 Private slot to handle changes of the radio button state.
343
344 @param checked state of the radio button
345 @type bool
346 """
347 self.__updateOkButton()
348
349 @pyqtSlot(str)
350 def on_inputFilePicker_textChanged(self, txt):
351 """
352 Private slot to handle changes of the input file.
353
354 @param txt text of the file edit
355 @type str
356 """
357 self.__updateOkButton()
358
359 @pyqtSlot(str)
360 def on_iconFilePicker_textChanged(self, txt):
361 """
362 Private slot to handle changes of the icon file.
363
364 @param txt text of the file edit
365 @type str
366 """
367 self.iconIdEdit.setEnabled(txt.endswith(".exe"))
368 self.__updateOkButton()
369
370 @pyqtSlot(str)
371 def on_iconIdEdit_textChanged(self, txt):
372 """
373 Private slot to handle changes of the icon ID.
374
375 @param txt iconID
376 @type str
377 """
378 self.__updateOkButton()

eric ide

mercurial