ProjectFlask/Project.py

branch
eric7
changeset 64
0ee58185b8df
parent 61
fe1e8783a95f
child 66
0d3168d0e310
equal deleted inserted replaced
63:7c05cbc8b3e5 64:0ee58185b8df
7 Module implementing the Flask project support. 7 Module implementing the Flask project support.
8 """ 8 """
9 9
10 import os 10 import os
11 11
12 from PyQt5.QtCore import ( 12 from PyQt6.QtCore import (
13 pyqtSlot, QObject, QProcess, QProcessEnvironment, QTimer, QFileInfo 13 pyqtSlot, QObject, QProcess, QProcessEnvironment, QTimer, QFileInfo
14 ) 14 )
15 from PyQt5.QtWidgets import QMenu, QDialog 15 from PyQt6.QtWidgets import QMenu, QDialog
16 16
17 from E5Gui import E5MessageBox, E5FileDialog 17 from EricWidgets import EricMessageBox, EricFileDialog
18 from E5Gui.E5Action import E5Action 18 from EricGui.EricAction import EricAction
19 from E5Gui.E5Application import e5App 19 from EricWidgets.EricApplication import ericApp
20 20
21 from Globals import isWindowsPlatform 21 from Globals import isWindowsPlatform
22 22
23 import UI.PixmapCache 23 import UI.PixmapCache
24 import Utilities 24 import Utilities
46 46
47 self.__plugin = plugin 47 self.__plugin = plugin
48 self.__iconSuffix = iconSuffix 48 self.__iconSuffix = iconSuffix
49 self.__ui = parent 49 self.__ui = parent
50 50
51 self.__e5project = e5App().getObject("Project") 51 self.__ericProject = ericApp().getObject("Project")
52 self.__virtualEnvManager = e5App().getObject("VirtualEnvManager") 52 self.__virtualEnvManager = ericApp().getObject("VirtualEnvManager")
53 53
54 self.__menus = {} # dictionary with references to menus 54 self.__menus = {} # dictionary with references to menus
55 self.__formsBrowser = None 55 self.__formsBrowser = None
56 self.__hooksInstalled = False 56 self.__hooksInstalled = False
57 57
84 84
85 ############################## 85 ##############################
86 ## run actions below ## 86 ## run actions below ##
87 ############################## 87 ##############################
88 88
89 self.runServerAct = E5Action( 89 self.runServerAct = EricAction(
90 self.tr('Run Server'), 90 self.tr('Run Server'),
91 self.tr('Run &Server'), 91 self.tr('Run &Server'),
92 0, 0, 92 0, 0,
93 self, 'flask_run_server') 93 self, 'flask_run_server')
94 self.runServerAct.setStatusTip(self.tr( 94 self.runServerAct.setStatusTip(self.tr(
98 """<p>Starts the Flask Web server.</p>""" 98 """<p>Starts the Flask Web server.</p>"""
99 )) 99 ))
100 self.runServerAct.triggered.connect(self.__runServer) 100 self.runServerAct.triggered.connect(self.__runServer)
101 self.actions.append(self.runServerAct) 101 self.actions.append(self.runServerAct)
102 102
103 self.runDevServerAct = E5Action( 103 self.runDevServerAct = EricAction(
104 self.tr('Run Development Server'), 104 self.tr('Run Development Server'),
105 self.tr('Run &Development Server'), 105 self.tr('Run &Development Server'),
106 0, 0, 106 0, 0,
107 self, 'flask_run_dev_server') 107 self, 'flask_run_dev_server')
108 self.runDevServerAct.setStatusTip(self.tr( 108 self.runDevServerAct.setStatusTip(self.tr(
112 """<p>Starts the Flask Web server in development mode.</p>""" 112 """<p>Starts the Flask Web server in development mode.</p>"""
113 )) 113 ))
114 self.runDevServerAct.triggered.connect(self.__runDevelopmentServer) 114 self.runDevServerAct.triggered.connect(self.__runDevelopmentServer)
115 self.actions.append(self.runDevServerAct) 115 self.actions.append(self.runDevServerAct)
116 116
117 self.askForServerOptionsAct = E5Action( 117 self.askForServerOptionsAct = EricAction(
118 self.tr('Ask for Server Start Options'), 118 self.tr('Ask for Server Start Options'),
119 self.tr('Ask for Server Start Options'), 119 self.tr('Ask for Server Start Options'),
120 0, 0, 120 0, 0,
121 self, 'flask_ask_server_options') 121 self, 'flask_ask_server_options')
122 self.askForServerOptionsAct.setStatusTip(self.tr( 122 self.askForServerOptionsAct.setStatusTip(self.tr(
132 132
133 ############################### 133 ###############################
134 ## shell action below ## 134 ## shell action below ##
135 ############################### 135 ###############################
136 136
137 self.runPythonShellAct = E5Action( 137 self.runPythonShellAct = EricAction(
138 self.tr('Start Flask Python Console'), 138 self.tr('Start Flask Python Console'),
139 self.tr('Start Flask &Python Console'), 139 self.tr('Start Flask &Python Console'),
140 0, 0, 140 0, 0,
141 self, 'flask_python_console') 141 self, 'flask_python_console')
142 self.runPythonShellAct.setStatusTip(self.tr( 142 self.runPythonShellAct.setStatusTip(self.tr(
150 150
151 ################################ 151 ################################
152 ## routes action below ## 152 ## routes action below ##
153 ################################ 153 ################################
154 154
155 self.showRoutesAct = E5Action( 155 self.showRoutesAct = EricAction(
156 self.tr('Show Routes'), 156 self.tr('Show Routes'),
157 self.tr('Show &Routes'), 157 self.tr('Show &Routes'),
158 0, 0, 158 0, 0,
159 self, 'flask_show_routes') 159 self, 'flask_show_routes')
160 self.showRoutesAct.setStatusTip(self.tr( 160 self.showRoutesAct.setStatusTip(self.tr(
168 168
169 ################################## 169 ##################################
170 ## documentation action below ## 170 ## documentation action below ##
171 ################################## 171 ##################################
172 172
173 self.documentationAct = E5Action( 173 self.documentationAct = EricAction(
174 self.tr('Documentation'), 174 self.tr('Documentation'),
175 self.tr('D&ocumentation'), 175 self.tr('D&ocumentation'),
176 0, 0, 176 0, 0,
177 self, 'flask_documentation') 177 self, 'flask_documentation')
178 self.documentationAct.setStatusTip(self.tr( 178 self.documentationAct.setStatusTip(self.tr(
186 186
187 ############################## 187 ##############################
188 ## about action below ## 188 ## about action below ##
189 ############################## 189 ##############################
190 190
191 self.aboutFlaskAct = E5Action( 191 self.aboutFlaskAct = EricAction(
192 self.tr('About Flask'), 192 self.tr('About Flask'),
193 self.tr('About &Flask'), 193 self.tr('About &Flask'),
194 0, 0, 194 0, 0,
195 self, 'flask_about') 195 self, 'flask_about')
196 self.aboutFlaskAct.setStatusTip(self.tr( 196 self.aboutFlaskAct.setStatusTip(self.tr(
207 207
208 ###################################### 208 ######################################
209 ## configuration action below ## 209 ## configuration action below ##
210 ###################################### 210 ######################################
211 211
212 self.flaskConfigAct = E5Action( 212 self.flaskConfigAct = EricAction(
213 self.tr('Configure Flask for Project'), 213 self.tr('Configure Flask for Project'),
214 self.tr('Configure Flask for &Project'), 214 self.tr('Configure Flask for &Project'),
215 0, 0, 215 0, 0,
216 self, 'flask_config_for_project') 216 self, 'flask_config_for_project')
217 self.flaskConfigAct.setStatusTip(self.tr( 217 self.flaskConfigAct.setStatusTip(self.tr(
288 288
289 def projectOpenedHooks(self): 289 def projectOpenedHooks(self):
290 """ 290 """
291 Public method to add our hook methods. 291 Public method to add our hook methods.
292 """ 292 """
293 if self.__e5project.getProjectType() == "Flask": 293 if self.__ericProject.getProjectType() == "Flask":
294 self.__formsBrowser = ( 294 self.__formsBrowser = (
295 e5App().getObject("ProjectBrowser") 295 ericApp().getObject("ProjectBrowser")
296 .getProjectBrowser("forms")) 296 .getProjectBrowser("forms"))
297 self.__formsBrowser.addHookMethodAndMenuEntry( 297 self.__formsBrowser.addHookMethodAndMenuEntry(
298 "newForm", self.newForm, self.tr("New template...")) 298 "newForm", self.newForm, self.tr("New template..."))
299 299
300 self.__determineCapabilities() 300 self.__determineCapabilities()
324 @type str 324 @type str
325 """ 325 """
326 from .FormSelectionDialog import FormSelectionDialog 326 from .FormSelectionDialog import FormSelectionDialog
327 327
328 dlg = FormSelectionDialog() 328 dlg = FormSelectionDialog()
329 if dlg.exec() == QDialog.Accepted: 329 if dlg.exec() == QDialog.DialogCode.Accepted:
330 template = dlg.getTemplateText() 330 template = dlg.getTemplateText()
331 331
332 fileFilters = self.tr( 332 fileFilters = self.tr(
333 "HTML Files (*.html);;" 333 "HTML Files (*.html);;"
334 "HTML Files (*.htm);;" 334 "HTML Files (*.htm);;"
335 "All Files (*)") 335 "All Files (*)")
336 fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( 336 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
337 self.__ui, 337 self.__ui,
338 self.tr("New Form"), 338 self.tr("New Form"),
339 dirPath, 339 dirPath,
340 fileFilters, 340 fileFilters,
341 None, 341 None,
342 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) 342 EricFileDialog.Options(EricFileDialog.DontConfirmOverwrite))
343 if fname: 343 if fname:
344 ext = QFileInfo(fname).suffix() 344 ext = QFileInfo(fname).suffix()
345 if not ext: 345 if not ext:
346 ex = selectedFilter.split("(*")[1].split(")")[0] 346 ex = selectedFilter.split("(*")[1].split(")")[0]
347 if ex: 347 if ex:
348 fname += ex 348 fname += ex
349 349
350 if os.path.exists(fname): 350 if os.path.exists(fname):
351 res = E5MessageBox.yesNo( 351 res = EricMessageBox.yesNo(
352 self.__ui, 352 self.__ui,
353 self.tr("New Form"), 353 self.tr("New Form"),
354 self.tr("""The file already exists! Overwrite""" 354 self.tr("""The file already exists! Overwrite"""
355 """ it?"""), 355 """ it?"""),
356 icon=E5MessageBox.Warning) 356 icon=EricMessageBox.Warning)
357 if not res: 357 if not res:
358 # user selected to not overwrite 358 # user selected to not overwrite
359 return 359 return
360 360
361 try: 361 try:
362 with open(fname, "w", encoding="utf-8") as f: 362 with open(fname, "w", encoding="utf-8") as f:
363 f.write(template) 363 f.write(template)
364 except OSError as err: 364 except OSError as err:
365 E5MessageBox.critical( 365 EricMessageBox.critical(
366 self.__ui, 366 self.__ui,
367 self.tr("New Form"), 367 self.tr("New Form"),
368 self.tr("<p>The new form file <b>{0}</b> could" 368 self.tr("<p>The new form file <b>{0}</b> could"
369 " not be created.</p><p>Problem: {1}</p>") 369 " not be created.</p><p>Problem: {1}</p>")
370 .format(fname, str(err))) 370 .format(fname, str(err)))
371 return 371 return
372 372
373 self.__e5project.appendFile(fname) 373 self.__ericProject.appendFile(fname)
374 self.__formsBrowser.sourceFile.emit(fname) 374 self.__formsBrowser.sourceFile.emit(fname)
375 375
376 ################################################################## 376 ##################################################################
377 ## methods below implement virtual environment handling 377 ## methods below implement virtual environment handling
378 ################################################################## 378 ##################################################################
382 Public method to get the path of the virtual environment. 382 Public method to get the path of the virtual environment.
383 383
384 @return path of the virtual environment 384 @return path of the virtual environment
385 @rtype str 385 @rtype str
386 """ 386 """
387 language = self.__e5project.getProjectLanguage() 387 language = self.__ericProject.getProjectLanguage()
388 if language == "Python3": 388 if language == "Python3":
389 # get project specific virtual environment name 389 # get project specific virtual environment name
390 venvName = self.getData("flask", "virtual_environment_name") 390 venvName = self.getData("flask", "virtual_environment_name")
391 if not venvName: 391 if not venvName:
392 venvName = self.__plugin.getPreferences( 392 venvName = self.__plugin.getPreferences(
522 Private slot to show some info about Flask. 522 Private slot to show some info about Flask.
523 """ 523 """
524 versions = self.getFlaskVersionStrings() 524 versions = self.getFlaskVersionStrings()
525 url = "https://palletsprojects.com/p/flask/" 525 url = "https://palletsprojects.com/p/flask/"
526 526
527 msgBox = E5MessageBox.E5MessageBox( 527 msgBox = EricMessageBox.EricMessageBox(
528 E5MessageBox.Question, 528 EricMessageBox.Question,
529 self.tr("About Flask"), 529 self.tr("About Flask"),
530 self.tr( 530 self.tr(
531 "<p>Flask is a lightweight WSGI web application framework." 531 "<p>Flask is a lightweight WSGI web application framework."
532 " It is designed to make getting started quick and easy," 532 " It is designed to make getting started quick and easy,"
533 " with the ability to scale up to complex applications.</p>" 533 " with the ability to scale up to complex applications.</p>"
540 "</table></p>", 540 "</table></p>",
541 "Do not translate the program names." 541 "Do not translate the program names."
542 ).format(versions["flask"], versions["werkzeug"], 542 ).format(versions["flask"], versions["werkzeug"],
543 versions["python"], url), 543 versions["python"], url),
544 modal=True, 544 modal=True,
545 buttons=E5MessageBox.Ok) 545 buttons=EricMessageBox.Ok)
546 msgBox.setIconPixmap(UI.PixmapCache.getPixmap( 546 msgBox.setIconPixmap(UI.PixmapCache.getPixmap(
547 os.path.join("ProjectFlask", "icons", 547 os.path.join("ProjectFlask", "icons",
548 "flask64-{0}".format(self.__iconSuffix)))) 548 "flask64-{0}".format(self.__iconSuffix))))
549 msgBox.exec() 549 msgBox.exec()
550 550
593 working directory. 593 working directory.
594 594
595 @return tuple containing the working directory and the application name 595 @return tuple containing the working directory and the application name
596 @rtype tuple of (str, str) 596 @rtype tuple of (str, str)
597 """ 597 """
598 mainScript = self.__e5project.getMainScript(normalized=True) 598 mainScript = self.__ericProject.getMainScript(normalized=True)
599 if not mainScript: 599 if not mainScript:
600 E5MessageBox.critical( 600 EricMessageBox.critical(
601 self.__ui, 601 self.__ui,
602 self.tr("Prepare Environment"), 602 self.tr("Prepare Environment"),
603 self.tr("""The project has no configured main script""" 603 self.tr("""The project has no configured main script"""
604 """ (= Flask application). Aborting...""")) 604 """ (= Flask application). Aborting..."""))
605 return "", None 605 return "", None
624 """ 624 """
625 if category not in self.__projectData: 625 if category not in self.__projectData:
626 self.__projectData[category] = {} 626 self.__projectData[category] = {}
627 627
628 if not self.__projectData[category]: 628 if not self.__projectData[category]:
629 data = self.__e5project.getData( 629 data = self.__ericProject.getData(
630 "PROJECTTYPESPECIFICDATA", category) 630 "PROJECTTYPESPECIFICDATA", category)
631 if data is not None: 631 if data is not None:
632 self.__projectData[category] = data 632 self.__projectData[category] = data
633 633
634 data = self.__projectData[category] 634 data = self.__projectData[category]
655 """ 655 """
656 if category not in self.__projectData: 656 if category not in self.__projectData:
657 self.__projectData[category] = {} 657 self.__projectData[category] = {}
658 658
659 if not self.__projectData[category]: 659 if not self.__projectData[category]:
660 data = self.__e5project.getData( 660 data = self.__ericProject.getData(
661 "PROJECTTYPESPECIFICDATA", category) 661 "PROJECTTYPESPECIFICDATA", category)
662 if data is not None: 662 if data is not None:
663 self.__projectData[category] = data 663 self.__projectData[category] = data
664 664
665 if not key: 665 if not key:
667 self.__projectData[category] = value 667 self.__projectData[category] = value
668 else: 668 else:
669 # update individual entry 669 # update individual entry
670 self.__projectData[category][key] = value 670 self.__projectData[category][key] = value
671 671
672 self.__e5project.setData( 672 self.__ericProject.setData(
673 "PROJECTTYPESPECIFICDATA", category, self.__projectData[category]) 673 "PROJECTTYPESPECIFICDATA", category, self.__projectData[category])
674 674
675 def __determineCapabilities(self): 675 def __determineCapabilities(self):
676 """ 676 """
677 Private method to determine capabilities provided by supported 677 Private method to determine capabilities provided by supported
707 @type bool 707 @type bool
708 """ 708 """
709 self.__capabilities[key] = available 709 self.__capabilities[key] = available
710 710
711 ################################################################## 711 ##################################################################
712 ## slot below implements project specific flask configuration 712 ## slots below implements project specific flask configuration
713 ################################################################## 713 ##################################################################
714 714
715 @pyqtSlot() 715 @pyqtSlot()
716 def __configureFlaskForProject(self): 716 def __configureFlaskForProject(self):
717 """ 717 """
719 """ 719 """
720 from .FlaskConfigDialog import FlaskConfigDialog 720 from .FlaskConfigDialog import FlaskConfigDialog
721 721
722 config = self.getData("flask", "") 722 config = self.getData("flask", "")
723 dlg = FlaskConfigDialog(config, self) 723 dlg = FlaskConfigDialog(config, self)
724 if dlg.exec() == QDialog.Accepted: 724 if dlg.exec() == QDialog.DialogCode.Accepted:
725 config = dlg.getConfiguration() 725 config = dlg.getConfiguration()
726 self.setData("flask", "", config) 726 self.setData("flask", "", config)
727 self.__setIgnoreVirtualEnvironment() 727 self.__setIgnoreVirtualEnvironment()
728 self.__setDebugEnvironment() 728 self.__setDebugEnvironment()
729 729
739 to the list of ignore files/directories. 739 to the list of ignore files/directories.
740 """ 740 """
741 virtenvName = self.getData("flask", "virtual_environment_name") 741 virtenvName = self.getData("flask", "virtual_environment_name")
742 if virtenvName: 742 if virtenvName:
743 virtenvPath = self.getVirtualEnvironment() 743 virtenvPath = self.getVirtualEnvironment()
744 if self.__e5project.startswithProjectPath(virtenvPath): 744 if self.__ericProject.startswithProjectPath(virtenvPath):
745 relVirtenvPath = self.__e5project.getRelativeUniversalPath( 745 relVirtenvPath = self.__ericProject.getRelativeUniversalPath(
746 virtenvPath) 746 virtenvPath)
747 if relVirtenvPath not in self.__e5project.pdata["FILETYPES"]: 747 if relVirtenvPath not in self.__ericProject.pdata["FILETYPES"]:
748 self.__e5project.pdata["FILETYPES"][relVirtenvPath] = ( 748 self.__ericProject.pdata["FILETYPES"][relVirtenvPath] = (
749 "__IGNORE__" 749 "__IGNORE__"
750 ) 750 )
751 self.__e5project.setDirty(True) 751 self.__ericProject.setDirty(True)
752 752
753 def __setDebugEnvironment(self): 753 def __setDebugEnvironment(self):
754 """ 754 """
755 Private method to set the virtual environment as the selected debug 755 Private method to set the virtual environment as the selected debug
756 environment. 756 environment.
757 """ 757 """
758 language = self.__e5project.getProjectLanguage() 758 language = self.__ericProject.getProjectLanguage()
759 if language == "Python3": 759 if language == "Python3":
760 # get project specific virtual environment name 760 # get project specific virtual environment name
761 venvName = self.getData("flask", "virtual_environment_name") 761 venvName = self.getData("flask", "virtual_environment_name")
762 if not venvName: 762 if not venvName:
763 venvName = self.__plugin.getPreferences( 763 venvName = self.__plugin.getPreferences(
764 "VirtualEnvironmentNamePy3") 764 "VirtualEnvironmentNamePy3")
765 if venvName: 765 if venvName:
766 self.__e5project.debugProperties["VIRTUALENV"] = venvName 766 self.__ericProject.debugProperties["VIRTUALENV"] = venvName
767 767
768 ################################################################## 768 ##################################################################
769 ## slot below implements documentation function 769 ## slot below implements documentation function
770 ################################################################## 770 ##################################################################
771 771
848 """ 848 """
849 Private method to terminate the current Python console. 849 Private method to terminate the current Python console.
850 """ 850 """
851 if ( 851 if (
852 self.__shellProcess is not None and 852 self.__shellProcess is not None and
853 self.__shellProcess.state() != QProcess.NotRunning 853 self.__shellProcess.state() != QProcess.ProcessState.NotRunning
854 ): 854 ):
855 self.__shellProcess.terminate() 855 self.__shellProcess.terminate()
856 QTimer.singleShot(2000, self.__shellProcess.kill) 856 QTimer.singleShot(2000, self.__shellProcess.kill)
857 self.__shellProcess.waitForFinished(3000) 857 self.__shellProcess.waitForFinished(3000)
858 858

eric ide

mercurial