Sun, 08 Nov 2020 17:54:22 +0100
Added code for the basic project support.
# -*- coding: utf-8 -*- # Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the Flask project support. """ import os from PyQt5.QtCore import pyqtSlot, QObject, QProcess, QTimer from PyQt5.QtWidgets import QMenu from E5Gui import E5MessageBox from E5Gui.E5Action import E5Action from E5Gui.E5Application import e5App from Globals import isWindowsPlatform import UI.PixmapCache import Utilities class Project(QObject): """ 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 @type str @param parent parent @type QObject """ super(Project, self).__init__(parent) self.__plugin = plugin self.__iconSuffix = iconSuffix self.__ui = parent self.__e5project = e5App().getObject("Project") self.__virtualEnvManager = e5App().getObject("VirtualEnvManager") self.__menus = {} # dictionary with references to menus self.__serverProc = None self.__flaskVersions = { "python": "", "flask": "", "werkzeug": "", } def initActions(self): """ Public method to define the Flask actions. """ self.actions = [] ############################## ## about action below ## ############################## self.aboutFlaskAct = E5Action( 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) def initMenu(self): """ Public method to initialize the Flask menu. @return the menu generated @rtype QMenu """ self.__menus = {} # clear menus references menu = QMenu(self.tr('&Flask'), self.__ui) menu.setTearOffEnabled(True) 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 name exists @rtype QMenu or None """ if name in self.__menus: 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()) ################################################################## ## slots below implement general functionality ################################################################## def projectClosed(self): """ Public method to handle the closing of a project. """ if self.__serverProc is not None: self.__serverProcFinished() # TODO: implement this correctly 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() if fullCmd: variants.append("Python3") else: fullCmd = self.getFlaskCommand() if isWindowsPlatform(): if fullCmd: variants.append("Python3") else: fullCmds = Utilities.getExecutablePaths("flask") for fullCmd in fullCmds: try: with open(fullCmd, 'r', encoding='utf-8') as f: l0 = f.readline() except (IOError, 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 @type str @return flag indicating a suitable file was found @rtype bool """ l0 = line0.lower() ok = (variant.lower() in l0 or "{0}.".format(variant[-1]) in l0) ok |= "pypy3" in l0 return ok def __getVirtualEnvironment(self): """ Private method to get the path of the virtual environment. @return path of the virtual environment @rtype str """ language = self.__e5project.getProjectLanguage() if language == "Python3": venvName = self.__plugin.getPreferences( "VirtualEnvironmentNamePy3") else: venvName = "" if venvName: virtEnv = self.__virtualEnvManager.getVirtualenvDirectory( venvName) else: virtEnv = "" if virtEnv and not os.path.exists(virtEnv): virtEnv = "" return virtEnv # __IGNORE_WARNING_M834__ def getFlaskCommand(self): """ Public method to build the Flask command. @return full flask command @rtype str """ cmd = "flask" virtualEnv = self.__getVirtualEnvironment() if isWindowsPlatform(): fullCmds = [ os.path.join(virtualEnv, "Scripts", cmd + '.exe'), os.path.join(virtualEnv, "bin", cmd + '.exe'), cmd # fall back to just cmd ] for cmd in fullCmds: if os.path.exists(cmd): break else: fullCmds = [ os.path.join(virtualEnv, "bin", cmd), os.path.join(virtualEnv, "local", "bin", cmd), Utilities.getExecutablePath(cmd), cmd # fall back to just cmd ] for cmd in fullCmds: if os.path.exists(cmd): break return cmd @pyqtSlot() def __flaskInfo(self): """ Private slot to show some info about Flask. """ versions = self.getFlaskVersionStrings() url = "https://flask.palletsprojects.com" msgBox = E5MessageBox.E5MessageBox( E5MessageBox.Question, self.tr("About Flask"), self.tr( "<p>Flask is a lightweight WSGI web application framework." " It is designed to make getting started quick and easy," " with the ability to scale up to complex applications.</p>" "<p><table>" "<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}\">" "{3}</a></td></tr>" "</table></p>" ).format(versions["flask"], versions["werkzeug"], versions["python"], url), modal=True, buttons=E5MessageBox.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 """ if not self.__flaskVersions["flask"]: cmd = self.getFlaskCommand() proc = QProcess() proc.start(cmd, ["--version"]) if proc.waitForFinished(10000): output = str(proc.readAllStandardOutput(), "utf-8") for line in output.lower().splitlines(): key, version = line.strip().split(None, 1) self.__flaskVersions[key] = version return self.__flaskVersions ################################################################## ## slots below implement run functions ################################################################## def __runServer(self, logging=False): """ Private slot to start the Pyramid Web server. @param logging flag indicating to enable logging @type bool """ # TODO: implement this def __serverProcFinished(self): """ Private slot connected to the finished signal. """ if ( self.__serverProc is not None and self.__serverProc.state() != QProcess.NotRunning ): self.__serverProc.terminate() QTimer.singleShot(2000, self.__serverProc.kill) self.__serverProc.waitForFinished(3000) self.__serverProc = None