ProjectPyramid/Project.py

branch
eric7
changeset 148
dcbd3a96f03c
parent 147
eb28b4b6f7f5
child 150
b916658d5014
equal deleted inserted replaced
147:eb28b4b6f7f5 148:dcbd3a96f03c
5 5
6 """ 6 """
7 Module implementing the Pyramid project support. 7 Module implementing the Pyramid project support.
8 """ 8 """
9 9
10 import configparser
11 import contextlib
12 import glob
10 import os 13 import os
11 import re 14 import re
12 import configparser 15 import subprocess # secok
13 import contextlib 16 import sys
14 17
15 from PyQt6.QtCore import QObject, QFileInfo, QTimer, QUrl, QIODeviceBase 18 from PyQt6.QtCore import (
19 pyqtSlot, QObject, QFileInfo, QTimer, QUrl, QIODeviceBase
20 )
16 from PyQt6.QtGui import QDesktopServices 21 from PyQt6.QtGui import QDesktopServices
17 from PyQt6.QtWidgets import QMenu, QDialog, QInputDialog, QLineEdit 22 from PyQt6.QtWidgets import QMenu, QDialog, QInputDialog, QLineEdit
18 from PyQt6.QtCore import QProcess as QProcessPyQt 23 from PyQt6.QtCore import QProcess as QProcessPyQt
19 24
20 from EricWidgets.EricApplication import ericApp 25 from EricWidgets.EricApplication import ericApp
123 self.__menus = {} # dictionary with references to menus 128 self.__menus = {} # dictionary with references to menus
124 129
125 self.__serverProc = None 130 self.__serverProc = None
126 131
127 self.__pyramidVersion = "" 132 self.__pyramidVersion = ""
133
134 self.__migrationSummaryDialog = None
128 135
129 def initActions(self): 136 def initActions(self):
130 """ 137 """
131 Public method to define the Pyramid actions. 138 Public method to define the Pyramid actions.
132 """ 139 """
181 """<p>Starts the Pyramid Web server using""" 188 """<p>Starts the Pyramid Web server using"""
182 """ "pserve --reload development.ini".</p>""" 189 """ "pserve --reload development.ini".</p>"""
183 )) 190 ))
184 self.runServerAct.triggered.connect(self.__runServer) 191 self.runServerAct.triggered.connect(self.__runServer)
185 self.actions.append(self.runServerAct) 192 self.actions.append(self.runServerAct)
186
187 self.runLoggingServerAct = EricAction(
188 self.tr('Run Server with Logging'),
189 self.tr('Run Server with &Logging'),
190 0, 0,
191 self, 'pyramid_run_logging_server')
192 self.runLoggingServerAct.setStatusTip(self.tr(
193 'Starts the Pyramid Web server with logging'))
194 self.runLoggingServerAct.setWhatsThis(self.tr(
195 """<b>Run Server with Logging</b>"""
196 """<p>Starts the Pyramid Web server with logging using"""
197 """ "pserve --log-file=server.log --reload development.ini".</p>"""
198 ))
199 self.runLoggingServerAct.triggered.connect(self.__runLoggingServer)
200 self.actions.append(self.runLoggingServerAct)
201 193
202 self.runBrowserAct = EricAction( 194 self.runBrowserAct = EricAction(
203 self.tr('Run Web-Browser'), 195 self.tr('Run Web-Browser'),
204 self.tr('Run &Web-Browser'), 196 self.tr('Run &Web-Browser'),
205 0, 0, 197 0, 0,
226 """<b>Start Pyramid Python Console</b>""" 218 """<b>Start Pyramid Python Console</b>"""
227 """<p>Starts an interactive Python interpreter.</p>""" 219 """<p>Starts an interactive Python interpreter.</p>"""
228 )) 220 ))
229 self.runPythonShellAct.triggered.connect(self.__runPythonShell) 221 self.runPythonShellAct.triggered.connect(self.__runPythonShell)
230 self.actions.append(self.runPythonShellAct) 222 self.actions.append(self.runPythonShellAct)
231
232 ##############################
233 ## setup actions below ##
234 ##############################
235
236 self.setupDevelopAct = EricAction(
237 self.tr('Setup Development Environment'),
238 self.tr('Setup &Development Environment'),
239 0, 0,
240 self, 'pyramid_setup_development')
241 self.setupDevelopAct.setStatusTip(self.tr(
242 'Setup the Pyramid project in development mode'))
243 self.setupDevelopAct.setWhatsThis(self.tr(
244 """<b>Setup Development Environment</b>"""
245 """<p>Setup the Pyramid project in development mode using"""
246 """ "python setup.py develop".</p>"""
247 ))
248 self.setupDevelopAct.triggered.connect(self.__setupDevelop)
249 self.actions.append(self.setupDevelopAct)
250
251 ###############################
252 ## database actions below ##
253 ###############################
254
255 self.initializeDbAct = EricAction(
256 self.tr('Initialize Database'),
257 self.tr('Initialize &Database'),
258 0, 0,
259 self, 'pyramid_initialize_database')
260 self.initializeDbAct.setStatusTip(self.tr(
261 'Initializes (or re-initializes) the database of the current'
262 ' Pyramid project'))
263 self.initializeDbAct.setWhatsThis(self.tr(
264 """<b>Initialize Database</b>"""
265 """<p>Initializes (or re-initializes) the database of the"""
266 """ current Pyramid project.</p>"""
267 ))
268 self.initializeDbAct.triggered.connect(self.__initializeDatabase)
269 self.actions.append(self.initializeDbAct)
270 223
271 ############################### 224 ###############################
272 ## show actions below ## 225 ## show actions below ##
273 ############################### 226 ###############################
274 227
370 """<p>Shows some information about Pyramid.</p>""" 323 """<p>Shows some information about Pyramid.</p>"""
371 )) 324 ))
372 self.aboutPyramidAct.triggered.connect(self.__pyramidInfo) 325 self.aboutPyramidAct.triggered.connect(self.__pyramidInfo)
373 self.actions.append(self.aboutPyramidAct) 326 self.actions.append(self.aboutPyramidAct)
374 327
328 self.__initDatabaseActions()
329
375 self.__setCurrentProject(None) 330 self.__setCurrentProject(None)
331
332 def __initDatabaseActions(self):
333 """
334 Private method to initialize the database related actions.
335 """
336 self.initializeDbAct = EricAction(
337 self.tr('Initialize Database'),
338 self.tr('Initialize &Database'),
339 0, 0,
340 self, 'pyramid_initialize_database')
341 self.initializeDbAct.setStatusTip(self.tr(
342 'Initializes (or re-initializes) the database of the current'
343 ' Pyramid project'))
344 self.initializeDbAct.setWhatsThis(self.tr(
345 """<b>Initialize Database</b>"""
346 """<p>Initializes (or re-initializes) the database of the"""
347 """ current Pyramid project.</p>"""
348 ))
349 self.initializeDbAct.triggered.connect(self.__initializeDatabase)
350 self.actions.append(self.initializeDbAct)
351
352 #########################################################
353 ## action to create a new database migration
354 #########################################################
355
356 self.migrateCreateAct = EricAction(
357 self.tr('Create Migration'),
358 self.tr('&Create Migration'),
359 0, 0,
360 self, 'flask_create_migration')
361 self.migrateCreateAct.setStatusTip(self.tr(
362 'Create a new migration for the current database'))
363 self.migrateCreateAct.setWhatsThis(self.tr(
364 """<b>Create Migration</b>"""
365 """<p>Creates a new migration for the current database"""
366 """ and stores it in the configured migrations directory.</p>"""
367 ))
368 self.migrateCreateAct.triggered.connect(
369 self.__createMigration)
370 self.actions.append(self.migrateCreateAct)
371
372 #########################################################
373 ## action to up- and downgrade a databse
374 #########################################################
375
376 self.upgradeDatabaseAct = EricAction(
377 self.tr('Upgrade Database'),
378 self.tr('&Upgrade Database'),
379 0, 0,
380 self, 'flask_upgrade_database')
381 self.upgradeDatabaseAct.setStatusTip(self.tr(
382 'Upgrade the database to the current migration'))
383 self.upgradeDatabaseAct.setWhatsThis(self.tr(
384 """<b>Upgrade Database</b>"""
385 """<p>Upgrades the database to the current migration.</p>"""
386 ))
387 self.upgradeDatabaseAct.triggered.connect(
388 self.upgradeDatabase)
389 self.actions.append(self.upgradeDatabaseAct)
390
391 self.downgradeDatabaseAct = EricAction(
392 self.tr('Downgrade Database'),
393 self.tr('&Downgrade Database'),
394 0, 0,
395 self, 'flask_downgrade_database')
396 self.downgradeDatabaseAct.setStatusTip(self.tr(
397 'Downgrade the database to the previous version'))
398 self.downgradeDatabaseAct.setWhatsThis(self.tr(
399 """<b>Downgrade Database</b>"""
400 """<p>Downgrades the database to the previous version.</p>"""
401 ))
402 self.downgradeDatabaseAct.triggered.connect(
403 self.downgradeDatabase)
404 self.actions.append(self.downgradeDatabaseAct)
405
406 #########################################################
407 ## actions to show migrations history information
408 #########################################################
409
410 self.migrationSummaryAct = EricAction(
411 self.tr('Show Migrations Summary'),
412 self.tr('Show Migrations &Summary'),
413 0, 0,
414 self, 'flask_show_migrations_summary')
415 self.migrationSummaryAct.setStatusTip(self.tr(
416 'Show a summary of the created database migrations'))
417 self.migrationSummaryAct.setWhatsThis(self.tr(
418 """<b>Show Migrations Summary</b>"""
419 """<p>Shows a summary list of the created database"""
420 """ migrations.</p>"""
421 ))
422 self.migrationSummaryAct.triggered.connect(
423 self.__showMigrationsSummary)
424 self.actions.append(self.migrationSummaryAct)
425
426 self.migrationHistoryAct = EricAction(
427 self.tr('Show Migrations History'),
428 self.tr('Show Migrations &History'),
429 0, 0,
430 self, 'flask_show_migrations_history')
431 self.migrationHistoryAct.setStatusTip(self.tr(
432 'Show the full history of the created database migrations'))
433 self.migrationHistoryAct.setWhatsThis(self.tr(
434 """<b>Show Migrations History</b>"""
435 """<p>Shows the full history of the created database"""
436 """ migrations.</p>"""
437 ))
438 self.migrationHistoryAct.triggered.connect(
439 self.__showMigrationsHistory)
440 self.actions.append(self.migrationHistoryAct)
376 441
377 def initMenu(self): 442 def initMenu(self):
378 """ 443 """
379 Public slot to initialize the Pyramid menu. 444 Public slot to initialize the Pyramid menu.
380 445
381 @return the menu generated 446 @return the menu generated
382 @rtype QMenu 447 @rtype QMenu
383 """ 448 """
384 self.__menus = {} # clear menus references 449 self.__menus = {} # clear menus references
385 450
451 # Database menu
452 dbMenu = QMenu(self.tr("Database"))
453 dbMenu.setTearOffEnabled(True)
454
455 dbMenu.addAction(self.initializeDbAct)
456 dbMenu.addSeparator()
457 dbMenu.addAction(self.migrateCreateAct)
458 dbMenu.addSeparator()
459 dbMenu.addAction(self.upgradeDatabaseAct)
460 dbMenu.addAction(self.downgradeDatabaseAct)
461 dbMenu.addSeparator()
462 dbMenu.addAction(self.migrationSummaryAct)
463 dbMenu.addAction(self.migrationHistoryAct)
464
465 # main Pyramid menu
386 menu = QMenu(self.tr('P&yramid'), self.__ui) 466 menu = QMenu(self.tr('P&yramid'), self.__ui)
387 menu.setTearOffEnabled(True) 467 menu.setTearOffEnabled(True)
388 468
389 menu.addAction(self.selectProjectAct) 469 menu.addAction(self.selectProjectAct)
390 menu.addSeparator() 470 menu.addSeparator()
391 menu.addAction(self.runServerAct) 471 menu.addAction(self.runServerAct)
392 menu.addAction(self.runLoggingServerAct)
393 menu.addAction(self.runBrowserAct) 472 menu.addAction(self.runBrowserAct)
473 menu.addSeparator()
474 menu.addAction(self.runPythonShellAct)
394 menu.addSeparator() 475 menu.addSeparator()
395 menu.addAction(self.createProjectAct) 476 menu.addAction(self.createProjectAct)
396 menu.addSeparator() 477 menu.addSeparator()
397 menu.addAction(self.setupDevelopAct) 478 menu.addMenu(dbMenu)
398 menu.addSeparator()
399 menu.addAction(self.initializeDbAct)
400 menu.addSeparator() 479 menu.addSeparator()
401 menu.addAction(self.showViewsAct) 480 menu.addAction(self.showViewsAct)
402 menu.addAction(self.showRoutesAct) 481 menu.addAction(self.showRoutesAct)
403 menu.addAction(self.showTweensAct) 482 menu.addAction(self.showTweensAct)
404 menu.addSeparator()
405 menu.addAction(self.runPythonShellAct)
406 menu.addSeparator() 483 menu.addSeparator()
407 menu.addAction(self.buildDistroAct) 484 menu.addAction(self.buildDistroAct)
408 menu.addSeparator() 485 menu.addSeparator()
409 menu.addAction(self.documentationAct) 486 menu.addAction(self.documentationAct)
410 menu.addSeparator() 487 menu.addSeparator()
411 menu.addAction(self.aboutPyramidAct) 488 menu.addAction(self.aboutPyramidAct)
412 489
413 self.__menus["main"] = menu 490 self.__menus["main"] = menu
491 self.__menus["database"] = dbMenu
492
493 self.__setCurrentProject(None)
414 494
415 return menu 495 return menu
416 496
417 def getMenu(self, name): 497 def getMenu(self, name):
418 """ 498 """
579 Public method to handle the closing of a project. 659 Public method to handle the closing of a project.
580 """ 660 """
581 if self.__serverProc is not None: 661 if self.__serverProc is not None:
582 self.__serverProcFinished() 662 self.__serverProcFinished()
583 self.__setCurrentProject(None) 663 self.__setCurrentProject(None)
664
665 for dlg in (self.__migrationSummaryDialog,):
666 if dlg is not None:
667 dlg.close()
584 668
585 def __getExecutablePaths(self, file): 669 def __getExecutablePaths(self, file):
586 """ 670 """
587 Private method to build all full paths of an executable file from 671 Private method to build all full paths of an executable file from
588 the environment. 672 the environment.
624 708
625 @return list of supported Python variants 709 @return list of supported Python variants
626 @rtype list of str 710 @rtype list of str
627 """ 711 """
628 variants = [] 712 variants = []
629 # TODO: that doesn't exist anymore 713 cmd = "cookiecutter"
630 cmd = "pcreate"
631 714
632 for variant in ['Python3']: 715 for variant in ['Python3']:
633 virtEnv = self.__getVirtualEnvironment(variant) 716 virtEnv = self.__getVirtualEnvironment(variant)
634 if virtEnv: 717 if virtEnv:
635 fullCmd = self.getPyramidCommand(cmd, variant) 718 fullCmd = self.getPyramidCommand(cmd, variant)
735 return self.__virtualEnvManager.getVirtualenvDirectory( 818 return self.__virtualEnvManager.getVirtualenvDirectory(
736 venvName) 819 venvName)
737 820
738 return "" 821 return ""
739 822
740 def getPyramidCommand(self, cmd, language=""): 823 def getProjectVirtualEnvironment(self):
824 """
825 Public method to generate the path of the project virtual environment.
826
827 @return path of the Pyramid project virtual environment
828 @rtype str
829 """
830 return os.path.join(self.projectPath(), "env")
831
832 def getPyramidCommand(self, cmd, language="", virtualEnv=""):
741 """ 833 """
742 Public method to build a Pyramid command. 834 Public method to build a Pyramid command.
743 835
744 @param cmd command 836 @param cmd command
745 @type str 837 @type str
746 @param language Python variant to get the virtual environment 838 @param language Python variant to get the virtual environment
747 for (one of '' or 'Python3') 839 for (one of '' or 'Python3')
748 @type str 840 @type str
841 @param virtualEnv path of the project's Python virtual environment
842 @type str
749 @return full pyramid command 843 @return full pyramid command
750 @rtype str 844 @rtype str
751 """ 845 """
752 if not language: 846 if not language:
753 language = self.__ericProject.getProjectLanguage() 847 language = self.__ericProject.getProjectLanguage()
754 848
755 virtualEnv = self.__getVirtualEnvironment(language) 849 if not virtualEnv:
756 if isWindowsPlatform() and not virtualEnv: 850 virtualEnv = self.__getVirtualEnvironment(language)
757 virtualEnv = self.__getDebugEnvironment(language) 851 if not virtualEnv:
852 virtualEnv = self.__getDebugEnvironment(language)
758 if isWindowsPlatform(): 853 if isWindowsPlatform():
759 fullCmds = [ 854 fullCmds = [
760 os.path.join(virtualEnv, "Scripts", cmd + '.exe'), 855 os.path.join(virtualEnv, "Scripts", cmd + '.exe'),
761 os.path.join(virtualEnv, "bin", cmd + '.exe'), 856 os.path.join(virtualEnv, "bin", cmd + '.exe'),
762 cmd # fall back to just cmd 857 cmd # fall back to just cmd
774 for cmd in fullCmds: 869 for cmd in fullCmds:
775 if os.path.exists(cmd): 870 if os.path.exists(cmd):
776 break 871 break
777 return cmd 872 return cmd
778 873
874 def __assemblePyramidCommand(self, cmd, virtualEnv):
875 """
876 Private method to assemble the full pyramid command for a given virtual
877 environment.
878
879 @param cmd command
880 @type str
881 @param virtualEnv path of the project's Python virtual environment
882 @type str
883 @return assembled pyramid command
884 @rtype str
885 """
886 return (
887 os.path.join(virtualEnv, "Scripts", cmd + '.exe')
888 if isWindowsPlatform() else
889 os.path.join(virtualEnv, "bin", cmd)
890 )
891
779 def getPythonCommand(self): 892 def getPythonCommand(self):
780 """ 893 """
781 Public method to build the Python command. 894 Public method to build the Python command.
782 895
783 @return python command 896 @return python command
833 946
834 @return Pyramid version 947 @return Pyramid version
835 @rtype str 948 @rtype str
836 """ 949 """
837 if not self.__pyramidVersion: 950 if not self.__pyramidVersion:
838 # TODO: that doesn't exist anymore 951 cmd = self.getPyramidCommand(
839 cmd = self.getPyramidCommand("pcreate") 952 "pdistreport",
840 if isWindowsPlatform(): 953 virtualEnv=self.getProjectVirtualEnvironment()
841 cmd = os.path.join(os.path.dirname(cmd), "pcreate-script.py") 954 )
842 try: 955 try:
843 with open(cmd, 'r', encoding="utf-8") as f: 956 output = subprocess.check_output([cmd]) # secok
844 lines = f.read().splitlines() 957 outputLines = output.decode().splitlines()
845 for line in lines: 958 for line in outputLines:
846 if line.startswith("__requires__"): 959 if line.startswith("Pyramid version:"):
847 #- sample: __requires__ = 'pyramid==1.4' 960 self.__pyramidVersion = line.rsplit(None, 1)[1]
848 vers = line.strip().split()[-1][1:-1].split("==")[1] 961 break
849 self.__pyramidVersion = vers 962 except (OSError, subprocess.CalledProcessError):
850 except OSError:
851 self.__pyramidVersion = "" 963 self.__pyramidVersion = ""
852 964
853 return self.__pyramidVersion 965 return self.__pyramidVersion
854 966
855 def getPyramidVersion(self): 967 def getPyramidVersion(self):
911 """ 1023 """
912 Private slot to create a new Pyramid project. 1024 Private slot to create a new Pyramid project.
913 """ 1025 """
914 from .CreateParametersDialog import CreateParametersDialog 1026 from .CreateParametersDialog import CreateParametersDialog
915 1027
916 dlg = CreateParametersDialog(self) 1028 dlg = CreateParametersDialog(self.__ui)
917 if dlg.exec() == QDialog.DialogCode.Accepted: 1029 if dlg.exec() == QDialog.DialogCode.Accepted:
918 scaffold, project, overwrite, simulate = dlg.getData() 1030 template, version, overwrite, contextData = dlg.getData()
919 1031
920 # TODO: that doesn't exist anymore 1032 cmd = self.getPyramidCommand("cookiecutter")
921 cmd = self.getPyramidCommand("pcreate") 1033 args = ["--no-input"]
922 args = []
923 if overwrite: 1034 if overwrite:
924 args.append("--overwrite") 1035 args.append("--overwrite-if-exists")
925 else: 1036 if version:
926 args.append("--interactive") 1037 args += ["--checkout", version]
927 if simulate: 1038 args.append(template)
928 args.append("--simulate") 1039 for context, data in contextData.items():
929 args.append("--scaffold={0}".format(scaffold)) 1040 args.append("{0}={1}".format(context, data))
930 args.append(project)
931 dlg = PyramidDialog(self.tr("Create Pyramid Project"), 1041 dlg = PyramidDialog(self.tr("Create Pyramid Project"),
932 linewrap=False, parent=self.__ui) 1042 linewrap=False, parent=self.__ui)
933 if dlg.startProcess( 1043 if dlg.startProcess(
934 cmd, args, self.__ericProject.getProjectPath() 1044 cmd, args, self.__ericProject.getProjectPath()
935 ): 1045 ):
936 dlg.exec() 1046 dlg.exec()
937 if dlg.normalExit() and not simulate: 1047 if dlg.normalExit() and "repo_name" in contextData:
938 # search for files created by pcreate and add them to the 1048 # search for files created by cookiecutter and add them
939 # project 1049 # to the project
940 projectPath = os.path.join( 1050 projectPath = os.path.join(
941 self.__ericProject.getProjectPath(), project) 1051 self.__ericProject.getProjectPath(),
1052 contextData["repo_name"])
942 for entry in os.walk(projectPath): 1053 for entry in os.walk(projectPath):
943 for fileName in entry[2]: 1054 for fileName in entry[2]:
944 fullName = os.path.join(entry[0], fileName) 1055 fullName = os.path.join(entry[0], fileName)
945 self.__ericProject.appendFile(fullName) 1056 self.__ericProject.appendFile(fullName)
946 1057
947 # create the base directory for translations 1058 # create the base directory for translations
948 i18nPath = os.path.join( 1059 i18nPath = os.path.join(
949 projectPath, project.lower(), "i18n") 1060 projectPath, contextData["repo_name"].lower(),
1061 "i18n")
950 if not os.path.exists(i18nPath): 1062 if not os.path.exists(i18nPath):
951 os.makedirs(i18nPath) 1063 os.makedirs(i18nPath)
952 self.__ericProject.setDirty(True) 1064 self.__ericProject.setDirty(True)
953 1065
954 self.__setCurrentProject(project) 1066 combinedOutput = False
1067 argsLists = []
1068
1069 # 1. create a Python virtual environment for the project
1070 argsLists.append([sys.executable, "-m", "venv", "env"])
1071 # 2. upgrade packaging tools
1072 python = self.__assemblePyramidCommand(
1073 "python", os.path.join(projectPath, "env"))
1074 argsLists.append([python, "-m", "pip", "install",
1075 "--upgrade", "pip", "setuptools"])
1076 # 3. install project in editable mode with testing
1077 argsLists.append([python, "-m", "pip", "install", "-e",
1078 ".[testing]"])
1079
1080 if (
1081 "backend" in contextData and
1082 contextData["backend"] == "sqlalchemy"
1083 ):
1084 # only SQLAlchemy needs initialization of alembic
1085 combinedOutput = True
1086
1087 # 4. initialize database
1088 alembic = self.__assemblePyramidCommand(
1089 "alembic", os.path.join(projectPath, "env"))
1090 argsLists.append([alembic, "-c", "development.ini",
1091 "revision", "--autogenerate",
1092 "--message", "initialized database"])
1093 # 5. upgrade database to initial version
1094 argsLists.append([alembic, "-c", "development.ini",
1095 "upgrade", "head"])
1096
1097 dlg = PyramidDialog(
1098 self.tr("Initializing Pyramid Project"),
1099 linewrap=False, combinedOutput=combinedOutput,
1100 parent=self.__ui)
1101 if dlg.startBatchProcesses(argsLists,
1102 workingDir=projectPath):
1103 dlg.exec()
1104
1105 self.__setCurrentProject(contextData["repo_name"])
1106
1107 if (
1108 "backend" in contextData and
1109 contextData["backend"] == "sqlalchemy"
1110 ):
1111 # add the alembic files created above to the project
1112 migrationsPath = self.migrationsPath()
1113 for entry in os.walk(migrationsPath):
1114 for fileName in entry[2]:
1115 fullName = os.path.join(entry[0], fileName)
1116 self.__ericProject.appendFile(fullName)
955 1117
956 ################################################################## 1118 ##################################################################
957 ## methods below implement site related functions 1119 ## methods below implement site related functions
958 ################################################################## 1120 ##################################################################
959 1121
971 if ( 1133 if (
972 entry[0] not in "._" and 1134 entry[0] not in "._" and
973 os.path.isdir(os.path.join(ppath, entry)) 1135 os.path.isdir(os.path.join(ppath, entry))
974 ): 1136 ):
975 projects.append(entry) 1137 projects.append(entry)
976 return projects 1138 return sorted(projects)
977 1139
978 def __selectProject(self): 1140 def __selectProject(self):
979 """ 1141 """
980 Private method to select a Pyramid project to work with. 1142 Private method to select a Pyramid project to work with.
981 """ 1143 """
1000 cur, False) 1162 cur, False)
1001 if not ok: 1163 if not ok:
1002 projects = None 1164 projects = None
1003 self.__setCurrentProject(project) 1165 self.__setCurrentProject(project)
1004 1166
1005 def __projectPath(self): 1167 def projectPath(self):
1006 """ 1168 """
1007 Private method to calculate the full path of the Pyramid project. 1169 Public method to calculate the full path of the Pyramid project.
1008 1170
1009 @return path of the project 1171 @return path of the project
1010 @rtype str 1172 @rtype str
1011 @exception PyramidNoProjectSelectedException raised, if no project is 1173 @exception PyramidNoProjectSelectedException raised, if no project is
1012 selected 1174 selected
1043 if self.__currentProject is None: 1205 if self.__currentProject is None:
1044 self.__ericProject.setTranslationPattern("") 1206 self.__ericProject.setTranslationPattern("")
1045 else: 1207 else:
1046 lowerProject = self.__project().lower() 1208 lowerProject = self.__project().lower()
1047 config = configparser.ConfigParser() 1209 config = configparser.ConfigParser()
1048 config.read(os.path.join(self.__projectPath(), "setup.cfg")) 1210 config.read(os.path.join(self.projectPath(), "setup.cfg"))
1049 try: 1211 try:
1050 outputDir = config.get("init_catalog", "output_dir") 1212 outputDir = config.get("init_catalog", "output_dir")
1051 except (configparser.NoOptionError, configparser.NoSectionError): 1213 except (configparser.NoOptionError, configparser.NoSectionError):
1052 outputDir = '{0}/locale'.format(lowerProject) 1214 outputDir = '{0}/locale'.format(lowerProject)
1053 try: 1215 try:
1059 "LC_MESSAGES", "{0}.po".format(domain)) 1221 "LC_MESSAGES", "{0}.po".format(domain))
1060 ) 1222 )
1061 1223
1062 if self.__currentProject is None: 1224 if self.__currentProject is None:
1063 self.initializeDbAct.setEnabled(False) 1225 self.initializeDbAct.setEnabled(False)
1226 with contextlib.suppress(KeyError):
1227 self.__menus["database"].setEnabled(False)
1064 else: 1228 else:
1065 initCmd = self.__getInitDbCommand() 1229 initCmd = self.__getInitDbCommand()
1066 self.initializeDbAct.setEnabled(os.path.exists(initCmd)) 1230 self.initializeDbAct.setEnabled(os.path.exists(initCmd))
1231
1232 alembicDir = os.path.join(
1233 self.projectPath(), self.__currentProject,
1234 "alembic", "versions")
1235 self.__menus["database"].setEnabled(os.path.exists(alembicDir))
1067 1236
1068 def __project(self): 1237 def __project(self):
1069 """ 1238 """
1070 Private method to get the name of the current Pyramid project. 1239 Private method to get the name of the current Pyramid project.
1071 1240
1084 1253
1085 ################################################################## 1254 ##################################################################
1086 ## slots below implement run functions 1255 ## slots below implement run functions
1087 ################################################################## 1256 ##################################################################
1088 1257
1089 def __runServer(self, logging=False): 1258 def __runServer(self):
1090 """ 1259 """
1091 Private slot to start the Pyramid Web server. 1260 Private slot to start the Pyramid Web server.
1092
1093 @param logging flag indicating to enable logging
1094 @type bool
1095 """ 1261 """
1096 consoleCmd = self.isSpawningConsole( 1262 consoleCmd = self.isSpawningConsole(
1097 self.__plugin.getPreferences("ConsoleCommand"))[1] 1263 self.__plugin.getPreferences("ConsoleCommand"))[1]
1098 if consoleCmd: 1264 if consoleCmd:
1099 try: 1265 try:
1100 projectPath = self.__projectPath() 1266 projectPath = self.projectPath()
1101 except PyramidNoProjectSelectedException: 1267 except PyramidNoProjectSelectedException:
1102 EricMessageBox.warning( 1268 EricMessageBox.warning(
1103 self.__ui, 1269 self.__ui,
1104 self.tr('Run Server'), 1270 self.tr('Run Server'),
1105 self.tr('No current Pyramid project selected or no' 1271 self.tr('No current Pyramid project selected or no'
1106 ' Pyramid project created yet. Aborting...')) 1272 ' Pyramid project created yet. Aborting...'))
1107 return 1273 return
1108 1274
1109 args = Utilities.parseOptionString(consoleCmd) 1275 args = Utilities.parseOptionString(consoleCmd)
1110 args[0] = Utilities.getExecutablePath(args[0]) 1276 args[0] = Utilities.getExecutablePath(args[0])
1111 args.append(self.getPyramidCommand("pserve")) 1277 args.append(self.getPyramidCommand(
1112 if logging: 1278 "pserve",
1113 args.append("--log-file=server.log") 1279 virtualEnv=self.getProjectVirtualEnvironment()
1280 ))
1114 args.append("--reload") 1281 args.append("--reload")
1115 args.append(os.path.join(projectPath, "development.ini")) 1282 args.append(os.path.join(projectPath, "development.ini"))
1116 1283
1117 if isWindowsPlatform(): 1284 if isWindowsPlatform():
1118 serverProcStarted, pid = QProcess.startDetached( 1285 serverProcStarted, pid = QProcess.startDetached(
1130 EricMessageBox.critical( 1297 EricMessageBox.critical(
1131 self.__ui, 1298 self.__ui,
1132 self.tr('Process Generation Error'), 1299 self.tr('Process Generation Error'),
1133 self.tr('The Pyramid server could not be started.')) 1300 self.tr('The Pyramid server could not be started.'))
1134 1301
1135 def __runLoggingServer(self):
1136 """
1137 Private slot to start the Pyramid Web server with logging.
1138 """
1139 self.__runServer(True)
1140
1141 def __serverProcFinished(self): 1302 def __serverProcFinished(self):
1142 """ 1303 """
1143 Private slot connected to the finished signal. 1304 Private slot connected to the finished signal.
1144 """ 1305 """
1145 if ( 1306 if (
1154 def __runBrowser(self): 1315 def __runBrowser(self):
1155 """ 1316 """
1156 Private slot to start the default web browser with the server URL. 1317 Private slot to start the default web browser with the server URL.
1157 """ 1318 """
1158 try: 1319 try:
1159 projectPath = self.__projectPath() 1320 projectPath = self.projectPath()
1160 except PyramidNoProjectSelectedException: 1321 except PyramidNoProjectSelectedException:
1161 EricMessageBox.warning( 1322 EricMessageBox.warning(
1162 self.__ui, 1323 self.__ui,
1163 self.tr('Run Web-Browser'), 1324 self.tr('Run Web-Browser'),
1164 self.tr('No current Pyramid project selected or no Pyramid' 1325 self.tr('No current Pyramid project selected or no Pyramid'
1166 return 1327 return
1167 1328
1168 config = configparser.ConfigParser() 1329 config = configparser.ConfigParser()
1169 config.read(os.path.join(projectPath, "development.ini")) 1330 config.read(os.path.join(projectPath, "development.ini"))
1170 try: 1331 try:
1171 port = config.get("server:main", "port") 1332 listen = config.get("server:main", "listen")
1172 except (configparser.NoOptionError, configparser.NoSectionError): 1333 except (configparser.NoOptionError, configparser.NoSectionError):
1173 port = "8080" 1334 listen = "localhost:6543"
1174 url = "http://localhost:{0}".format(port) 1335 url = "http://{0}".format(listen)
1175 if self.__plugin.getPreferences("UseExternalBrowser"): 1336 if self.__plugin.getPreferences("UseExternalBrowser"):
1176 res = QDesktopServices.openUrl(QUrl(url)) 1337 res = QDesktopServices.openUrl(QUrl(url))
1177 if not res: 1338 if not res:
1178 EricMessageBox.critical( 1339 EricMessageBox.critical(
1179 self.__ui, 1340 self.__ui,
1189 """ 1350 """
1190 consoleCmd = self.isSpawningConsole( 1351 consoleCmd = self.isSpawningConsole(
1191 self.__plugin.getPreferences("ConsoleCommand"))[1] 1352 self.__plugin.getPreferences("ConsoleCommand"))[1]
1192 if consoleCmd: 1353 if consoleCmd:
1193 try: 1354 try:
1194 projectPath = self.__projectPath() 1355 projectPath = self.projectPath()
1195 except PyramidNoProjectSelectedException: 1356 except PyramidNoProjectSelectedException:
1196 EricMessageBox.warning( 1357 EricMessageBox.warning(
1197 self.__ui, 1358 self.__ui,
1198 self.tr('Start Pyramid Python Console'), 1359 self.tr('Start Pyramid Python Console'),
1199 self.tr('No current Pyramid project selected or no' 1360 self.tr('No current Pyramid project selected or no'
1200 ' Pyramid project created yet. Aborting...')) 1361 ' Pyramid project created yet. Aborting...'))
1201 return 1362 return
1202 1363
1203 args = Utilities.parseOptionString(consoleCmd) 1364 args = Utilities.parseOptionString(consoleCmd)
1204 args[0] = Utilities.getExecutablePath(args[0]) 1365 args[0] = Utilities.getExecutablePath(args[0])
1205 args.append(self.getPyramidCommand("pshell")) 1366 args.append(self.getPyramidCommand(
1367 "pshell",
1368 virtualEnv=self.getProjectVirtualEnvironment()
1369 ))
1206 consoleType = self.__plugin.getPreferences("Python3ConsoleType") 1370 consoleType = self.__plugin.getPreferences("Python3ConsoleType")
1207 args.append("--python-shell={0}".format(consoleType)) 1371 args.append("--python-shell={0}".format(consoleType))
1208 args.append(os.path.join(projectPath, "development.ini")) 1372 args.append(os.path.join(projectPath, "development.ini"))
1209 1373
1210 self.__adjustWorkingDirectory(args, projectPath) 1374 self.__adjustWorkingDirectory(args, projectPath)
1216 self.tr('Process Generation Error'), 1380 self.tr('Process Generation Error'),
1217 self.tr('The Pyramid Shell process could not be' 1381 self.tr('The Pyramid Shell process could not be'
1218 ' started.')) 1382 ' started.'))
1219 1383
1220 ################################################################## 1384 ##################################################################
1221 ## slots below implement setup functions 1385 ## slots below implement distribution functions
1222 ################################################################## 1386 ##################################################################
1223 1387
1224 def __setupDevelop(self): 1388 def __buildDistribution(self):
1225 """ 1389 """
1226 Private slot to set up the development environment for the current 1390 Private slot to build a distribution file for the current Pyramid
1227 project. 1391 project.
1228 """ 1392 """
1229 title = self.tr("Setup Development Environment") 1393 title = self.tr("Build Distribution File")
1230 try: 1394 try:
1231 wd = self.__projectPath() 1395 projectPath = self.projectPath()
1232 except PyramidNoProjectSelectedException: 1396 except PyramidNoProjectSelectedException:
1233 EricMessageBox.warning( 1397 EricMessageBox.warning(
1234 self.__ui, 1398 self.__ui,
1235 title, 1399 title,
1236 self.tr('No current Pyramid project selected or no Pyramid' 1400 self.tr('No current Pyramid project selected or no Pyramid'
1237 ' project created yet. Aborting...')) 1401 ' project created yet. Aborting...'))
1238 return 1402 return
1239 1403
1240 cmd = self.getPythonCommand()
1241 args = []
1242 args.append("setup.py")
1243 args.append("develop")
1244
1245 dia = PyramidDialog(
1246 title,
1247 msgSuccess=self.tr("Pyramid development environment setup"
1248 " successfully."))
1249 res = dia.startProcess(cmd, args, wd)
1250 if res:
1251 dia.exec()
1252 initCmd = self.__getInitDbCommand()
1253 self.initializeDbAct.setEnabled(os.path.exists(initCmd))
1254
1255 ##################################################################
1256 ## slots below implement distribution functions
1257 ##################################################################
1258
1259 def __buildDistribution(self):
1260 """
1261 Private slot to build a distribution file for the current Pyramid
1262 project.
1263 """
1264 title = self.tr("Build Distribution File")
1265 try:
1266 projectPath = self.__projectPath()
1267 except PyramidNoProjectSelectedException:
1268 EricMessageBox.warning(
1269 self.__ui,
1270 title,
1271 self.tr('No current Pyramid project selected or no Pyramid'
1272 ' project created yet. Aborting...'))
1273 return
1274
1275 from .DistributionTypeSelectionDialog import ( 1404 from .DistributionTypeSelectionDialog import (
1276 DistributionTypeSelectionDialog 1405 DistributionTypeSelectionDialog
1277 ) 1406 )
1278 1407
1279 dlg = DistributionTypeSelectionDialog(self, projectPath, self.__ui) 1408 dlg = DistributionTypeSelectionDialog(self, projectPath, self.__ui)
1280 if dlg.exec() == QDialog.DialogCode.Accepted: 1409 if dlg.exec() == QDialog.DialogCode.Accepted:
1281 formats = dlg.getFormats() 1410 formats = dlg.getFormats()
1282 cmd = self.getPythonCommand() 1411 cmd = self.getPyramidCommand(
1412 "python",
1413 virtualEnv=self.getProjectVirtualEnvironment()
1414 )
1283 args = [] 1415 args = []
1284 args.append("setup.py") 1416 args.append("setup.py")
1285 args.append("sdist") 1417 args.append("sdist")
1286 if formats: 1418 if formats:
1287 args.append("--formats={0}".format(','.join(formats))) 1419 args.append("--formats={0}".format(','.join(formats)))
1293 res = dia.startProcess(cmd, args, projectPath) 1425 res = dia.startProcess(cmd, args, projectPath)
1294 if res: 1426 if res:
1295 dia.exec() 1427 dia.exec()
1296 1428
1297 ################################################################## 1429 ##################################################################
1298 ## slots below implement database functions
1299 ##################################################################
1300
1301 def __getInitDbCommand(self):
1302 """
1303 Private method to create the path to the initialization script.
1304
1305 @return path to the initialization script
1306 @rtype str
1307 """
1308 try:
1309 cmd = "initialize_{0}_db".format(self.__project())
1310 return self.getPyramidCommand(cmd)
1311 except PyramidNoProjectSelectedException:
1312 EricMessageBox.warning(
1313 self.__ui,
1314 self.tr("Initialize Database"),
1315 self.tr('No current Pyramid project selected or no Pyramid'
1316 ' project created yet. Aborting...'))
1317 return ""
1318
1319 def __initializeDatabase(self):
1320 """
1321 Private slot to initialize the database of the Pyramid project.
1322 """
1323 title = self.tr("Initialize Database")
1324 try:
1325 projectPath = self.__projectPath()
1326 except PyramidNoProjectSelectedException:
1327 EricMessageBox.warning(
1328 self.__ui,
1329 title,
1330 self.tr('No current Pyramid project selected or no Pyramid'
1331 ' project created yet. Aborting...'))
1332 return
1333
1334 cmd = self.__getInitDbCommand()
1335 args = []
1336 args.append("development.ini")
1337
1338 dia = PyramidDialog(
1339 title,
1340 msgSuccess=self.tr("Database initialized successfully."))
1341 res = dia.startProcess(cmd, args, projectPath)
1342 if res:
1343 dia.exec()
1344
1345 ##################################################################
1346 ## slots below implement various debugging functions 1430 ## slots below implement various debugging functions
1347 ################################################################## 1431 ##################################################################
1348 1432
1349 def __showMatchingViews(self): 1433 def __showMatchingViews(self):
1350 """ 1434 """
1351 Private slot showing all views that would match a given URL. 1435 Private slot showing all views that would match a given URL.
1352 """ 1436 """
1353 title = self.tr("Show Matching Views") 1437 title = self.tr("Show Matching Views")
1354 try: 1438 try:
1355 projectPath = self.__projectPath() 1439 projectPath = self.projectPath()
1356 except PyramidNoProjectSelectedException: 1440 except PyramidNoProjectSelectedException:
1357 EricMessageBox.warning( 1441 EricMessageBox.warning(
1358 self.__ui, 1442 self.__ui,
1359 title, 1443 title,
1360 self.tr('No current Pyramid project selected or no Pyramid' 1444 self.tr('No current Pyramid project selected or no Pyramid'
1368 QLineEdit.EchoMode.Normal, 1452 QLineEdit.EchoMode.Normal,
1369 "/") 1453 "/")
1370 if not ok or url == "": 1454 if not ok or url == "":
1371 return 1455 return
1372 1456
1373 cmd = self.getPyramidCommand("pviews") 1457 cmd = self.getPyramidCommand(
1458 "pviews",
1459 virtualEnv=self.getProjectVirtualEnvironment()
1460 )
1374 args = [] 1461 args = []
1375 args.append("development.ini") 1462 args.append("development.ini")
1376 args.append(url) 1463 args.append(url)
1377 1464
1378 dia = PyramidDialog(title, fixed=True, linewrap=False) 1465 dia = PyramidDialog(title, fixed=True, linewrap=False)
1384 """ 1471 """
1385 Private slot showing all URL dispatch routes. 1472 Private slot showing all URL dispatch routes.
1386 """ 1473 """
1387 title = self.tr("Show Routes") 1474 title = self.tr("Show Routes")
1388 try: 1475 try:
1389 projectPath = self.__projectPath() 1476 projectPath = self.projectPath()
1390 except PyramidNoProjectSelectedException: 1477 except PyramidNoProjectSelectedException:
1391 EricMessageBox.warning( 1478 EricMessageBox.warning(
1392 self.__ui, 1479 self.__ui,
1393 title, 1480 title,
1394 self.tr('No current Pyramid project selected or no Pyramid' 1481 self.tr('No current Pyramid project selected or no Pyramid'
1406 """ 1493 """
1407 Private slot showing all implicit and explicit tween objects. 1494 Private slot showing all implicit and explicit tween objects.
1408 """ 1495 """
1409 title = self.tr("Show Tween Objects") 1496 title = self.tr("Show Tween Objects")
1410 try: 1497 try:
1411 projectPath = self.__projectPath() 1498 projectPath = self.projectPath()
1412 except PyramidNoProjectSelectedException: 1499 except PyramidNoProjectSelectedException:
1413 EricMessageBox.warning( 1500 EricMessageBox.warning(
1414 self.__ui, 1501 self.__ui,
1415 title, 1502 title,
1416 self.tr('No current Pyramid project selected or no Pyramid' 1503 self.tr('No current Pyramid project selected or no Pyramid'
1417 ' project created yet. Aborting...')) 1504 ' project created yet. Aborting...'))
1418 return 1505 return
1419 1506
1420 cmd = self.getPyramidCommand("ptweens") 1507 cmd = self.getPyramidCommand(
1508 "ptweens",
1509 virtualEnv=self.getProjectVirtualEnvironment()
1510 )
1421 args = [] 1511 args = []
1422 args.append("development.ini") 1512 args.append("development.ini")
1423 1513
1424 dia = PyramidDialog(title, fixed=True, linewrap=False) 1514 dia = PyramidDialog(title, fixed=True, linewrap=False)
1425 res = dia.startProcess(cmd, args, projectPath) 1515 res = dia.startProcess(cmd, args, projectPath)
1503 """ 1593 """
1504 Public method to extract the messages catalog template file. 1594 Public method to extract the messages catalog template file.
1505 """ 1595 """
1506 title = self.tr("Extract messages") 1596 title = self.tr("Extract messages")
1507 try: 1597 try:
1508 projectPath = self.__projectPath() 1598 projectPath = self.projectPath()
1509 except PyramidNoProjectSelectedException: 1599 except PyramidNoProjectSelectedException:
1510 EricMessageBox.warning( 1600 EricMessageBox.warning(
1511 self.__ui, 1601 self.__ui,
1512 title, 1602 title,
1513 self.tr('No current Pyramid project selected or no Pyramid' 1603 self.tr('No current Pyramid project selected or no Pyramid'
1557 @type str 1647 @type str
1558 """ 1648 """
1559 title = self.tr( 1649 title = self.tr(
1560 "Initializing message catalog for '{0}'").format(code) 1650 "Initializing message catalog for '{0}'").format(code)
1561 try: 1651 try:
1562 projectPath = self.__projectPath() 1652 projectPath = self.projectPath()
1563 except PyramidNoProjectSelectedException: 1653 except PyramidNoProjectSelectedException:
1564 EricMessageBox.warning( 1654 EricMessageBox.warning(
1565 self.__ui, 1655 self.__ui,
1566 title, 1656 title,
1567 self.tr('No current Pyramid project selected or no Pyramid' 1657 self.tr('No current Pyramid project selected or no Pyramid'
1594 @param filenames list of filenames (not used) 1684 @param filenames list of filenames (not used)
1595 @type list of str 1685 @type list of str
1596 """ 1686 """
1597 title = self.tr("Compiling message catalogs") 1687 title = self.tr("Compiling message catalogs")
1598 try: 1688 try:
1599 projectPath = self.__projectPath() 1689 projectPath = self.projectPath()
1600 except PyramidNoProjectSelectedException: 1690 except PyramidNoProjectSelectedException:
1601 EricMessageBox.warning( 1691 EricMessageBox.warning(
1602 self.__ui, 1692 self.__ui,
1603 title, 1693 title,
1604 self.tr('No current Pyramid project selected or no Pyramid' 1694 self.tr('No current Pyramid project selected or no Pyramid'
1631 @param filenames list of file names 1721 @param filenames list of file names
1632 @type list of str 1722 @type list of str
1633 """ 1723 """
1634 title = self.tr("Compiling message catalogs") 1724 title = self.tr("Compiling message catalogs")
1635 try: 1725 try:
1636 projectPath = self.__projectPath() 1726 projectPath = self.projectPath()
1637 except PyramidNoProjectSelectedException: 1727 except PyramidNoProjectSelectedException:
1638 EricMessageBox.warning( 1728 EricMessageBox.warning(
1639 self.__ui, 1729 self.__ui,
1640 title, 1730 title,
1641 self.tr('No current Pyramid project selected or no Pyramid' 1731 self.tr('No current Pyramid project selected or no Pyramid'
1684 @param filenames list of filenames (not used) 1774 @param filenames list of filenames (not used)
1685 @type list of str 1775 @type list of str
1686 """ 1776 """
1687 title = self.tr("Updating message catalogs") 1777 title = self.tr("Updating message catalogs")
1688 try: 1778 try:
1689 projectPath = self.__projectPath() 1779 projectPath = self.projectPath()
1690 except PyramidNoProjectSelectedException: 1780 except PyramidNoProjectSelectedException:
1691 EricMessageBox.warning( 1781 EricMessageBox.warning(
1692 self.__ui, 1782 self.__ui,
1693 title, 1783 title,
1694 self.tr('No current Pyramid project selected or no Pyramid' 1784 self.tr('No current Pyramid project selected or no Pyramid'
1714 @param filenames list of filenames 1804 @param filenames list of filenames
1715 @type list of str 1805 @type list of str
1716 """ 1806 """
1717 title = self.tr("Updating message catalogs") 1807 title = self.tr("Updating message catalogs")
1718 try: 1808 try:
1719 projectPath = self.__projectPath() 1809 projectPath = self.projectPath()
1720 except PyramidNoProjectSelectedException: 1810 except PyramidNoProjectSelectedException:
1721 EricMessageBox.warning( 1811 EricMessageBox.warning(
1722 self.__ui, 1812 self.__ui,
1723 title, 1813 title,
1724 self.tr('No current Pyramid project selected or no Pyramid' 1814 self.tr('No current Pyramid project selected or no Pyramid'
1761 @type str 1851 @type str
1762 """ 1852 """
1763 editor = self.__plugin.getPreferences("TranslationsEditor") 1853 editor = self.__plugin.getPreferences("TranslationsEditor")
1764 if poFile.endswith(".po") and editor: 1854 if poFile.endswith(".po") and editor:
1765 try: 1855 try:
1766 wd = self.__projectPath() 1856 wd = self.projectPath()
1767 except PyramidNoProjectSelectedException: 1857 except PyramidNoProjectSelectedException:
1768 wd = "" 1858 wd = ""
1769 started, pid = QProcess.startDetached(editor, [poFile], wd) 1859 started, pid = QProcess.startDetached(editor, [poFile], wd)
1770 if not started: 1860 if not started:
1771 EricMessageBox.critical( 1861 EricMessageBox.critical(
1772 None, 1862 None,
1773 self.tr('Process Generation Error'), 1863 self.tr('Process Generation Error'),
1774 self.tr('The translations editor process ({0}) could' 1864 self.tr('The translations editor process ({0}) could'
1775 ' not be started.').format( 1865 ' not be started.').format(
1776 os.path.basename(editor))) 1866 os.path.basename(editor)))
1867
1868 #######################################################################
1869 ## database related methods and slots below
1870 #######################################################################
1871
1872 def getAlembicCommand(self):
1873 """
1874 Public method to get the path to the alembic executable of the current
1875 Pyramid project.
1876
1877 @return path to the alembic executable
1878 @rtype str
1879 """
1880 return self.getPyramidCommand(
1881 "alembic",
1882 virtualEnv=self.getProjectVirtualEnvironment()
1883 )
1884
1885 def migrationsPath(self):
1886 """
1887 Public method to get the path to the migrations directory of the
1888 current Pyramid project.
1889
1890 @return pathof the directory containing the migrations
1891 @rtype str
1892 """
1893 return os.path.join(self.projectPath(), self.__currentProject,
1894 "alembic", "versions")
1895
1896 def __getInitDbCommand(self):
1897 """
1898 Private method to create the path to the initialization script.
1899
1900 @return path to the initialization script
1901 @rtype str
1902 """
1903 try:
1904 cmd = "initialize_{0}_db".format(self.__project())
1905 return self.getPyramidCommand(
1906 cmd,
1907 virtualEnv=self.getProjectVirtualEnvironment()
1908 )
1909 except PyramidNoProjectSelectedException:
1910 EricMessageBox.warning(
1911 self.__ui,
1912 self.tr("Initialize Database"),
1913 self.tr('No current Pyramid project selected or no Pyramid'
1914 ' project created yet. Aborting...'))
1915 return ""
1916
1917 @pyqtSlot()
1918 def __initializeDatabase(self):
1919 """
1920 Private slot to initialize the database of the Pyramid project.
1921 """
1922 title = self.tr("Initialize Database")
1923 try:
1924 projectPath = self.projectPath()
1925 except PyramidNoProjectSelectedException:
1926 EricMessageBox.warning(
1927 self.__ui,
1928 title,
1929 self.tr('No current Pyramid project selected or no Pyramid'
1930 ' project created yet. Aborting...'))
1931 return
1932
1933 cmd = self.__getInitDbCommand()
1934 args = []
1935 args.append("development.ini")
1936
1937 dia = PyramidDialog(
1938 title,
1939 msgSuccess=self.tr("Database initialized successfully."))
1940 res = dia.startProcess(cmd, args, projectPath)
1941 if res:
1942 dia.exec()
1943
1944 @pyqtSlot()
1945 def __createMigration(self):
1946 """
1947 Private slot to create a new database migration.
1948 """
1949 title = self.tr("Create Migration")
1950 projectPath = self.projectPath()
1951 migrations = self.migrationsPath()
1952
1953 message, ok = QInputDialog.getText(
1954 None,
1955 title,
1956 self.tr("Enter a short message for the migration:"),
1957 QLineEdit.EchoMode.Normal)
1958 if ok:
1959 args = ["-c", "development.ini", "revision", "--autogenerate"]
1960 if migrations:
1961 args += ["--version-path", migrations]
1962 if message:
1963 args += ["--message", message]
1964
1965 dlg = PyramidDialog(
1966 title,
1967 msgSuccess=self.tr("\nMigration created successfully."),
1968 linewrap=False, combinedOutput=True,
1969 parent=self.__ui
1970 )
1971 if dlg.startProcess(self.getAlembicCommand(), args,
1972 workingDir=projectPath):
1973 dlg.exec()
1974 if dlg.normalExit():
1975 versionsPattern = os.path.join(migrations, "*.py")
1976 for fileName in glob.iglob(versionsPattern):
1977 self.__ericProject.appendFile(fileName)
1978
1979 @pyqtSlot()
1980 def upgradeDatabase(self, revision=None):
1981 """
1982 Public slot to upgrade the database to the head or a given version.
1983
1984 @param revision migration revision to upgrade to
1985 @type str
1986 """
1987 title = self.tr("Upgrade Database")
1988 projectPath = self.projectPath()
1989
1990 args = ["-c", "development.ini", "upgrade"]
1991 if revision:
1992 args.append(revision)
1993 else:
1994 args.append("head")
1995
1996 dlg = PyramidDialog(
1997 title,
1998 msgSuccess=self.tr("\nDatabase upgraded successfully."),
1999 linewrap=False, combinedOutput=True, parent=self.__ui
2000 )
2001 if dlg.startProcess(self.getAlembicCommand(), args,
2002 workingDir=projectPath):
2003 dlg.exec()
2004
2005 @pyqtSlot()
2006 def downgradeDatabase(self, revision=None):
2007 """
2008 Public slot to downgrade the database to the previous or a given
2009 version.
2010
2011 @param revision migration revision to downgrade to
2012 @type str
2013 """
2014 title = self.tr("Downgrade Database")
2015 projectPath = self.projectPath()
2016
2017 args = ["-c", "development.ini", "downgrade"]
2018 if revision:
2019 args.append(revision)
2020 else:
2021 args.append("-1")
2022
2023 dlg = PyramidDialog(
2024 title,
2025 msgSuccess=self.tr("\nDatabase downgraded successfully."),
2026 linewrap=False, combinedOutput=True, parent=self.__ui
2027 )
2028 if dlg.startProcess(self.getAlembicCommand(), args,
2029 workingDir=projectPath):
2030 dlg.exec()
2031
2032 @pyqtSlot()
2033 def __showMigrationsSummary(self):
2034 """
2035 Private slot to show a migrations history summary.
2036 """
2037 from .MigrateSummaryDialog import MigrateSummaryDialog
2038
2039 if self.__migrationSummaryDialog is None:
2040 self.__migrationSummaryDialog = MigrateSummaryDialog(
2041 self, parent=self.__ui)
2042
2043 self.__migrationSummaryDialog.showSummary()
2044
2045 @pyqtSlot()
2046 def __showMigrationsHistory(self):
2047 """
2048 Private slot to show the full migrations history.
2049 """
2050 title = self.tr("Migrations History")
2051 projectPath = self.projectPath()
2052
2053 args = ["-c", "development.ini", "history", "--indicate-current",
2054 "--verbose"]
2055
2056 dlg = PyramidDialog(
2057 title,
2058 linewrap=False, combinedOutput=True, parent=self.__ui
2059 )
2060 if dlg.startProcess(self.getAlembicCommand(), args,
2061 workingDir=projectPath):
2062 dlg.exec()

eric ide

mercurial