ProjectFlask/Project.py

branch
eric7
changeset 70
22e1d0f69668
parent 66
0d3168d0e310
child 72
4557829a4acf
equal deleted inserted replaced
69:c31a4f756a04 70:22e1d0f69668
8 """ 8 """
9 9
10 import os 10 import os
11 11
12 from PyQt6.QtCore import ( 12 from PyQt6.QtCore import (
13 pyqtSlot, QObject, QProcess, QProcessEnvironment, QTimer, QFileInfo 13 pyqtSlot,
14 QObject,
15 QProcess,
16 QProcessEnvironment,
17 QTimer,
18 QFileInfo,
14 ) 19 )
15 from PyQt6.QtWidgets import QMenu, QDialog 20 from PyQt6.QtWidgets import QMenu, QDialog
16 21
17 from EricWidgets import EricMessageBox, EricFileDialog 22 from EricWidgets import EricMessageBox, EricFileDialog
18 from EricGui.EricAction import EricAction 23 from EricGui.EricAction import EricAction
29 34
30 class Project(QObject): 35 class Project(QObject):
31 """ 36 """
32 Class implementing the Flask project support. 37 Class implementing the Flask project support.
33 """ 38 """
39
34 def __init__(self, plugin, iconSuffix, parent=None): 40 def __init__(self, plugin, iconSuffix, parent=None):
35 """ 41 """
36 Constructor 42 Constructor
37 43
38 @param plugin reference to the plugin object 44 @param plugin reference to the plugin object
39 @type ProjectFlaskPlugin 45 @type ProjectFlaskPlugin
40 @param iconSuffix suffix for the icons 46 @param iconSuffix suffix for the icons
41 @type str 47 @type str
42 @param parent parent 48 @param parent parent
43 @type QObject 49 @type QObject
44 """ 50 """
45 super().__init__(parent) 51 super().__init__(parent)
46 52
47 self.__plugin = plugin 53 self.__plugin = plugin
48 self.__iconSuffix = iconSuffix 54 self.__iconSuffix = iconSuffix
49 self.__ui = parent 55 self.__ui = parent
50 56
51 self.__ericProject = ericApp().getObject("Project") 57 self.__ericProject = ericApp().getObject("Project")
52 self.__virtualEnvManager = ericApp().getObject("VirtualEnvManager") 58 self.__virtualEnvManager = ericApp().getObject("VirtualEnvManager")
53 59
54 self.__menus = {} # dictionary with references to menus 60 self.__menus = {} # dictionary with references to menus
55 self.__formsBrowser = None 61 self.__formsBrowser = None
56 self.__hooksInstalled = False 62 self.__hooksInstalled = False
57 63
58 self.__serverDialog = None 64 self.__serverDialog = None
59 self.__routesDialog = None 65 self.__routesDialog = None
60 self.__shellProcess = None 66 self.__shellProcess = None
61 67
62 self.__projectData = { 68 self.__projectData = {
63 "flask": {}, 69 "flask": {},
64 "flask-babel": {}, 70 "flask-babel": {},
65 "flask-migrate": {}, 71 "flask-migrate": {},
66 } 72 }
67 73
68 self.__flaskVersions = { 74 self.__flaskVersions = {
69 "python": "", 75 "python": "",
70 "flask": "", 76 "flask": "",
71 "werkzeug": "", 77 "werkzeug": "",
72 } 78 }
73 79
74 self.__capabilities = {} 80 self.__capabilities = {}
75 81
76 self.__pybabelProject = PyBabelProject(self.__plugin, self, self) 82 self.__pybabelProject = PyBabelProject(self.__plugin, self, self)
77 self.__migrateProject = MigrateProject(self.__plugin, self, self) 83 self.__migrateProject = MigrateProject(self.__plugin, self, self)
78 84
79 def initActions(self): 85 def initActions(self):
80 """ 86 """
81 Public method to define the Flask actions. 87 Public method to define the Flask actions.
82 """ 88 """
83 self.actions = [] 89 self.actions = []
84 90
85 ############################## 91 ##############################
86 ## run actions below ## 92 ## run actions below ##
87 ############################## 93 ##############################
88 94
89 self.runServerAct = EricAction( 95 self.runServerAct = EricAction(
90 self.tr('Run Server'), 96 self.tr("Run Server"),
91 self.tr('Run &Server'), 97 self.tr("Run &Server"),
92 0, 0, 98 0,
93 self, 'flask_run_server') 99 0,
94 self.runServerAct.setStatusTip(self.tr( 100 self,
95 'Starts the Flask Web server')) 101 "flask_run_server",
96 self.runServerAct.setWhatsThis(self.tr( 102 )
97 """<b>Run Server</b>""" 103 self.runServerAct.setStatusTip(self.tr("Starts the Flask Web server"))
98 """<p>Starts the Flask Web server.</p>""" 104 self.runServerAct.setWhatsThis(
99 )) 105 self.tr("""<b>Run Server</b>""" """<p>Starts the Flask Web server.</p>""")
106 )
100 self.runServerAct.triggered.connect(self.__runServer) 107 self.runServerAct.triggered.connect(self.__runServer)
101 self.actions.append(self.runServerAct) 108 self.actions.append(self.runServerAct)
102 109
103 self.runDevServerAct = EricAction( 110 self.runDevServerAct = EricAction(
104 self.tr('Run Development Server'), 111 self.tr("Run Development Server"),
105 self.tr('Run &Development Server'), 112 self.tr("Run &Development Server"),
106 0, 0, 113 0,
107 self, 'flask_run_dev_server') 114 0,
108 self.runDevServerAct.setStatusTip(self.tr( 115 self,
109 'Starts the Flask Web server in development mode')) 116 "flask_run_dev_server",
110 self.runDevServerAct.setWhatsThis(self.tr( 117 )
111 """<b>Run Development Server</b>""" 118 self.runDevServerAct.setStatusTip(
112 """<p>Starts the Flask Web server in development mode.</p>""" 119 self.tr("Starts the Flask Web server in development mode")
113 )) 120 )
121 self.runDevServerAct.setWhatsThis(
122 self.tr(
123 """<b>Run Development Server</b>"""
124 """<p>Starts the Flask Web server in development mode.</p>"""
125 )
126 )
114 self.runDevServerAct.triggered.connect(self.__runDevelopmentServer) 127 self.runDevServerAct.triggered.connect(self.__runDevelopmentServer)
115 self.actions.append(self.runDevServerAct) 128 self.actions.append(self.runDevServerAct)
116 129
117 self.askForServerOptionsAct = EricAction( 130 self.askForServerOptionsAct = EricAction(
118 self.tr('Ask for Server Start Options'), 131 self.tr("Ask for Server Start Options"),
119 self.tr('Ask for Server Start Options'), 132 self.tr("Ask for Server Start Options"),
120 0, 0, 133 0,
121 self, 'flask_ask_server_options') 134 0,
122 self.askForServerOptionsAct.setStatusTip(self.tr( 135 self,
123 'Ask for server start options')) 136 "flask_ask_server_options",
124 self.askForServerOptionsAct.setWhatsThis(self.tr( 137 )
125 """<b>Ask for Server Start Options</b>""" 138 self.askForServerOptionsAct.setStatusTip(
126 """<p>Asks for server start options before the Flask Web server""" 139 self.tr("Ask for server start options")
127 """ is started. If this is unchecked, the server is started with""" 140 )
128 """ default parameters.</p>""" 141 self.askForServerOptionsAct.setWhatsThis(
129 )) 142 self.tr(
143 """<b>Ask for Server Start Options</b>"""
144 """<p>Asks for server start options before the Flask Web server"""
145 """ is started. If this is unchecked, the server is started with"""
146 """ default parameters.</p>"""
147 )
148 )
130 self.askForServerOptionsAct.setCheckable(True) 149 self.askForServerOptionsAct.setCheckable(True)
131 self.actions.append(self.askForServerOptionsAct) 150 self.actions.append(self.askForServerOptionsAct)
132 151
133 ############################### 152 ###############################
134 ## shell action below ## 153 ## shell action below ##
135 ############################### 154 ###############################
136 155
137 self.runPythonShellAct = EricAction( 156 self.runPythonShellAct = EricAction(
138 self.tr('Start Flask Python Console'), 157 self.tr("Start Flask Python Console"),
139 self.tr('Start Flask &Python Console'), 158 self.tr("Start Flask &Python Console"),
140 0, 0, 159 0,
141 self, 'flask_python_console') 160 0,
142 self.runPythonShellAct.setStatusTip(self.tr( 161 self,
143 'Starts an interactive Python interpreter')) 162 "flask_python_console",
144 self.runPythonShellAct.setWhatsThis(self.tr( 163 )
145 """<b>Start Flask Python Console</b>""" 164 self.runPythonShellAct.setStatusTip(
146 """<p>Starts an interactive Python interpreter.</p>""" 165 self.tr("Starts an interactive Python interpreter")
147 )) 166 )
167 self.runPythonShellAct.setWhatsThis(
168 self.tr(
169 """<b>Start Flask Python Console</b>"""
170 """<p>Starts an interactive Python interpreter.</p>"""
171 )
172 )
148 self.runPythonShellAct.triggered.connect(self.__runPythonShell) 173 self.runPythonShellAct.triggered.connect(self.__runPythonShell)
149 self.actions.append(self.runPythonShellAct) 174 self.actions.append(self.runPythonShellAct)
150 175
151 ################################ 176 ################################
152 ## routes action below ## 177 ## routes action below ##
153 ################################ 178 ################################
154 179
155 self.showRoutesAct = EricAction( 180 self.showRoutesAct = EricAction(
156 self.tr('Show Routes'), 181 self.tr("Show Routes"),
157 self.tr('Show &Routes'), 182 self.tr("Show &Routes"),
158 0, 0, 183 0,
159 self, 'flask_show_routes') 184 0,
160 self.showRoutesAct.setStatusTip(self.tr( 185 self,
161 'Shows a dialog with the routes of the flask app')) 186 "flask_show_routes",
162 self.showRoutesAct.setWhatsThis(self.tr( 187 )
163 """<b>Show Routes</b>""" 188 self.showRoutesAct.setStatusTip(
164 """<p>Shows a dialog with the routes of the flask app.</p>""" 189 self.tr("Shows a dialog with the routes of the flask app")
165 )) 190 )
191 self.showRoutesAct.setWhatsThis(
192 self.tr(
193 """<b>Show Routes</b>"""
194 """<p>Shows a dialog with the routes of the flask app.</p>"""
195 )
196 )
166 self.showRoutesAct.triggered.connect(self.__showRoutes) 197 self.showRoutesAct.triggered.connect(self.__showRoutes)
167 self.actions.append(self.showRoutesAct) 198 self.actions.append(self.showRoutesAct)
168 199
169 ################################## 200 ##################################
170 ## documentation action below ## 201 ## documentation action below ##
171 ################################## 202 ##################################
172 203
173 self.documentationAct = EricAction( 204 self.documentationAct = EricAction(
174 self.tr('Documentation'), 205 self.tr("Documentation"),
175 self.tr('D&ocumentation'), 206 self.tr("D&ocumentation"),
176 0, 0, 207 0,
177 self, 'flask_documentation') 208 0,
178 self.documentationAct.setStatusTip(self.tr( 209 self,
179 'Shows the help viewer with the Flask documentation')) 210 "flask_documentation",
180 self.documentationAct.setWhatsThis(self.tr( 211 )
181 """<b>Documentation</b>""" 212 self.documentationAct.setStatusTip(
182 """<p>Shows the help viewer with the Flask documentation.</p>""" 213 self.tr("Shows the help viewer with the Flask documentation")
183 )) 214 )
215 self.documentationAct.setWhatsThis(
216 self.tr(
217 """<b>Documentation</b>"""
218 """<p>Shows the help viewer with the Flask documentation.</p>"""
219 )
220 )
184 self.documentationAct.triggered.connect(self.__showDocumentation) 221 self.documentationAct.triggered.connect(self.__showDocumentation)
185 self.actions.append(self.documentationAct) 222 self.actions.append(self.documentationAct)
186 223
187 ############################## 224 ##############################
188 ## about action below ## 225 ## about action below ##
189 ############################## 226 ##############################
190 227
191 self.aboutFlaskAct = EricAction( 228 self.aboutFlaskAct = EricAction(
192 self.tr('About Flask'), 229 self.tr("About Flask"), self.tr("About &Flask"), 0, 0, self, "flask_about"
193 self.tr('About &Flask'), 230 )
194 0, 0, 231 self.aboutFlaskAct.setStatusTip(self.tr("Shows some information about Flask"))
195 self, 'flask_about') 232 self.aboutFlaskAct.setWhatsThis(
196 self.aboutFlaskAct.setStatusTip(self.tr( 233 self.tr(
197 'Shows some information about Flask')) 234 """<b>About Flask</b>"""
198 self.aboutFlaskAct.setWhatsThis(self.tr( 235 """<p>Shows some information about Flask.</p>"""
199 """<b>About Flask</b>""" 236 )
200 """<p>Shows some information about Flask.</p>""" 237 )
201 ))
202 self.aboutFlaskAct.triggered.connect(self.__flaskInfo) 238 self.aboutFlaskAct.triggered.connect(self.__flaskInfo)
203 self.actions.append(self.aboutFlaskAct) 239 self.actions.append(self.aboutFlaskAct)
204 240
205 self.__pybabelProject.initActions() 241 self.__pybabelProject.initActions()
206 self.__migrateProject.initActions() 242 self.__migrateProject.initActions()
207 243
208 ###################################### 244 ######################################
209 ## configuration action below ## 245 ## configuration action below ##
210 ###################################### 246 ######################################
211 247
212 self.flaskConfigAct = EricAction( 248 self.flaskConfigAct = EricAction(
213 self.tr('Configure Flask for Project'), 249 self.tr("Configure Flask for Project"),
214 self.tr('Configure Flask for &Project'), 250 self.tr("Configure Flask for &Project"),
215 0, 0, 251 0,
216 self, 'flask_config_for_project') 252 0,
217 self.flaskConfigAct.setStatusTip(self.tr( 253 self,
218 'Shows a dialog to edit the project specific flask configuration')) 254 "flask_config_for_project",
219 self.flaskConfigAct.setWhatsThis(self.tr( 255 )
220 """<b>Configure Flask for Project</b>""" 256 self.flaskConfigAct.setStatusTip(
221 """<p>Shows a dialog to edit the project specific flask""" 257 self.tr("Shows a dialog to edit the project specific flask configuration")
222 """ configuration.</p>""" 258 )
223 )) 259 self.flaskConfigAct.setWhatsThis(
224 self.flaskConfigAct.triggered.connect( 260 self.tr(
225 self.__configureFlaskForProject) 261 """<b>Configure Flask for Project</b>"""
262 """<p>Shows a dialog to edit the project specific flask"""
263 """ configuration.</p>"""
264 )
265 )
266 self.flaskConfigAct.triggered.connect(self.__configureFlaskForProject)
226 self.actions.append(self.flaskConfigAct) 267 self.actions.append(self.flaskConfigAct)
227 268
228 def initMenu(self): 269 def initMenu(self):
229 """ 270 """
230 Public method to initialize the Flask menu. 271 Public method to initialize the Flask menu.
231 272
232 @return the menu generated 273 @return the menu generated
233 @rtype QMenu 274 @rtype QMenu
234 """ 275 """
235 self.__menus = {} # clear menus references 276 self.__menus = {} # clear menus references
236 277
237 self.__menus["flask-babel"] = self.__pybabelProject.initMenu() 278 self.__menus["flask-babel"] = self.__pybabelProject.initMenu()
238 self.__menus["flask-migrate"] = self.__migrateProject.initMenu() 279 self.__menus["flask-migrate"] = self.__migrateProject.initMenu()
239 280
240 menu = QMenu(self.tr('&Flask'), self.__ui) 281 menu = QMenu(self.tr("&Flask"), self.__ui)
241 menu.setTearOffEnabled(True) 282 menu.setTearOffEnabled(True)
242 283
243 menu.addAction(self.flaskConfigAct) 284 menu.addAction(self.flaskConfigAct)
244 menu.addSeparator() 285 menu.addSeparator()
245 menu.addAction(self.runServerAct) 286 menu.addAction(self.runServerAct)
246 menu.addAction(self.runDevServerAct) 287 menu.addAction(self.runDevServerAct)
247 menu.addAction(self.askForServerOptionsAct) 288 menu.addAction(self.askForServerOptionsAct)
255 menu.addMenu(self.__menus["flask-babel"]) 296 menu.addMenu(self.__menus["flask-babel"])
256 menu.addSeparator() 297 menu.addSeparator()
257 menu.addAction(self.documentationAct) 298 menu.addAction(self.documentationAct)
258 menu.addSeparator() 299 menu.addSeparator()
259 menu.addAction(self.aboutFlaskAct) 300 menu.addAction(self.aboutFlaskAct)
260 301
261 self.__menus["main"] = menu 302 self.__menus["main"] = menu
262 303
263 return menu 304 return menu
264 305
265 def getMenu(self, name): 306 def getMenu(self, name):
266 """ 307 """
267 Public method to get a reference to the requested menu. 308 Public method to get a reference to the requested menu.
268 309
269 @param name name of the menu 310 @param name name of the menu
270 @type str 311 @type str
271 @return reference to the menu or None, if no menu with the given 312 @return reference to the menu or None, if no menu with the given
272 name exists 313 name exists
273 @rtype QMenu or None 314 @rtype QMenu or None
274 """ 315 """
275 if name in self.__menus: 316 if name in self.__menus:
276 return self.__menus[name] 317 return self.__menus[name]
277 else: 318 else:
278 return None 319 return None
279 320
280 def getMenuNames(self): 321 def getMenuNames(self):
281 """ 322 """
282 Public method to get the names of all menus. 323 Public method to get the names of all menus.
283 324
284 @return menu names 325 @return menu names
285 @rtype list of str 326 @rtype list of str
286 """ 327 """
287 return list(self.__menus.keys()) 328 return list(self.__menus.keys())
288 329
289 def projectOpenedHooks(self): 330 def projectOpenedHooks(self):
290 """ 331 """
291 Public method to add our hook methods. 332 Public method to add our hook methods.
292 """ 333 """
293 if self.__ericProject.getProjectType() == "Flask": 334 if self.__ericProject.getProjectType() == "Flask":
294 self.__formsBrowser = ( 335 self.__formsBrowser = (
295 ericApp().getObject("ProjectBrowser") 336 ericApp().getObject("ProjectBrowser").getProjectBrowser("forms")
296 .getProjectBrowser("forms")) 337 )
297 self.__formsBrowser.addHookMethodAndMenuEntry( 338 self.__formsBrowser.addHookMethodAndMenuEntry(
298 "newForm", self.newForm, self.tr("New template...")) 339 "newForm", self.newForm, self.tr("New template...")
299 340 )
341
300 self.__determineCapabilities() 342 self.__determineCapabilities()
301 self.__setDebugEnvironment() 343 self.__setDebugEnvironment()
302 344
303 self.__pybabelProject.projectOpenedHooks() 345 self.__pybabelProject.projectOpenedHooks()
304 346
305 self.__hooksInstalled = True 347 self.__hooksInstalled = True
306 348
307 def projectClosedHooks(self): 349 def projectClosedHooks(self):
308 """ 350 """
309 Public method to remove our hook methods. 351 Public method to remove our hook methods.
310 """ 352 """
311 self.__pybabelProject.projectClosedHooks() 353 self.__pybabelProject.projectClosedHooks()
312 354
313 if self.__hooksInstalled: 355 if self.__hooksInstalled:
314 self.__formsBrowser.removeHookMethod("newForm") 356 self.__formsBrowser.removeHookMethod("newForm")
315 self.__formsBrowser = None 357 self.__formsBrowser = None
316 358
317 self.__hooksInstalled = False 359 self.__hooksInstalled = False
318 360
319 def newForm(self, dirPath): 361 def newForm(self, dirPath):
320 """ 362 """
321 Public method to create a new form. 363 Public method to create a new form.
322 364
323 @param dirPath full directory path for the new form file 365 @param dirPath full directory path for the new form file
324 @type str 366 @type str
325 """ 367 """
326 from .FormSelectionDialog import FormSelectionDialog 368 from .FormSelectionDialog import FormSelectionDialog
327 369
328 dlg = FormSelectionDialog() 370 dlg = FormSelectionDialog()
329 if dlg.exec() == QDialog.DialogCode.Accepted: 371 if dlg.exec() == QDialog.DialogCode.Accepted:
330 template = dlg.getTemplateText() 372 template = dlg.getTemplateText()
331 373
332 fileFilters = self.tr( 374 fileFilters = self.tr(
333 "HTML Files (*.html);;" 375 "HTML Files (*.html);;" "HTML Files (*.htm);;" "All Files (*)"
334 "HTML Files (*.htm);;" 376 )
335 "All Files (*)")
336 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( 377 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
337 self.__ui, 378 self.__ui,
338 self.tr("New Form"), 379 self.tr("New Form"),
339 dirPath, 380 dirPath,
340 fileFilters, 381 fileFilters,
341 None, 382 None,
342 EricFileDialog.Options(EricFileDialog.DontConfirmOverwrite)) 383 EricFileDialog.Options(EricFileDialog.DontConfirmOverwrite),
384 )
343 if fname: 385 if fname:
344 ext = QFileInfo(fname).suffix() 386 ext = QFileInfo(fname).suffix()
345 if not ext: 387 if not ext:
346 ex = selectedFilter.split("(*")[1].split(")")[0] 388 ex = selectedFilter.split("(*")[1].split(")")[0]
347 if ex: 389 if ex:
348 fname += ex 390 fname += ex
349 391
350 if os.path.exists(fname): 392 if os.path.exists(fname):
351 res = EricMessageBox.yesNo( 393 res = EricMessageBox.yesNo(
352 self.__ui, 394 self.__ui,
353 self.tr("New Form"), 395 self.tr("New Form"),
354 self.tr("""The file already exists! Overwrite""" 396 self.tr("""The file already exists! Overwrite""" """ it?"""),
355 """ it?"""), 397 icon=EricMessageBox.Warning,
356 icon=EricMessageBox.Warning) 398 )
357 if not res: 399 if not res:
358 # user selected to not overwrite 400 # user selected to not overwrite
359 return 401 return
360 402
361 try: 403 try:
362 with open(fname, "w", encoding="utf-8") as f: 404 with open(fname, "w", encoding="utf-8") as f:
363 f.write(template) 405 f.write(template)
364 except OSError as err: 406 except OSError as err:
365 EricMessageBox.critical( 407 EricMessageBox.critical(
366 self.__ui, 408 self.__ui,
367 self.tr("New Form"), 409 self.tr("New Form"),
368 self.tr("<p>The new form file <b>{0}</b> could" 410 self.tr(
369 " not be created.</p><p>Problem: {1}</p>") 411 "<p>The new form file <b>{0}</b> could"
370 .format(fname, str(err))) 412 " not be created.</p><p>Problem: {1}</p>"
413 ).format(fname, str(err)),
414 )
371 return 415 return
372 416
373 self.__ericProject.appendFile(fname) 417 self.__ericProject.appendFile(fname)
374 self.__formsBrowser.sourceFile.emit(fname) 418 self.__formsBrowser.sourceFile.emit(fname)
375 419
376 ################################################################## 420 ##################################################################
377 ## methods below implement virtual environment handling 421 ## methods below implement virtual environment handling
378 ################################################################## 422 ##################################################################
379 423
380 def getVirtualEnvironment(self): 424 def getVirtualEnvironment(self):
381 """ 425 """
382 Public method to get the path of the virtual environment. 426 Public method to get the path of the virtual environment.
383 427
384 @return path of the virtual environment 428 @return path of the virtual environment
385 @rtype str 429 @rtype str
386 """ 430 """
387 language = self.__ericProject.getProjectLanguage() 431 language = self.__ericProject.getProjectLanguage()
388 if language == "Python3": 432 if language == "Python3":
389 # get project specific virtual environment name 433 # get project specific virtual environment name
390 venvName = self.getData("flask", "virtual_environment_name") 434 venvName = self.getData("flask", "virtual_environment_name")
391 if not venvName: 435 if not venvName:
392 venvName = self.__plugin.getPreferences( 436 venvName = self.__plugin.getPreferences("VirtualEnvironmentNamePy3")
393 "VirtualEnvironmentNamePy3")
394 else: 437 else:
395 venvName = "" 438 venvName = ""
396 virtEnv = ( 439 virtEnv = (
397 self.__virtualEnvManager.getVirtualenvDirectory(venvName) 440 self.__virtualEnvManager.getVirtualenvDirectory(venvName)
398 if venvName else 441 if venvName
399 "" 442 else ""
400 ) 443 )
401 444
402 if virtEnv and not os.path.exists(virtEnv): 445 if virtEnv and not os.path.exists(virtEnv):
403 virtEnv = "" 446 virtEnv = ""
404 447
405 return virtEnv # __IGNORE_WARNING_M834__ 448 return virtEnv # __IGNORE_WARNING_M834__
406 449
407 def getVirtualenvInterpreter(self): 450 def getVirtualenvInterpreter(self):
408 """ 451 """
409 Public method to get the path of the Python interpreter to be used 452 Public method to get the path of the Python interpreter to be used
410 with the current project. 453 with the current project.
411 454
412 @return path of the Python interpreter 455 @return path of the Python interpreter
413 @rtype str 456 @rtype str
414 """ 457 """
415 return self.getFullCommand("python") 458 return self.getFullCommand("python")
416 459
417 def getFullCommand(self, command, virtualEnvPath=None): 460 def getFullCommand(self, command, virtualEnvPath=None):
418 """ 461 """
419 Public method to get the full command for a given command name. 462 Public method to get the full command for a given command name.
420 463
421 @param command command name 464 @param command command name
422 @type str 465 @type str
423 @param virtualEnvPath path of the virtual environment 466 @param virtualEnvPath path of the virtual environment
424 @type str 467 @type str
425 @return full command 468 @return full command
426 @rtype str 469 @rtype str
427 """ 470 """
428 virtualEnv = virtualEnvPath or self.getVirtualEnvironment() 471 virtualEnv = virtualEnvPath or self.getVirtualEnvironment()
429 fullCmds = ( 472 fullCmds = (
430 [os.path.join(virtualEnv, "Scripts", command + '.exe'), 473 [
431 os.path.join(virtualEnv, "bin", command + '.exe'), 474 os.path.join(virtualEnv, "Scripts", command + ".exe"),
432 command] # fall back to just cmd 475 os.path.join(virtualEnv, "bin", command + ".exe"),
433 if isWindowsPlatform() else 476 command,
434 [os.path.join(virtualEnv, "bin", command), 477 ] # fall back to just cmd
435 os.path.join(virtualEnv, "local", "bin", command), 478 if isWindowsPlatform()
436 Utilities.getExecutablePath(command), 479 else [
437 command] # fall back to just cmd 480 os.path.join(virtualEnv, "bin", command),
481 os.path.join(virtualEnv, "local", "bin", command),
482 Utilities.getExecutablePath(command),
483 command,
484 ] # fall back to just cmd
438 ) 485 )
439 for command in fullCmds: 486 for command in fullCmds:
440 if os.path.exists(command): 487 if os.path.exists(command):
441 break 488 break
442 return command 489 return command
443 490
444 ################################################################## 491 ##################################################################
445 ## methods below implement general functionality 492 ## methods below implement general functionality
446 ################################################################## 493 ##################################################################
447 494
448 def projectClosed(self): 495 def projectClosed(self):
449 """ 496 """
450 Public method to handle the closing of a project. 497 Public method to handle the closing of a project.
451 """ 498 """
452 for dlg in (self.__serverDialog, self.__routesDialog): 499 for dlg in (self.__serverDialog, self.__routesDialog):
453 if dlg is not None: 500 if dlg is not None:
454 dlg.close() 501 dlg.close()
455 502
456 self.__migrateProject.projectClosed() 503 self.__migrateProject.projectClosed()
457 504
458 def supportedPythonVariants(self): 505 def supportedPythonVariants(self):
459 """ 506 """
460 Public method to get the supported Python variants. 507 Public method to get the supported Python variants.
461 508
462 @return list of supported Python variants 509 @return list of supported Python variants
463 @rtype list of str 510 @rtype list of str
464 """ 511 """
465 variants = [] 512 variants = []
466 513
467 virtEnv = self.getVirtualEnvironment() 514 virtEnv = self.getVirtualEnvironment()
468 if virtEnv: 515 if virtEnv:
469 fullCmd = self.getFlaskCommand() 516 fullCmd = self.getFlaskCommand()
470 if fullCmd: 517 if fullCmd:
471 variants.append("Python3") 518 variants.append("Python3")
476 variants.append("Python3") 523 variants.append("Python3")
477 else: 524 else:
478 fullCmds = Utilities.getExecutablePaths("flask") 525 fullCmds = Utilities.getExecutablePaths("flask")
479 for fullCmd in fullCmds: 526 for fullCmd in fullCmds:
480 try: 527 try:
481 with open(fullCmd, 'r', encoding='utf-8') as f: 528 with open(fullCmd, "r", encoding="utf-8") as f:
482 l0 = f.readline() 529 l0 = f.readline()
483 except OSError: 530 except OSError:
484 l0 = "" 531 l0 = ""
485 if self.__isSuitableForVariant("Python3", l0): 532 if self.__isSuitableForVariant("Python3", l0):
486 variants.append("Python3") 533 variants.append("Python3")
487 break 534 break
488 535
489 return variants 536 return variants
490 537
491 def __isSuitableForVariant(self, variant, line0): 538 def __isSuitableForVariant(self, variant, line0):
492 """ 539 """
493 Private method to test, if a detected command file is suitable for the 540 Private method to test, if a detected command file is suitable for the
494 given Python variant. 541 given Python variant.
495 542
496 @param variant Python variant to test for 543 @param variant Python variant to test for
497 @type str 544 @type str
498 @param line0 first line of the executable 545 @param line0 first line of the executable
499 @type str 546 @type str
500 @return flag indicating a suitable file was found 547 @return flag indicating a suitable file was found
501 @rtype bool 548 @rtype bool
502 """ 549 """
503 l0 = line0.lower() 550 l0 = line0.lower()
504 ok = (variant.lower() in l0 or 551 ok = variant.lower() in l0 or "{0}.".format(variant[-1]) in l0
505 "{0}.".format(variant[-1]) in l0)
506 ok |= "pypy3" in l0 552 ok |= "pypy3" in l0
507 553
508 return ok 554 return ok
509 555
510 def getFlaskCommand(self): 556 def getFlaskCommand(self):
511 """ 557 """
512 Public method to build the Flask command. 558 Public method to build the Flask command.
513 559
514 @return full flask command 560 @return full flask command
515 @rtype str 561 @rtype str
516 """ 562 """
517 return self.getFullCommand("flask") 563 return self.getFullCommand("flask")
518 564
519 @pyqtSlot() 565 @pyqtSlot()
520 def __flaskInfo(self): 566 def __flaskInfo(self):
521 """ 567 """
522 Private slot to show some info about Flask. 568 Private slot to show some info about Flask.
523 """ 569 """
524 versions = self.getFlaskVersionStrings() 570 versions = self.getFlaskVersionStrings()
525 url = "https://palletsprojects.com/p/flask/" 571 url = "https://palletsprojects.com/p/flask/"
526 572
527 msgBox = EricMessageBox.EricMessageBox( 573 msgBox = EricMessageBox.EricMessageBox(
528 EricMessageBox.Question, 574 EricMessageBox.Question,
529 self.tr("About Flask"), 575 self.tr("About Flask"),
530 self.tr( 576 self.tr(
531 "<p>Flask is a lightweight WSGI web application framework." 577 "<p>Flask is a lightweight WSGI web application framework."
533 " with the ability to scale up to complex applications.</p>" 579 " with the ability to scale up to complex applications.</p>"
534 "<p><table>" 580 "<p><table>"
535 "<tr><td>Flask Version:</td><td>{0}</td></tr>" 581 "<tr><td>Flask Version:</td><td>{0}</td></tr>"
536 "<tr><td>Werkzeug Version:</td><td>{1}</td></tr>" 582 "<tr><td>Werkzeug Version:</td><td>{1}</td></tr>"
537 "<tr><td>Python Version:</td><td>{2}</td></tr>" 583 "<tr><td>Python Version:</td><td>{2}</td></tr>"
538 "<tr><td>Flask URL:</td><td><a href=\"{3}\">" 584 '<tr><td>Flask URL:</td><td><a href="{3}">'
539 "The Pallets Projects - Flask</a></td></tr>" 585 "The Pallets Projects - Flask</a></td></tr>"
540 "</table></p>", 586 "</table></p>",
541 "Do not translate the program names." 587 "Do not translate the program names.",
542 ).format(versions["flask"], versions["werkzeug"], 588 ).format(versions["flask"], versions["werkzeug"], versions["python"], url),
543 versions["python"], url),
544 modal=True, 589 modal=True,
545 buttons=EricMessageBox.Ok) 590 buttons=EricMessageBox.Ok,
546 msgBox.setIconPixmap(UI.PixmapCache.getPixmap( 591 )
547 os.path.join("ProjectFlask", "icons", 592 msgBox.setIconPixmap(
548 "flask64-{0}".format(self.__iconSuffix)))) 593 UI.PixmapCache.getPixmap(
594 os.path.join(
595 "ProjectFlask", "icons", "flask64-{0}".format(self.__iconSuffix)
596 )
597 )
598 )
549 msgBox.exec() 599 msgBox.exec()
550 600
551 def getFlaskVersionStrings(self): 601 def getFlaskVersionStrings(self):
552 """ 602 """
553 Public method to get the Flask, Werkzeug and Python versions as a 603 Public method to get the Flask, Werkzeug and Python versions as a
554 string. 604 string.
555 605
556 @return dictionary containing the Flask, Werkzeug and Python versions 606 @return dictionary containing the Flask, Werkzeug and Python versions
557 @rtype dict 607 @rtype dict
558 """ 608 """
559 if not self.__flaskVersions["flask"]: 609 if not self.__flaskVersions["flask"]:
560 cmd = self.getFlaskCommand() 610 cmd = self.getFlaskCommand()
563 if proc.waitForFinished(10000): 613 if proc.waitForFinished(10000):
564 output = str(proc.readAllStandardOutput(), "utf-8") 614 output = str(proc.readAllStandardOutput(), "utf-8")
565 for line in output.lower().splitlines(): 615 for line in output.lower().splitlines():
566 key, version = line.strip().split(None, 1) 616 key, version = line.strip().split(None, 1)
567 self.__flaskVersions[key] = version 617 self.__flaskVersions[key] = version
568 618
569 return self.__flaskVersions 619 return self.__flaskVersions
570 620
571 def prepareRuntimeEnvironment(self, development=False): 621 def prepareRuntimeEnvironment(self, development=False):
572 """ 622 """
573 Public method to prepare a QProcessEnvironment object and determine 623 Public method to prepare a QProcessEnvironment object and determine
574 the appropriate working directory. 624 the appropriate working directory.
575 625
576 @param development flag indicating development mode 626 @param development flag indicating development mode
577 @type bool 627 @type bool
578 @return tuple containing the working directory and a prepared 628 @return tuple containing the working directory and a prepared
579 environment object to be used with QProcess 629 environment object to be used with QProcess
580 @rtype tuple of (str, QProcessEnvironment) 630 @rtype tuple of (str, QProcessEnvironment)
582 workdir, app = self.getApplication() 632 workdir, app = self.getApplication()
583 env = QProcessEnvironment.systemEnvironment() 633 env = QProcessEnvironment.systemEnvironment()
584 env.insert("FLASK_APP", app) 634 env.insert("FLASK_APP", app)
585 if development: 635 if development:
586 env.insert("FLASK_ENV", "development") 636 env.insert("FLASK_ENV", "development")
587 637
588 return workdir, env 638 return workdir, env
589 639
590 def getApplication(self): 640 def getApplication(self):
591 """ 641 """
592 Public method to determine the application name and the respective 642 Public method to determine the application name and the respective
593 working directory. 643 working directory.
594 644
595 @return tuple containing the working directory and the application name 645 @return tuple containing the working directory and the application name
596 @rtype tuple of (str, str) 646 @rtype tuple of (str, str)
597 """ 647 """
598 mainScript = self.__ericProject.getMainScript(normalized=True) 648 mainScript = self.__ericProject.getMainScript(normalized=True)
599 if not mainScript: 649 if not mainScript:
600 EricMessageBox.critical( 650 EricMessageBox.critical(
601 self.__ui, 651 self.__ui,
602 self.tr("Prepare Environment"), 652 self.tr("Prepare Environment"),
603 self.tr("""The project has no configured main script""" 653 self.tr(
604 """ (= Flask application). Aborting...""")) 654 """The project has no configured main script"""
655 """ (= Flask application). Aborting..."""
656 ),
657 )
605 return "", None 658 return "", None
606 659
607 scriptPath, scriptName = os.path.split(mainScript) 660 scriptPath, scriptName = os.path.split(mainScript)
608 if scriptName == "__init__.py": 661 if scriptName == "__init__.py":
609 workdir, app = os.path.split(scriptPath) 662 workdir, app = os.path.split(scriptPath)
610 else: 663 else:
611 workdir, app = scriptPath, scriptName 664 workdir, app = scriptPath, scriptName
612 return workdir, app 665 return workdir, app
613 666
614 def getData(self, category, key): 667 def getData(self, category, key):
615 """ 668 """
616 Public method to get data stored in the project store. 669 Public method to get data stored in the project store.
617 670
618 @param category data category 671 @param category data category
619 @type str 672 @type str
620 @param key data key 673 @param key data key
621 @type str 674 @type str
622 @return referenced data 675 @return referenced data
623 @rtype any 676 @rtype any
624 """ 677 """
625 if category not in self.__projectData: 678 if category not in self.__projectData:
626 self.__projectData[category] = {} 679 self.__projectData[category] = {}
627 680
628 if not self.__projectData[category]: 681 if not self.__projectData[category]:
629 data = self.__ericProject.getData( 682 data = self.__ericProject.getData("PROJECTTYPESPECIFICDATA", category)
630 "PROJECTTYPESPECIFICDATA", category)
631 if data is not None: 683 if data is not None:
632 self.__projectData[category] = data 684 self.__projectData[category] = data
633 685
634 data = self.__projectData[category] 686 data = self.__projectData[category]
635 if not key: 687 if not key:
636 # return complete category dictionary 688 # return complete category dictionary
637 return data 689 return data
638 elif key in data: 690 elif key in data:
639 # return individual entry 691 # return individual entry
640 return data[key] 692 return data[key]
641 else: 693 else:
642 # failure 694 # failure
643 return None 695 return None
644 696
645 def setData(self, category, key, value): 697 def setData(self, category, key, value):
646 """ 698 """
647 Public method to store data in the project store. 699 Public method to store data in the project store.
648 700
649 @param category data category 701 @param category data category
650 @type str 702 @type str
651 @param key data key 703 @param key data key
652 @type str 704 @type str
653 @param value data to be stored 705 @param value data to be stored
654 @type any (serializable type) 706 @type any (serializable type)
655 """ 707 """
656 if category not in self.__projectData: 708 if category not in self.__projectData:
657 self.__projectData[category] = {} 709 self.__projectData[category] = {}
658 710
659 if not self.__projectData[category]: 711 if not self.__projectData[category]:
660 data = self.__ericProject.getData( 712 data = self.__ericProject.getData("PROJECTTYPESPECIFICDATA", category)
661 "PROJECTTYPESPECIFICDATA", category)
662 if data is not None: 713 if data is not None:
663 self.__projectData[category] = data 714 self.__projectData[category] = data
664 715
665 if not key: 716 if not key:
666 # update the complete category 717 # update the complete category
667 self.__projectData[category] = value 718 self.__projectData[category] = value
668 else: 719 else:
669 # update individual entry 720 # update individual entry
670 self.__projectData[category][key] = value 721 self.__projectData[category][key] = value
671 722
672 self.__ericProject.setData( 723 self.__ericProject.setData(
673 "PROJECTTYPESPECIFICDATA", category, self.__projectData[category]) 724 "PROJECTTYPESPECIFICDATA", category, self.__projectData[category]
674 725 )
726
675 def __determineCapabilities(self): 727 def __determineCapabilities(self):
676 """ 728 """
677 Private method to determine capabilities provided by supported 729 Private method to determine capabilities provided by supported
678 extensions. 730 extensions.
679 """ 731 """
680 # 1. support for flask-babel (i.e. pybabel) 732 # 1. support for flask-babel (i.e. pybabel)
681 self.__pybabelProject.determineCapability() 733 self.__pybabelProject.determineCapability()
682 734
683 # 2. support for flask-migrate 735 # 2. support for flask-migrate
684 self.__migrateProject.determineCapability() 736 self.__migrateProject.determineCapability()
685 737
686 def hasCapability(self, key): 738 def hasCapability(self, key):
687 """ 739 """
688 Public method to check, if a capability is available. 740 Public method to check, if a capability is available.
689 741
690 @param key key of the capability to check 742 @param key key of the capability to check
691 @type str 743 @type str
692 @return flag indicating the availability of the capability 744 @return flag indicating the availability of the capability
693 @rtype bool 745 @rtype bool
694 """ 746 """
695 try: 747 try:
696 return self.__capabilities[key] 748 return self.__capabilities[key]
697 except KeyError: 749 except KeyError:
698 return False 750 return False
699 751
700 def setCapability(self, key, available): 752 def setCapability(self, key, available):
701 """ 753 """
702 Public method to set the availability status of a capability. 754 Public method to set the availability status of a capability.
703 755
704 @param key key of the capability to set 756 @param key key of the capability to set
705 @type str 757 @type str
706 @param available flag indicating the availability of the capability 758 @param available flag indicating the availability of the capability
707 @type bool 759 @type bool
708 """ 760 """
709 self.__capabilities[key] = available 761 self.__capabilities[key] = available
710 762
711 ################################################################## 763 ##################################################################
712 ## slots below implements project specific flask configuration 764 ## slots below implements project specific flask configuration
713 ################################################################## 765 ##################################################################
714 766
715 @pyqtSlot() 767 @pyqtSlot()
716 def __configureFlaskForProject(self): 768 def __configureFlaskForProject(self):
717 """ 769 """
718 Private slot to configure the project specific flask parameters. 770 Private slot to configure the project specific flask parameters.
719 """ 771 """
720 from .FlaskConfigDialog import FlaskConfigDialog 772 from .FlaskConfigDialog import FlaskConfigDialog
721 773
722 config = self.getData("flask", "") 774 config = self.getData("flask", "")
723 dlg = FlaskConfigDialog(config, self) 775 dlg = FlaskConfigDialog(config, self)
724 if dlg.exec() == QDialog.DialogCode.Accepted: 776 if dlg.exec() == QDialog.DialogCode.Accepted:
725 config = dlg.getConfiguration() 777 config = dlg.getConfiguration()
726 self.setData("flask", "", config) 778 self.setData("flask", "", config)
727 self.__setIgnoreVirtualEnvironment() 779 self.__setIgnoreVirtualEnvironment()
728 self.__setDebugEnvironment() 780 self.__setDebugEnvironment()
729 781
730 self.__migrateProject.determineCapability() 782 self.__migrateProject.determineCapability()
731 783
732 self.__pybabelProject.determineCapability() 784 self.__pybabelProject.determineCapability()
733 self.projectClosedHooks() 785 self.projectClosedHooks()
734 self.projectOpenedHooks() 786 self.projectOpenedHooks()
735 787
736 def __setIgnoreVirtualEnvironment(self): 788 def __setIgnoreVirtualEnvironment(self):
737 """ 789 """
738 Private method to add an embedded project specific virtual environment 790 Private method to add an embedded project specific virtual environment
739 to the list of ignore files/directories. 791 to the list of ignore files/directories.
740 """ 792 """
741 virtenvName = self.getData("flask", "virtual_environment_name") 793 virtenvName = self.getData("flask", "virtual_environment_name")
742 if virtenvName: 794 if virtenvName:
743 virtenvPath = self.getVirtualEnvironment() 795 virtenvPath = self.getVirtualEnvironment()
744 if self.__ericProject.startswithProjectPath(virtenvPath): 796 if self.__ericProject.startswithProjectPath(virtenvPath):
745 relVirtenvPath = self.__ericProject.getRelativeUniversalPath( 797 relVirtenvPath = self.__ericProject.getRelativeUniversalPath(
746 virtenvPath) 798 virtenvPath
799 )
747 if relVirtenvPath not in self.__ericProject.pdata["FILETYPES"]: 800 if relVirtenvPath not in self.__ericProject.pdata["FILETYPES"]:
748 self.__ericProject.pdata["FILETYPES"][relVirtenvPath] = ( 801 self.__ericProject.pdata["FILETYPES"][relVirtenvPath] = "__IGNORE__"
749 "__IGNORE__"
750 )
751 self.__ericProject.setDirty(True) 802 self.__ericProject.setDirty(True)
752 803
753 def __setDebugEnvironment(self): 804 def __setDebugEnvironment(self):
754 """ 805 """
755 Private method to set the virtual environment as the selected debug 806 Private method to set the virtual environment as the selected debug
756 environment. 807 environment.
757 """ 808 """
758 language = self.__ericProject.getProjectLanguage() 809 language = self.__ericProject.getProjectLanguage()
759 if language == "Python3": 810 if language == "Python3":
760 # get project specific virtual environment name 811 # get project specific virtual environment name
761 venvName = self.getData("flask", "virtual_environment_name") 812 venvName = self.getData("flask", "virtual_environment_name")
762 if not venvName: 813 if not venvName:
763 venvName = self.__plugin.getPreferences( 814 venvName = self.__plugin.getPreferences("VirtualEnvironmentNamePy3")
764 "VirtualEnvironmentNamePy3")
765 if venvName: 815 if venvName:
766 self.__ericProject.debugProperties["VIRTUALENV"] = venvName 816 self.__ericProject.debugProperties["VIRTUALENV"] = venvName
767 817
768 ################################################################## 818 ##################################################################
769 ## slot below implements documentation function 819 ## slot below implements documentation function
770 ################################################################## 820 ##################################################################
771 821
772 def __showDocumentation(self): 822 def __showDocumentation(self):
773 """ 823 """
774 Private slot to show the helpviewer with the Flask documentation. 824 Private slot to show the helpviewer with the Flask documentation.
775 """ 825 """
776 page = self.__plugin.getPreferences("FlaskDocUrl") 826 page = self.__plugin.getPreferences("FlaskDocUrl")
777 self.__ui.launchHelpViewer(page) 827 self.__ui.launchHelpViewer(page)
778 828
779 ################################################################## 829 ##################################################################
780 ## slots below implement run functions for the server 830 ## slots below implement run functions for the server
781 ################################################################## 831 ##################################################################
782 832
783 @pyqtSlot() 833 @pyqtSlot()
784 def __runServer(self, development=False): 834 def __runServer(self, development=False):
785 """ 835 """
786 Private slot to start the Flask Web server. 836 Private slot to start the Flask Web server.
787 837
788 @param development flag indicating development mode 838 @param development flag indicating development mode
789 @type bool 839 @type bool
790 """ 840 """
791 from .RunServerDialog import RunServerDialog 841 from .RunServerDialog import RunServerDialog
792 842
793 if self.__serverDialog is not None: 843 if self.__serverDialog is not None:
794 self.__serverDialog.close() 844 self.__serverDialog.close()
795 845
796 askForOptions = self.askForServerOptionsAct.isChecked() 846 askForOptions = self.askForServerOptionsAct.isChecked()
797 dlg = RunServerDialog(self.__plugin, self) 847 dlg = RunServerDialog(self.__plugin, self)
798 if dlg.startServer(development=development, 848 if dlg.startServer(development=development, askForOptions=askForOptions):
799 askForOptions=askForOptions):
800 dlg.show() 849 dlg.show()
801 self.__serverDialog = dlg 850 self.__serverDialog = dlg
802 851
803 @pyqtSlot() 852 @pyqtSlot()
804 def __runDevelopmentServer(self): 853 def __runDevelopmentServer(self):
805 """ 854 """
806 Private slot to start the Flask Web server in development mode. 855 Private slot to start the Flask Web server in development mode.
807 """ 856 """
808 self.__runServer(development=True) 857 self.__runServer(development=True)
809 858
810 ################################################################## 859 ##################################################################
811 ## slots below implement functions for the flask console 860 ## slots below implement functions for the flask console
812 ################################################################## 861 ##################################################################
813 862
814 @pyqtSlot() 863 @pyqtSlot()
815 def __runPythonShell(self): 864 def __runPythonShell(self):
816 """ 865 """
817 Private slot to start a Python console in the app context. 866 Private slot to start a Python console in the app context.
818 """ 867 """
819 workdir, env = self.prepareRuntimeEnvironment() 868 workdir, env = self.prepareRuntimeEnvironment()
820 if env is not None: 869 if env is not None:
821 command = self.getFlaskCommand() 870 command = self.getFlaskCommand()
822 871
823 consoleCmd = self.__plugin.getPreferences("ConsoleCommand") 872 consoleCmd = self.__plugin.getPreferences("ConsoleCommand")
824 if consoleCmd: 873 if consoleCmd:
825 self.__terminatePythonShell() 874 self.__terminatePythonShell()
826 875
827 args = Utilities.parseOptionString(consoleCmd) 876 args = Utilities.parseOptionString(consoleCmd)
828 args[0] = Utilities.getExecutablePath(args[0]) 877 args[0] = Utilities.getExecutablePath(args[0])
829 args += [command, "shell"] 878 args += [command, "shell"]
830 879
831 self.__shellProcess = QProcess() 880 self.__shellProcess = QProcess()
832 self.__shellProcess.setProcessEnvironment(env) 881 self.__shellProcess.setProcessEnvironment(env)
833 self.__shellProcess.setWorkingDirectory(workdir) 882 self.__shellProcess.setWorkingDirectory(workdir)
834 self.__shellProcess.finished.connect( 883 self.__shellProcess.finished.connect(self.__shellProcessFinished)
835 self.__shellProcessFinished) 884
836
837 self.__shellProcess.start(args[0], args[1:]) 885 self.__shellProcess.start(args[0], args[1:])
838 self.__shellProcess.waitForStarted(10000) 886 self.__shellProcess.waitForStarted(10000)
839 887
840 @pyqtSlot() 888 @pyqtSlot()
841 def __shellProcessFinished(self): 889 def __shellProcessFinished(self):
842 """ 890 """
843 Private slot connected to the finished signal. 891 Private slot connected to the finished signal.
844 """ 892 """
845 self.__shellProcess = None 893 self.__shellProcess = None
846 894
847 def __terminatePythonShell(self): 895 def __terminatePythonShell(self):
848 """ 896 """
849 Private method to terminate the current Python console. 897 Private method to terminate the current Python console.
850 """ 898 """
851 if ( 899 if (
852 self.__shellProcess is not None and 900 self.__shellProcess is not None
853 self.__shellProcess.state() != QProcess.ProcessState.NotRunning 901 and self.__shellProcess.state() != QProcess.ProcessState.NotRunning
854 ): 902 ):
855 self.__shellProcess.terminate() 903 self.__shellProcess.terminate()
856 QTimer.singleShot(2000, self.__shellProcess.kill) 904 QTimer.singleShot(2000, self.__shellProcess.kill)
857 self.__shellProcess.waitForFinished(3000) 905 self.__shellProcess.waitForFinished(3000)
858 906
859 ################################################################## 907 ##################################################################
860 ## slots below implement various debugging functions 908 ## slots below implement various debugging functions
861 ################################################################## 909 ##################################################################
862 910
863 @pyqtSlot() 911 @pyqtSlot()
864 def __showRoutes(self): 912 def __showRoutes(self):
865 """ 913 """
866 Private slot showing all URL dispatch routes. 914 Private slot showing all URL dispatch routes.
867 """ 915 """
868 from .RoutesDialog import RoutesDialog 916 from .RoutesDialog import RoutesDialog
869 917
870 if self.__routesDialog is not None: 918 if self.__routesDialog is not None:
871 self.__routesDialog.close() 919 self.__routesDialog.close()
872 920
873 dlg = RoutesDialog(self) 921 dlg = RoutesDialog(self)
874 if dlg.showRoutes(): 922 if dlg.showRoutes():
875 dlg.show() 923 dlg.show()
876 self.__routesDialog = dlg 924 self.__routesDialog = dlg

eric ide

mercurial