PluginCxFreeze.py

branch
eric7
changeset 139
4df5e67b084b
parent 137
da8cc28e689f
child 140
9e20ee9c7ca2
equal deleted inserted replaced
138:54f57d052146 139:4df5e67b084b
14 from PyQt6.QtWidgets import QDialog 14 from PyQt6.QtWidgets import QDialog
15 15
16 from EricWidgets import EricMessageBox 16 from EricWidgets import EricMessageBox
17 from EricGui.EricAction import EricAction 17 from EricGui.EricAction import EricAction
18 from EricWidgets.EricApplication import ericApp 18 from EricWidgets.EricApplication import ericApp
19 19
20 import Utilities 20 import Utilities
21 21
22 # Start-of-Header 22 # Start-of-Header
23 name = "CxFreeze Plugin" 23 name = "CxFreeze Plugin"
24 author = "Detlev Offenbach <detlev@die-offenbachs.de>" 24 author = "Detlev Offenbach <detlev@die-offenbachs.de>"
42 42
43 43
44 def exeDisplayDataList(): 44 def exeDisplayDataList():
45 """ 45 """
46 Public method to support the display of some executable info. 46 Public method to support the display of some executable info.
47 47
48 @return dictionary containing the data to query the presence of 48 @return dictionary containing the data to query the presence of
49 the executable 49 the executable
50 @rtype dict 50 @rtype dict
51 """ 51 """
52 dataList = [] 52 dataList = []
53 data = { 53 data = {
54 "programEntry": True, 54 "programEntry": True,
55 "header": QCoreApplication.translate( 55 "header": QCoreApplication.translate("CxFreezePlugin", "Packagers - cx_freeze"),
56 "CxFreezePlugin", "Packagers - cx_freeze"), 56 "exe": "dummyfreeze",
57 "exe": 'dummyfreeze', 57 "versionCommand": "--version",
58 "versionCommand": '--version', 58 "versionStartsWith": "dummyfreeze",
59 "versionStartsWith": 'dummyfreeze',
60 "versionPosition": -1, 59 "versionPosition": -1,
61 "version": "", 60 "version": "",
62 "versionCleanup": None, 61 "versionCleanup": None,
63 } 62 }
64 63
65 if _checkProgram(): 64 if _checkProgram():
66 for exePath in exePy3: 65 for exePath in exePy3:
67 data["exe"] = exePath 66 data["exe"] = exePath
68 data["versionStartsWith"] = "cxfreeze" 67 data["versionStartsWith"] = "cxfreeze"
69 dataList.append(data.copy()) 68 dataList.append(data.copy())
73 72
74 73
75 def _findExecutable(majorVersion): 74 def _findExecutable(majorVersion):
76 """ 75 """
77 Restricted function to determine the names of the executable. 76 Restricted function to determine the names of the executable.
78 77
79 @param majorVersion major Python version of the executables 78 @param majorVersion major Python version of the executables
80 @type int 79 @type int
81 @return names of the executable 80 @return names of the executable
82 @rtype list of str 81 @rtype list of str
83 """ 82 """
84 # Determine Python Version 83 # Determine Python Version
85 if majorVersion == 3: 84 if majorVersion == 3:
86 minorVersions = range(10) 85 minorVersions = range(10)
87 else: 86 else:
88 return [] 87 return []
89 88
90 executables = set() 89 executables = set()
91 if Utilities.isWindowsPlatform(): 90 if Utilities.isWindowsPlatform():
92 # 91 #
93 # Windows 92 # Windows
94 # 93 #
95 try: 94 try:
96 import winreg 95 import winreg
97 except ImportError: 96 except ImportError:
98 import _winreg as winreg # __IGNORE_WARNING__ 97 import _winreg as winreg # __IGNORE_WARNING__
99 98
100 def getExePath(branch, access, versionStr): 99 def getExePath(branch, access, versionStr):
101 try: 100 try:
102 software = winreg.OpenKey(branch, 'Software', 0, access) 101 software = winreg.OpenKey(branch, "Software", 0, access)
103 python = winreg.OpenKey(software, 'Python', 0, access) 102 python = winreg.OpenKey(software, "Python", 0, access)
104 pcore = winreg.OpenKey(python, 'PythonCore', 0, access) 103 pcore = winreg.OpenKey(python, "PythonCore", 0, access)
105 version = winreg.OpenKey(pcore, versionStr, 0, access) 104 version = winreg.OpenKey(pcore, versionStr, 0, access)
106 installpath = winreg.QueryValue(version, 'InstallPath') 105 installpath = winreg.QueryValue(version, "InstallPath")
107 exe = os.path.join(installpath, 'Scripts', 'cxfreeze.bat') 106 exe = os.path.join(installpath, "Scripts", "cxfreeze.bat")
108 if os.access(exe, os.X_OK): 107 if os.access(exe, os.X_OK):
109 return exe 108 return exe
110 except WindowsError: # __IGNORE_WARNING__ 109 except WindowsError: # __IGNORE_WARNING__
111 return None 110 return None
112 return None 111 return None
113 112
114 versionSuffixes = ["", "-32", "-64"] 113 versionSuffixes = ["", "-32", "-64"]
115 for minorVersion in minorVersions: 114 for minorVersion in minorVersions:
116 for versionSuffix in versionSuffixes: 115 for versionSuffix in versionSuffixes:
117 versionStr = '{0}.{1}{2}'.format(majorVersion, minorVersion, 116 versionStr = "{0}.{1}{2}".format(
118 versionSuffix) 117 majorVersion, minorVersion, versionSuffix
118 )
119 exePath = getExePath( 119 exePath = getExePath(
120 winreg.HKEY_CURRENT_USER, 120 winreg.HKEY_CURRENT_USER,
121 winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr) 121 winreg.KEY_WOW64_32KEY | winreg.KEY_READ,
122 versionStr,
123 )
122 if exePath is not None: 124 if exePath is not None:
123 executables.add(exePath) 125 executables.add(exePath)
124 126
125 exePath = getExePath( 127 exePath = getExePath(
126 winreg.HKEY_LOCAL_MACHINE, 128 winreg.HKEY_LOCAL_MACHINE,
127 winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr) 129 winreg.KEY_WOW64_32KEY | winreg.KEY_READ,
130 versionStr,
131 )
128 if exePath is not None: 132 if exePath is not None:
129 executables.add(exePath) 133 executables.add(exePath)
130 134
131 # Even on Intel 64-bit machines it's 'AMD64' 135 # Even on Intel 64-bit machines it's 'AMD64'
132 if platform.machine() == 'AMD64': 136 if platform.machine() == "AMD64":
133 exePath = getExePath( 137 exePath = getExePath(
134 winreg.HKEY_CURRENT_USER, 138 winreg.HKEY_CURRENT_USER,
135 winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr) 139 winreg.KEY_WOW64_64KEY | winreg.KEY_READ,
140 versionStr,
141 )
136 if exePath is not None: 142 if exePath is not None:
137 executables.add(exePath) 143 executables.add(exePath)
138 144
139 exePath = getExePath( 145 exePath = getExePath(
140 winreg.HKEY_LOCAL_MACHINE, 146 winreg.HKEY_LOCAL_MACHINE,
141 winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr) 147 winreg.KEY_WOW64_64KEY | winreg.KEY_READ,
148 versionStr,
149 )
142 if exePath is not None: 150 if exePath is not None:
143 executables.add(exePath) 151 executables.add(exePath)
144 152
145 if not executables and majorVersion >= 3: 153 if not executables and majorVersion >= 3:
146 # check the PATH environment variable if nothing was found 154 # check the PATH environment variable if nothing was found
147 # Python 3 only 155 # Python 3 only
148 path = Utilities.getEnvironmentEntry('PATH') 156 path = Utilities.getEnvironmentEntry("PATH")
149 if path: 157 if path:
150 dirs = path.split(os.pathsep) 158 dirs = path.split(os.pathsep)
151 for directory in dirs: 159 for directory in dirs:
152 for suffix in (".bat", ".exe"): 160 for suffix in (".bat", ".exe"):
153 exe = os.path.join(directory, "cxfreeze" + suffix) 161 exe = os.path.join(directory, "cxfreeze" + suffix)
154 if os.access(exe, os.X_OK): 162 if os.access(exe, os.X_OK):
155 executables.add(exe) 163 executables.add(exe)
156 else: 164 else:
157 # 165 #
158 # Linux, Unix ... 166 # Linux, Unix ...
159 cxfreezeScript = 'cxfreeze' 167 cxfreezeScript = "cxfreeze"
160 scriptSuffixes = ["", "-python{0}".format(majorVersion)] 168 scriptSuffixes = ["", "-python{0}".format(majorVersion)]
161 for minorVersion in minorVersions: 169 for minorVersion in minorVersions:
162 scriptSuffixes.append( 170 scriptSuffixes.append("-python{0}.{1}".format(majorVersion, minorVersion))
163 "-python{0}.{1}".format(majorVersion, minorVersion))
164 # There could be multiple cxfreeze executables in the path 171 # There could be multiple cxfreeze executables in the path
165 # e.g. for different python variants 172 # e.g. for different python variants
166 path = Utilities.getEnvironmentEntry('PATH') 173 path = Utilities.getEnvironmentEntry("PATH")
167 # environment variable not defined 174 # environment variable not defined
168 if path is None: 175 if path is None:
169 return [] 176 return []
170 177
171 # step 1: determine possible candidates 178 # step 1: determine possible candidates
172 exes = [] 179 exes = []
173 dirs = path.split(os.pathsep) 180 dirs = path.split(os.pathsep)
174 for directory in dirs: 181 for directory in dirs:
175 for suffix in scriptSuffixes: 182 for suffix in scriptSuffixes:
176 exe = os.path.join(directory, cxfreezeScript + suffix) 183 exe = os.path.join(directory, cxfreezeScript + suffix)
177 if os.access(exe, os.X_OK): 184 if os.access(exe, os.X_OK):
178 exes.append(exe) 185 exes.append(exe)
179 186
180 # step 2: determine the Python variant 187 # step 2: determine the Python variant
181 _exePy3 = set() 188 _exePy3 = set()
182 versionArgs = ["-c", "import sys; print(sys.version_info[0])"] 189 versionArgs = ["-c", "import sys; print(sys.version_info[0])"]
183 for exe in exes: 190 for exe in exes:
184 with open(exe, "r") as f: 191 with open(exe, "r") as f:
187 process = QProcess() 194 process = QProcess()
188 process.start(program, versionArgs) 195 process.start(program, versionArgs)
189 process.waitForFinished(5000) 196 process.waitForFinished(5000)
190 # get a QByteArray of the output 197 # get a QByteArray of the output
191 versionBytes = process.readAllStandardOutput() 198 versionBytes = process.readAllStandardOutput()
192 versionStr = str(versionBytes, encoding='utf-8').strip() 199 versionStr = str(versionBytes, encoding="utf-8").strip()
193 if versionStr == "3": 200 if versionStr == "3":
194 _exePy3.add(exe) 201 _exePy3.add(exe)
195 202
196 executables = _exePy3 203 executables = _exePy3
197 204
198 # sort items, the probably newest topmost 205 # sort items, the probably newest topmost
199 executables = list(executables) 206 executables = list(executables)
200 executables.sort(reverse=True) 207 executables.sort(reverse=True)
201 return executables 208 return executables
202 209
203 210
204 def _checkProgram(): 211 def _checkProgram():
205 """ 212 """
206 Restricted function to check the availability of cxfreeze. 213 Restricted function to check the availability of cxfreeze.
207 214
208 @return flag indicating availability 215 @return flag indicating availability
209 @rtype bool 216 @rtype bool
210 """ 217 """
211 global error, exePy3 218 global error, exePy3
212 219
213 exePy3 = _findExecutable(3) 220 exePy3 = _findExecutable(3)
214 if exePy3 == []: 221 if exePy3 == []:
215 if Utilities.isWindowsPlatform(): 222 if Utilities.isWindowsPlatform():
216 error = QCoreApplication.translate( 223 error = QCoreApplication.translate(
217 "CxFreezePlugin", 224 "CxFreezePlugin",
218 "The cxfreeze.bat executable could not be found." 225 "The cxfreeze.bat executable could not be found."
219 "Did you run the cxfreeze-postinstall script?") 226 "Did you run the cxfreeze-postinstall script?",
227 )
220 else: 228 else:
221 error = QCoreApplication.translate( 229 error = QCoreApplication.translate(
222 "CxFreezePlugin", 230 "CxFreezePlugin", "The cxfreeze executable could not be found."
223 "The cxfreeze executable could not be found.") 231 )
224 return False 232 return False
225 else: 233 else:
226 return True 234 return True
227 235
228 236
229 class CxFreezePlugin(QObject): 237 class CxFreezePlugin(QObject):
230 """ 238 """
231 Class implementing the CxFreeze plugin. 239 Class implementing the CxFreeze plugin.
232 """ 240 """
241
233 def __init__(self, ui): 242 def __init__(self, ui):
234 """ 243 """
235 Constructor 244 Constructor
236 245
237 @param ui reference to the user interface object 246 @param ui reference to the user interface object
238 @type UserInterface 247 @type UserInterface
239 """ 248 """
240 super().__init__(ui) 249 super().__init__(ui)
241 self.__ui = ui 250 self.__ui = ui
242 self.__initialize() 251 self.__initialize()
243 _checkProgram() 252 _checkProgram()
244 253
245 self.__translator = None 254 self.__translator = None
246 self.__loadTranslator() 255 self.__loadTranslator()
247 256
248 def __initialize(self): 257 def __initialize(self):
249 """ 258 """
250 Private slot to (re)initialize the plugin. 259 Private slot to (re)initialize the plugin.
251 """ 260 """
252 self.__projectAct = None 261 self.__projectAct = None
253 self.__projectSeparator = None 262 self.__projectSeparator = None
254 263
255 def activate(self): 264 def activate(self):
256 """ 265 """
257 Public method to activate this plugin. 266 Public method to activate this plugin.
258 267
259 @return tuple of None and activation status 268 @return tuple of None and activation status
260 @rtype tuple of (None, bool) 269 @rtype tuple of (None, bool)
261 """ 270 """
262 global error 271 global error
263 272
264 # There is already an error, don't activate 273 # There is already an error, don't activate
265 if error: 274 if error:
266 return None, False 275 return None, False
267 276
268 # cxfreeze is only activated if it is available 277 # cxfreeze is only activated if it is available
269 if not _checkProgram(): 278 if not _checkProgram():
270 return None, False 279 return None, False
271 280
272 project = ericApp().getObject("Project") 281 project = ericApp().getObject("Project")
273 menu = project.getMenu("Packagers") 282 menu = project.getMenu("Packagers")
274 if menu: 283 if menu:
275 self.__projectAct = EricAction( 284 self.__projectAct = EricAction(
276 self.tr('Use cx_freeze'), 285 self.tr("Use cx_freeze"),
277 self.tr('Use cx_&freeze'), 0, 0, 286 self.tr("Use cx_&freeze"),
278 self, 'packagers_cxfreeze') 287 0,
288 0,
289 self,
290 "packagers_cxfreeze",
291 )
279 self.__projectAct.setStatusTip( 292 self.__projectAct.setStatusTip(
280 self.tr('Generate a distribution package using cx_freeze')) 293 self.tr("Generate a distribution package using cx_freeze")
281 self.__projectAct.setWhatsThis(self.tr( 294 )
282 """<b>Use cx_freeze</b>""" 295 self.__projectAct.setWhatsThis(
283 """<p>Generate a distribution package using cx_freeze.""" 296 self.tr(
284 """ The command is executed in the project path. All""" 297 """<b>Use cx_freeze</b>"""
285 """ files and directories must be given absolute or""" 298 """<p>Generate a distribution package using cx_freeze."""
286 """ relative to the project directory.</p>""" 299 """ The command is executed in the project path. All"""
287 )) 300 """ files and directories must be given absolute or"""
301 """ relative to the project directory.</p>"""
302 )
303 )
288 self.__projectAct.triggered.connect(self.__cxfreeze) 304 self.__projectAct.triggered.connect(self.__cxfreeze)
289 project.addEricActions([self.__projectAct]) 305 project.addEricActions([self.__projectAct])
290 self.__projectSeparator = menu.addSeparator() 306 self.__projectSeparator = menu.addSeparator()
291 menu.addAction(self.__projectAct) 307 menu.addAction(self.__projectAct)
292 project.showMenu.connect(self.__projectShowMenu) 308 project.showMenu.connect(self.__projectShowMenu)
293 309
294 error = "" 310 error = ""
295 return None, True 311 return None, True
296 312
297 def deactivate(self): 313 def deactivate(self):
298 """ 314 """
300 """ 316 """
301 menu = ericApp().getObject("Project").getMenu("Packagers") 317 menu = ericApp().getObject("Project").getMenu("Packagers")
302 if menu: 318 if menu:
303 if self.__projectAct: 319 if self.__projectAct:
304 menu.removeAction(self.__projectAct) 320 menu.removeAction(self.__projectAct)
305 ericApp().getObject("Project").removeEricActions( 321 ericApp().getObject("Project").removeEricActions([self.__projectAct])
306 [self.__projectAct])
307 if self.__projectSeparator: 322 if self.__projectSeparator:
308 menu.removeAction(self.__projectSeparator) 323 menu.removeAction(self.__projectSeparator)
309 324
310 self.__initialize() 325 self.__initialize()
311 326
312 def __projectShowMenu(self, menuName, menu): 327 def __projectShowMenu(self, menuName, menu):
313 """ 328 """
314 Private slot called, when the the project menu or a submenu is 329 Private slot called, when the the project menu or a submenu is
315 about to be shown. 330 about to be shown.
316 331
317 @param menuName name of the menu to be shown 332 @param menuName name of the menu to be shown
318 @type str 333 @type str
319 @param menu reference to the menu 334 @param menu reference to the menu
320 @type QMenu 335 @type QMenu
321 """ 336 """
322 if ( 337 if menuName == "Packagers" and self.__projectAct is not None:
323 menuName == "Packagers" and
324 self.__projectAct is not None
325 ):
326 self.__projectAct.setEnabled( 338 self.__projectAct.setEnabled(
327 ericApp().getObject("Project").getProjectLanguage() == 339 ericApp().getObject("Project").getProjectLanguage() == "Python3"
328 "Python3" 340 )
329 ) 341
330
331 def __loadTranslator(self): 342 def __loadTranslator(self):
332 """ 343 """
333 Private method to load the translation file. 344 Private method to load the translation file.
334 """ 345 """
335 if self.__ui is not None: 346 if self.__ui is not None:
336 loc = self.__ui.getLocale() 347 loc = self.__ui.getLocale()
337 if loc and loc != "C": 348 if loc and loc != "C":
338 locale_dir = os.path.join(os.path.dirname(__file__), 349 locale_dir = os.path.join(os.path.dirname(__file__), "CxFreeze", "i18n")
339 "CxFreeze", "i18n")
340 translation = "cxfreeze_{0}".format(loc) 350 translation = "cxfreeze_{0}".format(loc)
341 translator = QTranslator(None) 351 translator = QTranslator(None)
342 loaded = translator.load(translation, locale_dir) 352 loaded = translator.load(translation, locale_dir)
343 if loaded: 353 if loaded:
344 self.__translator = translator 354 self.__translator = translator
345 ericApp().installTranslator(self.__translator) 355 ericApp().installTranslator(self.__translator)
346 else: 356 else:
347 print("Warning: translation file '{0}' could not be" 357 print(
348 " loaded.".format(translation)) 358 "Warning: translation file '{0}' could not be"
359 " loaded.".format(translation)
360 )
349 print("Using default.") 361 print("Using default.")
350 362
351 def __cxfreeze(self): 363 def __cxfreeze(self):
352 """ 364 """
353 Private slot to handle the cxfreeze execution. 365 Private slot to handle the cxfreeze execution.
354 """ 366 """
355 project = ericApp().getObject("Project") 367 project = ericApp().getObject("Project")
358 EricMessageBox.critical( 370 EricMessageBox.critical(
359 self.__ui, 371 self.__ui,
360 self.tr("cxfreeze"), 372 self.tr("cxfreeze"),
361 self.tr( 373 self.tr(
362 """There is no main script defined for the current""" 374 """There is no main script defined for the current"""
363 """ project."""), 375 """ project."""
364 EricMessageBox.StandardButtons(EricMessageBox.Abort)) 376 ),
377 EricMessageBox.StandardButtons(EricMessageBox.Abort),
378 )
365 return 379 return
366 380
367 majorVersionStr = project.getProjectLanguage() 381 majorVersionStr = project.getProjectLanguage()
368 exe = {"Python3": exePy3}.get(majorVersionStr) 382 exe = {"Python3": exePy3}.get(majorVersionStr)
369 if exe == []: 383 if exe == []:
370 EricMessageBox.critical( 384 EricMessageBox.critical(
371 self.__ui, 385 self.__ui,
372 self.tr("cxfreeze"), 386 self.tr("cxfreeze"),
373 self.tr("""The cxfreeze executable could not be found.""")) 387 self.tr("""The cxfreeze executable could not be found."""),
388 )
374 return 389 return
375 390
376 # check if all files saved and errorfree before continue 391 # check if all files saved and errorfree before continue
377 if not project.checkAllScriptsDirty(reportSyntaxErrors=True): 392 if not project.checkAllScriptsDirty(reportSyntaxErrors=True):
378 return 393 return
379 394
380 from CxFreeze.CxfreezeConfigDialog import CxfreezeConfigDialog 395 from CxFreeze.CxfreezeConfigDialog import CxfreezeConfigDialog
381 parms = project.getData('PACKAGERSPARMS', "CXFREEZE") 396
397 parms = project.getData("PACKAGERSPARMS", "CXFREEZE")
382 dlg = CxfreezeConfigDialog(project, exe, parms) 398 dlg = CxfreezeConfigDialog(project, exe, parms)
383 if dlg.exec() == QDialog.DialogCode.Accepted: 399 if dlg.exec() == QDialog.DialogCode.Accepted:
384 args, parms = dlg.generateParameters() 400 args, parms = dlg.generateParameters()
385 project.setData('PACKAGERSPARMS', "CXFREEZE", parms) 401 project.setData("PACKAGERSPARMS", "CXFREEZE", parms)
386 402
387 # now do the call 403 # now do the call
388 from CxFreeze.CxfreezeExecDialog import CxfreezeExecDialog 404 from CxFreeze.CxfreezeExecDialog import CxfreezeExecDialog
405
389 dia = CxfreezeExecDialog("cxfreeze") 406 dia = CxfreezeExecDialog("cxfreeze")
390 dia.show() 407 dia.show()
391 res = dia.start(args, parms, project.ppath, 408 res = dia.start(args, parms, project.ppath, project.getMainScript())
392 project.getMainScript())
393 if res: 409 if res:
394 dia.exec() 410 dia.exec()
395 411
396 412
397 def installDependencies(pipInstall): 413 def installDependencies(pipInstall):
398 """ 414 """
399 Function to install dependencies of this plug-in. 415 Function to install dependencies of this plug-in.
400 416
401 @param pipInstall function to be called with a list of package names. 417 @param pipInstall function to be called with a list of package names.
402 @type function 418 @type function
403 """ 419 """
404 try: 420 try:
405 import cx_Freeze # __IGNORE_WARNING__ 421 import cx_Freeze # __IGNORE_WARNING__
406 except ImportError: 422 except ImportError:
407 pipInstall(["cx-Freeze"]) 423 pipInstall(["cx-Freeze"])
408 424
425
409 # 426 #
410 # eflag: noqa = M801 427 # eflag: noqa = M801

eric ide

mercurial