diff -r babe80d84a3e -r 7eb04391adf7 eric6/UI/UserInterface.py --- a/eric6/UI/UserInterface.py Mon Sep 09 18:52:08 2019 +0200 +++ b/eric6/UI/UserInterface.py Thu Oct 03 11:12:10 2019 +0200 @@ -7,26 +7,25 @@ Module implementing the main user interface. """ -from __future__ import unicode_literals -try: - str = unicode # __IGNORE_EXCEPTION__ -except NameError: - pass import os import sys import logging -from PyQt5.QtCore import pyqtSlot, QTimer, QFile, QFileInfo, pyqtSignal, \ - PYQT_VERSION_STR, QDate, QIODevice, qVersion, QProcess, QSize, QUrl, \ - QObject, Qt, QUuid, QThread +from PyQt5.QtCore import ( + pyqtSlot, QTimer, QFile, QFileInfo, pyqtSignal, PYQT_VERSION_STR, QDate, + QIODevice, qVersion, QProcess, QSize, QUrl, QObject, Qt, QUuid, QThread, + QUrlQuery +) from PyQt5.QtGui import QKeySequence, QDesktopServices -from PyQt5.QtWidgets import QSizePolicy, QWidget, QWhatsThis, QToolBar, \ - QDialog, QSplitter, QApplication, QMenu, QVBoxLayout, QDockWidget, \ - QAction, QLabel +from PyQt5.QtWidgets import ( + QSizePolicy, QWidget, QWhatsThis, QToolBar, QDialog, QSplitter, + QApplication, QMenu, QVBoxLayout, QDockWidget, QAction, QLabel +) from PyQt5.Qsci import QSCINTILLA_VERSION_STR -from PyQt5.QtNetwork import QNetworkProxyFactory, QNetworkAccessManager, \ - QNetworkRequest, QNetworkReply +from PyQt5.QtNetwork import ( + QNetworkProxyFactory, QNetworkAccessManager, QNetworkRequest, QNetworkReply +) from .Info import Version, VersionOnly, BugAddress, Program, FeatureAddress from . import Config @@ -47,8 +46,9 @@ import UI.PixmapCache from E5Network.E5NetworkIcon import E5NetworkIcon -from E5Network.E5NetworkProxyFactory import E5NetworkProxyFactory, \ - proxyAuthenticationRequired +from E5Network.E5NetworkProxyFactory import ( + E5NetworkProxyFactory, proxyAuthenticationRequired +) try: from E5Network.E5SslErrorHandler import E5SslErrorHandler SSL_AVAILABLE = True @@ -57,8 +57,6 @@ from eric6config import getConfig -from Globals import qVersionTuple - class Redirector(QObject): """ @@ -663,8 +661,9 @@ self.pluginManager.initPluginToolbars(self.toolbarManager) if Preferences.getPluginManager("StartupCleanup"): splash.showMessage(self.tr("Cleaning Plugins Download Area...")) - from PluginManager.PluginRepositoryDialog import \ + from PluginManager.PluginRepositoryDialog import ( PluginRepositoryDownloadCleanup + ) PluginRepositoryDownloadCleanup(quiet=True) # now read the keyboard shortcuts for all the actions @@ -746,8 +745,8 @@ # Create the view manager depending on the configuration setting logging.debug("Creating Viewmanager...") import ViewManager - self.viewmanager = \ - ViewManager.factory(self, self, debugServer, self.pluginManager) + self.viewmanager = ViewManager.factory( + self, self, debugServer, self.pluginManager) leftWidget = QWidget() layout = QVBoxLayout() layout.setContentsMargins(1, 1, 1, 1) @@ -979,8 +978,8 @@ else: self.__shellParent = self.hToolboxDock from QScintilla.Shell import ShellAssembly - self.shellAssembly = \ - ShellAssembly(debugServer, self.viewmanager, self.project, True) + self.shellAssembly = ShellAssembly( + debugServer, self.viewmanager, self.project, True) self.shell = self.shellAssembly.shell() self.__shellParent.widget().insertItem( 0, self.shellAssembly, UI.PixmapCache.getIcon("shell.png"), @@ -1176,8 +1175,8 @@ else: self.__shellParent = self.bottomSidebar from QScintilla.Shell import ShellAssembly - self.shellAssembly = \ - ShellAssembly(debugServer, self.viewmanager, self.project, True) + self.shellAssembly = ShellAssembly( + debugServer, self.viewmanager, self.project, True) self.shell = self.shellAssembly.shell() self.__shellParent.insertTab(0, self.shellAssembly, UI.PixmapCache.getIcon("shell.png"), @@ -1475,8 +1474,7 @@ @param project project name to be displayed (string) """ if editor is not None and self.captionShowsFilename: - self.capEditor = \ - Utilities.compactPath(editor, self.maxFilePathLen) + self.capEditor = Utilities.compactPath(editor, self.maxFilePathLen) if project is not None: self.capProject = project @@ -1981,7 +1979,6 @@ self.actions.append(self.condaWidgetActivateAct) self.addAction(self.condaWidgetActivateAct) - # TODO: add action for "MicroPython", Ctrl+Alt+Shift+M if self.microPythonWidget is not None: self.microPythonWidgetActivateAct = E5Action( self.tr('MicroPython'), @@ -2039,8 +2036,6 @@ )) self.helpviewerAct.triggered.connect(self.__helpViewer) self.actions.append(self.helpviewerAct) -## else: -## self.helpviewerAct = None self.__initQtDocActions() self.__initPythonDocActions() @@ -2782,25 +2777,21 @@ except ImportError: self.pyqt4DocAct = None - try: - import PyQt5 # __IGNORE_WARNING__ - self.pyqt5DocAct = E5Action( - self.tr('PyQt5 Documentation'), - self.tr('PyQt&5 Documentation'), - 0, 0, self, 'pyqt5_documentation') - self.pyqt5DocAct.setStatusTip(self.tr( - 'Open PyQt5 Documentation')) - self.pyqt5DocAct.setWhatsThis(self.tr( - """<b>PyQt5 Documentation</b>""" - """<p>Display the PyQt5 Documentation. Dependent upon your""" - """ settings, this will either show the help in Eric's""" - """ internal help viewer/web browser, or execute a web""" - """ browser or Qt Assistant. </p>""" - )) - self.pyqt5DocAct.triggered.connect(self.__showPyQt5Doc) - self.actions.append(self.pyqt5DocAct) - except ImportError: - self.pyqt5DocAct = None + self.pyqt5DocAct = E5Action( + self.tr('PyQt5 Documentation'), + self.tr('PyQt&5 Documentation'), + 0, 0, self, 'pyqt5_documentation') + self.pyqt5DocAct.setStatusTip(self.tr( + 'Open PyQt5 Documentation')) + self.pyqt5DocAct.setWhatsThis(self.tr( + """<b>PyQt5 Documentation</b>""" + """<p>Display the PyQt5 Documentation. Dependent upon your""" + """ settings, this will either show the help in Eric's""" + """ internal help viewer/web browser, or execute a web""" + """ browser or Qt Assistant. </p>""" + )) + self.pyqt5DocAct.triggered.connect(self.__showPyQt5Doc) + self.actions.append(self.pyqt5DocAct) def __initPythonDocActions(self): """ @@ -2917,8 +2908,10 @@ """ self.__menus = {} mb = self.menuBar() - if Utilities.isLinuxPlatform() and \ - not Preferences.getUI("UseNativeMenuBar"): + if ( + Utilities.isLinuxPlatform() and + not Preferences.getUI("UseNativeMenuBar") + ): mb.setNativeMenuBar(False) ############################################################## @@ -2978,8 +2971,9 @@ ## Project menu ############################################################## - self.__menus["project"], self.__menus["project_tools"] = \ + self.__menus["project"], self.__menus["project_tools"] = ( self.project.initMenus() + ) mb.addMenu(self.__menus["project"]) mb.addMenu(self.__menus["project_tools"]) @@ -2987,8 +2981,9 @@ ## Start and Debug menus ############################################################## - self.__menus["start"], self.__menus["debug"] = \ + self.__menus["start"], self.__menus["debug"] = ( self.debuggerUI.initMenus() + ) mb.addMenu(self.__menus["start"]) mb.addMenu(self.__menus["debug"]) @@ -3123,18 +3118,10 @@ self.__menus["window"]) self.__menus["subwindow"].setTearOffEnabled(True) # central park - try: - self.__menus["subwindow"].addSection(self.tr("Central Park")) - except AttributeError: - # Qt4 - self.__menus["subwindow"].addSeparator() + self.__menus["subwindow"].addSection(self.tr("Central Park")) self.__menus["subwindow"].addAction(self.viewmanagerActivateAct) # left side - try: - self.__menus["subwindow"].addSection(self.tr("Left Side")) - except AttributeError: - # Qt4 - pass + self.__menus["subwindow"].addSection(self.tr("Left Side")) if self.__shellPosition == "left": self.__menus["subwindow"].addAction(self.shellActivateAct) self.__menus["subwindow"].addAction(self.pbActivateAct) @@ -3146,22 +3133,14 @@ if self.symbolsViewer is not None: self.__menus["subwindow"].addAction(self.symbolsViewerActivateAct) # bottom side - try: - self.__menus["subwindow"].addSection(self.tr("Bottom Side")) - except AttributeError: - # Qt4 - self.__menus["subwindow"].addSeparator() + self.__menus["subwindow"].addSection(self.tr("Bottom Side")) if self.__shellPosition == "bottom": self.__menus["subwindow"].addAction(self.shellActivateAct) self.__menus["subwindow"].addAction(self.taskViewerActivateAct) self.__menus["subwindow"].addAction(self.logViewerActivateAct) if self.numbersViewer is not None: self.__menus["subwindow"].addAction(self.numbersViewerActivateAct) - try: - self.__menus["subwindow"].addSection(self.tr("Right Side")) - except AttributeError: - # Qt4 - self.__menus["subwindow"].addSeparator() + self.__menus["subwindow"].addSection(self.tr("Right Side")) # right side if self.__shellPosition == "right": self.__menus["subwindow"].addAction(self.shellActivateAct) @@ -3181,18 +3160,14 @@ if self.microPythonWidget is not None: self.__menus["subwindow"].addAction( self.microPythonWidgetActivateAct) - try: - self.__menus["subwindow"].addSection(self.tr("Plug-ins")) - except AttributeError: - # Qt4 - self.__menus["subwindow"].addSeparator() + self.__menus["subwindow"].addSection(self.tr("Plug-ins")) ############################################################## ## Window/Toolbars menu ############################################################## - self.__menus["toolbars"] = \ - QMenu(self.tr("&Toolbars"), self.__menus["window"]) + self.__menus["toolbars"] = QMenu( + self.tr("&Toolbars"), self.__menus["window"]) self.__menus["toolbars"].setTearOffEnabled(True) self.__menus["toolbars"].aboutToShow.connect(self.__showToolbarsMenu) self.__menus["toolbars"].triggered.connect(self.__TBMenuTriggered) @@ -3670,32 +3645,31 @@ versionText = self.tr( """<h3>Version Numbers</h3>""" """<table>""") - versionText += """<tr><td><b>Python</b></td><td>{0}, {1}</td></tr>"""\ - .format(sys.version.split()[0], sizeStr) - versionText += """<tr><td><b>Qt</b></td><td>{0}</td></tr>"""\ - .format(qVersion()) - versionText += """<tr><td><b>PyQt</b></td><td>{0}</td></tr>"""\ - .format(PYQT_VERSION_STR) - versionText += """<tr><td><b>sip</b></td><td>{0}</td></tr>"""\ - .format(sip_version_str) - versionText += """<tr><td><b>QScintilla</b></td><td>{0}</td></tr>"""\ - .format(QSCINTILLA_VERSION_STR) + versionText += ( + """<tr><td><b>Python</b></td><td>{0}, {1}</td></tr>""" + ).format(sys.version.split()[0], sizeStr) + versionText += ( + """<tr><td><b>Qt</b></td><td>{0}</td></tr>""" + ).format(qVersion()) + versionText += ( + """<tr><td><b>PyQt</b></td><td>{0}</td></tr>""" + ).format(PYQT_VERSION_STR) + versionText += ( + """<tr><td><b>sip</b></td><td>{0}</td></tr>""" + ).format(sip_version_str) + versionText += ( + """<tr><td><b>QScintilla</b></td><td>{0}</td></tr>""" + ).format(QSCINTILLA_VERSION_STR) try: from WebBrowser.Tools import WebBrowserTools chromeVersion = WebBrowserTools.getWebEngineVersions()[0] - versionText += \ - """<tr><td><b>WebEngine</b></td><td>{0}</td></tr>"""\ - .format(chromeVersion) + versionText += ( + """<tr><td><b>WebEngine</b></td><td>{0}</td></tr>""" + ).format(chromeVersion) except ImportError: pass - try: - from PyQt5.QtWebKit import qWebKitVersion - versionText += """<tr><td><b>WebKit</b></td><td>{0}</td></tr>"""\ - .format(qWebKitVersion()) - except ImportError: - pass - versionText += """<tr><td><b>{0}</b></td><td>{1}</td></tr>"""\ - .format(Program, Version) + versionText += ("""<tr><td><b>{0}</b></td><td>{1}</td></tr>""" + ).format(Program, Version) versionText += self.tr("""</table>""") E5MessageBox.about(self, Program, versionText) @@ -3772,15 +3746,10 @@ Utilities.generateDistroInfo("\r\n")) url = QUrl("mailto:{0}".format(address)) - if qVersionTuple() >= (5, 0, 0): - from PyQt5.QtCore import QUrlQuery - urlQuery = QUrlQuery(url) - urlQuery.addQueryItem("subject", subject) - urlQuery.addQueryItem("body", body) - url.setQuery(urlQuery) - else: - url.addQueryItem("subject", subject) - url.addQueryItem("body", body) + urlQuery = QUrlQuery(url) + urlQuery.addQueryItem("subject", subject) + urlQuery.addQueryItem("body", body) + url.setQuery(urlQuery) QDesktopServices.openUrl(url) def checkForErrorLog(self): @@ -4314,19 +4283,25 @@ self.profiles[self.currentProfile][2][5] = state # step 2: save the visibility of the windows of the active profile if self.__layoutType == "Toolboxes": - self.profiles[self.currentProfile][1][0] = \ + self.profiles[self.currentProfile][1][0] = ( self.lToolboxDock.isVisible() - self.profiles[self.currentProfile][1][1] = \ + ) + self.profiles[self.currentProfile][1][1] = ( self.hToolboxDock.isVisible() - self.profiles[self.currentProfile][1][2] = \ + ) + self.profiles[self.currentProfile][1][2] = ( self.rToolboxDock.isVisible() + ) elif self.__layoutType == "Sidebars": - self.profiles[self.currentProfile][1][0] = \ + self.profiles[self.currentProfile][1][0] = ( self.leftSidebar.isVisible() - self.profiles[self.currentProfile][1][1] = \ + ) + self.profiles[self.currentProfile][1][1] = ( self.bottomSidebar.isVisible() - self.profiles[self.currentProfile][1][2] = \ + ) + self.profiles[self.currentProfile][1][2] = ( self.rightSidebar.isVisible() + ) Preferences.setUI("ViewProfiles2", self.profiles) def __activateViewProfile(self, name, save=True): @@ -4797,8 +4772,9 @@ """ Private slot to handle the tool groups configuration menu entry. """ - from Preferences.ToolGroupConfigurationDialog import \ + from Preferences.ToolGroupConfigurationDialog import ( ToolGroupConfigurationDialog + ) dlg = ToolGroupConfigurationDialog( self.toolGroups, self.currentToolGroup, self) if dlg.exec_() == QDialog.Accepted: @@ -4998,8 +4974,11 @@ if fn is not None: fn = fn.replace('.qm', '.ts') try: - if os.path.isfile(fn) and os.path.getsize(fn) and \ - fn not in args: + if ( + os.path.isfile(fn) and + os.path.getsize(fn) and + fn not in args + ): args.append(fn) else: E5MessageBox.critical( @@ -5194,8 +5173,10 @@ .format(fn)) return - if not os.path.isfile(viewer) or \ - not proc.startDetached(sys.executable, args): + if ( + not os.path.isfile(viewer) or + not proc.startDetached(sys.executable, args) + ): E5MessageBox.critical( self, self.tr('Process Generation Error'), @@ -5249,8 +5230,10 @@ .format(fn)) return - if not os.path.isfile(viewer) or \ - not proc.startDetached(sys.executable, args): + if ( + not os.path.isfile(viewer) or + not proc.startDetached(sys.executable, args) + ): E5MessageBox.critical( self, self.tr('Process Generation Error'), @@ -5270,8 +5253,10 @@ args = [] args.append(browser) - if not os.path.isfile(browser) or \ - not proc.startDetached(sys.executable, args): + if ( + not os.path.isfile(browser) or + not proc.startDetached(sys.executable, args) + ): E5MessageBox.critical( self, self.tr('Process Generation Error'), @@ -5340,8 +5325,10 @@ args = [] args.append(snap) - if not os.path.isfile(snap) or \ - not proc.startDetached(sys.executable, args): + if ( + not os.path.isfile(snap) or + not proc.startDetached(sys.executable, args) + ): E5MessageBox.critical( self, self.tr('Process Generation Error'), @@ -5413,8 +5400,8 @@ args = [] argv = Utilities.parseOptionString(tool['arguments']) args.extend(argv) - t = self.tr("Starting process '{0} {1}'.\n")\ - .format(program, tool['arguments']) + t = self.tr("Starting process '{0} {1}'.\n" + ).format(program, tool['arguments']) self.appendToStdout(t) proc.finished.connect(self.__toolFinished) @@ -5453,8 +5440,10 @@ for program, toolProc, toolProcData in self.toolProcs: toolProc.setReadChannel(QProcess.StandardOutput) - if toolProcData[0] is None or \ - toolProcData[1] not in ["insert", "replaceSelection"]: + if ( + toolProcData[0] is None or + toolProcData[1] not in ["insert", "replaceSelection"] + ): # not connected to an editor or wrong mode while toolProc.canReadLine(): output = str(toolProc.readLine(), ioEncoding, 'replace') @@ -5516,14 +5505,16 @@ if not pythonDocDir: if Utilities.isWindowsPlatform(): venvName = Preferences.getDebugger("Python3VirtualEnv") - interpreter = e5App().getObject("VirtualEnvManager")\ + interpreter = ( + e5App().getObject("VirtualEnvManager") .getVirtualenvInterpreter(venvName) + ) if interpreter: default = os.path.join(os.path.dirname(interpreter), "doc") else: default = "" - pythonDocDir = \ - Utilities.getEnvironmentEntry("PYTHON3DOCDIR", default) + pythonDocDir = Utilities.getEnvironmentEntry( + "PYTHON3DOCDIR", default) else: pythonDocDir = Utilities.getEnvironmentEntry( "PYTHON3DOCDIR", @@ -5584,14 +5575,16 @@ if not pythonDocDir: if Utilities.isWindowsPlatform(): venvName = Preferences.getDebugger("Python2VirtualEnv") - interpreter = e5App().getObject("VirtualEnvManager")\ + interpreter = ( + e5App().getObject("VirtualEnvManager") .getVirtualenvInterpreter(venvName) + ) if interpreter: default = os.path.join(os.path.dirname(interpreter), "doc") else: default = "" - pythonDocDir = \ - Utilities.getEnvironmentEntry("PYTHON2DOCDIR", default) + pythonDocDir = Utilities.getEnvironmentEntry( + "PYTHON2DOCDIR", default) else: pythonDocDir = Utilities.getEnvironmentEntry( "PYTHON2DOCDIR", @@ -5987,9 +5980,6 @@ os.path.join( os.path.dirname(__file__), "..", "eric6_browser.py"), # QtWebEngine based web browser - os.path.join( - os.path.dirname(__file__), "..", "eric6_webbrowser.py"), - # QtWebKit based web browser ] process = QProcess() for browser in webBrowsers: @@ -6041,8 +6031,9 @@ -1 = server exited with an error code) @rtype int """ - from WebBrowser.WebBrowserSingleApplication import \ + from WebBrowser.WebBrowserSingleApplication import ( WebBrowserSingleApplicationClient + ) webBrowserClient = WebBrowserSingleApplicationClient( self.__webBrowserSAName) @@ -6055,9 +6046,11 @@ connectCount -= 1 QThread.msleep(1000) QApplication.processEvents() - if process.state() == QProcess.NotRunning and \ - process.exitStatus() == QProcess.NormalExit and \ - process.exitCode() == 100: + if ( + process.state() == QProcess.NotRunning and + process.exitStatus() == QProcess.NormalExit and + process.exitCode() == 100 + ): # Process exited prematurely due to missing pre-requisites return -1 if res <= 0: @@ -6145,10 +6138,12 @@ self.__configurationDialog.setPreferences() Preferences.syncPreferences() self.__preferencesChanged() - self.__lastConfigurationPageName = \ + self.__lastConfigurationPageName = ( self.__configurationDialog.getConfigurationPageName() - self.__expandedConfigurationEntries = \ + ) + self.__expandedConfigurationEntries = ( self.__configurationDialog.getExpandedEntries() + ) self.__configurationDialog.deleteLater() self.__configurationDialog = None @@ -6248,13 +6243,9 @@ Preferences.convertPasswords(oldPassword, newPassword) variant = Globals.getWebBrowserSupport() if variant == "QtWebEngine": - from WebBrowser.Passwords.PasswordManager import \ + from WebBrowser.Passwords.PasswordManager import ( PasswordManager - pwManager = PasswordManager() - pwManager.masterPasswordChanged(oldPassword, newPassword) - elif variant == "QtWebKit": - from Helpviewer.Passwords.PasswordManager import \ - PasswordManager + ) pwManager = PasswordManager() pwManager.masterPasswordChanged(oldPassword, newPassword) Utilities.crypto.changeRememberedMaster(newPassword) @@ -6368,8 +6359,9 @@ if dlg.exec_() == QDialog.Accepted: # recent files, recent projects, recent multi projects, # debug histories, shell histories - (files, projects, multiProjects, debug, shell, vcs, plugins) = \ + (files, projects, multiProjects, debug, shell, vcs, plugins) = ( dlg.getData() + ) if files: # clear list of recently opened files self.viewmanager.clearRecent() @@ -6406,8 +6398,8 @@ """ from Debugger.DebugClientCapabilities import HasUnittest self.__setWindowCaption(project=self.project.name) - cap = e5App().getObject("DebugServer")\ - .getClientCapabilities(self.project.getProjectLanguage()) + cap = e5App().getObject("DebugServer").getClientCapabilities( + self.project.getProjectLanguage()) self.utProjectAct.setEnabled(cap & HasUnittest) self.utProjectOpen = cap & HasUnittest @@ -6684,9 +6676,11 @@ """ Private slot to write a crash session file. """ - if not self.__readingSession and \ - not self.__disableCrashSession and \ - Preferences.getUI("CrashSessionEnabled"): + if ( + not self.__readingSession and + not self.__disableCrashSession and + Preferences.getUI("CrashSessionEnabled") + ): self.__writeSession(crashSession=True) def __readCrashSession(self): @@ -6697,9 +6691,11 @@ @rtype bool """ res = False - if not self.__disableCrashSession and \ - not self.__noCrashOpenAtStartup and \ - Preferences.getUI("OpenCrashSessionOnStartup"): + if ( + not self.__disableCrashSession and + not self.__noCrashOpenAtStartup and + Preferences.getUI("OpenCrashSessionOnStartup") + ): fn = os.path.join(Utilities.getConfigDir(), "eric6_crash_session.e5s") if os.path.exists(fn): @@ -6759,8 +6755,8 @@ """ if self.replaceFilesDialog is None: from .FindFileDialog import FindFileDialog - self.replaceFilesDialog = \ - FindFileDialog(self.project, replaceMode=True) + self.replaceFilesDialog = FindFileDialog( + self.project, replaceMode=True) self.replaceFilesDialog.sourceFile.connect( self.viewmanager.openSourceFile) self.replaceFilesDialog.designerFile.connect(self.__designer) @@ -7133,9 +7129,11 @@ ioEncoding = Preferences.getSystem("IOEncoding") versions = str(reply.readAll(), ioEncoding, 'replace').splitlines() reply.close() - if reply.error() != QNetworkReply.NoError or \ - len(versions) == 0 or \ - versions[0].startswith("<"): + if ( + reply.error() != QNetworkReply.NoError or + len(versions) == 0 or + versions[0].startswith("<") + ): # network error or an error page self.httpAlternative += 1 if self.httpAlternative >= len(self.__httpAlternatives): @@ -7299,11 +7297,12 @@ if versions[line] == "---": break - versionText += """<tr><td>{0}</td><td><a href="{1}">{2}</a>""" \ - """</td></tr>""".format( - versions[line], versions[line + 1], - 'sourceforge' in versions[line + 1] and - "SourceForge" or versions[line + 1]) + versionText += ( + """<tr><td>{0}</td><td><a href="{1}">{2}</a></td></tr>""" + ).format( + versions[line], versions[line + 1], + 'sourceforge' in versions[line + 1] and + "SourceForge" or versions[line + 1]) line += 2 versionText += self.tr("""</table>""")