Wed, 21 Sep 2022 16:30:15 +0200
Reformatted source code with 'Black'.
--- a/.hgignore Thu Dec 30 12:13:22 2021 +0100 +++ b/.hgignore Wed Sep 21 16:30:15 2022 +0200 @@ -1,6 +1,7 @@ glob:.eric7project glob:.eric6project glob:.ropeproject +glob:.jedi glob:.directory glob:**.pyc glob:**.pyo
--- a/PluginFlask.epj Thu Dec 30 12:13:22 2021 +0100 +++ b/PluginFlask.epj Wed Sep 21 16:30:15 2022 +0200 @@ -1,7 +1,7 @@ { "header": { "comment": "eric project file for project PluginFlask", - "copyright": "Copyright (C) 2021 Detlev Offenbach, detlev@die-offenbachs.de" + "copyright": "Copyright (C) 2022 Detlev Offenbach, detlev@die-offenbachs.de" }, "project": { "AUTHOR": "Detlev Offenbach", @@ -128,6 +128,7 @@ } }, "EMAIL": "detlev@die-offenbachs.de", + "EMBEDDED_VENV": false, "EOL": 1, "FILETYPES": { "*.epj": "OTHERS", @@ -171,6 +172,7 @@ }, "INTERFACES": [], "LEXERASSOCS": {}, + "LICENSE": "GNU General Public License v3 or later (GPLv3+)", "MAINSCRIPT": "PluginProjectFlask.py", "MAKEPARAMS": { "MakeEnabled": false, @@ -185,6 +187,7 @@ ".hgignore", "ChangeLog", "PKGLIST", + "PluginFlask.epj", "PluginProjectFlask.zip", "ProjectFlask/APIs", "ProjectFlask/Documentation/LICENSE.GPL3", @@ -192,8 +195,7 @@ "ProjectFlask/icons/flask-dark.svg", "ProjectFlask/icons/flask-light.svg", "ProjectFlask/icons/flask64-dark.svg", - "ProjectFlask/icons/flask64-light.svg", - "PluginFlask.epj" + "ProjectFlask/icons/flask64-light.svg" ], "OTHERTOOLSPARMS": {}, "PACKAGERSPARMS": {}, @@ -237,6 +239,7 @@ "SPELLEXCLUDES": "", "SPELLLANGUAGE": "en", "SPELLWORDS": "", + "TESTING_FRAMEWORK": "", "TRANSLATIONEXCEPTIONS": [], "TRANSLATIONPATTERN": "ProjectFlask/i18n/flask_%language%.ts", "TRANSLATIONS": [
--- a/PluginProjectFlask.py Thu Dec 30 12:13:22 2021 +0100 +++ b/PluginProjectFlask.py Wed Sep 21 16:30:15 2022 +0200 @@ -30,9 +30,7 @@ className = "ProjectFlaskPlugin" packageName = "ProjectFlask" shortDescription = "Project support for Flask projects." -longDescription = ( - """This plugin implements project support for Flask projects.""" -) +longDescription = """This plugin implements project support for Flask projects.""" needsRestart = False pyqtApi = 2 # End-of-Header @@ -45,16 +43,15 @@ def apiFiles(language): """ Module function to return the API files made available by this plugin. - + @param language language to get APIs for @type str @return list of API filenames @rtype list of str """ if language in ["Python3"]: - apisDir = os.path.join(os.path.dirname(__file__), - "ProjectFlask", "APIs") - apis = glob.glob(os.path.join(apisDir, '*.api')) + apisDir = os.path.join(os.path.dirname(__file__), "ProjectFlask", "APIs") + apis = glob.glob(os.path.join(apisDir, "*.api")) else: apis = [] return apis @@ -63,7 +60,7 @@ def createFlaskPage(configDlg): """ Module function to create the Flask configuration page. - + @param configDlg reference to the configuration dialog @type ConfigurationWidget @return reference to the configuration page @@ -71,6 +68,7 @@ """ global flaskPluginObject from ProjectFlask.ConfigurationPage.FlaskPage import FlaskPage + page = FlaskPage(flaskPluginObject) return page @@ -78,19 +76,21 @@ def getConfigData(): """ Module function returning data as required by the configuration dialog. - + @return dictionary containing the relevant data @rtype dict """ usesDarkPalette = ericApp().usesDarkPalette() iconSuffix = "dark" if usesDarkPalette else "light" - + return { "flaskPage": [ QCoreApplication.translate("ProjectFlaskPlugin", "Flask"), - os.path.join("ProjectFlask", "icons", - "flask-{0}".format(iconSuffix)), - createFlaskPage, None, None], + os.path.join("ProjectFlask", "icons", "flask-{0}".format(iconSuffix)), + createFlaskPage, + None, + None, + ], } @@ -107,31 +107,29 @@ """ Class implementing the Flask project plugin. """ + PreferencesKey = "Flask" - + lexerAssociations = { "*.htm": "Pygments|HTML+Django/Jinja", "*.html": "Pygments|HTML+Django/Jinja", } - + def __init__(self, ui): """ Constructor - + @param ui reference to the user interface object @type UserInterface """ QObject.__init__(self, ui) self.__ui = ui self.__initialize() - + self.__defaults = { "VirtualEnvironmentNamePy3": "", - "FlaskDocUrl": "https://flask.palletsprojects.com", - "TranslationsEditor": "", - "UseExternalBrowser": False, } if isWindowsPlatform(): @@ -143,110 +141,117 @@ else: self.__defaults["AnsiColorScheme"] = "Ubuntu" self.__defaults["ConsoleCommand"] = "konsole -e" - + self.__translator = None self.__loadTranslator() - + def __initialize(self): """ Private slot to (re)initialize the plugin. """ self.__object = None - + self.__mainMenu = None self.__mainAct = None self.__separatorAct = None - + self.__ericProject = ericApp().getObject("Project") - + self.__supportedVariants = [] - + def activate(self): """ Public method to activate this plugin. - + @return tuple of None and activation status @rtype tuple of (None, bool) """ global flaskPluginObject flaskPluginObject = self - + usesDarkPalette = ericApp().usesDarkPalette() iconSuffix = "dark" if usesDarkPalette else "light" - + self.__object = Project(self, iconSuffix, self.__ui) self.__object.initActions() ericApp().registerPluginObject("ProjectFlask", self.__object) - + self.__mainMenu = self.__object.initMenu() - + self.__supportedVariants = self.__object.supportedPythonVariants() - + if self.__supportedVariants: self.__ericProject.registerProjectType( - "Flask", self.tr("Flask"), + "Flask", + self.tr("Flask"), self.fileTypesCallback, lexerAssociationCallback=self.lexerAssociationCallback, binaryTranslationsCallback=self.binaryTranslationsCallback, - progLanguages=self.__supportedVariants[:]) - + progLanguages=self.__supportedVariants[:], + ) + from Project.ProjectBrowser import ( - SourcesBrowserFlag, FormsBrowserFlag, TranslationsBrowserFlag, - OthersBrowserFlag + SourcesBrowserFlag, + FormsBrowserFlag, + TranslationsBrowserFlag, + OthersBrowserFlag, ) + Preferences.setProjectBrowserFlagsDefault( "Flask", - SourcesBrowserFlag | FormsBrowserFlag | - TranslationsBrowserFlag | OthersBrowserFlag, + SourcesBrowserFlag + | FormsBrowserFlag + | TranslationsBrowserFlag + | OthersBrowserFlag, ) - + if self.__ericProject.isOpen(): self.__projectOpened() self.__object.projectOpenedHooks() - - ericApp().getObject("Project").projectOpened.connect( - self.__projectOpened) - ericApp().getObject("Project").projectClosed.connect( - self.__projectClosed) - ericApp().getObject("Project").newProject.connect( - self.__projectOpened) - + + ericApp().getObject("Project").projectOpened.connect(self.__projectOpened) + ericApp().getObject("Project").projectClosed.connect(self.__projectClosed) + ericApp().getObject("Project").newProject.connect(self.__projectOpened) + ericApp().getObject("Project").projectOpenedHooks.connect( - self.__object.projectOpenedHooks) + self.__object.projectOpenedHooks + ) ericApp().getObject("Project").projectClosedHooks.connect( - self.__object.projectClosedHooks) + self.__object.projectClosedHooks + ) ericApp().getObject("Project").newProjectHooks.connect( - self.__object.projectOpenedHooks) - + self.__object.projectOpenedHooks + ) + return None, True - + def deactivate(self): """ Public method to deactivate this plugin. """ ericApp().unregisterPluginObject("ProjectFlask") - - ericApp().getObject("Project").projectOpened.disconnect( - self.__projectOpened) - ericApp().getObject("Project").projectClosed.disconnect( - self.__projectClosed) - ericApp().getObject("Project").newProject.disconnect( - self.__projectOpened) - + + ericApp().getObject("Project").projectOpened.disconnect(self.__projectOpened) + ericApp().getObject("Project").projectClosed.disconnect(self.__projectClosed) + ericApp().getObject("Project").newProject.disconnect(self.__projectOpened) + ericApp().getObject("Project").projectOpenedHooks.disconnect( - self.__object.projectOpenedHooks) + self.__object.projectOpenedHooks + ) ericApp().getObject("Project").projectClosedHooks.disconnect( - self.__object.projectClosedHooks) + self.__object.projectClosedHooks + ) ericApp().getObject("Project").newProjectHooks.disconnect( - self.__object.projectOpenedHooks) - + self.__object.projectOpenedHooks + ) + self.__ericProject.unregisterProjectType("Flask") - + self.__object.projectClosedHooks() self.__projectClosed() - + self.__initialize() - + def __loadTranslator(self): """ Private method to load the translation file. @@ -255,7 +260,8 @@ loc = self.__ui.getLocale() if loc and loc != "C": locale_dir = os.path.join( - os.path.dirname(__file__), "ProjectFlask", "i18n") + os.path.dirname(__file__), "ProjectFlask", "i18n" + ) translation = "flask_{0}".format(loc) translator = QTranslator(None) loaded = translator.load(translation, locale_dir) @@ -263,10 +269,12 @@ self.__translator = translator ericApp().installTranslator(self.__translator) else: - print("Warning: translation file '{0}' could not be" - " loaded.".format(translation)) + print( + "Warning: translation file '{0}' could not be" + " loaded.".format(translation) + ) print("Using default.") - + def __projectOpened(self): """ Private slot to handle the projectOpened signal. @@ -275,10 +283,10 @@ projectToolsMenu = self.__ui.getMenu("project_tools") insertBeforeAct = projectToolsMenu.actions()[0] self.__mainAct = projectToolsMenu.insertMenu( - insertBeforeAct, self.__mainMenu) - self.__separatorAct = projectToolsMenu.insertSeparator( - insertBeforeAct) - + insertBeforeAct, self.__mainMenu + ) + self.__separatorAct = projectToolsMenu.insertSeparator(insertBeforeAct) + def __projectClosed(self): """ Private slot to handle the projectClosed signal. @@ -290,32 +298,34 @@ self.__mainAct = None self.__separatorAct = None self.__object.projectClosed() - + def fileTypesCallback(self): """ Public method get the filetype associations of the Django project type. - + @return dictionary with file type associations @rtype dict """ fileTypes = ( - {"*.py": "SOURCES", - "*.js": "SOURCES", - "*.html": "FORMS", - "*.htm": "FORMS", - "*.pot": "TRANSLATIONS", - "*.po": "TRANSLATIONS", - "*.mo": "TRANSLATIONS", } - if self.__ericProject.getProjectType() == "Flask" else - {} + { + "*.py": "SOURCES", + "*.js": "SOURCES", + "*.html": "FORMS", + "*.htm": "FORMS", + "*.pot": "TRANSLATIONS", + "*.po": "TRANSLATIONS", + "*.mo": "TRANSLATIONS", + } + if self.__ericProject.getProjectType() == "Flask" + else {} ) return fileTypes - + def lexerAssociationCallback(self, filename): """ Public method to get the lexer association of the Django project type for a file. - + @param filename name of the file @type str @return name of the lexer (Pygments lexers are prefixed with @@ -325,14 +335,14 @@ for pattern, language in self.lexerAssociations.items(): if fnmatch.fnmatch(filename, pattern): return language - + return "" - + def binaryTranslationsCallback(self, filename): """ Public method to determine the filename of a compiled translation file given the translation source file. - + @param filename name of the translation source file @type str @return name of the binary translation file @@ -340,51 +350,54 @@ """ if filename.endswith(".po"): return filename.replace(".po", ".mo") - + return filename - + def getDefaultPreference(self, key): """ Public method to get the default value for a setting. - + @param key the key of the value to get @type str @return the requested setting @rtype any """ return self.__defaults[key] - + def getPreferences(self, key): """ Public method to retrieve the various settings. - + @param key the key of the value to get @type str @return the requested setting @rtype any """ if key in ["UseExternalBrowser"]: - return Preferences.toBool(Preferences.Prefs.settings.value( - self.PreferencesKey + "/" + key, self.__defaults[key])) + return Preferences.toBool( + Preferences.Prefs.settings.value( + self.PreferencesKey + "/" + key, self.__defaults[key] + ) + ) else: return Preferences.Prefs.settings.value( - self.PreferencesKey + "/" + key, self.__defaults[key]) - + self.PreferencesKey + "/" + key, self.__defaults[key] + ) + def setPreferences(self, key, value): """ Public method to store the various settings. - + @param key the key of the setting to be set @type str @param value the value to be set @type any """ - Preferences.Prefs.settings.setValue( - self.PreferencesKey + "/" + key, value) - + Preferences.Prefs.settings.setValue(self.PreferencesKey + "/" + key, value) + if key in ["VirtualEnvironmentNamePy3"]: self.__reregisterProjectType() - + def __reregisterProjectType(self): """ Private method to re-register the project type. @@ -393,21 +406,23 @@ if supportedVariants != self.__supportedVariants: # step 1: unregister self.__ericProject.unregisterProjectType("Flask") - + # step 2: register again with new language settings self.__supportedVariants = supportedVariants if self.__supportedVariants: self.__ericProject.registerProjectType( "Flask", - self.tr("Flask"), self.fileTypesCallback, + self.tr("Flask"), + self.fileTypesCallback, lexerAssociationCallback=self.lexerAssociationCallback, binaryTranslationsCallback=self.binaryTranslationsCallback, - progLanguages=self.__supportedVariants[:]) - + progLanguages=self.__supportedVariants[:], + ) + def getMenu(self, name): """ Public method to get a reference to the requested menu. - + @param name name of the menu @type str @return reference to the menu or None, if no @@ -418,11 +433,11 @@ return self.__object.getMenu(name) else: return None - + def getMenuNames(self): """ Public method to get the names of all menus. - + @return menu names @rtype list of str """ @@ -431,5 +446,6 @@ else: return [] + # # eflag: noqa = M801
--- a/ProjectFlask/AnsiTools.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/AnsiTools.py Wed Sep 21 16:30:15 2022 +0200 @@ -87,7 +87,7 @@ def getAvailableColorSchemes(): """ Function to get a list of available color schemes. - + @return list containing the names of the supported color schemes @rtype list of str """ @@ -97,7 +97,7 @@ def getColor(scheme, color): """ Function to get the brush for a given scheme and color. - + @param scheme name of the color scheme @type str @param color ANSI color code
--- a/ProjectFlask/ConfigurationPage/FlaskPage.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/ConfigurationPage/FlaskPage.py Wed Sep 21 16:30:15 2022 +0200 @@ -12,9 +12,7 @@ from EricWidgets.EricApplication import ericApp from EricWidgets.EricPathPicker import EricPathPickerModes -from Preferences.ConfigurationPages.ConfigurationPageBase import ( - ConfigurationPageBase -) +from Preferences.ConfigurationPages.ConfigurationPageBase import ConfigurationPageBase from .Ui_FlaskPage import Ui_FlaskPage import UI.PixmapCache @@ -28,19 +26,20 @@ """ Class implementing the Flask configuration page. """ + def __init__(self, plugin): """ Constructor - + @param plugin reference to the plugin object @type ProjectFlaskPlugin """ super().__init__() self.setupUi(self) self.setObjectName("FlaskPage") - + self.__plugin = plugin - + consoleList = [] if isWindowsPlatform(): consoleList.append("cmd.exe /c") @@ -54,71 +53,72 @@ consoleList.append("xfce4-terminal -e") consoleList.append("xterm -e") self.consoleCommandCombo.addItems(consoleList) - - self.colorSchemeComboBox.addItems( - sorted(AnsiTools.getAvailableColorSchemes())) - - self.urlResetButton.setIcon( - UI.PixmapCache.getIcon("editUndo")) - self.py3VenvNamesReloadButton.setIcon( - UI.PixmapCache.getIcon("reload")) - + + self.colorSchemeComboBox.addItems(sorted(AnsiTools.getAvailableColorSchemes())) + + self.urlResetButton.setIcon(UI.PixmapCache.getIcon("editUndo")) + self.py3VenvNamesReloadButton.setIcon(UI.PixmapCache.getIcon("reload")) + venvManager = ericApp().getObject("VirtualEnvManager") self.py3VenvNameComboBox.addItems( - [""] + sorted(venvManager.getVirtualenvNames())) - - self.translationsEditorPicker.setMode( - EricPathPickerModes.OPEN_FILE_MODE) + [""] + sorted(venvManager.getVirtualenvNames()) + ) + + self.translationsEditorPicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) self.translationsEditorPicker.setFilters(self.tr("All Files (*)")) - + # set initial values self.consoleCommandCombo.setEditText( - self.__plugin.getPreferences("ConsoleCommand")) - + self.__plugin.getPreferences("ConsoleCommand") + ) + self.externalBrowserCheckBox.setChecked( - self.__plugin.getPreferences("UseExternalBrowser")) - - venvName = self.__plugin.getPreferences( - "VirtualEnvironmentNamePy3") + self.__plugin.getPreferences("UseExternalBrowser") + ) + + venvName = self.__plugin.getPreferences("VirtualEnvironmentNamePy3") if venvName: index = self.py3VenvNameComboBox.findText(venvName) if index < 0: index = 0 self.py3VenvNameComboBox.setCurrentIndex(index) - + self.colorSchemeComboBox.setCurrentText( - self.__plugin.getPreferences("AnsiColorScheme")) - - self.urlEdit.setText( - self.__plugin.getPreferences("FlaskDocUrl")) - + self.__plugin.getPreferences("AnsiColorScheme") + ) + + self.urlEdit.setText(self.__plugin.getPreferences("FlaskDocUrl")) + self.translationsEditorPicker.setText( - self.__plugin.getPreferences("TranslationsEditor")) - + self.__plugin.getPreferences("TranslationsEditor") + ) + def save(self): """ Public slot to save the Flask configuration. """ self.__plugin.setPreferences( - "ConsoleCommand", self.consoleCommandCombo.currentText()) - + "ConsoleCommand", self.consoleCommandCombo.currentText() + ) + self.__plugin.setPreferences( - "UseExternalBrowser", self.externalBrowserCheckBox.isChecked()) - - self.__plugin.setPreferences( - "VirtualEnvironmentNamePy3", - self.py3VenvNameComboBox.currentText()) - + "UseExternalBrowser", self.externalBrowserCheckBox.isChecked() + ) + self.__plugin.setPreferences( - "AnsiColorScheme", - self.colorSchemeComboBox.currentText()) - + "VirtualEnvironmentNamePy3", self.py3VenvNameComboBox.currentText() + ) + self.__plugin.setPreferences( - "FlaskDocUrl", self.urlEdit.text()) - + "AnsiColorScheme", self.colorSchemeComboBox.currentText() + ) + + self.__plugin.setPreferences("FlaskDocUrl", self.urlEdit.text()) + self.__plugin.setPreferences( - "TranslationsEditor", self.translationsEditorPicker.text()) - + "TranslationsEditor", self.translationsEditorPicker.text() + ) + @pyqtSlot() def on_py3VenvNamesReloadButton_clicked(self): """ @@ -128,17 +128,17 @@ self.py3VenvNameComboBox.clear() venvManager = ericApp().getObject("VirtualEnvManager") self.py3VenvNameComboBox.addItems( - [""] + sorted(venvManager.getVirtualenvNames())) + [""] + sorted(venvManager.getVirtualenvNames()) + ) if currentVenvName: index = self.py3VenvNameComboBox.findText(currentVenvName) if index < 0: index = 0 self.py3VenvNameComboBox.setCurrentIndex(index) - + @pyqtSlot() def on_urlResetButton_clicked(self): """ Private slot to reset the Flask documentation URL. """ - self.urlEdit.setText( - self.__plugin.getDefaultPreference("FlaskDocUrl")) + self.urlEdit.setText(self.__plugin.getDefaultPreference("FlaskDocUrl"))
--- a/ProjectFlask/FlaskBabelExtension/FlaskBabelDetector.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskBabelExtension/FlaskBabelDetector.py Wed Sep 21 16:30:15 2022 +0200 @@ -11,9 +11,10 @@ if __name__ == "__main__": try: - import flask_babel # __IGNORE_EXCEPTION__ __IGNORE_WARNING__ + import flask_babel # __IGNORE_EXCEPTION__ __IGNORE_WARNING__ + ret = 0 except ImportError: ret = 1 - + sys.exit(ret)
--- a/ProjectFlask/FlaskBabelExtension/PyBabelCommandDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskBabelExtension/PyBabelCommandDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -19,11 +19,11 @@ """ Class implementing a dialog to run a flask command and show its output. """ - def __init__(self, project, title="", msgSuccess="", msgError="", - parent=None): + + def __init__(self, project, title="", msgSuccess="", msgError="", parent=None): """ Constructor - + @param project reference to the project object @type Project @param title window title of the dialog @@ -37,29 +37,26 @@ """ super().__init__(parent) self.setupUi(self) - + if title: self.setWindowTitle(title) - + self.__project = project self.__successMessage = msgSuccess self.__errorMessage = msgError - + self.__process = None self.__argsLists = [] self.__workdir = "" - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setDefault(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setEnabled(False) - + + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) + def startCommand(self, command, args, workdir, clearOutput=True): """ Public method to start a pybabel command and show its output. - + @param command pybabel command to be run @type str @param args list of command line arguments for the command @@ -72,47 +69,50 @@ @rtype bool """ babelCommand = self.__project.getBabelCommand() - + self.__process = QProcess() self.__process.setWorkingDirectory(workdir) - self.__process.setProcessChannelMode( - QProcess.ProcessChannelMode.MergedChannels) - + self.__process.setProcessChannelMode(QProcess.ProcessChannelMode.MergedChannels) + self.__process.readyReadStandardOutput.connect(self.__readStdOut) self.__process.finished.connect(self.__processFinished) - + if clearOutput: self.outputEdit.clear() - + babelArgs = [command] if args: babelArgs += args - + self.__process.start(babelCommand, babelArgs) ok = self.__process.waitForStarted(10000) if not ok: EricMessageBox.critical( None, self.tr("Execute PyBabel Command"), - self.tr("""The pybabel process could not be started.""")) + self.tr("""The pybabel process could not be started."""), + ) else: - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(False) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setDefault(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setFocus( - Qt.FocusReason.OtherFocusReason) - + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled( + False + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault( + True + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled( + True + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setFocus( + Qt.FocusReason.OtherFocusReason + ) + return ok - + def startBatchCommand(self, argsLists, workdir): """ Public method to start a pybabel command repeatedly with a list of arguments and show the output. - + @param argsLists list of command line arguments for the batch commands @type list of lists of str @param workdir working directory for the command @@ -122,26 +122,26 @@ """ self.__argsLists = argsLists[:] self.__workdir = workdir - + # start the first process args = self.__argsLists.pop(0) res = self.startCommand(args[0], args[1:], workdir) if not res: self.__argsLists = [] - + return res - + def closeEvent(self, evt): """ Protected method handling the close event of the dialog. - + @param evt reference to the close event object @type QCloseEvent """ self.__argsLists = [] self.__cancelProcess() evt.accept() - + @pyqtSlot() def __readStdOut(self): """ @@ -150,71 +150,61 @@ if self.__process is not None: out = str(self.__process.readAllStandardOutput(), "utf-8") self.outputEdit.insertPlainText(out) - + def __processFinished(self, exitCode, exitStatus): """ Private slot connected to the finished signal. - + @param exitCode exit code of the process @type int @param exitStatus exit status of the process @type QProcess.ExitStatus """ - normal = ( - exitStatus == QProcess.ExitStatus.NormalExit and - exitCode == 0 - ) + normal = exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0 self.__cancelProcess() - + if self.__argsLists: args = self.__argsLists.pop(0) - self.startCommand(args[0], args[1:], self.__workdir, - clearOutput=False) + self.startCommand(args[0], args[1:], self.__workdir, clearOutput=False) return - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setEnabled(False) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setDefault(True) + + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus( - Qt.FocusReason.OtherFocusReason) - + Qt.FocusReason.OtherFocusReason + ) + if normal and self.__successMessage: self.outputEdit.insertPlainText(self.__successMessage) elif not normal and self.__errorMessage: self.outputEdit.insertPlainText(self.__errorMessage) - + @pyqtSlot() def __cancelProcess(self): """ Private slot to terminate the current process. """ if ( - self.__process is not None and - self.__process.state() != QProcess.ProcessState.NotRunning + self.__process is not None + and self.__process.state() != QProcess.ProcessState.NotRunning ): self.__process.terminate() QTimer.singleShot(2000, self.__process.kill) self.__process.waitForFinished(3000) - + self.__process = None - + @pyqtSlot(QAbstractButton) def on_buttonBox_clicked(self, button): """ Private slot handling presses of the button box buttons. - + @param button reference to the button been clicked @type QAbstractButton """ - if button is self.buttonBox.button( - QDialogButtonBox.StandardButton.Close - ): + if button is self.buttonBox.button(QDialogButtonBox.StandardButton.Close): self.close() - elif button is self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel - ): + elif button is self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel): self.__argsLists = [] self.__cancelProcess()
--- a/ProjectFlask/FlaskBabelExtension/PyBabelConfigDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskBabelExtension/PyBabelConfigDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -22,10 +22,11 @@ """ Class implementing a dialog to edit the flask-babel configuration. """ + def __init__(self, configuration, parent=None): """ Constructor - + @param configuration current pybabel configuration @type dict @param parent reference to the parent widget @@ -33,140 +34,141 @@ """ super().__init__(parent) self.setupUi(self) - + self.__ericProject = ericApp().getObject("Project") - + self.configFilePicker.setMode( - EricPathPickerModes.SAVE_FILE_ENSURE_EXTENSION_MODE) - self.configFilePicker.setFilters(self.tr( - "Configuration Files (*.cfg);;" - "All Files (*)" - )) - self.configFilePicker.setDefaultDirectory( - self.__ericProject.getProjectPath()) - - self.translationsDirectoryPicker.setMode( - EricPathPickerModes.DIRECTORY_MODE) + EricPathPickerModes.SAVE_FILE_ENSURE_EXTENSION_MODE + ) + self.configFilePicker.setFilters( + self.tr("Configuration Files (*.cfg);;" "All Files (*)") + ) + self.configFilePicker.setDefaultDirectory(self.__ericProject.getProjectPath()) + + self.translationsDirectoryPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) self.translationsDirectoryPicker.setDefaultDirectory( - self.__ericProject.getProjectPath()) - + self.__ericProject.getProjectPath() + ) + self.catalogFilePicker.setMode( - EricPathPickerModes.SAVE_FILE_ENSURE_EXTENSION_MODE) - self.catalogFilePicker.setFilters(self.tr( - "Message Catalog Files (*.pot);;" - "All Files (*)" - )) - self.catalogFilePicker.setDefaultDirectory( - self.__ericProject.getProjectPath()) - + EricPathPickerModes.SAVE_FILE_ENSURE_EXTENSION_MODE + ) + self.catalogFilePicker.setFilters( + self.tr("Message Catalog Files (*.pot);;" "All Files (*)") + ) + self.catalogFilePicker.setDefaultDirectory(self.__ericProject.getProjectPath()) + self.configFilePicker.setFocus(Qt.FocusReason.OtherFocusReason) - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Ok).setEnabled(False) - + + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) + if "configFile" in configuration: self.configFilePicker.setText( - self.__ericProject.getAbsoluteUniversalPath( - configuration["configFile"])) + self.__ericProject.getAbsoluteUniversalPath(configuration["configFile"]) + ) if "translationsDirectory" in configuration: self.translationsDirectoryPicker.setText( self.__ericProject.getAbsoluteUniversalPath( - configuration["translationsDirectory"])) + configuration["translationsDirectory"] + ) + ) if "domain" in configuration: self.domainEdit.setText(configuration["domain"]) if "catalogFile" in configuration: self.catalogFilePicker.setText( self.__ericProject.getAbsoluteUniversalPath( - configuration["catalogFile"])) + configuration["catalogFile"] + ) + ) if "markersList" in configuration: self.markersEdit.setText(" ".join(configuration["markersList"])) - + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) - + def getConfiguration(self): """ Public method to get the entered configuration data. - + @return pybabel configuration @rtype dict """ configuration = { - "configFile": - self.__ericProject.getRelativeUniversalPath( - self.configFilePicker.text()), - "translationsDirectory": - self.__ericProject.getRelativeUniversalPath( - self.translationsDirectoryPicker.text()), + "configFile": self.__ericProject.getRelativeUniversalPath( + self.configFilePicker.text() + ), + "translationsDirectory": self.__ericProject.getRelativeUniversalPath( + self.translationsDirectoryPicker.text() + ), } - + domain = self.domainEdit.text() if domain: configuration["domain"] = domain else: configuration["domain"] = "messages" - + catalogFile = self.catalogFilePicker.text() if not catalogFile: # use a default name made of translations dir and domain catalogFile = os.path.join( configuration["translationsDirectory"], - "{0}.pot".format(configuration["domain"])) - configuration["catalogFile"] = ( - self.__ericProject.getRelativeUniversalPath(catalogFile) + "{0}.pot".format(configuration["domain"]), + ) + configuration["catalogFile"] = self.__ericProject.getRelativeUniversalPath( + catalogFile ) - + if self.markersEdit.text(): configuration["markersList"] = self.markersEdit.text().split() - + return configuration - + def __updateOK(self): """ Private method to update the status of the OK button. """ - enable = ( - bool(self.configFilePicker.text()) and - bool(self.translationsDirectoryPicker.text()) + enable = bool(self.configFilePicker.text()) and bool( + self.translationsDirectoryPicker.text() ) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Ok).setEnabled(enable) - + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(enable) + def __updateCatalogPicker(self): """ Private method to update the contents of the catalog picker. """ translationsDirectory = self.translationsDirectoryPicker.text() domain = self.domainEdit.text() - self.catalogFilePicker.setText(os.path.join( - translationsDirectory, "{0}.pot".format(domain))) - + self.catalogFilePicker.setText( + os.path.join(translationsDirectory, "{0}.pot".format(domain)) + ) + @pyqtSlot(str) def on_configFilePicker_textChanged(self, txt): """ Private slot to handle a change of the configuration file name. - + @param txt configuration file name @type str """ self.__updateOK() - + @pyqtSlot(str) def on_translationsDirectoryPicker_textChanged(self, txt): """ Private slot to handle a change of the catalog file name. - + @param txt configuration file name @type str """ self.__updateOK() self.__updateCatalogPicker() - + @pyqtSlot(str) def on_domainEdit_textChanged(self, txt): """ Private slot to handle a change of the translations domain. - + @param txt entered translations domain @type str """
--- a/ProjectFlask/FlaskBabelExtension/PyBabelProjectExtension.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskBabelExtension/PyBabelProjectExtension.py Wed Sep 21 16:30:15 2022 +0200 @@ -27,10 +27,11 @@ """ Class implementing the flask-babel project support. """ + def __init__(self, plugin, project, parent=None): """ Constructor - + @param plugin reference to the plugin object @type ProjectFlaskPlugin @param project reference to the project object @@ -39,85 +40,101 @@ @type QObject """ super().__init__(parent) - + self.__plugin = plugin self.__project = project - + self.__ericProject = ericApp().getObject("Project") - + self.__hooksInstalled = False - + def initActions(self): """ Public method to define the flask-babel actions. """ self.actions = [] - + self.pybabelConfigAct = EricAction( - self.tr('Configure flask-babel'), - self.tr('&Configure flask-babel'), - 0, 0, - self, 'flask_config_pybabel') - self.pybabelConfigAct.setStatusTip(self.tr( - 'Shows a dialog to edit the configuration for flask-babel')) - self.pybabelConfigAct.setWhatsThis(self.tr( - """<b>Configure flask-babel</b>""" - """<p>Shows a dialog to edit the configuration for """ - """flask-babel.</p>""" - )) - self.pybabelConfigAct.triggered.connect( - self.__configurePyBabel) + self.tr("Configure flask-babel"), + self.tr("&Configure flask-babel"), + 0, + 0, + self, + "flask_config_pybabel", + ) + self.pybabelConfigAct.setStatusTip( + self.tr("Shows a dialog to edit the configuration for flask-babel") + ) + self.pybabelConfigAct.setWhatsThis( + self.tr( + """<b>Configure flask-babel</b>""" + """<p>Shows a dialog to edit the configuration for """ + """flask-babel.</p>""" + ) + ) + self.pybabelConfigAct.triggered.connect(self.__configurePyBabel) self.actions.append(self.pybabelConfigAct) - + self.pybabelInstallAct = EricAction( - self.tr('Install flask-babel'), - self.tr('&Install flask-babel'), - 0, 0, - self, 'flask_install_pybabel') - self.pybabelInstallAct.setStatusTip(self.tr( - 'Installs the flask-babel extension into the configured' - ' environment')) - self.pybabelInstallAct.setWhatsThis(self.tr( - """<b>Install flask-babel</b>""" - """<p>Installs the flask-babel extension into the configured""" - """ environment using the pip interface.</p>""" - )) - self.pybabelInstallAct.triggered.connect( - self.__installFlaskBabel) + self.tr("Install flask-babel"), + self.tr("&Install flask-babel"), + 0, + 0, + self, + "flask_install_pybabel", + ) + self.pybabelInstallAct.setStatusTip( + self.tr( + "Installs the flask-babel extension into the configured" " environment" + ) + ) + self.pybabelInstallAct.setWhatsThis( + self.tr( + """<b>Install flask-babel</b>""" + """<p>Installs the flask-babel extension into the configured""" + """ environment using the pip interface.</p>""" + ) + ) + self.pybabelInstallAct.triggered.connect(self.__installFlaskBabel) self.actions.append(self.pybabelInstallAct) - + self.pybabelAvailabilityAct = EricAction( - self.tr('Check flask-babel Availability'), - self.tr('Check flask-babel &Availability'), - 0, 0, - self, 'flask_check_pybabel') - self.pybabelAvailabilityAct.setStatusTip(self.tr( - 'Check the availability of the flask-babel extension')) - self.pybabelAvailabilityAct.setWhatsThis(self.tr( - """<b>Check flask-babel Availability</b>""" - """<p>Check the availability of the flask-babel extension.</p>""" - )) - self.pybabelAvailabilityAct.triggered.connect( - self.__checkAvailability) + self.tr("Check flask-babel Availability"), + self.tr("Check flask-babel &Availability"), + 0, + 0, + self, + "flask_check_pybabel", + ) + self.pybabelAvailabilityAct.setStatusTip( + self.tr("Check the availability of the flask-babel extension") + ) + self.pybabelAvailabilityAct.setWhatsThis( + self.tr( + """<b>Check flask-babel Availability</b>""" + """<p>Check the availability of the flask-babel extension.</p>""" + ) + ) + self.pybabelAvailabilityAct.triggered.connect(self.__checkAvailability) self.actions.append(self.pybabelAvailabilityAct) - + def initMenu(self): """ Public method to initialize the flask-babel menu. - + @return the menu generated @rtype QMenu """ menu = QMenu(self.tr("Translations")) menu.setTearOffEnabled(True) - + menu.addAction(self.pybabelConfigAct) menu.addSeparator() menu.addAction(self.pybabelAvailabilityAct) menu.addAction(self.pybabelInstallAct) - + return menu - + def registerOpenHook(self): """ Public method to register the open hook to open a translations file @@ -127,156 +144,161 @@ editor = self.__plugin.getPreferences("TranslationsEditor") if editor: self.__translationsBrowser.addHookMethodAndMenuEntry( - "open", self.openPOEditor, - self.tr("Open with {0}").format( - os.path.basename(editor))) + "open", + self.openPOEditor, + self.tr("Open with {0}").format(os.path.basename(editor)), + ) else: self.__translationsBrowser.removeHookMethod("open") - + def projectOpenedHooks(self): """ Public method to add our hook methods. """ if self.__project.hasCapability("flask-babel"): self.__ericProject.projectLanguageAddedByCode.connect( - self.__projectLanguageAdded) + self.__projectLanguageAdded + ) self.__translationsBrowser = ( - ericApp().getObject("ProjectBrowser") - .getProjectBrowser("translations")) + ericApp().getObject("ProjectBrowser").getProjectBrowser("translations") + ) self.__translationsBrowser.addHookMethodAndMenuEntry( - "extractMessages", self.extractMessages, - self.tr("Extract Messages")) + "extractMessages", self.extractMessages, self.tr("Extract Messages") + ) self.__translationsBrowser.addHookMethodAndMenuEntry( - "releaseAll", self.compileCatalogs, - self.tr("Compile All Catalogs")) + "releaseAll", self.compileCatalogs, self.tr("Compile All Catalogs") + ) self.__translationsBrowser.addHookMethodAndMenuEntry( - "releaseSelected", self.compileSelectedCatalogs, - self.tr("Compile Selected Catalogs")) + "releaseSelected", + self.compileSelectedCatalogs, + self.tr("Compile Selected Catalogs"), + ) self.__translationsBrowser.addHookMethodAndMenuEntry( - "generateAll", self.updateCatalogs, - self.tr("Update All Catalogs")) + "generateAll", self.updateCatalogs, self.tr("Update All Catalogs") + ) self.__translationsBrowser.addHookMethodAndMenuEntry( - "generateAllWithObsolete", self.updateCatalogsObsolete, - self.tr("Update All Catalogs (with obsolete)")) + "generateAllWithObsolete", + self.updateCatalogsObsolete, + self.tr("Update All Catalogs (with obsolete)"), + ) self.__translationsBrowser.addHookMethodAndMenuEntry( - "generateSelected", self.updateSelectedCatalogs, - self.tr("Update Selected Catalogs")) + "generateSelected", + self.updateSelectedCatalogs, + self.tr("Update Selected Catalogs"), + ) self.__translationsBrowser.addHookMethodAndMenuEntry( "generateSelectedWithObsolete", self.updateSelectedCatalogsObsolete, - self.tr("Update Selected Catalogs (with obsolete)")) - + self.tr("Update Selected Catalogs (with obsolete)"), + ) + self.__hooksInstalled = True - + self.registerOpenHook() - + def projectClosedHooks(self): """ Public method to remove our hook methods. """ if self.__hooksInstalled: self.__ericProject.projectLanguageAddedByCode.disconnect( - self.__projectLanguageAdded) - self.__translationsBrowser.removeHookMethod( - "extractMessages") - self.__translationsBrowser.removeHookMethod( - "releaseAll") - self.__translationsBrowser.removeHookMethod( - "releaseSelected") - self.__translationsBrowser.removeHookMethod( - "generateAll") - self.__translationsBrowser.removeHookMethod( - "generateAllWithObsolete") - self.__translationsBrowser.removeHookMethod( - "generateSelected") - self.__translationsBrowser.removeHookMethod( - "generateSelectedWithObsolete") - self.__translationsBrowser.removeHookMethod( - "open") + self.__projectLanguageAdded + ) + self.__translationsBrowser.removeHookMethod("extractMessages") + self.__translationsBrowser.removeHookMethod("releaseAll") + self.__translationsBrowser.removeHookMethod("releaseSelected") + self.__translationsBrowser.removeHookMethod("generateAll") + self.__translationsBrowser.removeHookMethod("generateAllWithObsolete") + self.__translationsBrowser.removeHookMethod("generateSelected") + self.__translationsBrowser.removeHookMethod("generateSelectedWithObsolete") + self.__translationsBrowser.removeHookMethod("open") self.__translationsBrowser = None - + self.__hooksInstalled = False - + def determineCapability(self): """ Public method to determine the availability of flask-babel. """ available = ( self.__project.getData("flask", "flask_babel_available") - if self.__project.getData("flask", "flask_babel_override") else - self.__flaskBabelAvailable() + if self.__project.getData("flask", "flask_babel_override") + else self.__flaskBabelAvailable() ) self.__project.setCapability("flask-babel", available) - + self.pybabelConfigAct.setEnabled(available) self.pybabelInstallAct.setEnabled(not available) - + ################################################################## ## slots and methods below implement general functionality ################################################################## - + def getBabelCommand(self): """ Public method to build the Babel command. - + @return full pybabel command @rtype str """ return self.__project.getFullCommand("pybabel") - + ################################################################## ## slots and methods below implement i18n and l10n support ################################################################## - + def __flaskBabelAvailable(self): """ Private method to check, if the 'flask-babel' package is available. - + @return flag indicating the availability of 'flask-babel' @rtype bool """ interpreter = self.__project.getVirtualenvInterpreter() if interpreter and Utilities.isinpath(interpreter): - detector = os.path.join( - os.path.dirname(__file__), "FlaskBabelDetector.py") + detector = os.path.join(os.path.dirname(__file__), "FlaskBabelDetector.py") proc = QProcess() - proc.setProcessChannelMode( - QProcess.ProcessChannelMode.MergedChannels) + proc.setProcessChannelMode(QProcess.ProcessChannelMode.MergedChannels) proc.start(interpreter, [detector]) finished = proc.waitForFinished(30000) if finished and proc.exitCode() == 0: return True - + return False - + @pyqtSlot() def __configurePyBabel(self): """ Private slot to show a dialog to edit the pybabel configuration. """ from .PyBabelConfigDialog import PyBabelConfigDialog - + config = self.__project.getData("flask-babel", "") dlg = PyBabelConfigDialog(config) if dlg.exec() == QDialog.DialogCode.Accepted: config = dlg.getConfiguration() self.__project.setData("flask-babel", "", config) - - self.__ericProject.setTranslationPattern(os.path.join( - config["translationsDirectory"], "%language%", "LC_MESSAGES", - "{0}.po".format(config["domain"]) - )) + + self.__ericProject.setTranslationPattern( + os.path.join( + config["translationsDirectory"], + "%language%", + "LC_MESSAGES", + "{0}.po".format(config["domain"]), + ) + ) self.__ericProject.setDirty(True) - + cfgFileName = self.__ericProject.getAbsoluteUniversalPath( - config["configFile"]) + config["configFile"] + ) if not os.path.exists(cfgFileName): self.__createBabelCfg(cfgFileName) - + def __ensurePybabelConfigured(self): """ Private method to ensure, that PyBabel has been configured. - + @return flag indicating successful configuration @rtype bool """ @@ -284,22 +306,21 @@ if not config: self.__configurePybabel() return True - + configFileName = self.__project.getData("flask-babel", "configFile") if configFileName: - cfgFileName = self.__ericProject.getAbsoluteUniversalPath( - configFileName) + cfgFileName = self.__ericProject.getAbsoluteUniversalPath(configFileName) if os.path.exists(cfgFileName): return True else: return self.__createBabelCfg(cfgFileName) - + return False - + def __createBabelCfg(self, configFile): """ Private method to create a template pybabel configuration file. - + @param configFile name of the configuration file to be created @type str @return flag indicating successful configuration file creation @@ -307,13 +328,17 @@ """ _, app = self.__project.getApplication() template = ( - ("[python: {0}]\n" - "[jinja2: templates/**.html]\n" - "extensions=jinja2.ext.autoescape,jinja2.ext.with_\n") - if app.endswith(".py") else - ("[python: {0}/**.py]\n" - "[jinja2: {0}/templates/**.html]\n" - "extensions=jinja2.ext.autoescape,jinja2.ext.with_\n") + ( + "[python: {0}]\n" + "[jinja2: templates/**.html]\n" + "extensions=jinja2.ext.autoescape,jinja2.ext.with_\n" + ) + if app.endswith(".py") + else ( + "[python: {0}/**.py]\n" + "[jinja2: {0}/templates/**.html]\n" + "extensions=jinja2.ext.autoescape,jinja2.ext.with_\n" + ) ) try: with open(configFile, "w") as f: @@ -322,21 +347,24 @@ EricMessageBox.information( None, self.tr("Generate PyBabel Configuration File"), - self.tr("""The PyBabel configuration file was created.""" - """ Please edit it to adjust the entries as""" - """ required.""") + self.tr( + """The PyBabel configuration file was created.""" + """ Please edit it to adjust the entries as""" + """ required.""" + ), ) return True except OSError as err: EricMessageBox.warning( None, self.tr("Generate PyBabel Configuration File"), - self.tr("""<p>The PyBabel Configuration File could not be""" - """ generated.</p><p>Reason: {0}</p>""") - .format(str(err)) + self.tr( + """<p>The PyBabel Configuration File could not be""" + """ generated.</p><p>Reason: {0}</p>""" + ).format(str(err)), ) return False - + @pyqtSlot() def __installFlaskBabel(self): """ @@ -353,10 +381,13 @@ EricMessageBox.critical( None, self.tr("Install flask-babel"), - self.tr("The 'flask-babel' extension could not be installed" - " because no virtual environment has been" - " configured.")) - + self.tr( + "The 'flask-babel' extension could not be installed" + " because no virtual environment has been" + " configured." + ), + ) + @pyqtSlot() def __checkAvailability(self): """ @@ -365,18 +396,15 @@ self.determineCapability() msg = ( self.tr("The 'flask-babel' extension is installed.") - if self.__project.hasCapability("flask-babel") else - self.tr("The 'flask-babel' extension is not installed.") + if self.__project.hasCapability("flask-babel") + else self.tr("The 'flask-babel' extension is not installed.") ) - EricMessageBox.information( - None, - self.tr("flask-babel Availability"), - msg) - + EricMessageBox.information(None, self.tr("flask-babel Availability"), msg) + def __getLocale(self, filename): """ Private method to extract the locale out of a file name. - + @param filename name of the file used for extraction @type str @return extracted locale @@ -384,24 +412,24 @@ """ if self.__ericProject.getTranslationPattern(): filename = os.path.splitext(filename)[0] + ".po" - + # On Windows, path typically contains backslashes. This leads # to an invalid search pattern '...\(' because the opening bracket # will be escaped. pattern = self.__ericProject.getTranslationPattern() pattern = os.path.normpath(pattern) pattern = pattern.replace("%language%", "(.*?)") - pattern = pattern.replace('\\', '\\\\') + pattern = pattern.replace("\\", "\\\\") match = re.search(pattern, filename) if match is not None: return match.group(1) - + return None - + def openPOEditor(self, poFile): """ Public method to edit the given file in an external .po editor. - + @param poFile name of the .po file @type str """ @@ -412,11 +440,12 @@ if not started: EricMessageBox.critical( None, - self.tr('Process Generation Error'), - self.tr('The translations editor process ({0}) could' - ' not be started.').format( - os.path.basename(editor))) - + self.tr("Process Generation Error"), + self.tr( + "The translations editor process ({0}) could" " not be started." + ).format(os.path.basename(editor)), + ) + def extractMessages(self): """ Public method to extract the messages catalog template file. @@ -425,280 +454,272 @@ if self.__ensurePybabelConfigured(): workdir = self.__project.getApplication()[0] potFile = self.__ericProject.getAbsoluteUniversalPath( - self.__project.getData("flask-babel", "catalogFile")) - + self.__project.getData("flask-babel", "catalogFile") + ) + with contextlib.suppress(OSError): potFilePath = os.path.dirname(potFile) os.makedirs(potFilePath) - + args = [ "-F", os.path.relpath( self.__ericProject.getAbsoluteUniversalPath( - self.__project.getData("flask-babel", "configFile")), - workdir - ) + self.__project.getData("flask-babel", "configFile") + ), + workdir, + ), ] if self.__project.getData("flask-babel", "markersList"): - for marker in self.__project.getData("flask-babel", - "markersList"): + for marker in self.__project.getData("flask-babel", "markersList"): args += ["-k", marker] - args += [ - "-o", - os.path.relpath(potFile, workdir), - "." - ] - + args += ["-o", os.path.relpath(potFile, workdir), "."] + dlg = PyBabelCommandDialog( - self, title, - msgSuccess=self.tr("\nMessages extracted successfully.") + self, title, msgSuccess=self.tr("\nMessages extracted successfully.") ) res = dlg.startCommand("extract", args, workdir) if res: dlg.exec() self.__ericProject.appendFile(potFile) - + def __projectLanguageAdded(self, code): """ Private slot handling the addition of a new language. - + @param code language code of the new language @type str """ - title = self.tr( - "Initializing message catalog for '{0}'").format(code) - + title = self.tr("Initializing message catalog for '{0}'").format(code) + if self.__ensurePybabelConfigured(): workdir = self.__project.getApplication()[0] langFile = self.__ericProject.getAbsoluteUniversalPath( - self.__ericProject.getTranslationPattern().replace( - "%language%", code)) + self.__ericProject.getTranslationPattern().replace("%language%", code) + ) potFile = self.__ericProject.getAbsoluteUniversalPath( - self.__project.getData("flask-babel", "catalogFile")) - + self.__project.getData("flask-babel", "catalogFile") + ) + args = [ - "--domain={0}".format( - self.__project.getData("flask-babel", "domain")), + "--domain={0}".format(self.__project.getData("flask-babel", "domain")), "--input-file={0}".format(os.path.relpath(potFile, workdir)), "--output-file={0}".format(os.path.relpath(langFile, workdir)), "--locale={0}".format(code), ] - + dlg = PyBabelCommandDialog( - self, title, - msgSuccess=self.tr( - "\nMessage catalog initialized successfully.") + self, + title, + msgSuccess=self.tr("\nMessage catalog initialized successfully."), ) res = dlg.startCommand("init", args, workdir) if res: dlg.exec() - + self.__ericProject.appendFile(langFile) - + def compileCatalogs(self, filenames): """ Public method to compile the message catalogs. - + @param filenames list of filenames (not used) @type list of str """ title = self.tr("Compiling message catalogs") - + if self.__ensurePybabelConfigured(): workdir = self.__project.getApplication()[0] - translationsDirectory = ( - self.__ericProject.getAbsoluteUniversalPath( - self.__project.getData( - "flask-babel", "translationsDirectory") - ) + translationsDirectory = self.__ericProject.getAbsoluteUniversalPath( + self.__project.getData("flask-babel", "translationsDirectory") ) - + args = [ - "--domain={0}".format( - self.__project.getData("flask-babel", "domain")), + "--domain={0}".format(self.__project.getData("flask-babel", "domain")), "--directory={0}".format( - os.path.relpath(translationsDirectory, workdir)), + os.path.relpath(translationsDirectory, workdir) + ), "--use-fuzzy", "--statistics", ] - + dlg = PyBabelCommandDialog( - self, title, - msgSuccess=self.tr("\nMessage catalogs compiled successfully.") + self, + title, + msgSuccess=self.tr("\nMessage catalogs compiled successfully."), ) res = dlg.startCommand("compile", args, workdir) if res: dlg.exec() - + for entry in os.walk(translationsDirectory): for fileName in entry[2]: fullName = os.path.join(entry[0], fileName) - if fullName.endswith('.mo'): + if fullName.endswith(".mo"): self.__ericProject.appendFile(fullName) - + def compileSelectedCatalogs(self, filenames): """ Public method to update the message catalogs. - + @param filenames list of file names @type list of str """ title = self.tr("Compiling message catalogs") - + locales = {self.__getLocale(f) for f in filenames} - + if len(locales) == 0: EricMessageBox.warning( - self.__ui, - title, - self.tr('No locales detected. Aborting...')) + self.__ui, title, self.tr("No locales detected. Aborting...") + ) return - + if self.__ensurePybabelConfigured(): workdir = self.__project.getApplication()[0] - translationsDirectory = ( - self.__ericProject.getAbsoluteUniversalPath( - self.__project.getData( - "flask-babel", "translationsDirectory") - ) + translationsDirectory = self.__ericProject.getAbsoluteUniversalPath( + self.__project.getData("flask-babel", "translationsDirectory") ) - + argsList = [] for loc in locales: - argsList.append([ - "compile", - "--domain={0}".format( - self.__project.getData("flask-babel", "domain")), - "--directory={0}".format( - os.path.relpath(translationsDirectory, workdir)), - "--use-fuzzy", - "--statistics", - "--locale={0}".format(loc), - ]) - + argsList.append( + [ + "compile", + "--domain={0}".format( + self.__project.getData("flask-babel", "domain") + ), + "--directory={0}".format( + os.path.relpath(translationsDirectory, workdir) + ), + "--use-fuzzy", + "--statistics", + "--locale={0}".format(loc), + ] + ) + dlg = PyBabelCommandDialog( - self, title=title, - msgSuccess=self.tr("\nMessage catalogs compiled successfully.") + self, + title=title, + msgSuccess=self.tr("\nMessage catalogs compiled successfully."), ) res = dlg.startBatchCommand(argsList, workdir) if res: dlg.exec() - + for entry in os.walk(translationsDirectory): for fileName in entry[2]: fullName = os.path.join(entry[0], fileName) - if fullName.endswith('.mo'): + if fullName.endswith(".mo"): self.__ericProject.appendFile(fullName) - + def updateCatalogs(self, filenames, withObsolete=False): """ Public method to update the message catalogs. - + @param filenames list of filenames (not used) @type list of str @param withObsolete flag indicating to keep obsolete translations @type bool """ title = self.tr("Updating message catalogs") - + if self.__ensurePybabelConfigured(): workdir = self.__project.getApplication()[0] - translationsDirectory = ( - self.__ericProject.getAbsoluteUniversalPath( - self.__project.getData( - "flask-babel", "translationsDirectory") - ) + translationsDirectory = self.__ericProject.getAbsoluteUniversalPath( + self.__project.getData("flask-babel", "translationsDirectory") ) potFile = self.__ericProject.getAbsoluteUniversalPath( - self.__project.getData("flask-babel", "catalogFile")) - + self.__project.getData("flask-babel", "catalogFile") + ) + args = [ - "--domain={0}".format( - self.__project.getData("flask-babel", "domain")), + "--domain={0}".format(self.__project.getData("flask-babel", "domain")), "--input-file={0}".format(os.path.relpath(potFile, workdir)), "--output-dir={0}".format( - os.path.relpath(translationsDirectory, workdir)), + os.path.relpath(translationsDirectory, workdir) + ), ] if not withObsolete: args.append("--ignore-obsolete") - + dlg = PyBabelCommandDialog( - self, title, - msgSuccess=self.tr("\nMessage catalogs updated successfully.") + self, + title, + msgSuccess=self.tr("\nMessage catalogs updated successfully."), ) res = dlg.startCommand("update", args, workdir) if res: dlg.exec() - + def updateCatalogsObsolete(self, filenames): """ Public method to update the message catalogs keeping obsolete translations. - + @param filenames list of filenames (not used) @type list of str """ self.updateCatalogs(filenames, withObsolete=True) - + def updateSelectedCatalogs(self, filenames, withObsolete=False): """ Public method to update the selected message catalogs. - + @param filenames list of filenames @type list of str @param withObsolete flag indicating to keep obsolete translations @type bool """ title = self.tr("Updating message catalogs") - + locales = {self.__getLocale(f) for f in filenames} - + if len(locales) == 0: EricMessageBox.warning( - self.__ui, - title, - self.tr('No locales detected. Aborting...')) + self.__ui, title, self.tr("No locales detected. Aborting...") + ) return - + if self.__ensurePybabelConfigured(): workdir = self.__project.getApplication()[0] - translationsDirectory = ( - self.__ericProject.getAbsoluteUniversalPath( - self.__project.getData( - "flask-babel", "translationsDirectory") - ) + translationsDirectory = self.__ericProject.getAbsoluteUniversalPath( + self.__project.getData("flask-babel", "translationsDirectory") ) potFile = self.__ericProject.getAbsoluteUniversalPath( - self.__project.getData("flask-babel", "catalogFile")) + self.__project.getData("flask-babel", "catalogFile") + ) argsList = [] for loc in locales: args = [ "update", "--domain={0}".format( - self.__project.getData("flask-babel", "domain")), - "--input-file={0}".format( - os.path.relpath(potFile, workdir)), + self.__project.getData("flask-babel", "domain") + ), + "--input-file={0}".format(os.path.relpath(potFile, workdir)), "--output-dir={0}".format( - os.path.relpath(translationsDirectory, workdir)), + os.path.relpath(translationsDirectory, workdir) + ), "--locale={0}".format(loc), ] if not withObsolete: args.append("--ignore-obsolete") argsList.append(args) - + dlg = PyBabelCommandDialog( - self, title=title, - msgSuccess=self.tr("\nMessage catalogs updated successfully.") + self, + title=title, + msgSuccess=self.tr("\nMessage catalogs updated successfully."), ) res = dlg.startBatchCommand(argsList, workdir) if res: dlg.exec() - + def updateSelectedCatalogsObsolete(self, filenames): """ Public method to update the message catalogs keeping obsolete translations. - + @param filenames list of filenames (not used) @type list of str """
--- a/ProjectFlask/FlaskCommandDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskCommandDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -19,11 +19,11 @@ """ Class implementing a dialog to run a flask command and show its output. """ - def __init__(self, project, title="", msgSuccess="", msgError="", - parent=None): + + def __init__(self, project, title="", msgSuccess="", msgError="", parent=None): """ Constructor - + @param project reference to the project object @type Project @param title window title of the dialog @@ -37,27 +37,24 @@ """ super().__init__(parent) self.setupUi(self) - + if title: self.setWindowTitle(title) - + self.__project = project self.__successMessage = msgSuccess self.__errorMessage = msgError - + self.__process = None - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setDefault(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setEnabled(False) - + + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) + def startCommand(self, command, args=None): """ Public method to start a flask command and show its output. - + @param command flask command to be run @type str @param args list of command line arguments for the command @@ -69,54 +66,59 @@ workdir, env = self.__project.prepareRuntimeEnvironment() if env is not None: flaskCommand = self.__project.getFlaskCommand() - + self.__process = QProcess() self.__process.setProcessEnvironment(env) self.__process.setWorkingDirectory(workdir) self.__process.setProcessChannelMode( - QProcess.ProcessChannelMode.MergedChannels) - + QProcess.ProcessChannelMode.MergedChannels + ) + self.__process.readyReadStandardOutput.connect(self.__readStdOut) self.__process.finished.connect(self.__processFinished) - + self.outputEdit.clear() - + flaskArgs = [command] if args: flaskArgs += args - + self.__process.start(flaskCommand, flaskArgs) ok = self.__process.waitForStarted(10000) if not ok: EricMessageBox.critical( None, self.tr("Execute Flask Command"), - self.tr("""The Flask process could not be started.""")) + self.tr("""The Flask process could not be started."""), + ) else: - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(False) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled( + False + ) self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setDefault(True) + QDialogButtonBox.StandardButton.Cancel + ).setDefault(True) self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setFocus( - Qt.FocusReason.OtherFocusReason) + QDialogButtonBox.StandardButton.Cancel + ).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setFocus( + Qt.FocusReason.OtherFocusReason + ) else: ok = False - + return ok - + def closeEvent(self, evt): """ Protected method handling the close event of the dialog. - + @param evt reference to the close event object @type QCloseEvent """ self.__cancelProcess() evt.accept() - + @pyqtSlot() def __readStdOut(self): """ @@ -125,73 +127,63 @@ if self.__process is not None: out = str(self.__process.readAllStandardOutput(), "utf-8") self.outputEdit.insertPlainText(out) - + def __processFinished(self, exitCode, exitStatus): """ Private slot connected to the finished signal. - + @param exitCode exit code of the process @type int @param exitStatus exit status of the process @type QProcess.ExitStatus """ - self.__normal = ( - exitStatus == QProcess.ExitStatus.NormalExit and - exitCode == 0 - ) + self.__normal = exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0 self.__cancelProcess() - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setEnabled(False) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setDefault(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setFocus( - Qt.FocusReason.OtherFocusReason) - + + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus( + Qt.FocusReason.OtherFocusReason + ) + if self.__normal and self.__successMessage: self.outputEdit.insertPlainText(self.__successMessage) elif not self.__normal and self.__errorMessage: self.outputEdit.insertPlainText(self.__errorMessage) - + @pyqtSlot() def __cancelProcess(self): """ Private slot to terminate the current process. """ if ( - self.__process is not None and - self.__process.state() != QProcess.ProcessState.NotRunning + self.__process is not None + and self.__process.state() != QProcess.ProcessState.NotRunning ): self.__process.terminate() QTimer.singleShot(2000, self.__process.kill) self.__process.waitForFinished(3000) - + self.__process = None - + @pyqtSlot(QAbstractButton) def on_buttonBox_clicked(self, button): """ Private slot handling presses of the button box buttons. - + @param button reference to the button been clicked @type QAbstractButton """ - if button is self.buttonBox.button( - QDialogButtonBox.StandardButton.Close - ): + if button is self.buttonBox.button(QDialogButtonBox.StandardButton.Close): self.close() - elif button is self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel - ): + elif button is self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel): self.__cancelProcess() - + def normalExit(self): """ Public method to test, if the process ended without errors. - + @return flag indicating a normal process exit @rtype bool """
--- a/ProjectFlask/FlaskConfigDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskConfigDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -22,10 +22,11 @@ """ Class implementing a dialog to configure project specific flask settings. """ + def __init__(self, configuration, project, parent=None): """ Constructor - + @param configuration current project specific configuration @type dict @param project reference to the flask project object @@ -35,105 +36,102 @@ """ super().__init__(parent) self.setupUi(self) - - self.newEnvironmentButton.setIcon( - UI.PixmapCache.getIcon("virtualenvConfig")) - + + self.newEnvironmentButton.setIcon(UI.PixmapCache.getIcon("virtualenvConfig")) + self.__project = project - + self.__virtualEnvManager = ericApp().getObject("VirtualEnvManager") - + self.virtualEnvironmentComboBox.addItem("") self.virtualEnvironmentComboBox.addItems( - sorted(self.__virtualEnvManager.getVirtualenvNames( - noRemote=True, noConda=True - )) + sorted( + self.__virtualEnvManager.getVirtualenvNames(noRemote=True, noConda=True) + ) ) - + if "virtual_environment_name" in configuration: self.virtualEnvironmentComboBox.setCurrentText( - configuration["virtual_environment_name"]) - self.flaskBabelBox.setChecked( - configuration.get("flask_babel_override", False)) + configuration["virtual_environment_name"] + ) + self.flaskBabelBox.setChecked(configuration.get("flask_babel_override", False)) self.flaskBabelCheckBox.setChecked( - configuration.get("flask_babel_available", False)) + configuration.get("flask_babel_available", False) + ) self.flaskMigrateBox.setChecked( - configuration.get("flask_migrate_override", False)) + configuration.get("flask_migrate_override", False) + ) self.flaskMigrateCheckBox.setChecked( - configuration.get("flask_migrate_available", False)) - + configuration.get("flask_migrate_available", False) + ) + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) - + def getConfiguration(self): """ Public method to get the entered configuration data. - + @return project specific configuration @rtype dict """ configuration = { - "virtual_environment_name": - self.virtualEnvironmentComboBox.currentText(), - "flask_babel_override": - self.flaskBabelBox.isChecked(), - "flask_babel_available": - self.flaskBabelCheckBox.isChecked(), - "flask_migrate_override": - self.flaskMigrateBox.isChecked(), - "flask_migrate_available": - self.flaskMigrateCheckBox.isChecked(), + "virtual_environment_name": self.virtualEnvironmentComboBox.currentText(), + "flask_babel_override": self.flaskBabelBox.isChecked(), + "flask_babel_available": self.flaskBabelCheckBox.isChecked(), + "flask_migrate_override": self.flaskMigrateBox.isChecked(), + "flask_migrate_available": self.flaskMigrateCheckBox.isChecked(), } - + return configuration - + @pyqtSlot() def on_newEnvironmentButton_clicked(self): """ Private slot to open a dialog for adding a new virtual environment. """ from .FlaskVirtualenvConfigurationDialog import ( - FlaskVirtualenvConfigurationDialog + FlaskVirtualenvConfigurationDialog, ) - + ericProject = ericApp().getObject("Project") dlg = FlaskVirtualenvConfigurationDialog( - ericProject.getProjectPath(), - ericProject.getProjectName(), - self) + ericProject.getProjectPath(), ericProject.getProjectName(), self + ) if dlg.exec() == QDialog.DialogCode.Accepted: resultDict = dlg.getData() - + # now do the call from VirtualEnv.VirtualenvExecDialog import VirtualenvExecDialog - dia = VirtualenvExecDialog( - resultDict, self.__virtualEnvManager, self) + + dia = VirtualenvExecDialog(resultDict, self.__virtualEnvManager, self) dia.show() dia.start(resultDict["arguments"]) dia.exec() - + self.virtualEnvironmentComboBox.clear() self.virtualEnvironmentComboBox.addItem("") self.virtualEnvironmentComboBox.addItems( - sorted(self.__virtualEnvManager.getVirtualenvNames( - noRemote=True, noConda=True - )) + sorted( + self.__virtualEnvManager.getVirtualenvNames( + noRemote=True, noConda=True + ) + ) ) - - self.virtualEnvironmentComboBox.setCurrentText( - resultDict["logicalName"]) - + + self.virtualEnvironmentComboBox.setCurrentText(resultDict["logicalName"]) + self.__installFlask(resultDict["targetDirectory"]) - + def __installFlask(self, venvDir): """ Private method to install flask into the newly created environment. - + @param venvDir directory containing the virtual environment @type str """ from PipInterface.PipDialog import PipDialog - + interpreter = self.__project.getFullCommand("python", venvDir) if Preferences.getPip("PipSearchIndex"): indexUrl = Preferences.getPip("PipSearchIndex") + "/simple" @@ -141,7 +139,7 @@ else: args = ["-m", "pip", "install"] args.append("flask") - dia = PipDialog(self.tr('Install Flask'), self) + dia = PipDialog(self.tr("Install Flask"), self) res = dia.startProcess(interpreter, args) if res: dia.exec()
--- a/ProjectFlask/FlaskMigrateExtension/FlaskMigrateDetector.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskMigrateExtension/FlaskMigrateDetector.py Wed Sep 21 16:30:15 2022 +0200 @@ -11,9 +11,10 @@ if __name__ == "__main__": try: - import flask_migrate # __IGNORE_EXCEPTION__ __IGNORE_WARNING__ + import flask_migrate # __IGNORE_EXCEPTION__ __IGNORE_WARNING__ + ret = 0 except ImportError: ret = 1 - + sys.exit(ret)
--- a/ProjectFlask/FlaskMigrateExtension/MigrateConfigDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskMigrateExtension/MigrateConfigDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -20,10 +20,11 @@ """ Class implementing a dialog to edit the flask-migrate configuration. """ + def __init__(self, configuration, parent=None): """ Constructor - + @param configuration current pybabel configuration @type dict @param parent reference to the parent widget @@ -31,38 +32,40 @@ """ super().__init__(parent) self.setupUi(self) - + self.__ericProject = ericApp().getObject("Project") - - self.migrationsDirectoryPicker.setMode( - EricPathPickerModes.DIRECTORY_MODE) + + self.migrationsDirectoryPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) self.migrationsDirectoryPicker.setDefaultDirectory( - self.__ericProject.getProjectPath()) - - self.migrationsDirectoryPicker.setFocus( - Qt.FocusReason.OtherFocusReason) - + self.__ericProject.getProjectPath() + ) + + self.migrationsDirectoryPicker.setFocus(Qt.FocusReason.OtherFocusReason) + if ( - "migrationsDirectory" in configuration and - configuration["migrationsDirectory"] + "migrationsDirectory" in configuration + and configuration["migrationsDirectory"] ): self.migrationsDirectoryPicker.setText( self.__ericProject.getAbsoluteUniversalPath( - configuration["migrationsDirectory"])) - + configuration["migrationsDirectory"] + ) + ) + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) - + def getConfiguration(self): """ Public method to get the entered configuration data. - + @return pybabel configuration @rtype dict """ configuration = { "migrationsDirectory": self.__ericProject.getRelativeUniversalPath( - self.migrationsDirectoryPicker.text()), + self.migrationsDirectoryPicker.text() + ), } - + return configuration
--- a/ProjectFlask/FlaskMigrateExtension/MigrateProjectExtension.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskMigrateExtension/MigrateProjectExtension.py Wed Sep 21 16:30:15 2022 +0200 @@ -27,10 +27,11 @@ """ Class implementing the flask-migrate project support. """ + def __init__(self, plugin, project, parent=None): """ Constructor - + @param plugin reference to the plugin object @type ProjectFlaskPlugin @param project reference to the project object @@ -39,188 +40,235 @@ @type QObject """ super().__init__(parent) - + self.__plugin = plugin self.__project = project - + self.__ericProject = ericApp().getObject("Project") - + self.__migrationSummaryDialog = None - + def initActions(self): """ Public method to define the flask-migrate actions. """ self.actions = [] - + self.migrateConfigAct = EricAction( - self.tr('Configure Migrate'), - self.tr('C&onfigure Migrate'), - 0, 0, - self, 'flask_config_migrate') - self.migrateConfigAct.setStatusTip(self.tr( - 'Shows a dialog to edit the configuration for flask-migrate')) - self.migrateConfigAct.setWhatsThis(self.tr( - """<b>Configure Migrate</b>""" - """<p>Shows a dialog to edit the configuration for""" - """ flask-migrate.</p>""" - )) - self.migrateConfigAct.triggered.connect( - self.__configureMigrate) + self.tr("Configure Migrate"), + self.tr("C&onfigure Migrate"), + 0, + 0, + self, + "flask_config_migrate", + ) + self.migrateConfigAct.setStatusTip( + self.tr("Shows a dialog to edit the configuration for flask-migrate") + ) + self.migrateConfigAct.setWhatsThis( + self.tr( + """<b>Configure Migrate</b>""" + """<p>Shows a dialog to edit the configuration for""" + """ flask-migrate.</p>""" + ) + ) + self.migrateConfigAct.triggered.connect(self.__configureMigrate) self.actions.append(self.migrateConfigAct) - + self.migrateInstallAct = EricAction( - self.tr('Install flask-migrate'), - self.tr('Install &flask-migrate'), - 0, 0, - self, 'flask_install_migrate') - self.migrateInstallAct.setStatusTip(self.tr( - 'Installs the flask-migrate extension into the configured' - ' environment')) - self.migrateInstallAct.setWhatsThis(self.tr( - """<b>Install flask-migrate</b>""" - """<p>Installs the flask-migrate extension into the configured""" - """ environment using the pip interface.</p>""" - )) - self.migrateInstallAct.triggered.connect( - self.__installFlaskMigrate) + self.tr("Install flask-migrate"), + self.tr("Install &flask-migrate"), + 0, + 0, + self, + "flask_install_migrate", + ) + self.migrateInstallAct.setStatusTip( + self.tr( + "Installs the flask-migrate extension into the configured" + " environment" + ) + ) + self.migrateInstallAct.setWhatsThis( + self.tr( + """<b>Install flask-migrate</b>""" + """<p>Installs the flask-migrate extension into the configured""" + """ environment using the pip interface.</p>""" + ) + ) + self.migrateInstallAct.triggered.connect(self.__installFlaskMigrate) self.actions.append(self.migrateInstallAct) - + self.migrateAvailabilityAct = EricAction( - self.tr('Check flask-migrate Availability'), - self.tr('Check flask-migrate &Availability'), - 0, 0, - self, 'flask_check_migrate') - self.migrateAvailabilityAct.setStatusTip(self.tr( - 'Check the availability of the flask-migrate extension')) - self.migrateAvailabilityAct.setWhatsThis(self.tr( - """<b>Check flask-migrate Availability</b>""" - """<p>Check the availability of the flask-migrate extension.</p>""" - )) - self.migrateAvailabilityAct.triggered.connect( - self.__checkAvailability) + self.tr("Check flask-migrate Availability"), + self.tr("Check flask-migrate &Availability"), + 0, + 0, + self, + "flask_check_migrate", + ) + self.migrateAvailabilityAct.setStatusTip( + self.tr("Check the availability of the flask-migrate extension") + ) + self.migrateAvailabilityAct.setWhatsThis( + self.tr( + """<b>Check flask-migrate Availability</b>""" + """<p>Check the availability of the flask-migrate extension.</p>""" + ) + ) + self.migrateAvailabilityAct.triggered.connect(self.__checkAvailability) self.actions.append(self.migrateAvailabilityAct) - + ######################################################### ## action to initialize the database migration system ######################################################### - + self.migrateInitAct = EricAction( - self.tr('Initialize Migrations'), - self.tr('&Initialize Migrations'), - 0, 0, - self, 'flask_init_migrations') - self.migrateInitAct.setStatusTip(self.tr( - 'Initialize support for database migrations')) - self.migrateInitAct.setWhatsThis(self.tr( - """<b>Initialize Migrations</b>""" - """<p>Initializes the support for database migrations to be""" - """ stored in the configured migrations directory.</p>""" - )) - self.migrateInitAct.triggered.connect( - self.__initMigrations) + self.tr("Initialize Migrations"), + self.tr("&Initialize Migrations"), + 0, + 0, + self, + "flask_init_migrations", + ) + self.migrateInitAct.setStatusTip( + self.tr("Initialize support for database migrations") + ) + self.migrateInitAct.setWhatsThis( + self.tr( + """<b>Initialize Migrations</b>""" + """<p>Initializes the support for database migrations to be""" + """ stored in the configured migrations directory.</p>""" + ) + ) + self.migrateInitAct.triggered.connect(self.__initMigrations) self.actions.append(self.migrateInitAct) - + ######################################################### ## action to create a new database migration ######################################################### - + self.migrateCreateAct = EricAction( - self.tr('Create Migration'), - self.tr('&Create Migration'), - 0, 0, - self, 'flask_create_migration') - self.migrateCreateAct.setStatusTip(self.tr( - 'Create a new migration for the current database')) - self.migrateCreateAct.setWhatsThis(self.tr( - """<b>Create Migration</b>""" - """<p>Creates a new migration for the current database""" - """ and stores it in the configured migrations directory.</p>""" - )) - self.migrateCreateAct.triggered.connect( - self.__createMigration) + self.tr("Create Migration"), + self.tr("&Create Migration"), + 0, + 0, + self, + "flask_create_migration", + ) + self.migrateCreateAct.setStatusTip( + self.tr("Create a new migration for the current database") + ) + self.migrateCreateAct.setWhatsThis( + self.tr( + """<b>Create Migration</b>""" + """<p>Creates a new migration for the current database""" + """ and stores it in the configured migrations directory.</p>""" + ) + ) + self.migrateCreateAct.triggered.connect(self.__createMigration) self.actions.append(self.migrateCreateAct) - + ######################################################### ## action to up- and downgrade a databse ######################################################### - + self.upgradeDatabaseAct = EricAction( - self.tr('Upgrade Database'), - self.tr('&Upgrade Database'), - 0, 0, - self, 'flask_upgrade_database') - self.upgradeDatabaseAct.setStatusTip(self.tr( - 'Upgrade the database to the current migration')) - self.upgradeDatabaseAct.setWhatsThis(self.tr( - """<b>Upgrade Database</b>""" - """<p>Upgrades the database to the current migration.</p>""" - )) - self.upgradeDatabaseAct.triggered.connect( - self.upgradeDatabase) + self.tr("Upgrade Database"), + self.tr("&Upgrade Database"), + 0, + 0, + self, + "flask_upgrade_database", + ) + self.upgradeDatabaseAct.setStatusTip( + self.tr("Upgrade the database to the current migration") + ) + self.upgradeDatabaseAct.setWhatsThis( + self.tr( + """<b>Upgrade Database</b>""" + """<p>Upgrades the database to the current migration.</p>""" + ) + ) + self.upgradeDatabaseAct.triggered.connect(self.upgradeDatabase) self.actions.append(self.upgradeDatabaseAct) - + self.downgradeDatabaseAct = EricAction( - self.tr('Downgrade Database'), - self.tr('&Downgrade Database'), - 0, 0, - self, 'flask_downgrade_database') - self.downgradeDatabaseAct.setStatusTip(self.tr( - 'Downgrade the database to the previous version')) - self.downgradeDatabaseAct.setWhatsThis(self.tr( - """<b>Downgrade Database</b>""" - """<p>Downgrades the database to the previous version.</p>""" - )) - self.downgradeDatabaseAct.triggered.connect( - self.downgradeDatabase) + self.tr("Downgrade Database"), + self.tr("&Downgrade Database"), + 0, + 0, + self, + "flask_downgrade_database", + ) + self.downgradeDatabaseAct.setStatusTip( + self.tr("Downgrade the database to the previous version") + ) + self.downgradeDatabaseAct.setWhatsThis( + self.tr( + """<b>Downgrade Database</b>""" + """<p>Downgrades the database to the previous version.</p>""" + ) + ) + self.downgradeDatabaseAct.triggered.connect(self.downgradeDatabase) self.actions.append(self.downgradeDatabaseAct) - + ######################################################### ## actions to show migrations history information ######################################################### - + self.migrationSummaryAct = EricAction( - self.tr('Show Migrations Summary'), - self.tr('Show Migrations &Summary'), - 0, 0, - self, 'flask_show_migrations_summary') - self.migrationSummaryAct.setStatusTip(self.tr( - 'Show a summary of the created database migrations')) - self.migrationSummaryAct.setWhatsThis(self.tr( - """<b>Show Migrations Summary</b>""" - """<p>Shows a summary list of the created database""" - """ migrations.</p>""" - )) - self.migrationSummaryAct.triggered.connect( - self.__showMigrationsSummary) + self.tr("Show Migrations Summary"), + self.tr("Show Migrations &Summary"), + 0, + 0, + self, + "flask_show_migrations_summary", + ) + self.migrationSummaryAct.setStatusTip( + self.tr("Show a summary of the created database migrations") + ) + self.migrationSummaryAct.setWhatsThis( + self.tr( + """<b>Show Migrations Summary</b>""" + """<p>Shows a summary list of the created database""" + """ migrations.</p>""" + ) + ) + self.migrationSummaryAct.triggered.connect(self.__showMigrationsSummary) self.actions.append(self.migrationSummaryAct) - + self.migrationHistoryAct = EricAction( - self.tr('Show Migrations History'), - self.tr('Show Migrations &History'), - 0, 0, - self, 'flask_show_migrations_history') - self.migrationHistoryAct.setStatusTip(self.tr( - 'Show the full history of the created database migrations')) - self.migrationHistoryAct.setWhatsThis(self.tr( - """<b>Show Migrations History</b>""" - """<p>Shows the full history of the created database""" - """ migrations.</p>""" - )) - self.migrationHistoryAct.triggered.connect( - self.__showMigrationsHistory) + self.tr("Show Migrations History"), + self.tr("Show Migrations &History"), + 0, + 0, + self, + "flask_show_migrations_history", + ) + self.migrationHistoryAct.setStatusTip( + self.tr("Show the full history of the created database migrations") + ) + self.migrationHistoryAct.setWhatsThis( + self.tr( + """<b>Show Migrations History</b>""" + """<p>Shows the full history of the created database""" + """ migrations.</p>""" + ) + ) + self.migrationHistoryAct.triggered.connect(self.__showMigrationsHistory) self.actions.append(self.migrationHistoryAct) - + def initMenu(self): """ Public method to initialize the flask-migrate menu. - + @return the menu generated @rtype QMenu """ menu = QMenu(self.tr("Database")) menu.setTearOffEnabled(True) - + menu.addAction(self.migrateConfigAct) menu.addSeparator() menu.addAction(self.migrateInitAct) @@ -235,84 +283,83 @@ menu.addSeparator() menu.addAction(self.migrateAvailabilityAct) menu.addAction(self.migrateInstallAct) - + return menu - + def determineCapability(self): """ Public method to determine the availability of flask-migrate. """ available = ( self.__project.getData("flask", "flask_migrate_available") - if self.__project.getData("flask", "flask_migrate_override") else - self.__flaskMigrateAvailable() + if self.__project.getData("flask", "flask_migrate_override") + else self.__flaskMigrateAvailable() ) self.__project.setCapability("flask-migrate", available) - + self.migrateInstallAct.setEnabled(not available) - + for act in ( - self.migrateConfigAct, self.migrateInitAct, + self.migrateConfigAct, + self.migrateInitAct, self.migrateCreateAct, - self.upgradeDatabaseAct, self.downgradeDatabaseAct, - self.migrationSummaryAct, self.migrationHistoryAct, + self.upgradeDatabaseAct, + self.downgradeDatabaseAct, + self.migrationSummaryAct, + self.migrationHistoryAct, ): act.setEnabled(available) - + def __flaskMigrateAvailable(self): """ Private method to check, if the 'flask-babel' package is available. - + @return flag indicating the availability of 'flask-babel' @rtype bool """ interpreter = self.__project.getVirtualenvInterpreter() if interpreter and Utilities.isinpath(interpreter): detector = os.path.join( - os.path.dirname(__file__), "FlaskMigrateDetector.py") + os.path.dirname(__file__), "FlaskMigrateDetector.py" + ) proc = QProcess() - proc.setProcessChannelMode( - QProcess.ProcessChannelMode.MergedChannels) + proc.setProcessChannelMode(QProcess.ProcessChannelMode.MergedChannels) proc.start(interpreter, [detector]) finished = proc.waitForFinished(30000) if finished and proc.exitCode() == 0: return True - + return False - + def __migrationsDirectory(self, abspath=False): """ Private method to calculate the path of the configured migrations directory. - + @param abspath flag indicating to return an absolute path @type bool @return path of the migrations directory @rtype str """ migrations = "" - + self.__ensureMigrateConfigured() - - migrations = self.__project.getData("flask-migrate", - "migrationsDirectory") + + migrations = self.__project.getData("flask-migrate", "migrationsDirectory") if migrations: if abspath: - migrations = self.__ericProject.getAbsoluteUniversalPath( - migrations) + migrations = self.__ericProject.getAbsoluteUniversalPath(migrations) else: workdir = self.__project.getApplication()[0] migrations = os.path.relpath( - self.__ericProject.getAbsoluteUniversalPath(migrations), - workdir + self.__ericProject.getAbsoluteUniversalPath(migrations), workdir ) else: if abspath: - migrations = self.__ericProject.getAbsoluteUniversalPath( - "migrations") - + migrations = self.__ericProject.getAbsoluteUniversalPath("migrations") + return migrations - + def projectClosed(self): """ Public method to handle the closing of a project. @@ -320,24 +367,24 @@ for dlg in (self.__migrationSummaryDialog,): if dlg is not None: dlg.close() - + ######################################################## ## Menu related slots below ######################################################## - + @pyqtSlot() def __configureMigrate(self): """ Private slot to show a dialog to edit the migrate configuration. """ from .MigrateConfigDialog import MigrateConfigDialog - + config = self.__project.getData("flask-migrate", "") dlg = MigrateConfigDialog(config) if dlg.exec() == QDialog.DialogCode.Accepted: config = dlg.getConfiguration() self.__project.setData("flask-migrate", "", config) - + def __ensureMigrateConfigured(self): """ Private method to ensure, that flask-migrate has been configured. @@ -345,7 +392,7 @@ config = self.__project.getData("flask-migrate", "") if not config: self.__configureMigrate() - + @pyqtSlot() def __installFlaskMigrate(self): """ @@ -362,10 +409,13 @@ EricMessageBox.critical( None, self.tr("Install flask-migrate"), - self.tr("The 'flask-migrate' extension could not be installed" - " because no virtual environment has been" - " configured.")) - + self.tr( + "The 'flask-migrate' extension could not be installed" + " because no virtual environment has been" + " configured." + ), + ) + @pyqtSlot() def __checkAvailability(self): """ @@ -374,43 +424,43 @@ self.determineCapability() msg = ( self.tr("The 'flask-migrate' extension is installed.") - if self.__project.hasCapability("flask-migrate") else - self.tr("The 'flask-migrate' extension is not installed.") + if self.__project.hasCapability("flask-migrate") + else self.tr("The 'flask-migrate' extension is not installed.") ) - EricMessageBox.information( - None, - self.tr("flask-migrate Availability"), - msg) - + EricMessageBox.information(None, self.tr("flask-migrate Availability"), msg) + ######################################################### ## slot to initialize the database migration system ######################################################### - + @pyqtSlot() def __initMigrations(self): """ Private slot to initialize the database migration system. """ title = self.tr("Initialize Migrations") - + self.__ensureMigrateConfigured() migrations = self.__migrationsDirectory() - + args = ["init"] if migrations: args += ["--directory", migrations] - + multidb = EricMessageBox.yesNo( None, self.tr("Multiple Databases"), - self.tr("""Shall the support for multiple databases be""" - """ activated?""")) + self.tr( + """Shall the support for multiple databases be""" """ activated?""" + ), + ) if multidb: args.append("--multidb") - + dlg = FlaskCommandDialog( - self.__project, title=title, - msgSuccess=self.tr("\nMigrations initialized successfully.") + self.__project, + title=title, + msgSuccess=self.tr("\nMigrations initialized successfully."), ) if dlg.startCommand("db", args): dlg.exec() @@ -421,144 +471,149 @@ for fileName in files: fullName = os.path.join(root, fileName) self.__ericProject.appendFile(fullName) - - browser = (ericApp().getObject("ProjectBrowser") - .getProjectBrowser("others")) + + browser = ( + ericApp().getObject("ProjectBrowser").getProjectBrowser("others") + ) alembic = os.path.join( - self.__migrationsDirectory(abspath=True), - "alembic.ini" + self.__migrationsDirectory(abspath=True), "alembic.ini" ) browser.sourceFile.emit(alembic) - + ######################################################### ## slot to create a new database migration ######################################################### - + @pyqtSlot() def __createMigration(self): """ Private slot to create a new database migration. """ title = self.tr("Create Migration") - + self.__ensureMigrateConfigured() migrations = self.__migrationsDirectory() - + message, ok = QInputDialog.getText( None, title, self.tr("Enter a short message for the migration:"), - QLineEdit.EchoMode.Normal) + QLineEdit.EchoMode.Normal, + ) if ok: args = ["migrate"] if migrations: args += ["--directory", migrations] if message: args += ["--message", message] - + dlg = FlaskCommandDialog( - self.__project, title=title, - msgSuccess=self.tr("\nMigration created successfully.") + self.__project, + title=title, + msgSuccess=self.tr("\nMigration created successfully."), ) if dlg.startCommand("db", args): dlg.exec() if dlg.normalExit(): versionsPattern = os.path.join( - self.__migrationsDirectory(abspath=True), - "versions", "*.py") + self.__migrationsDirectory(abspath=True), "versions", "*.py" + ) for fileName in glob.iglob(versionsPattern): self.__ericProject.appendFile(fileName) - + ######################################################### ## slots to up- and downgrade a databse ######################################################### - + @pyqtSlot() def upgradeDatabase(self, revision=None): """ Public slot to upgrade the database to the current migration. - + @param revision migration revision to upgrade to @type str """ title = self.tr("Upgrade Database") - + self.__ensureMigrateConfigured() migrations = self.__migrationsDirectory() - + args = ["upgrade"] if migrations: args += ["--directory", migrations] if revision: args.append(revision) - + dlg = FlaskCommandDialog( - self.__project, title=title, - msgSuccess=self.tr("\nDatabase upgraded successfully.") + self.__project, + title=title, + msgSuccess=self.tr("\nDatabase upgraded successfully."), ) if dlg.startCommand("db", args): dlg.exec() - + @pyqtSlot() def downgradeDatabase(self, revision=None): """ Public slot to downgrade the database to the previous version. - + @param revision migration revision to downgrade to @type str """ title = self.tr("Downgrade Database") - + self.__ensureMigrateConfigured() migrations = self.__migrationsDirectory() - + args = ["downgrade"] if migrations: args += ["--directory", migrations] if revision: args.append(revision) - + dlg = FlaskCommandDialog( - self.__project, title=title, - msgSuccess=self.tr("\nDatabase downgraded successfully.") + self.__project, + title=title, + msgSuccess=self.tr("\nDatabase downgraded successfully."), ) if dlg.startCommand("db", args): dlg.exec() - + ######################################################### ## slots to show migrations history information ######################################################### - + @pyqtSlot() def __showMigrationsSummary(self): """ Private slot to show a migrations history summary. """ from .MigrateSummaryDialog import MigrateSummaryDialog - + self.__ensureMigrateConfigured() migrations = self.__migrationsDirectory() - + if self.__migrationSummaryDialog is None: self.__migrationSummaryDialog = MigrateSummaryDialog( - self.__project, self, migrations=migrations) - + self.__project, self, migrations=migrations + ) + self.__migrationSummaryDialog.showSummary() - + @pyqtSlot() def __showMigrationsHistory(self): """ Private slot to show the full migrations history. """ title = self.tr("Migrations History") - + self.__ensureMigrateConfigured() migrations = self.__migrationsDirectory() - + args = ["history", "--indicate-current", "--verbose"] if migrations: args += ["--directory", migrations] - + dlg = FlaskCommandDialog(self.__project, title=title) if dlg.startCommand("db", args): dlg.exec()
--- a/ProjectFlask/FlaskMigrateExtension/MigrateSummaryDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskMigrateExtension/MigrateSummaryDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -10,8 +10,11 @@ from PyQt6.QtCore import pyqtSlot, Qt, QProcess, QEventLoop, QTimer from PyQt6.QtGui import QGuiApplication from PyQt6.QtWidgets import ( - QDialog, QDialogButtonBox, QAbstractButton, QTreeWidgetItem, - QAbstractItemView + QDialog, + QDialogButtonBox, + QAbstractButton, + QTreeWidgetItem, + QAbstractItemView, ) from EricGui.EricOverrideCursor import EricOverrideCursor, EricOverridenCursor @@ -24,10 +27,11 @@ """ Class implementing a dialog showing a summary of all created.migrations. """ + def __init__(self, project, migrateProject, migrations="", parent=None): """ Constructor - + @param project reference to the project object @type Project @param migrateProject reference to the migrate project extension @@ -39,19 +43,20 @@ """ super().__init__(parent) self.setupUi(self) - + self.__refreshButton = self.buttonBox.addButton( - self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole) + self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole + ) self.__refreshButton.clicked.connect(self.showSummary) - + self.__project = project self.__migrateProject = migrateProject self.__migrations = migrations - + self.__process = None self.__currentItemIndex = 1000000 self.__currentRevision = "" - + def showSummary(self): """ Public method to show the migrations summary. @@ -60,37 +65,40 @@ if env is not None: self.show() self.raise_() - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(False) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setDefault(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setFocus( - Qt.FocusReason.OtherFocusReason) + + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled( + False + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault( + True + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled( + True + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setFocus( + Qt.FocusReason.OtherFocusReason + ) QGuiApplication.processEvents( - QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) - + QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents + ) + command = self.__project.getFlaskCommand() - + self.__process = QProcess() self.__process.setProcessEnvironment(env) self.__process.setWorkingDirectory(workdir) - + args = ["db", "history", "--indicate-current"] if self.__migrations: args += ["--directory", self.__migrations] - + with EricOverrideCursor(): self.__process.start(command, args) ok = self.__process.waitForStarted(10000) if ok: ok = self.__process.waitForFinished(10000) if ok: - out = str(self.__process.readAllStandardOutput(), - "utf-8") + out = str(self.__process.readAllStandardOutput(), "utf-8") self.__processOutput(out) self.__selectItem(self.__currentRevision) else: @@ -98,33 +106,41 @@ EricMessageBox.critical( None, self.tr("Migrations Summary"), - self.tr("""The Flask process did not finish""" - """ within 10 seconds.""")) + self.tr( + """The Flask process did not finish""" + """ within 10 seconds.""" + ), + ) else: with EricOverridenCursor(): EricMessageBox.critical( None, self.tr("Migrations Summary"), - self.tr("""The Flask process could not be""" - """ started.""")) + self.tr( + """The Flask process could not be""" """ started.""" + ), + ) for column in range(self.summaryWidget.columnCount()): self.summaryWidget.resizeColumnToContents(column) - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setEnabled(False) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setDefault(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setFocus( - Qt.FocusReason.OtherFocusReason) - + + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled( + False + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled( + True + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault( + True + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus( + Qt.FocusReason.OtherFocusReason + ) + def __processOutput(self, output): """ Private method to process the flask output and populate the summary list. - + @param output output of the flask process @type str """ @@ -132,7 +148,7 @@ self.upDownButton.setEnabled(False) self.__currentItemIndex = 1000000 self.__currentRevision = "" - + lines = output.splitlines() for line in lines: isCurrent = False @@ -141,32 +157,32 @@ newRev, *labels = rest.split() if labels: labelList = [ - label.replace("(", "").replace(")", "") - for label in labels + label.replace("(", "").replace(")", "") for label in labels ] labelsStr = ", ".join(labelList) if "current" in labelList: isCurrent = True else: labelsStr = "" - - itm = QTreeWidgetItem(self.summaryWidget, [ - oldRev.strip(), - newRev.strip(), - message.strip(), - labelsStr, - ]) + + itm = QTreeWidgetItem( + self.summaryWidget, + [ + oldRev.strip(), + newRev.strip(), + message.strip(), + labelsStr, + ], + ) if isCurrent: font = itm.font(0) font.setBold(True) for column in range(self.summaryWidget.columnCount()): itm.setFont(column, font) - - self.__currentItemIndex = ( - self.summaryWidget.indexOfTopLevelItem(itm) - ) + + self.__currentItemIndex = self.summaryWidget.indexOfTopLevelItem(itm) self.__currentRevision = newRev.strip() - + @pyqtSlot() def on_summaryWidget_itemSelectionChanged(self): """ @@ -182,7 +198,7 @@ self.upDownButton.setEnabled(index != self.__currentItemIndex) else: self.upDownButton.setEnabled(False) - + @pyqtSlot() def on_upDownButton_clicked(self): """ @@ -195,47 +211,45 @@ else: self.__migrateProject.downgradeDatabase(revision=rev) self.showSummary() - + @pyqtSlot(QAbstractButton) def on_buttonBox_clicked(self, button): """ Private slot handling a button press of the button box. - + @param button reference to the pressed button @type QAbstractButton """ - if button is self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel - ): + if button is self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel): self.__cancelProcess() - + @pyqtSlot() def __cancelProcess(self): """ Private slot to terminate the current process. """ if ( - self.__process is not None and - self.__process.state() != QProcess.ProcessState.NotRunning + self.__process is not None + and self.__process.state() != QProcess.ProcessState.NotRunning ): self.__process.terminate() QTimer.singleShot(2000, self.__process.kill) self.__process.waitForFinished(3000) - + self.__process = None - + def __selectItem(self, revision): """ Private method to select an item given its revision. - + @param revision revision of the item to select @type str """ if revision: - items = self.summaryWidget.findItems( - revision, Qt.MatchFlag.MatchExactly, 1) + items = self.summaryWidget.findItems(revision, Qt.MatchFlag.MatchExactly, 1) if items: # select the first item items[0].setSelected(True) self.summaryWidget.scrollToItem( - items[0], QAbstractItemView.ScrollHint.PositionAtCenter) + items[0], QAbstractItemView.ScrollHint.PositionAtCenter + )
--- a/ProjectFlask/FlaskVirtualenvConfigurationDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FlaskVirtualenvConfigurationDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -16,9 +16,7 @@ from EricWidgets.EricPathPicker import EricPathPickerModes -from .Ui_FlaskVirtualenvConfigurationDialog import ( - Ui_FlaskVirtualenvConfigurationDialog -) +from .Ui_FlaskVirtualenvConfigurationDialog import Ui_FlaskVirtualenvConfigurationDialog import Utilities @@ -29,14 +27,15 @@ """ Class implementing a dialog to configure a project specific virtual environment. - + Note: This dialog is a simplified variant of the one found in the eric package. """ + def __init__(self, projectPath, projectName, parent=None): """ Constructor - + @param projectPath directory path of the project @type str @param projectName name of the project @@ -46,79 +45,79 @@ """ super().__init__(parent) self.setupUi(self) - + self.targetDirectoryPicker.setMode(EricPathPickerModes.DIRECTORY_MODE) self.targetDirectoryPicker.setWindowTitle( - self.tr("Virtualenv Target Directory")) + self.tr("Virtualenv Target Directory") + ) self.targetDirectoryPicker.setDefaultDirectory(projectPath) - + self.pythonExecPicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) - self.pythonExecPicker.setWindowTitle( - self.tr("Python Interpreter")) + self.pythonExecPicker.setWindowTitle(self.tr("Python Interpreter")) self.pythonExecPicker.setDefaultDirectory( - sys.executable.replace("w.exe", ".exe")) - + sys.executable.replace("w.exe", ".exe") + ) + mandatoryStyleSheet = "QLineEdit {border: 2px solid;}" self.targetDirectoryPicker.setStyleSheet(mandatoryStyleSheet) self.nameEdit.setStyleSheet(mandatoryStyleSheet) - + # pre-populate some fields self.nameEdit.setText("Project {0}".format(projectName)) self.targetDirectoryPicker.setText(os.path.join(projectPath, "venv")) - + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) - + def __updateOK(self): """ Private method to update the enabled status of the OK button. """ self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled( - bool(self.targetDirectoryPicker.text()) and - bool(self.nameEdit.text()) + bool(self.targetDirectoryPicker.text()) and bool(self.nameEdit.text()) ) - + @pyqtSlot(str) def on_nameEdit_textChanged(self, txt): """ Private slot handling a change of the virtual environment name. - + @param txt name of the virtual environment @type str """ self.__updateOK() - + @pyqtSlot(str) def on_targetDirectoryPicker_textChanged(self, txt): """ Private slot handling a change of the target directory. - + @param txt target directory @type str """ self.__updateOK() - + def __generateTargetDir(self): """ Private method to generate a valid target directory path. - + @return target directory path @rtype str """ targetDirectory = Utilities.toNativeSeparators( - self.targetDirectoryPicker.text()) + self.targetDirectoryPicker.text() + ) if not os.path.isabs(targetDirectory): - targetDirectory = os.path.join(os.path.expanduser("~"), - targetDirectory) + targetDirectory = os.path.join(os.path.expanduser("~"), targetDirectory) return targetDirectory - + def getData(self): """ Public method to retrieve the dialog data. - + Note: This method returns a data structure compatible with the one returned by the eric virtual environment configuration dialog. - + @return dictionary containing the data for the environment to be created. The keys for both variants are 'arguments' containing the command line arguments, 'logicalName' containing the environment @@ -140,8 +139,7 @@ "createLog": False, "createScript": False, "targetDirectory": self.__generateTargetDir(), - "pythonExe": Utilities.toNativeSeparators( - self.pythonExecPicker.text()), + "pythonExe": Utilities.toNativeSeparators(self.pythonExecPicker.text()), } - + return resultDict
--- a/ProjectFlask/FormSelectionDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/FormSelectionDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -17,113 +17,116 @@ """ Class implementing a dialog to select the template type. """ + Templates = { "html5": { "title": QCoreApplication.translate( - "FormSelectionDialog", "Standard HTML 5 template"), - "template": '''<!DOCTYPE html>\n''' - ''' <head>\n''' - ''' <title></title>\n''' - ''' <style>\n''' - ''' </style>\n''' - ''' </head>\n''' - '''\n''' - ''' <body>\n''' - ''' </body>\n''' - '''</html>\n''', + "FormSelectionDialog", "Standard HTML 5 template" + ), + "template": """<!DOCTYPE html>\n""" + """ <head>\n""" + """ <title></title>\n""" + """ <style>\n""" + """ </style>\n""" + """ </head>\n""" + """\n""" + """ <body>\n""" + """ </body>\n""" + """</html>\n""", }, "basic_jinja": { "title": QCoreApplication.translate( - "FormSelectionDialog", "Basic Jinja template"), - "template": '''<!DOCTYPE html>\n''' - ''' <head>\n''' - ''' {% if title %}\n''' - ''' <title>{{ title }}</title>\n''' - ''' {% else %}\n''' - ''' <title>Title</title>\n''' - ''' {% endif %}\n''' - ''' </head>\n''' - '''\n''' - ''' <body>\n''' - ''' <h1>Hello, {{ user.username }}!</h1>\n''' - ''' </body>\n''' - '''</html>\n''', + "FormSelectionDialog", "Basic Jinja template" + ), + "template": """<!DOCTYPE html>\n""" + """ <head>\n""" + """ {% if title %}\n""" + """ <title>{{ title }}</title>\n""" + """ {% else %}\n""" + """ <title>Title</title>\n""" + """ {% endif %}\n""" + """ </head>\n""" + """\n""" + """ <body>\n""" + """ <h1>Hello, {{ user.username }}!</h1>\n""" + """ </body>\n""" + """</html>\n""", }, "jinja_base": { "title": QCoreApplication.translate( - "FormSelectionDialog", "Jinja base template"), - "template": '''<!DOCTYPE html>\n''' - ''' <head>\n''' - ''' {% if title %}\n''' - ''' <title>{{ title }}</title>\n''' - ''' {% else %}\n''' - ''' <title>Title</title>\n''' - ''' {% endif %}\n''' - ''' </head>\n''' - '''\n''' - ''' <body>\n''' - ''' {% block content %}{% endblock %}\n''' - ''' </body>\n''' - '''</html>\n''', + "FormSelectionDialog", "Jinja base template" + ), + "template": """<!DOCTYPE html>\n""" + """ <head>\n""" + """ {% if title %}\n""" + """ <title>{{ title }}</title>\n""" + """ {% else %}\n""" + """ <title>Title</title>\n""" + """ {% endif %}\n""" + """ </head>\n""" + """\n""" + """ <body>\n""" + """ {% block content %}{% endblock %}\n""" + """ </body>\n""" + """</html>\n""", }, "jinja_extends": { "title": QCoreApplication.translate( - "FormSelectionDialog", "Jinja extension template"), - "template": '''{% extends "base.html" %}\n''' - '''\n''' - '''{% block content %}\n''' - ''' <h1>{{ user.username }}</h1>\n''' - ''' {% for item in items %}\n''' - ''' <div><p>{{ item.field1 }}: {{ item.field2 }}''' - '''</p></div>\n''' - ''' {% endfor %}\n''' - '''{% endblock %}\n''' + "FormSelectionDialog", "Jinja extension template" + ), + "template": """{% extends "base.html" %}\n""" + """\n""" + """{% block content %}\n""" + """ <h1>{{ user.username }}</h1>\n""" + """ {% for item in items %}\n""" + """ <div><p>{{ item.field1 }}: {{ item.field2 }}""" + """</p></div>\n""" + """ {% endfor %}\n""" + """{% endblock %}\n""", }, } - + def __init__(self, parent=None): """ Constructor - + @param parent reference to the parent widget @type QWidget """ super().__init__(parent) self.setupUi(self) - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Ok).setEnabled(False) - + + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) + self.typeCombo.addItem("") for templateType in FormSelectionDialog.Templates: self.typeCombo.addItem( - FormSelectionDialog.Templates[templateType]["title"], - templateType) + FormSelectionDialog.Templates[templateType]["title"], templateType + ) self.typeCombo.setCurrentIndex(0) - + @pyqtSlot(int) def on_typeCombo_currentIndexChanged(self, index): """ Private slot to act upon a change of the selected template type. - + @param index selected index @type int """ templateType = self.typeCombo.itemData(index) if templateType: self.preview.setPlainText( - FormSelectionDialog.Templates[templateType]["template"]) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Ok).setEnabled(True) + FormSelectionDialog.Templates[templateType]["template"] + ) + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(True) else: self.preview.clear() - self.buttonBox.button( - QDialogButtonBox.StandardButton.Ok).setEnabled(False) - + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) + def getTemplateText(self): """ Public method to get the template text. - + @return text of the template @rtype str """
--- a/ProjectFlask/Project.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/Project.py Wed Sep 21 16:30:15 2022 +0200 @@ -10,7 +10,12 @@ import os from PyQt6.QtCore import ( - pyqtSlot, QObject, QProcess, QProcessEnvironment, QTimer, QFileInfo + pyqtSlot, + QObject, + QProcess, + QProcessEnvironment, + QTimer, + QFileInfo, ) from PyQt6.QtWidgets import QMenu, QDialog @@ -31,10 +36,11 @@ """ Class implementing the Flask project support. """ + def __init__(self, plugin, iconSuffix, parent=None): """ Constructor - + @param plugin reference to the plugin object @type ProjectFlaskPlugin @param iconSuffix suffix for the icons @@ -43,203 +49,238 @@ @type QObject """ super().__init__(parent) - + self.__plugin = plugin self.__iconSuffix = iconSuffix self.__ui = parent self.__ericProject = ericApp().getObject("Project") self.__virtualEnvManager = ericApp().getObject("VirtualEnvManager") - - self.__menus = {} # dictionary with references to menus + + self.__menus = {} # dictionary with references to menus self.__formsBrowser = None self.__hooksInstalled = False - + self.__serverDialog = None self.__routesDialog = None self.__shellProcess = None - + self.__projectData = { "flask": {}, "flask-babel": {}, "flask-migrate": {}, } - + self.__flaskVersions = { "python": "", "flask": "", "werkzeug": "", } - + self.__capabilities = {} - + self.__pybabelProject = PyBabelProject(self.__plugin, self, self) self.__migrateProject = MigrateProject(self.__plugin, self, self) - + def initActions(self): """ Public method to define the Flask actions. """ self.actions = [] - + ############################## ## run actions below ## ############################## - + self.runServerAct = EricAction( - self.tr('Run Server'), - self.tr('Run &Server'), - 0, 0, - self, 'flask_run_server') - self.runServerAct.setStatusTip(self.tr( - 'Starts the Flask Web server')) - self.runServerAct.setWhatsThis(self.tr( - """<b>Run Server</b>""" - """<p>Starts the Flask Web server.</p>""" - )) + self.tr("Run Server"), + self.tr("Run &Server"), + 0, + 0, + self, + "flask_run_server", + ) + self.runServerAct.setStatusTip(self.tr("Starts the Flask Web server")) + self.runServerAct.setWhatsThis( + self.tr("""<b>Run Server</b>""" """<p>Starts the Flask Web server.</p>""") + ) self.runServerAct.triggered.connect(self.__runServer) self.actions.append(self.runServerAct) - + self.runDevServerAct = EricAction( - self.tr('Run Development Server'), - self.tr('Run &Development Server'), - 0, 0, - self, 'flask_run_dev_server') - self.runDevServerAct.setStatusTip(self.tr( - 'Starts the Flask Web server in development mode')) - self.runDevServerAct.setWhatsThis(self.tr( - """<b>Run Development Server</b>""" - """<p>Starts the Flask Web server in development mode.</p>""" - )) + self.tr("Run Development Server"), + self.tr("Run &Development Server"), + 0, + 0, + self, + "flask_run_dev_server", + ) + self.runDevServerAct.setStatusTip( + self.tr("Starts the Flask Web server in development mode") + ) + self.runDevServerAct.setWhatsThis( + self.tr( + """<b>Run Development Server</b>""" + """<p>Starts the Flask Web server in development mode.</p>""" + ) + ) self.runDevServerAct.triggered.connect(self.__runDevelopmentServer) self.actions.append(self.runDevServerAct) - + self.askForServerOptionsAct = EricAction( - self.tr('Ask for Server Start Options'), - self.tr('Ask for Server Start Options'), - 0, 0, - self, 'flask_ask_server_options') - self.askForServerOptionsAct.setStatusTip(self.tr( - 'Ask for server start options')) - self.askForServerOptionsAct.setWhatsThis(self.tr( - """<b>Ask for Server Start Options</b>""" - """<p>Asks for server start options before the Flask Web server""" - """ is started. If this is unchecked, the server is started with""" - """ default parameters.</p>""" - )) + self.tr("Ask for Server Start Options"), + self.tr("Ask for Server Start Options"), + 0, + 0, + self, + "flask_ask_server_options", + ) + self.askForServerOptionsAct.setStatusTip( + self.tr("Ask for server start options") + ) + self.askForServerOptionsAct.setWhatsThis( + self.tr( + """<b>Ask for Server Start Options</b>""" + """<p>Asks for server start options before the Flask Web server""" + """ is started. If this is unchecked, the server is started with""" + """ default parameters.</p>""" + ) + ) self.askForServerOptionsAct.setCheckable(True) self.actions.append(self.askForServerOptionsAct) - + ############################### ## shell action below ## ############################### - + self.runPythonShellAct = EricAction( - self.tr('Start Flask Python Console'), - self.tr('Start Flask &Python Console'), - 0, 0, - self, 'flask_python_console') - self.runPythonShellAct.setStatusTip(self.tr( - 'Starts an interactive Python interpreter')) - self.runPythonShellAct.setWhatsThis(self.tr( - """<b>Start Flask Python Console</b>""" - """<p>Starts an interactive Python interpreter.</p>""" - )) + self.tr("Start Flask Python Console"), + self.tr("Start Flask &Python Console"), + 0, + 0, + self, + "flask_python_console", + ) + self.runPythonShellAct.setStatusTip( + self.tr("Starts an interactive Python interpreter") + ) + self.runPythonShellAct.setWhatsThis( + self.tr( + """<b>Start Flask Python Console</b>""" + """<p>Starts an interactive Python interpreter.</p>""" + ) + ) self.runPythonShellAct.triggered.connect(self.__runPythonShell) self.actions.append(self.runPythonShellAct) - + ################################ ## routes action below ## ################################ - + self.showRoutesAct = EricAction( - self.tr('Show Routes'), - self.tr('Show &Routes'), - 0, 0, - self, 'flask_show_routes') - self.showRoutesAct.setStatusTip(self.tr( - 'Shows a dialog with the routes of the flask app')) - self.showRoutesAct.setWhatsThis(self.tr( - """<b>Show Routes</b>""" - """<p>Shows a dialog with the routes of the flask app.</p>""" - )) + self.tr("Show Routes"), + self.tr("Show &Routes"), + 0, + 0, + self, + "flask_show_routes", + ) + self.showRoutesAct.setStatusTip( + self.tr("Shows a dialog with the routes of the flask app") + ) + self.showRoutesAct.setWhatsThis( + self.tr( + """<b>Show Routes</b>""" + """<p>Shows a dialog with the routes of the flask app.</p>""" + ) + ) self.showRoutesAct.triggered.connect(self.__showRoutes) self.actions.append(self.showRoutesAct) - + ################################## ## documentation action below ## ################################## - + self.documentationAct = EricAction( - self.tr('Documentation'), - self.tr('D&ocumentation'), - 0, 0, - self, 'flask_documentation') - self.documentationAct.setStatusTip(self.tr( - 'Shows the help viewer with the Flask documentation')) - self.documentationAct.setWhatsThis(self.tr( - """<b>Documentation</b>""" - """<p>Shows the help viewer with the Flask documentation.</p>""" - )) + self.tr("Documentation"), + self.tr("D&ocumentation"), + 0, + 0, + self, + "flask_documentation", + ) + self.documentationAct.setStatusTip( + self.tr("Shows the help viewer with the Flask documentation") + ) + self.documentationAct.setWhatsThis( + self.tr( + """<b>Documentation</b>""" + """<p>Shows the help viewer with the Flask documentation.</p>""" + ) + ) self.documentationAct.triggered.connect(self.__showDocumentation) self.actions.append(self.documentationAct) - + ############################## ## about action below ## ############################## - + self.aboutFlaskAct = EricAction( - self.tr('About Flask'), - self.tr('About &Flask'), - 0, 0, - self, 'flask_about') - self.aboutFlaskAct.setStatusTip(self.tr( - 'Shows some information about Flask')) - self.aboutFlaskAct.setWhatsThis(self.tr( - """<b>About Flask</b>""" - """<p>Shows some information about Flask.</p>""" - )) + self.tr("About Flask"), self.tr("About &Flask"), 0, 0, self, "flask_about" + ) + self.aboutFlaskAct.setStatusTip(self.tr("Shows some information about Flask")) + self.aboutFlaskAct.setWhatsThis( + self.tr( + """<b>About Flask</b>""" + """<p>Shows some information about Flask.</p>""" + ) + ) self.aboutFlaskAct.triggered.connect(self.__flaskInfo) self.actions.append(self.aboutFlaskAct) - + self.__pybabelProject.initActions() self.__migrateProject.initActions() - + ###################################### ## configuration action below ## ###################################### - + self.flaskConfigAct = EricAction( - self.tr('Configure Flask for Project'), - self.tr('Configure Flask for &Project'), - 0, 0, - self, 'flask_config_for_project') - self.flaskConfigAct.setStatusTip(self.tr( - 'Shows a dialog to edit the project specific flask configuration')) - self.flaskConfigAct.setWhatsThis(self.tr( - """<b>Configure Flask for Project</b>""" - """<p>Shows a dialog to edit the project specific flask""" - """ configuration.</p>""" - )) - self.flaskConfigAct.triggered.connect( - self.__configureFlaskForProject) + self.tr("Configure Flask for Project"), + self.tr("Configure Flask for &Project"), + 0, + 0, + self, + "flask_config_for_project", + ) + self.flaskConfigAct.setStatusTip( + self.tr("Shows a dialog to edit the project specific flask configuration") + ) + self.flaskConfigAct.setWhatsThis( + self.tr( + """<b>Configure Flask for Project</b>""" + """<p>Shows a dialog to edit the project specific flask""" + """ configuration.</p>""" + ) + ) + self.flaskConfigAct.triggered.connect(self.__configureFlaskForProject) self.actions.append(self.flaskConfigAct) - + def initMenu(self): """ Public method to initialize the Flask menu. - + @return the menu generated @rtype QMenu """ - self.__menus = {} # clear menus references - + self.__menus = {} # clear menus references + self.__menus["flask-babel"] = self.__pybabelProject.initMenu() self.__menus["flask-migrate"] = self.__migrateProject.initMenu() - - menu = QMenu(self.tr('&Flask'), self.__ui) + + menu = QMenu(self.tr("&Flask"), self.__ui) menu.setTearOffEnabled(True) - + menu.addAction(self.flaskConfigAct) menu.addSeparator() menu.addAction(self.runServerAct) @@ -257,15 +298,15 @@ menu.addAction(self.documentationAct) menu.addSeparator() menu.addAction(self.aboutFlaskAct) - + self.__menus["main"] = menu - + return menu - + def getMenu(self, name): """ Public method to get a reference to the requested menu. - + @param name name of the menu @type str @return reference to the menu or None, if no menu with the given @@ -276,88 +317,89 @@ return self.__menus[name] else: return None - + def getMenuNames(self): """ Public method to get the names of all menus. - + @return menu names @rtype list of str """ return list(self.__menus.keys()) - + def projectOpenedHooks(self): """ Public method to add our hook methods. """ if self.__ericProject.getProjectType() == "Flask": self.__formsBrowser = ( - ericApp().getObject("ProjectBrowser") - .getProjectBrowser("forms")) + ericApp().getObject("ProjectBrowser").getProjectBrowser("forms") + ) self.__formsBrowser.addHookMethodAndMenuEntry( - "newForm", self.newForm, self.tr("New template...")) - + "newForm", self.newForm, self.tr("New template...") + ) + self.__determineCapabilities() self.__setDebugEnvironment() - + self.__pybabelProject.projectOpenedHooks() - + self.__hooksInstalled = True - + def projectClosedHooks(self): """ Public method to remove our hook methods. """ self.__pybabelProject.projectClosedHooks() - + if self.__hooksInstalled: self.__formsBrowser.removeHookMethod("newForm") self.__formsBrowser = None - + self.__hooksInstalled = False - + def newForm(self, dirPath): """ Public method to create a new form. - + @param dirPath full directory path for the new form file @type str """ from .FormSelectionDialog import FormSelectionDialog - + dlg = FormSelectionDialog() if dlg.exec() == QDialog.DialogCode.Accepted: template = dlg.getTemplateText() - + fileFilters = self.tr( - "HTML Files (*.html);;" - "HTML Files (*.htm);;" - "All Files (*)") + "HTML Files (*.html);;" "HTML Files (*.htm);;" "All Files (*)" + ) fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( self.__ui, self.tr("New Form"), dirPath, fileFilters, None, - EricFileDialog.Options(EricFileDialog.DontConfirmOverwrite)) + EricFileDialog.Options(EricFileDialog.DontConfirmOverwrite), + ) if fname: ext = QFileInfo(fname).suffix() if not ext: ex = selectedFilter.split("(*")[1].split(")")[0] if ex: fname += ex - + if os.path.exists(fname): res = EricMessageBox.yesNo( self.__ui, self.tr("New Form"), - self.tr("""The file already exists! Overwrite""" - """ it?"""), - icon=EricMessageBox.Warning) + self.tr("""The file already exists! Overwrite""" """ it?"""), + icon=EricMessageBox.Warning, + ) if not res: # user selected to not overwrite return - + try: with open(fname, "w", encoding="utf-8") as f: f.write(template) @@ -365,22 +407,24 @@ EricMessageBox.critical( self.__ui, self.tr("New Form"), - self.tr("<p>The new form file <b>{0}</b> could" - " not be created.</p><p>Problem: {1}</p>") - .format(fname, str(err))) + self.tr( + "<p>The new form file <b>{0}</b> could" + " not be created.</p><p>Problem: {1}</p>" + ).format(fname, str(err)), + ) return - + self.__ericProject.appendFile(fname) self.__formsBrowser.sourceFile.emit(fname) - + ################################################################## ## methods below implement virtual environment handling ################################################################## - + def getVirtualEnvironment(self): """ Public method to get the path of the virtual environment. - + @return path of the virtual environment @rtype str """ @@ -389,35 +433,34 @@ # get project specific virtual environment name venvName = self.getData("flask", "virtual_environment_name") if not venvName: - venvName = self.__plugin.getPreferences( - "VirtualEnvironmentNamePy3") + venvName = self.__plugin.getPreferences("VirtualEnvironmentNamePy3") else: venvName = "" virtEnv = ( self.__virtualEnvManager.getVirtualenvDirectory(venvName) - if venvName else - "" + if venvName + else "" ) - + if virtEnv and not os.path.exists(virtEnv): virtEnv = "" - - return virtEnv # __IGNORE_WARNING_M834__ - + + return virtEnv # __IGNORE_WARNING_M834__ + def getVirtualenvInterpreter(self): """ Public method to get the path of the Python interpreter to be used with the current project. - + @return path of the Python interpreter @rtype str """ return self.getFullCommand("python") - + def getFullCommand(self, command, virtualEnvPath=None): """ Public method to get the full command for a given command name. - + @param command command name @type str @param virtualEnvPath path of the virtual environment @@ -427,24 +470,28 @@ """ virtualEnv = virtualEnvPath or self.getVirtualEnvironment() fullCmds = ( - [os.path.join(virtualEnv, "Scripts", command + '.exe'), - os.path.join(virtualEnv, "bin", command + '.exe'), - command] # fall back to just cmd - if isWindowsPlatform() else - [os.path.join(virtualEnv, "bin", command), - os.path.join(virtualEnv, "local", "bin", command), - Utilities.getExecutablePath(command), - command] # fall back to just cmd + [ + os.path.join(virtualEnv, "Scripts", command + ".exe"), + os.path.join(virtualEnv, "bin", command + ".exe"), + command, + ] # fall back to just cmd + if isWindowsPlatform() + else [ + os.path.join(virtualEnv, "bin", command), + os.path.join(virtualEnv, "local", "bin", command), + Utilities.getExecutablePath(command), + command, + ] # fall back to just cmd ) for command in fullCmds: if os.path.exists(command): break return command - + ################################################################## ## methods below implement general functionality ################################################################## - + def projectClosed(self): """ Public method to handle the closing of a project. @@ -452,18 +499,18 @@ for dlg in (self.__serverDialog, self.__routesDialog): if dlg is not None: dlg.close() - + self.__migrateProject.projectClosed() - + def supportedPythonVariants(self): """ Public method to get the supported Python variants. - + @return list of supported Python variants @rtype list of str """ variants = [] - + virtEnv = self.getVirtualEnvironment() if virtEnv: fullCmd = self.getFlaskCommand() @@ -478,21 +525,21 @@ fullCmds = Utilities.getExecutablePaths("flask") for fullCmd in fullCmds: try: - with open(fullCmd, 'r', encoding='utf-8') as f: + with open(fullCmd, "r", encoding="utf-8") as f: l0 = f.readline() except OSError: l0 = "" if self.__isSuitableForVariant("Python3", l0): variants.append("Python3") break - + return variants - + def __isSuitableForVariant(self, variant, line0): """ Private method to test, if a detected command file is suitable for the given Python variant. - + @param variant Python variant to test for @type str @param line0 first line of the executable @@ -501,21 +548,20 @@ @rtype bool """ l0 = line0.lower() - ok = (variant.lower() in l0 or - "{0}.".format(variant[-1]) in l0) + ok = variant.lower() in l0 or "{0}.".format(variant[-1]) in l0 ok |= "pypy3" in l0 - + return ok - + def getFlaskCommand(self): """ Public method to build the Flask command. - + @return full flask command @rtype str """ return self.getFullCommand("flask") - + @pyqtSlot() def __flaskInfo(self): """ @@ -523,7 +569,7 @@ """ versions = self.getFlaskVersionStrings() url = "https://palletsprojects.com/p/flask/" - + msgBox = EricMessageBox.EricMessageBox( EricMessageBox.Question, self.tr("About Flask"), @@ -535,24 +581,28 @@ "<tr><td>Flask Version:</td><td>{0}</td></tr>" "<tr><td>Werkzeug Version:</td><td>{1}</td></tr>" "<tr><td>Python Version:</td><td>{2}</td></tr>" - "<tr><td>Flask URL:</td><td><a href=\"{3}\">" + '<tr><td>Flask URL:</td><td><a href="{3}">' "The Pallets Projects - Flask</a></td></tr>" "</table></p>", - "Do not translate the program names." - ).format(versions["flask"], versions["werkzeug"], - versions["python"], url), + "Do not translate the program names.", + ).format(versions["flask"], versions["werkzeug"], versions["python"], url), modal=True, - buttons=EricMessageBox.Ok) - msgBox.setIconPixmap(UI.PixmapCache.getPixmap( - os.path.join("ProjectFlask", "icons", - "flask64-{0}".format(self.__iconSuffix)))) + buttons=EricMessageBox.Ok, + ) + msgBox.setIconPixmap( + UI.PixmapCache.getPixmap( + os.path.join( + "ProjectFlask", "icons", "flask64-{0}".format(self.__iconSuffix) + ) + ) + ) msgBox.exec() - + def getFlaskVersionStrings(self): """ Public method to get the Flask, Werkzeug and Python versions as a string. - + @return dictionary containing the Flask, Werkzeug and Python versions @rtype dict """ @@ -565,14 +615,14 @@ for line in output.lower().splitlines(): key, version = line.strip().split(None, 1) self.__flaskVersions[key] = version - + return self.__flaskVersions - + def prepareRuntimeEnvironment(self, development=False): """ Public method to prepare a QProcessEnvironment object and determine the appropriate working directory. - + @param development flag indicating development mode @type bool @return tuple containing the working directory and a prepared @@ -584,14 +634,14 @@ env.insert("FLASK_APP", app) if development: env.insert("FLASK_ENV", "development") - + return workdir, env - + def getApplication(self): """ Public method to determine the application name and the respective working directory. - + @return tuple containing the working directory and the application name @rtype tuple of (str, str) """ @@ -600,21 +650,24 @@ EricMessageBox.critical( self.__ui, self.tr("Prepare Environment"), - self.tr("""The project has no configured main script""" - """ (= Flask application). Aborting...""")) + self.tr( + """The project has no configured main script""" + """ (= Flask application). Aborting...""" + ), + ) return "", None - + scriptPath, scriptName = os.path.split(mainScript) if scriptName == "__init__.py": workdir, app = os.path.split(scriptPath) else: workdir, app = scriptPath, scriptName return workdir, app - + def getData(self, category, key): """ Public method to get data stored in the project store. - + @param category data category @type str @param key data key @@ -624,13 +677,12 @@ """ if category not in self.__projectData: self.__projectData[category] = {} - + if not self.__projectData[category]: - data = self.__ericProject.getData( - "PROJECTTYPESPECIFICDATA", category) + data = self.__ericProject.getData("PROJECTTYPESPECIFICDATA", category) if data is not None: self.__projectData[category] = data - + data = self.__projectData[category] if not key: # return complete category dictionary @@ -641,11 +693,11 @@ else: # failure return None - + def setData(self, category, key, value): """ Public method to store data in the project store. - + @param category data category @type str @param key data key @@ -655,23 +707,23 @@ """ if category not in self.__projectData: self.__projectData[category] = {} - + if not self.__projectData[category]: - data = self.__ericProject.getData( - "PROJECTTYPESPECIFICDATA", category) + data = self.__ericProject.getData("PROJECTTYPESPECIFICDATA", category) if data is not None: self.__projectData[category] = data - + if not key: # update the complete category self.__projectData[category] = value else: # update individual entry self.__projectData[category][key] = value - + self.__ericProject.setData( - "PROJECTTYPESPECIFICDATA", category, self.__projectData[category]) - + "PROJECTTYPESPECIFICDATA", category, self.__projectData[category] + ) + def __determineCapabilities(self): """ Private method to determine capabilities provided by supported @@ -679,14 +731,14 @@ """ # 1. support for flask-babel (i.e. pybabel) self.__pybabelProject.determineCapability() - + # 2. support for flask-migrate self.__migrateProject.determineCapability() - + def hasCapability(self, key): """ Public method to check, if a capability is available. - + @param key key of the capability to check @type str @return flag indicating the availability of the capability @@ -696,29 +748,29 @@ return self.__capabilities[key] except KeyError: return False - + def setCapability(self, key, available): """ Public method to set the availability status of a capability. - + @param key key of the capability to set @type str @param available flag indicating the availability of the capability @type bool """ self.__capabilities[key] = available - + ################################################################## ## slots below implements project specific flask configuration ################################################################## - + @pyqtSlot() def __configureFlaskForProject(self): """ Private slot to configure the project specific flask parameters. """ from .FlaskConfigDialog import FlaskConfigDialog - + config = self.getData("flask", "") dlg = FlaskConfigDialog(config, self) if dlg.exec() == QDialog.DialogCode.Accepted: @@ -726,13 +778,13 @@ self.setData("flask", "", config) self.__setIgnoreVirtualEnvironment() self.__setDebugEnvironment() - + self.__migrateProject.determineCapability() - + self.__pybabelProject.determineCapability() self.projectClosedHooks() self.projectOpenedHooks() - + def __setIgnoreVirtualEnvironment(self): """ Private method to add an embedded project specific virtual environment @@ -743,13 +795,12 @@ virtenvPath = self.getVirtualEnvironment() if self.__ericProject.startswithProjectPath(virtenvPath): relVirtenvPath = self.__ericProject.getRelativeUniversalPath( - virtenvPath) + virtenvPath + ) if relVirtenvPath not in self.__ericProject.pdata["FILETYPES"]: - self.__ericProject.pdata["FILETYPES"][relVirtenvPath] = ( - "__IGNORE__" - ) + self.__ericProject.pdata["FILETYPES"][relVirtenvPath] = "__IGNORE__" self.__ericProject.setDirty(True) - + def __setDebugEnvironment(self): """ Private method to set the virtual environment as the selected debug @@ -760,57 +811,55 @@ # get project specific virtual environment name venvName = self.getData("flask", "virtual_environment_name") if not venvName: - venvName = self.__plugin.getPreferences( - "VirtualEnvironmentNamePy3") + venvName = self.__plugin.getPreferences("VirtualEnvironmentNamePy3") if venvName: self.__ericProject.debugProperties["VIRTUALENV"] = venvName - + ################################################################## ## slot below implements documentation function ################################################################## - + def __showDocumentation(self): """ Private slot to show the helpviewer with the Flask documentation. """ page = self.__plugin.getPreferences("FlaskDocUrl") self.__ui.launchHelpViewer(page) - + ################################################################## ## slots below implement run functions for the server ################################################################## - + @pyqtSlot() def __runServer(self, development=False): """ Private slot to start the Flask Web server. - + @param development flag indicating development mode @type bool """ from .RunServerDialog import RunServerDialog - + if self.__serverDialog is not None: self.__serverDialog.close() - + askForOptions = self.askForServerOptionsAct.isChecked() dlg = RunServerDialog(self.__plugin, self) - if dlg.startServer(development=development, - askForOptions=askForOptions): + if dlg.startServer(development=development, askForOptions=askForOptions): dlg.show() self.__serverDialog = dlg - + @pyqtSlot() def __runDevelopmentServer(self): """ Private slot to start the Flask Web server in development mode. """ self.__runServer(development=True) - + ################################################################## ## slots below implement functions for the flask console ################################################################## - + @pyqtSlot() def __runPythonShell(self): """ @@ -819,57 +868,56 @@ workdir, env = self.prepareRuntimeEnvironment() if env is not None: command = self.getFlaskCommand() - + consoleCmd = self.__plugin.getPreferences("ConsoleCommand") if consoleCmd: self.__terminatePythonShell() - + args = Utilities.parseOptionString(consoleCmd) args[0] = Utilities.getExecutablePath(args[0]) args += [command, "shell"] - + self.__shellProcess = QProcess() self.__shellProcess.setProcessEnvironment(env) self.__shellProcess.setWorkingDirectory(workdir) - self.__shellProcess.finished.connect( - self.__shellProcessFinished) - + self.__shellProcess.finished.connect(self.__shellProcessFinished) + self.__shellProcess.start(args[0], args[1:]) self.__shellProcess.waitForStarted(10000) - + @pyqtSlot() def __shellProcessFinished(self): """ Private slot connected to the finished signal. """ self.__shellProcess = None - + def __terminatePythonShell(self): """ Private method to terminate the current Python console. """ if ( - self.__shellProcess is not None and - self.__shellProcess.state() != QProcess.ProcessState.NotRunning + self.__shellProcess is not None + and self.__shellProcess.state() != QProcess.ProcessState.NotRunning ): self.__shellProcess.terminate() QTimer.singleShot(2000, self.__shellProcess.kill) self.__shellProcess.waitForFinished(3000) - + ################################################################## ## slots below implement various debugging functions ################################################################## - + @pyqtSlot() def __showRoutes(self): """ Private slot showing all URL dispatch routes. """ from .RoutesDialog import RoutesDialog - + if self.__routesDialog is not None: self.__routesDialog.close() - + dlg = RoutesDialog(self) if dlg.showRoutes(): dlg.show()
--- a/ProjectFlask/RoutesDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/RoutesDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -20,10 +20,11 @@ """ Class implementing a dialog to show the application routes. """ + def __init__(self, project, parent=None): """ Constructor - + @param project reference to the project object @type Project @param parent reference to the parent widget @@ -31,31 +32,33 @@ """ super().__init__(parent) self.setupUi(self) - + self.__refreshButton = self.buttonBox.addButton( - self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole) + self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole + ) self.__refreshButton.clicked.connect(self.showRoutes) - + self.__project = project self.__process = None - + def showRoutes(self): """ Public method to show the list of routes. - + @return flag indicating success @rtype bool """ workdir, env = self.__project.prepareRuntimeEnvironment() if env is not None: command = self.__project.getFlaskCommand() - + self.__process = QProcess() self.__process.setProcessEnvironment(env) self.__process.setWorkingDirectory(workdir) self.__process.setProcessChannelMode( - QProcess.ProcessChannelMode.MergedChannels) - + QProcess.ProcessChannelMode.MergedChannels + ) + args = ["routes"] if self.matchButton.isChecked(): sortorder = "match" @@ -71,46 +74,50 @@ args += ["--sort", sortorder] if self.allMethodsCheckBox.isChecked(): args.append("--all-methods") - + with EricOverrideCursor(): self.__process.start(command, args) ok = self.__process.waitForStarted(10000) if ok: ok = self.__process.waitForFinished(10000) if ok: - out = str(self.__process.readAllStandardOutput(), - "utf-8") + out = str(self.__process.readAllStandardOutput(), "utf-8") self.__processOutput(out) else: with EricOverridenCursor(): EricMessageBox.critical( None, self.tr("Flask Routes"), - self.tr("""The Flask process did not finish""" - """ within 10 seconds.""")) + self.tr( + """The Flask process did not finish""" + """ within 10 seconds.""" + ), + ) else: with EricOverridenCursor(): EricMessageBox.critical( None, self.tr("Flask Routes"), - self.tr("""The Flask process could not be""" - """ started.""")) + self.tr( + """The Flask process could not be""" """ started.""" + ), + ) for column in range(self.routesList.columnCount()): self.routesList.resizeColumnToContents(column) return ok else: return False - + def __processOutput(self, output): """ Private method to process the flask output and populate the routes list. - + @param output output of the flask process @type str """ self.routesList.clear() - + lines = output.splitlines() widths = [] for line in lines: @@ -124,58 +131,58 @@ for width in widths: parts.append(line[:width].strip()) line = line[width:].lstrip() - + QTreeWidgetItem(self.routesList, parts) - + @pyqtSlot(bool) def on_matchButton_toggled(self, checked): """ Private slot handling the selection of the 'match' sort order. - + @param checked state of the button @type bool """ if checked: self.showRoutes() - + @pyqtSlot(bool) def on_endpointButton_toggled(self, checked): """ Private slot handling the selection of the 'endpoint' sort order. - + @param checked state of the button @type bool """ if checked: self.showRoutes() - + @pyqtSlot(bool) def on_methodsButton_toggled(self, checked): """ Private slot handling the selection of the 'methods' sort order. - + @param checked state of the button @type bool """ if checked: self.showRoutes() - + @pyqtSlot(bool) def on_ruleButton_toggled(self, checked): """ Private slot handling the selection of the 'rule' sort order. - + @param checked state of the button @type bool """ if checked: self.showRoutes() - + @pyqtSlot(bool) def on_allMethodsCheckBox_toggled(self, checked): """ Private slot handling the selection to show all methods. - + @param checked state of the button @type bool """
--- a/ProjectFlask/RunServerDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/RunServerDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -29,10 +29,11 @@ """ Class implementing a dialog to run the Flask server. """ + def __init__(self, plugin, project, parent=None): """ Constructor - + @param plugin reference to the plug-in object @type PluginProjectFlask @param project reference to the project object @@ -42,30 +43,26 @@ """ super().__init__(parent) self.setupUi(self) - + self.__plugin = plugin self.__project = project - - self.__serverOptions = { - "development": False - } - + + self.__serverOptions = {"development": False} + self.__process = None self.__serverUrl = "" - + self.__ansiRe = re.compile(r"(\x1b\[\d+m)") - + self.__urlRe = re.compile(r" \* Running on ([^(]+) \(.*") - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setDefault(True) - + + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) + self.__defaultTextFormat = self.outputEdit.currentCharFormat() - + self.__initActionsMenu() - + def __initActionsMenu(self): """ Private method to populate the actions button menu. @@ -74,39 +71,35 @@ self.__actionsMenu.setTearOffEnabled(True) self.__actionsMenu.setToolTipsVisible(True) self.__actionsMenu.aboutToShow.connect(self.__showActionsMenu) - + # re-start server - self.__actionsMenu.addAction( - self.tr("Re-start Server"), - self.__restartServer) + self.__actionsMenu.addAction(self.tr("Re-start Server"), self.__restartServer) self.__restartModeAct = self.__actionsMenu.addAction( - self.tr("Re-start Server"), - self.__restartServerDifferentMode) + self.tr("Re-start Server"), self.__restartServerDifferentMode + ) self.__actionsMenu.addSeparator() # re-start server with options self.__actionsMenu.addAction( - self.tr("Re-start Server with Options"), - self.__restartServerWithOptions) - + self.tr("Re-start Server with Options"), self.__restartServerWithOptions + ) + self.menuButton.setIcon(UI.PixmapCache.getIcon("actionsToolButton")) self.menuButton.setMenu(self.__actionsMenu) - + @pyqtSlot() def __showActionsMenu(self): """ Private slot handling the actions menu about to be shown. """ if self.__serverOptions["development"]: - self.__restartModeAct.setText( - self.tr("Re-start Server (Production Mode)")) + self.__restartModeAct.setText(self.tr("Re-start Server (Production Mode)")) else: - self.__restartModeAct.setText( - self.tr("Re-start Server (Development Mode)")) - + self.__restartModeAct.setText(self.tr("Re-start Server (Development Mode)")) + def startServer(self, development=False, askForOptions=False): """ Public method to start the Flask server process. - + @param development flag indicating development mode @type bool @param askForOptions flag indicating to ask for server start options @@ -116,30 +109,32 @@ @rtype bool """ self.__serverOptions["development"] = development - + if askForOptions: dlg = ServerStartOptionsDialog(self.__serverOptions) if dlg.exec() != QDialog.DialogCode.Accepted: return False - + self.__serverOptions.update(dlg.getDataDict()) - + workdir, env = self.__project.prepareRuntimeEnvironment( - development=self.__serverOptions["development"]) + development=self.__serverOptions["development"] + ) if env is not None: command = self.__project.getFlaskCommand() - + self.__process = QProcess() self.__process.setProcessEnvironment(env) self.__process.setWorkingDirectory(workdir) self.__process.setProcessChannelMode( - QProcess.ProcessChannelMode.MergedChannels) - + QProcess.ProcessChannelMode.MergedChannels + ) + self.__process.readyReadStandardOutput.connect(self.__readStdOut) self.__process.finished.connect(self.__processFinished) - + self.outputEdit.clear() - + args = ["run"] if "host" in self.__serverOptions and self.__serverOptions["host"]: args += ["--host", self.__serverOptions["host"]] @@ -149,36 +144,39 @@ args += ["--cert", self.__serverOptions["cert"]] if "key" in self.__serverOptions and self.__serverOptions["key"]: args += ["--key", self.__serverOptions["key"]] - + self.__process.start(command, args) ok = self.__process.waitForStarted(10000) if not ok: EricMessageBox.critical( None, self.tr("Run Flask Server"), - self.tr("""The Flask server process could not be""" - """ started.""")) + self.tr( + """The Flask server process could not be""" """ started.""" + ), + ) else: - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(False) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled( + False + ) self.stopServerButton.setEnabled(True) self.stopServerButton.setDefault(True) self.startBrowserButton.setEnabled(True) else: ok = False - + return ok - + def closeEvent(self, evt): """ Protected method handling a close event. - + @param evt reference to the close event @type QCloseEvent """ self.on_stopServerButton_clicked() evt.accept() - + @pyqtSlot() def __readStdOut(self): """ @@ -190,56 +188,53 @@ urlMatch = self.__urlRe.search(out) if urlMatch: self.__serverUrl = urlMatch.group(1) - + for txt in self.__ansiRe.split(out): if txt.startswith("\x1b["): - color = int(txt[2:-1]) # strip off ANSI command parts + color = int(txt[2:-1]) # strip off ANSI command parts if color == 0: - self.outputEdit.setCurrentCharFormat( - self.__defaultTextFormat) + self.outputEdit.setCurrentCharFormat(self.__defaultTextFormat) elif 30 <= color <= 37: brush = AnsiTools.getColor( - self.__plugin.getPreferences("AnsiColorScheme"), - color - 30) + self.__plugin.getPreferences("AnsiColorScheme"), color - 30 + ) if brush is not None: - charFormat = QTextCharFormat( - self.__defaultTextFormat) + charFormat = QTextCharFormat(self.__defaultTextFormat) charFormat.setForeground(brush) self.outputEdit.setCurrentCharFormat(charFormat) else: self.outputEdit.insertPlainText(txt) - + @pyqtSlot() def __processFinished(self): """ Private slot handling the finishing of the server process. """ if ( - self.__process is not None and - self.__process.state() != QProcess.ProcessState.NotRunning + self.__process is not None + and self.__process.state() != QProcess.ProcessState.NotRunning ): self.__process.terminate() QTimer.singleShot(2000, self.__process.kill) self.__process.waitForFinished(3000) - + self.__process = None - + self.startBrowserButton.setEnabled(False) self.stopServerButton.setEnabled(False) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setDefault(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus( - Qt.FocusReason.OtherFocusReason) - + Qt.FocusReason.OtherFocusReason + ) + @pyqtSlot() def on_stopServerButton_clicked(self): """ Private slot to stop the running server. """ self.__processFinished() - + @pyqtSlot() def on_startBrowserButton_clicked(self): """ @@ -247,11 +242,11 @@ """ if self.__plugin.getPreferences("UseExternalBrowser"): import webbrowser + webbrowser.open(self.__serverUrl) else: - ericApp().getObject("UserInterface").launchHelpViewer( - self.__serverUrl) - + ericApp().getObject("UserInterface").launchHelpViewer(self.__serverUrl) + @pyqtSlot() def __restartServer(self): """ @@ -259,10 +254,10 @@ """ # step 1: stop the current server self.on_stopServerButton_clicked() - + # step 2: start a new server self.startServer(development=self.__serverOptions["development"]) - + @pyqtSlot() def __restartServerDifferentMode(self): """ @@ -270,10 +265,10 @@ """ # step 1: stop the current server self.on_stopServerButton_clicked() - + # step 2: start a new server self.startServer(development=not self.__serverOptions["development"]) - + @pyqtSlot() def __restartServerWithOptions(self): """ @@ -281,7 +276,8 @@ """ # step 1: stop the current server self.on_stopServerButton_clicked() - + # step 2: start a new server - self.startServer(development=self.__serverOptions["development"], - askForOptions=True) + self.startServer( + development=self.__serverOptions["development"], askForOptions=True + )
--- a/ProjectFlask/ServerStartOptionsDialog.py Thu Dec 30 12:13:22 2021 +0100 +++ b/ProjectFlask/ServerStartOptionsDialog.py Wed Sep 21 16:30:15 2022 +0200 @@ -19,10 +19,11 @@ """ Class implementing a dialog to enter parameters to start the server. """ + def __init__(self, options, parent=None): """ Constructor - + @param options dictionary containing the current server start options @type dict @param parent reference to the parent widget @@ -30,39 +31,39 @@ """ super().__init__(parent) self.setupUi(self) - + ericProject = ericApp().getObject("Project") - + self.certFilePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) - self.certFilePicker.setFilters(self.tr( - "Certificate Files (*.pem);;" - "Certificate Files (*.cert *.cer *.crt)" - )) + self.certFilePicker.setFilters( + self.tr( + "Certificate Files (*.pem);;" "Certificate Files (*.cert *.cer *.crt)" + ) + ) self.certFilePicker.setDefaultDirectory(ericProject.getProjectPath()) - + self.keyFilePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) - self.keyFilePicker.setFilters(self.tr( - "Key Files (*.pem *.key)" - )) + self.keyFilePicker.setFilters(self.tr("Key Files (*.pem *.key)")) self.keyFilePicker.setDefaultDirectory(ericProject.getProjectPath()) - + self.developmentCheckBox.setChecked(options.get("development", False)) self.hostEdit.setText(options.get("host", "")) self.portSpinBox.setValue(int(options.get("port", "5000"))) - + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) - + def getDataDict(self): """ Public method to get a dictionary containing the entered data. - + @return dictionary containing the entered data @rtype dict """ - options = {} - - options["development"] = self.developmentCheckBox.isChecked() + options = { + "development": self.developmentCheckBox.isChecked(), + } + host = self.hostEdit.text() if host: options["host"] = host @@ -73,5 +74,5 @@ options["cert"] = self.certFilePicker.text() if self.keyFilePicker.text(): options["key"] = self.keyFilePicker.text() - + return options