PipInterface: continued with the pip interface widget. pypi

Tue, 19 Feb 2019 19:56:24 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Tue, 19 Feb 2019 19:56:24 +0100
branch
pypi
changeset 6792
9dd854f05c83
parent 6785
058d63c537a4
child 6793
cca6a35f3ad2

PipInterface: continued with the pip interface widget.

PipInterface/Pip.py file | annotate | diff | comparison | revisions
PipInterface/PipListDialog.py file | annotate | diff | comparison | revisions
PipInterface/PipListDialog.ui file | annotate | diff | comparison | revisions
PipInterface/PipPackagesWidget.py file | annotate | diff | comparison | revisions
VirtualEnv/VirtualenvManager.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
--- a/PipInterface/Pip.py	Mon Feb 18 19:49:43 2019 +0100
+++ b/PipInterface/Pip.py	Tue Feb 19 19:56:24 2019 +0100
@@ -15,6 +15,7 @@
 
 import os
 import sys
+import json
 
 from PyQt5.QtCore import pyqtSlot, QObject, QProcess
 from PyQt5.QtWidgets import QMenu, QInputDialog, QDialog
@@ -45,7 +46,7 @@
         """
         super(Pip, self).__init__(parent)
         
-        self.__virtualenvManager = e5App().getObject("VirtualEnvManager")
+##        self.__virtualenvManager = e5App().getObject("VirtualEnvManager")
 ##        self.__project = e5App().getObject("Project")
         
         self.__menus = {}   # dictionary with references to menus
@@ -545,11 +546,11 @@
             if not venvName:
                 self.__selectPipVirtualenv()
                 venvName = Preferences.getPip("CurrentEnvironment")
-            if self.__virtualenvManager.isGlobalEnvironment(venvName):
+            venvManager = e5App().getObject("VirtualEnvManager")
+            if venvManager.isGlobalEnvironment(venvName):
                 venvDirectory = self.__getUserConfig()
             else:
-                venvDirectory = \
-                    self.__virtualenvManager.getVirtualenvDirectory(venvName)
+                venvDirectory = venvManager.getVirtualenvDirectory(venvName)
         
         if venvDirectory:
             config = os.path.join(venvDirectory, pip)
@@ -591,13 +592,15 @@
         if venvName == self.getDefaultEnvironmentString():
             venvName = Preferences.getPip("CurrentEnvironment")
         elif venvName == self.getProjectEnvironmentString():
-            venvName = e5App().getObject("Project").getDebugProperty("VIRTUALENV")
+            venvName = \
+                e5App().getObject("Project").getDebugProperty("VIRTUALENV")
             if not venvName:
                 # fall back to standard if not defined
                 venvName = Preferences.getPip("CurrentEnvironment")
         
-        interpreter = self.__virtualenvManager.getVirtualenvInterpreter(
-            venvName)
+        interpreter = \
+            e5App().getObject("VirtualEnvManager").getVirtualenvInterpreter(
+                venvName)
         if not interpreter:
             E5MessageBox.critical(
                 None,
@@ -614,7 +617,8 @@
         @return sorted list of virtual environment names
         @rtype list of str
         """
-        return sorted(self.__virtualenvManager.getVirtualenvNames())
+        return sorted(
+            e5App().getObject("VirtualEnvManager").getVirtualenvNames())
     
     ##########################################################################
     ## Methods below implement the individual menu entries
@@ -1130,6 +1134,121 @@
         self.__searchDialog = PipSearchDialog(self, indexUrl)
         self.__searchDialog.show()
     
+    def getInstalledPackages(self, envName, localPackages=True,
+                             notRequired=False, usersite=False):
+        """
+        Public method to get the list of installed packages.
+        
+        @param envName name of the environment to get the packages for
+        @type str
+        @param localPackages flag indicating to get local packages only
+        @type bool
+        @param notRequired flag indicating to list packages that are not
+            dependencies of installed packages as well
+        @type bool
+        @param usersite flag indicating to only list packages installed
+            in user-site
+        @type bool
+        @return list of tuples containing the package name and version
+        @rtype list of tuple of (str, str)
+        """
+        packages = []
+        
+        if envName:
+            interpreter = self.getVirtualenvInterpreter(envName)
+            if interpreter:
+                args = [
+                    "-m", "pip",
+                    "list",
+                    "--format=json",
+                ]
+                if localPackages:
+                    args.append("--local")
+                if notRequired:
+                    args.append("--not-required")
+                if usersite:
+                    args.append("--user")
+                
+                proc = QProcess()
+                proc.start(interpreter, args)
+                if proc.waitForStarted(15000):
+                    if proc.waitForFinished(30000):
+                        output = str(proc.readAllStandardOutput(),
+                                     Preferences.getSystem("IOEncoding"),
+                                     'replace').strip()
+                        try:
+                            jsonList = json.loads(output)
+                        except Exception:
+                            jsonList = []
+                        
+                        for package in jsonList:
+                            if isinstance(package, dict):
+                                packages.append((
+                                    package["name"],
+                                    package["version"],
+                                ))
+           
+        return packages
+    
+    def getOutdatedPackages(self, envName, localPackages=True,
+                            notRequired=False, usersite=False):
+        """
+        Public method to get the list of outdated packages.
+        
+        @param envName name of the environment to get the packages for
+        @type str
+        @param localPackages flag indicating to get local packages only
+        @type bool
+        @param notRequired flag indicating to list packages that are not
+            dependencies of installed packages as well
+        @type bool
+        @param usersite flag indicating to only list packages installed
+            in user-site
+        @type bool
+        @return list of tuples containing the package name, installed version
+            and available version
+        @rtype list of tuple of (str, str, str)
+        """
+        packages = []
+        
+        if envName:
+            interpreter = self.getVirtualenvInterpreter(envName)
+            if interpreter:
+                args = [
+                    "-m", "pip",
+                    "list",
+                    "--outdated",
+                    "--format=json",
+                ]
+                if localPackages:
+                    args.append("--local")
+                if notRequired:
+                    args.append("--not-required")
+                if usersite:
+                    args.append("--user")
+                
+                proc = QProcess()
+                proc.start(interpreter, args)
+                if proc.waitForStarted(15000):
+                    if proc.waitForFinished(30000):
+                        output = str(proc.readAllStandardOutput(),
+                                     Preferences.getSystem("IOEncoding"),
+                                     'replace').strip()
+                        try:
+                            jsonList = json.loads(output)
+                        except Exception:
+                            jsonList = []
+                        
+                        for package in jsonList:
+                            if isinstance(package, dict):
+                                packages.append((
+                                    package["name"],
+                                    package["version"],
+                                    package["latest_version"],
+                                ))
+           
+        return packages
+ 
     def __pipConfigure(self):
         """
         Private slot to open the configuration page.
--- a/PipInterface/PipListDialog.py	Mon Feb 18 19:49:43 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,551 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2015 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a dialog to list installed packages.
-"""
-
-from __future__ import unicode_literals
-try:
-    str = unicode       # __IGNORE_EXCEPTION__
-except NameError:
-    pass
-
-import json
-
-from PyQt5.QtCore import pyqtSlot, Qt, QProcess, QTimer
-from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QAbstractButton, \
-    QApplication, QTreeWidgetItem, QHeaderView
-
-from E5Gui import E5MessageBox
-
-from .Ui_PipListDialog import Ui_PipListDialog
-
-import Preferences
-
-
-class PipListDialog(QDialog, Ui_PipListDialog):
-    """
-    Class implementing a dialog to list installed packages.
-    """
-    CommandArguments = {
-        "list": ["list", "--format=json"],
-        "uptodate": ["list", "--uptodate", "--format=json"],
-        "outdated": ["list", "--outdated", "--format=json"],
-    }
-    
-    ShowProcessGeneralMode = 0
-    ShowProcessClassifiersMode = 1
-    ShowProcessEntryPointsMode = 2
-    ShowProcessFilesListMode = 3
-    
-    def __init__(self, pip, mode, indexUrl, title, parent=None):
-        """
-        Constructor
-        
-        @param pip reference to the master object
-        @type Pip
-        @param mode list command mode (one of 'list', 'uptodate', 'outdated')
-        @type str
-        @param indexUrl URL of the pypi index
-        @type str
-        @param title title of the dialog
-        @type str
-        @param parent reference to the parent widget
-        @type QWidget
-        """
-        assert mode in PipListDialog.CommandArguments
-        
-        super(PipListDialog, self).__init__(parent)
-        self.setupUi(self)
-        self.setWindowFlags(Qt.Window)
-        
-        self.setWindowTitle(title)
-        
-        self.__refreshButton = self.buttonBox.addButton(
-            self.tr("&Refresh"), QDialogButtonBox.ActionRole)
-        self.__refreshButton.setEnabled(False)
-        if mode == "outdated":
-            self.__upgradeButton = self.buttonBox.addButton(
-                self.tr("Up&grade"), QDialogButtonBox.ActionRole)
-            self.__upgradeButton.setEnabled(False)
-            self.__upgradeAllButton = self.buttonBox.addButton(
-                self.tr("Upgrade &All"), QDialogButtonBox.ActionRole)
-            self.__upgradeAllButton.setEnabled(False)
-        else:
-            self.__upgradeButton = None
-            self.__upgradeAllButton = None
-        self.__uninstallButton = self.buttonBox.addButton(
-            self.tr("&Uninstall"), QDialogButtonBox.ActionRole)
-        self.__uninstallButton.setEnabled(False)
-        
-        self.__pip = pip
-        self.__mode = mode
-        self.__ioEncoding = Preferences.getSystem("IOEncoding")
-        self.__indexUrl = indexUrl
-        self.__errors = ""
-        self.__output = []
-        
-        self.__nothingStrings = {
-            "list": self.tr("Nothing to show"),
-            "uptodate": self.tr("All packages outdated"),
-            "outdated": self.tr("All packages up-to-date"),
-        }
-        
-        self.venvComboBox.addItem(self.__pip.getDefaultEnvironmentString())
-        projectVenv = self.__pip.getProjectEnvironmentString()
-        if projectVenv:
-            self.venvComboBox.addItem(projectVenv)
-        self.venvComboBox.addItems(self.__pip.getVirtualenvNames())
-        
-        if mode == "list":
-            self.infoLabel.setText(self.tr("Installed Packages:"))
-            self.packageList.setHeaderLabels([
-                self.tr("Package"),
-                self.tr("Version"),
-            ])
-        elif mode == "uptodate":
-            self.infoLabel.setText(self.tr("Up-to-date Packages:"))
-            self.packageList.setHeaderLabels([
-                self.tr("Package"),
-                self.tr("Version"),
-            ])
-        elif mode == "outdated":
-            self.infoLabel.setText(self.tr("Outdated Packages:"))
-            self.packageList.setHeaderLabels([
-                self.tr("Package"),
-                self.tr("Current Version"),
-                self.tr("Latest Version"),
-                self.tr("Package Type"),
-            ])
-        
-        self.packageList.header().setSortIndicator(0, Qt.AscendingOrder)
-        
-        self.__infoLabels = {
-            "name": self.tr("Name:"),
-            "version": self.tr("Version:"),
-            "location": self.tr("Location:"),
-            "requires": self.tr("Requires:"),
-            "summary": self.tr("Summary:"),
-            "home-page": self.tr("Homepage:"),
-            "author": self.tr("Author:"),
-            "author-email": self.tr("Author Email:"),
-            "license": self.tr("License:"),
-            "metadata-version": self.tr("Metadata Version:"),
-            "installer": self.tr("Installer:"),
-            "classifiers": self.tr("Classifiers:"),
-            "entry-points": self.tr("Entry Points:"),
-            "files": self.tr("Files:"),
-        }
-        self.infoWidget.setHeaderLabels(["Key", "Value"])
-        
-        self.process = QProcess()
-        self.process.finished.connect(self.__procFinished)
-        self.process.readyReadStandardOutput.connect(self.__readStdout)
-        self.process.readyReadStandardError.connect(self.__readStderr)
-        
-        self.show()
-        QApplication.processEvents()
-    
-    def __stopProcess(self):
-        """
-        Private slot to stop the running process.
-        """
-        if self.process.state() != QProcess.NotRunning:
-            self.process.terminate()
-            QTimer.singleShot(2000, self.process.kill)
-            self.process.waitForFinished(3000)
-        
-        QApplication.restoreOverrideCursor()
-    
-    def closeEvent(self, e):
-        """
-        Protected slot implementing a close event handler.
-        
-        @param e close event
-        @type QCloseEvent
-        """
-        self.__stopProcess()
-        e.accept()
-    
-    def __finish(self):
-        """
-        Private slot called when the process finished or the user pressed
-        the cancel button.
-        """
-        self.__stopProcess()
-        
-        self.__processOutput()
-        
-        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
-        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
-        self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
-        self.buttonBox.button(QDialogButtonBox.Close).setFocus(
-            Qt.OtherFocusReason)
-        self.__refreshButton.setEnabled(True)
-        
-        if self.packageList.topLevelItemCount() == 0:
-            QTreeWidgetItem(self.packageList,
-                            [self.__nothingStrings[self.__mode]])
-            if self.__errors and not self.__errors.startswith("DEPRECATION"):
-                E5MessageBox.critical(
-                    self,
-                    self.windowTitle(),
-                    self.tr("""<p>The command failed.</p>"""
-                            """<p>Reason: {0}</p>""").format(
-                        self.__errors.replace("\r\n", "<br/>")
-                            .replace("\n", "<br/>").replace("\r", "<br/>")
-                            .replace(" ", "&nbsp;")))
-            if self.__upgradeAllButton is not None:
-                self.__upgradeAllButton.setEnabled(False)
-        else:
-            if self.__upgradeAllButton is not None:
-                self.__upgradeAllButton.setEnabled(True)
-        
-        self.packageList.sortItems(
-            0,
-            self.packageList.header().sortIndicatorOrder())
-        self.packageList.header().resizeSections(
-            QHeaderView.ResizeToContents)
-        self.packageList.header().setStretchLastSection(True)
-    
-    @pyqtSlot(QAbstractButton)
-    def on_buttonBox_clicked(self, button):
-        """
-        Private slot called by a button of the button box clicked.
-        
-        @param button button that was clicked
-        @type QAbstractButton
-        """
-        if button == self.buttonBox.button(QDialogButtonBox.Close):
-            self.close()
-        elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
-            self.__finish()
-        elif button == self.__refreshButton:
-            self.__refresh()
-        elif button == self.__upgradeButton:
-            self.__upgradePackages()
-        elif button == self.__upgradeAllButton:
-            self.__upgradeAllPackages()
-        elif button == self.__uninstallButton:
-            self.__uninstallPackages()
-    
-    def __procFinished(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.__finish()
-    
-    def __refresh(self):
-        """
-        Private slot to refresh the displayed list.
-        """
-        self.__stopProcess()
-        self.start()
-    
-    def start(self):
-        """
-        Public method to start the command.
-        """
-        self.packageList.clear()
-        self.__errors = ""
-        self.__output = []
-        
-        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
-        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True)
-        self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
-        self.__refreshButton.setEnabled(False)
-        if self.__upgradeAllButton is not None:
-            self.__upgradeAllButton.setEnabled(False)
-        QApplication.processEvents()
-        
-        QApplication.setOverrideCursor(Qt.WaitCursor)
-        QApplication.processEvents()
-        
-        venvName = self.venvComboBox.currentText()
-        interpreter = self.__pip.getVirtualenvInterpreter(venvName)
-        if not interpreter:
-            return
-        
-        args = ["-m", "pip"] + PipListDialog.CommandArguments[self.__mode]
-        if self.localCheckBox.isChecked():
-            args.append("--local")
-        if self.notRequiredCheckBox.isChecked():
-            args.append("--not-required")
-        if self.userCheckBox.isChecked():
-            args.append("--user")
-        
-        if self.__indexUrl:
-            args.append("--index-url")
-            args.append(self.__indexUrl + "/simple")
-        
-        self.process.start(interpreter, args)
-        procStarted = self.process.waitForStarted(5000)
-        if not procStarted:
-            self.buttonBox.setFocus()
-            self.__stopProcess()
-            E5MessageBox.critical(
-                self,
-                self.tr('Process Generation Error'),
-                self.tr(
-                    'The process {0} could not be started.'
-                ).format(interpreter))
-            self.__finish()
-    
-    def __processOutput(self):
-        """
-        Private method to process the captured output.
-        """
-        if self.__output:
-            try:
-                packageData = json.loads("\n".join(self.__output))
-                for package in packageData:
-                    data = [
-                        package["name"],
-                        package["version"],
-                    ]
-                    if self.__mode == "outdated":
-                        data.extend([
-                            package["latest_version"],
-                            package["latest_filetype"],
-                        ])
-                    QTreeWidgetItem(self.packageList, data)
-            except ValueError as err:
-                self.__errors += str(err) + "\n"
-                self.__errors += "received output:\n"
-                self.__errors += "\n".join(self.__output)
-    
-    def __readStdout(self):
-        """
-        Private slot to handle the readyReadStandardOutput signal.
-        
-        It reads the output of the process, formats it and inserts it into
-        the contents pane.
-        """
-        self.process.setReadChannel(QProcess.StandardOutput)
-        
-        while self.process.canReadLine():
-            line = str(self.process.readLine(), self.__ioEncoding,
-                       'replace').strip()
-            self.__output.append(line)
-    
-    def __readStderr(self):
-        """
-        Private slot to handle the readyReadStandardError signal.
-        
-        It reads the error output of the process and inserts it into the
-        error pane.
-        """
-        self.__errors += str(self.process.readAllStandardError(),
-                             self.__ioEncoding, 'replace')
-    
-    @pyqtSlot(str)
-    def on_venvComboBox_activated(self, txt):
-        """
-        Private slot handling the selection of a virtual environment.
-        
-        @param txt virtual environment
-        @type str
-        """
-        self.__refresh()
-    
-    @pyqtSlot(bool)
-    def on_localCheckBox_clicked(self, checked):
-        """
-        Private slot handling the switching of the local mode.
-        
-        @param checked state of the local check box
-        @type bool
-        """
-        self.__refresh()
-    
-    @pyqtSlot(bool)
-    def on_notRequiredCheckBox_clicked(self, checked):
-        """
-        Private slot handling the switching of the 'not required' mode.
-        
-        @param checked state of the 'not required' check box
-        @type bool
-        """
-        self.__refresh()
-    
-    @pyqtSlot(bool)
-    def on_userCheckBox_clicked(self, checked):
-        """
-        Private slot handling the switching of the 'user-site' mode.
-        
-        @param checked state of the 'user-site' check box
-        @type bool
-        """
-        self.__refresh()
-    
-    @pyqtSlot()
-    def on_packageList_itemSelectionChanged(self):
-        """
-        Private slot handling the selection of a package.
-        """
-        self.infoWidget.clear()
-        
-        if len(self.packageList.selectedItems()) == 1:
-            itm = self.packageList.selectedItems()[0]
-            
-            environment = self.venvComboBox.currentText()
-            interpreter = self.__pip.getVirtualenvInterpreter(environment)
-            if not interpreter:
-                return
-            
-            QApplication.setOverrideCursor(Qt.WaitCursor)
-            
-            args = ["-m", "pip", "show"]
-            if self.verboseCheckBox.isChecked():
-                args.append("--verbose")
-            if self.installedFilesCheckBox.isChecked():
-                args.append("--files")
-            args.append(itm.text(0))
-            success, output = self.__pip.runProcess(args, interpreter)
-            
-            if success and output:
-                mode = PipListDialog.ShowProcessGeneralMode
-                for line in output.splitlines():
-                    line = line.rstrip()
-                    if line != "---":
-                        if mode != PipListDialog.ShowProcessGeneralMode:
-                            if line[0] == " ":
-                                QTreeWidgetItem(
-                                    self.infoWidget,
-                                    [" ", line.strip()])
-                            else:
-                                mode = PipListDialog.ShowProcessGeneralMode
-                        if mode == PipListDialog.ShowProcessGeneralMode:
-                            try:
-                                label, info = line.split(": ", 1)
-                            except ValueError:
-                                label = line[:-1]
-                                info = ""
-                            label = label.lower()
-                            if label in self.__infoLabels:
-                                QTreeWidgetItem(
-                                    self.infoWidget,
-                                    [self.__infoLabels[label], info])
-                            if label == "files":
-                                mode = PipListDialog.ShowProcessFilesListMode
-                            elif label == "classifiers":
-                                mode = PipListDialog.ShowProcessClassifiersMode
-                            elif label == "entry-points":
-                                mode = PipListDialog.ShowProcessEntryPointsMode
-                self.infoWidget.scrollToTop()
-            
-            header = self.infoWidget.header()
-            header.setStretchLastSection(False)
-            header.resizeSections(QHeaderView.ResizeToContents)
-            if header.sectionSize(0) + header.sectionSize(1) < header.width():
-                header.setStretchLastSection(True)
-            
-            QApplication.restoreOverrideCursor()
-        
-        enable = (len(self.packageList.selectedItems()) > 1 or
-                  (len(self.packageList.selectedItems()) == 1 and
-                   self.packageList.selectedItems()[0].text(0) not in
-                   self.__nothingStrings.values()))
-        self.__upgradeButton and self.__upgradeButton.setEnabled(enable)
-        self.__uninstallButton.setEnabled(enable)
-    
-    @pyqtSlot(bool)
-    def on_verboseCheckBox_clicked(self, checked):
-        """
-        Private slot to handle a change of the verbose package information
-        checkbox.
-        
-        @param checked state of the checkbox
-        @type bool
-        """
-        self.on_packageList_itemSelectionChanged()
-    
-    @pyqtSlot(bool)
-    def on_installedFilesCheckBox_clicked(self, checked):
-        """
-        Private slot to handle a change of the installed files information
-        checkbox.
-        
-        @param checked state of the checkbox
-        @type bool
-        """
-        self.on_packageList_itemSelectionChanged()
-    
-    def __upgradePackages(self):
-        """
-        Private slot to upgrade the selected packages.
-        """
-        packages = []
-        for itm in self.packageList.selectedItems():
-            packages.append(itm.text(0))
-        
-        if packages:
-            if "pip" in packages:
-                self.__upgradePip()
-            else:
-                self.__executeUpgradePackages(packages)
-    
-    def __upgradeAllPackages(self):
-        """
-        Private slot to upgrade all listed packages.
-        """
-        packages = []
-        for index in range(self.packageList.topLevelItemCount()):
-            itm = self.packageList.topLevelItem(index)
-            packages.append(itm.text(0))
-        
-        if packages:
-            if "pip" in packages:
-                self.__upgradePip()
-            else:
-                self.__executeUpgradePackages(packages)
-    
-    def __upgradePip(self):
-        """
-        Private slot to upgrade pip itself.
-        """
-        res = self.__pip.upgradePip(
-            venvName=self.venvComboBox.currentText(),
-            userSite=self.userCheckBox.isChecked())
-        if res:
-            self.__refresh()
-    
-    def __executeUpgradePackages(self, packages):
-        """
-        Private method to execute the pip upgrade command.
-        
-        @param packages list of package names to be upgraded
-        @type list of str
-        """
-        res = self.__pip.upgradePackages(
-            packages, venvName=self.venvComboBox.currentText(),
-            userSite=self.userCheckBox.isChecked())
-        if res:
-            self.activateWindow()
-            self.raise_()
-            self.__refresh()
-    
-    def __uninstallPackages(self):
-        """
-        Private slot to uninstall the selected packages.
-        """
-        packages = []
-        for itm in self.packageList.selectedItems():
-            packages.append(itm.text(0))
-        
-        if packages:
-            res = self.__pip.uninstallPackages(
-                packages,
-                venvName=self.venvComboBox.currentText())
-            if res:
-                self.activateWindow()
-                self.raise_()
-                self.__refresh()
--- a/PipInterface/PipListDialog.ui	Mon Feb 18 19:49:43 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,253 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>PipListDialog</class>
- <widget class="QDialog" name="PipListDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>600</width>
-    <height>650</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Package List</string>
-  </property>
-  <property name="sizeGripEnabled">
-   <bool>true</bool>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout_2">
-   <item>
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <widget class="QLabel" name="label_2">
-       <property name="text">
-        <string>Virtual Environment:</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QComboBox" name="venvComboBox">
-       <property name="sizePolicy">
-        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-         <horstretch>0</horstretch>
-         <verstretch>0</verstretch>
-        </sizepolicy>
-       </property>
-       <property name="toolTip">
-        <string>Select the virtual environment to be used</string>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
-      <widget class="QLabel" name="infoLabel">
-       <property name="text">
-        <string notr="true">TextLabel</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <spacer name="horizontalSpacer">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>40</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-     <item row="0" column="2">
-      <widget class="QCheckBox" name="localCheckBox">
-       <property name="toolTip">
-        <string>Select to show only locally-installed packages</string>
-       </property>
-       <property name="text">
-        <string>Local packages only</string>
-       </property>
-       <property name="checked">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="3">
-      <widget class="QCheckBox" name="notRequiredCheckBox">
-       <property name="toolTip">
-        <string>Select to list packages that are not dependencies of installed packages</string>
-       </property>
-       <property name="text">
-        <string>Not required Packages</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="2">
-      <widget class="QCheckBox" name="userCheckBox">
-       <property name="toolTip">
-        <string>Select to show only packages installed to the user-site</string>
-       </property>
-       <property name="text">
-        <string>User-Site only</string>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <widget class="QSplitter" name="splitter">
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="childrenCollapsible">
-      <bool>false</bool>
-     </property>
-     <widget class="QTreeWidget" name="packageList">
-      <property name="sizePolicy">
-       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-        <horstretch>0</horstretch>
-        <verstretch>3</verstretch>
-       </sizepolicy>
-      </property>
-      <property name="alternatingRowColors">
-       <bool>true</bool>
-      </property>
-      <property name="selectionMode">
-       <enum>QAbstractItemView::ExtendedSelection</enum>
-      </property>
-      <property name="rootIsDecorated">
-       <bool>false</bool>
-      </property>
-      <property name="itemsExpandable">
-       <bool>false</bool>
-      </property>
-      <property name="sortingEnabled">
-       <bool>true</bool>
-      </property>
-      <column>
-       <property name="text">
-        <string notr="true">1</string>
-       </property>
-      </column>
-     </widget>
-     <widget class="QWidget" name="widget" native="true">
-      <property name="sizePolicy">
-       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-        <horstretch>0</horstretch>
-        <verstretch>1</verstretch>
-       </sizepolicy>
-      </property>
-      <layout class="QVBoxLayout" name="verticalLayout">
-       <property name="leftMargin">
-        <number>0</number>
-       </property>
-       <property name="topMargin">
-        <number>0</number>
-       </property>
-       <property name="rightMargin">
-        <number>0</number>
-       </property>
-       <property name="bottomMargin">
-        <number>0</number>
-       </property>
-       <item>
-        <layout class="QHBoxLayout" name="horizontalLayout_2">
-         <item>
-          <widget class="QCheckBox" name="verboseCheckBox">
-           <property name="toolTip">
-            <string>Select to show verbose package information</string>
-           </property>
-           <property name="text">
-            <string>Verbose Package Information</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QCheckBox" name="installedFilesCheckBox">
-           <property name="toolTip">
-            <string>Select to show information about installed files</string>
-           </property>
-           <property name="text">
-            <string>Installed Files Information</string>
-           </property>
-          </widget>
-         </item>
-        </layout>
-       </item>
-       <item>
-        <widget class="QTreeWidget" name="infoWidget">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-           <horstretch>0</horstretch>
-           <verstretch>1</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="alternatingRowColors">
-          <bool>true</bool>
-         </property>
-         <property name="rootIsDecorated">
-          <bool>false</bool>
-         </property>
-         <property name="itemsExpandable">
-          <bool>false</bool>
-         </property>
-         <property name="allColumnsShowFocus">
-          <bool>true</bool>
-         </property>
-         <property name="wordWrap">
-          <bool>true</bool>
-         </property>
-         <property name="columnCount">
-          <number>2</number>
-         </property>
-         <attribute name="headerVisible">
-          <bool>false</bool>
-         </attribute>
-         <attribute name="headerStretchLastSection">
-          <bool>false</bool>
-         </attribute>
-         <column>
-          <property name="text">
-           <string notr="true">1</string>
-          </property>
-         </column>
-         <column>
-          <property name="text">
-           <string notr="true">2</string>
-          </property>
-         </column>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </widget>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Close</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <tabstops>
-  <tabstop>venvComboBox</tabstop>
-  <tabstop>localCheckBox</tabstop>
-  <tabstop>notRequiredCheckBox</tabstop>
-  <tabstop>userCheckBox</tabstop>
-  <tabstop>packageList</tabstop>
-  <tabstop>verboseCheckBox</tabstop>
-  <tabstop>installedFilesCheckBox</tabstop>
-  <tabstop>infoWidget</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
--- a/PipInterface/PipPackagesWidget.py	Mon Feb 18 19:49:43 2019 +0100
+++ b/PipInterface/PipPackagesWidget.py	Tue Feb 19 19:56:24 2019 +0100
@@ -11,7 +11,10 @@
 
 from PyQt5.QtCore import pyqtSlot, Qt
 from PyQt5.QtGui import QCursor
-from PyQt5.QtWidgets import QWidget, QToolButton, QApplication
+from PyQt5.QtWidgets import QWidget, QToolButton, QApplication, QHeaderView, \
+    QTreeWidgetItem
+
+from E5Gui.E5Application import e5App
 
 from .Ui_PipPackagesWidget import Ui_PipPackagesWidget
 
@@ -22,8 +25,13 @@
 
 class PipPackagesWidget(QWidget, Ui_PipPackagesWidget):
     """
-    Class documentation goes here.
+    Class implementing the pip packages management widget.
     """
+    ShowProcessGeneralMode = 0
+    ShowProcessClassifiersMode = 1
+    ShowProcessEntryPointsMode = 2
+    ShowProcessFilesListMode = 3
+    
     def __init__(self, parent=None):
         """
         Constructor
@@ -48,23 +56,44 @@
         
         self.__pip = Pip(self)
         
+        self.packagesList.header().setSortIndicator(0, Qt.AscendingOrder)
+        
+        self.__infoLabels = {
+            "name": self.tr("Name:"),
+            "version": self.tr("Version:"),
+            "location": self.tr("Location:"),
+            "requires": self.tr("Requires:"),
+            "summary": self.tr("Summary:"),
+            "home-page": self.tr("Homepage:"),
+            "author": self.tr("Author:"),
+            "author-email": self.tr("Author Email:"),
+            "license": self.tr("License:"),
+            "metadata-version": self.tr("Metadata Version:"),
+            "installer": self.tr("Installer:"),
+            "classifiers": self.tr("Classifiers:"),
+            "entry-points": self.tr("Entry Points:"),
+            "files": self.tr("Files:"),
+        }
+        self.infoWidget.setHeaderLabels(["Key", "Value"])
+        
+        venvManager = e5App().getObject("VirtualEnvManager")
+        venvManager.virtualEnvironmentAdded.connect(
+            self.on_refreshButton_clicked)
+        venvManager.virtualEnvironmentRemoved.connect(
+            self.on_refreshButton_clicked)
+        
+        project = e5App().getObject("Project")
+        project.projectOpened.connect(
+            self.on_refreshButton_clicked)
+        project.projectClosed.connect(
+            self.on_refreshButton_clicked)
+        
         self.__initPipMenu()
         self.__populateEnvironments()
         self.__updateActionButtons()
         
         self.statusLabel.hide()
         self.searchWidget.hide()
-        
-    def __initPipMenu(self):
-        """
-        Private method to create the super menu and attach it to the super
-        menu button.
-        """
-        self.__pip.initActions()
-        
-        self.__pipMenu = self.__pip.initMenu()
-        
-        self.pipMenuButton.setMenu(self.__pipMenu)
     
     def __populateEnvironments(self):
         """
@@ -76,24 +105,51 @@
             self.environmentsComboBox.addItem(projectVenv)
         self.environmentsComboBox.addItems(self.__pip.getVirtualenvNames())
     
+    #######################################################################
+    ## Slots handling widget signals below
+    #######################################################################
+    
+    def __selectedUpdateableItems(self):
+        """
+        Private method to get a list of selected items that can be updated.
+        
+        @return list of selected items that can be updated
+        @rtype list of QTreeWidgetItem
+        """
+        return [
+            itm for itm in self.packagesList.selectedItems()
+            if bool(itm.text(2))
+        ]
+    
+    def __allUpdateableItems(self):
+        """
+        Private method to get a list of all items that can be updated.
+        
+        @return list of all items that can be updated
+        @rtype list of QTreeWidgetItem
+        """
+        updateableItems = []
+        for index in range(self.packagesList.topLevelItemCount()):
+            itm = self.packagesList.topLevelItem(index)
+            if itm.text(2):
+                updateableItems.append(itm)
+        
+        return updateableItems
+    
     def __updateActionButtons(self):
         """
         Private method to set the state of the action buttons.
         """
-        # TODO: not yet implemented
-        pass
-    
-    #######################################################################
-    ## Slots handling widget signals below
-    #######################################################################
+        self.upgradeButton.setEnabled(
+            bool(self.__selectedUpdateableItems()))
+        self.uninstallButton.setEnabled(
+            bool(self.packagesList.selectedItems()))
+        self.upgradeAllButton.setEnabled(
+            bool(self.__allUpdateableItems()))
     
-    @pyqtSlot(int)
-    def on_environmentsComboBox_currentIndexChanged(self, index):
+    def __refreshPackagesList(self):
         """
-        Private slot handling the selection of a conda environment.
-        
-        @param index index of the selected conda environment
-        @type int
+        Private method to referesh the packages list.
         """
         self.packagesList.clear()
         venvName = self.environmentsComboBox.currentText()
@@ -107,10 +163,34 @@
                 QApplication.processEvents()
                 
                 # 1. populate with installed packages
-                pass    # TODO: add code to list installed
+                self.packagesList.setUpdatesEnabled(False)
+                installedPackages = self.__pip.getInstalledPackages(
+                    venvName,
+                    localPackages=self.localCheckBox.isChecked(),
+                    notRequired=self.notRequiredCheckBox.isChecked(),
+                    usersite=self.userCheckBox.isChecked(),
+                )
+                for package, version in installedPackages:
+                    QTreeWidgetItem(self.packagesList, [package, version])
+                self.packagesList.setUpdatesEnabled(True)
+                self.statusLabel.setText(
+                    self.tr("Getting outdated packages..."))
+                QApplication.processEvents()
                 
                 # 2. update with update information
-                pass    # TODO: add code to list outdated
+                self.packagesList.setUpdatesEnabled(False)
+                outdatedPackages = self.__pip.getOutdatedPackages(
+                    venvName,
+                    localPackages=self.localCheckBox.isChecked(),
+                    notRequired=self.notRequiredCheckBox.isChecked(),
+                    usersite=self.userCheckBox.isChecked(),
+                )
+                for package, _version, latest in outdatedPackages:
+                    items = self.packagesList.findItems(
+                        package, Qt.MatchExactly | Qt.MatchCaseSensitive)
+                    if items:
+                        itm = items[0]
+                        itm.setText(2, latest)
                 
                 self.packagesList.sortItems(0, Qt.AscendingOrder)
                 for col in range(self.packagesList.columnCount()):
@@ -122,6 +202,205 @@
         self.__updateActionButtons()
         self.__updateSearchActionButtons()
     
+    @pyqtSlot(int)
+    def on_environmentsComboBox_currentIndexChanged(self, index):
+        """
+        Private slot handling the selection of a conda environment.
+        
+        @param index index of the selected conda environment
+        @type int
+        """
+        self.__refreshPackagesList()
+    
+    @pyqtSlot(bool)
+    def on_localCheckBox_clicked(self, checked):
+        """
+        Private slot handling the switching of the local mode.
+        
+        @param checked state of the local check box
+        @type bool
+        """
+        self.__refreshPackagesList()
+    
+    @pyqtSlot(bool)
+    def on_notRequiredCheckBox_clicked(self, checked):
+        """
+        Private slot handling the switching of the 'not required' mode.
+        
+        @param checked state of the 'not required' check box
+        @type bool
+        """
+        self.__refreshPackagesList()
+    
+    @pyqtSlot(bool)
+    def on_userCheckBox_clicked(self, checked):
+        """
+        Private slot handling the switching of the 'user-site' mode.
+        
+        @param checked state of the 'user-site' check box
+        @type bool
+        """
+        self.__refreshPackagesList()
+    
+    @pyqtSlot()
+    def on_packagesList_itemSelectionChanged(self):
+        """
+        Private slot handling the selection of a package.
+        """
+        self.infoWidget.clear()
+        
+        if len(self.packagesList.selectedItems()) == 1:
+            itm = self.packagesList.selectedItems()[0]
+            
+            environment = self.environmentsComboBox.currentText()
+            interpreter = self.__pip.getVirtualenvInterpreter(environment)
+            if not interpreter:
+                return
+            
+            QApplication.setOverrideCursor(Qt.WaitCursor)
+            
+            args = ["-m", "pip", "show"]
+            if self.verboseCheckBox.isChecked():
+                args.append("--verbose")
+            if self.installedFilesCheckBox.isChecked():
+                args.append("--files")
+            args.append(itm.text(0))
+            success, output = self.__pip.runProcess(args, interpreter)
+            
+            if success and output:
+                mode = self.ShowProcessGeneralMode
+                for line in output.splitlines():
+                    line = line.rstrip()
+                    if line != "---":
+                        if mode != self.ShowProcessGeneralMode:
+                            if line[0] == " ":
+                                QTreeWidgetItem(
+                                    self.infoWidget,
+                                    [" ", line.strip()])
+                            else:
+                                mode = self.ShowProcessGeneralMode
+                        if mode == self.ShowProcessGeneralMode:
+                            try:
+                                label, info = line.split(": ", 1)
+                            except ValueError:
+                                label = line[:-1]
+                                info = ""
+                            label = label.lower()
+                            if label in self.__infoLabels:
+                                QTreeWidgetItem(
+                                    self.infoWidget,
+                                    [self.__infoLabels[label], info])
+                            if label == "files":
+                                mode = self.ShowProcessFilesListMode
+                            elif label == "classifiers":
+                                mode = self.ShowProcessClassifiersMode
+                            elif label == "entry-points":
+                                mode = self.ShowProcessEntryPointsMode
+                self.infoWidget.scrollToTop()
+            
+            header = self.infoWidget.header()
+            header.setStretchLastSection(False)
+            header.resizeSections(QHeaderView.ResizeToContents)
+            if header.sectionSize(0) + header.sectionSize(1) < header.width():
+                header.setStretchLastSection(True)
+            
+            QApplication.restoreOverrideCursor()
+        
+        self.__updateActionButtons()
+    
+    @pyqtSlot(bool)
+    def on_verboseCheckBox_clicked(self, checked):
+        """
+        Private slot to handle a change of the verbose package information
+        checkbox.
+        
+        @param checked state of the checkbox
+        @type bool
+        """
+        self.on_packagesList_itemSelectionChanged()
+    
+    @pyqtSlot(bool)
+    def on_installedFilesCheckBox_clicked(self, checked):
+        """
+        Private slot to handle a change of the installed files information
+        checkbox.
+        
+        @param checked state of the checkbox
+        @type bool
+        """
+        self.on_packagesList_itemSelectionChanged()
+    
+    @pyqtSlot()
+    def on_refreshButton_clicked(self):
+        """
+        Private slot to refresh the display.
+        """
+        currentEnvironment = self.environmentsComboBox.currentText()
+        self.environmentsComboBox.clear()
+        self.packagesList.clear()
+        
+        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
+        QApplication.processEvents()
+        
+        self.__populateEnvironments()
+        
+        index = self.environmentsComboBox.findText(
+            currentEnvironment, Qt.MatchExactly | Qt.MatchCaseSensitive)
+        if index != -1:
+            self.environmentsComboBox.setCurrentIndex(index)
+        
+        QApplication.restoreOverrideCursor()
+        self.__updateActionButtons()
+    
+    @pyqtSlot()
+    def on_upgradeButton_clicked(self):
+        """
+        Private slot to upgrade selected packages of the selected environment.
+        """
+        packages = [itm.text(0) for itm in self.__selectedUpdateableItems()]
+        if packages:
+            ok = self.__executeUpgradePackages(packages)
+            if ok:
+                self.on_refreshButton_clicked()
+    
+    @pyqtSlot()
+    def on_upgradeAllButton_clicked(self):
+        """
+        Private slot to upgrade all packages of the selected environment.
+        """
+        packages = [itm.text(0) for itm in self.__allUpdateableItems()]
+        if packages:
+            ok = self.__executeUpgradePackages(packages)
+            if ok:
+                self.on_refreshButton_clicked()
+    
+    @pyqtSlot()
+    def on_uninstallButton_clicked(self):
+        """
+        Private slot to remove selected packages of the selected environment.
+        """
+        packages = [itm.text(0) for itm in self.packagesList.selectedItems()]
+        if packages:
+            ok = self.__pip.uninstallPackages(
+                packages,
+                venvName=self.environmentsComboBox.currentText())
+            if ok:
+                self.on_refreshButton_clicked()
+    
+    def __executeUpgradePackages(self, packages):
+        """
+        Private method to execute the pip upgrade command.
+        
+        @param packages list of package names to be upgraded
+        @type list of str
+        @return flag indicating success
+        @rtype bool
+        """
+        ok = self.__pip.upgradePackages(
+            packages, venvName=self.environmentsComboBox.currentText(),
+            userSite=self.userCheckBox.isChecked())
+        return ok
+    
     #######################################################################
     ## Search widget related methods below
     #######################################################################
@@ -156,4 +435,14 @@
     #######################################################################
     ## Menu related methods below
     #######################################################################
-    
+        
+    def __initPipMenu(self):
+        """
+        Private method to create the super menu and attach it to the super
+        menu button.
+        """
+        self.__pip.initActions()
+        
+        self.__pipMenu = self.__pip.initMenu()
+        
+        self.pipMenuButton.setMenu(self.__pipMenu)
--- a/VirtualEnv/VirtualenvManager.py	Mon Feb 18 19:49:43 2019 +0100
+++ b/VirtualEnv/VirtualenvManager.py	Tue Feb 19 19:56:24 2019 +0100
@@ -15,7 +15,7 @@
 import json
 import copy
 
-from PyQt5.QtCore import pyqtSlot, QObject
+from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
 from PyQt5.QtWidgets import QDialog
 
 from E5Gui import E5MessageBox
@@ -27,9 +27,20 @@
 class VirtualenvManager(QObject):
     """
     Class implementing an object to manage Python virtual environments.
+    
+    @signal virtualEnvironmentAdded() emitted to indicate the addition of
+        a virtual environment
+    @signal virtualEnvironmentRemoved() emitted to indicate the removal and
+        deletion of a virtual environment
+    @signal virtualEnvironmentChanged(name) emitted to indicate a change of
+        a virtual environment
     """
     DefaultKey = "<default>"
     
+    virtualEnvironmentAdded = pyqtSignal()
+    virtualEnvironmentRemoved = pyqtSignal()
+    virtualEnvironmentChanged = pyqtSignal(str)
+    
     def __init__(self, parent=None):
         """
         Constructor
@@ -234,6 +245,7 @@
             
             self.__saveSettings()
             
+            self.virtualEnvironmentAdded.emit()
             if self.__virtualenvManagerDialog:
                 self.__virtualenvManagerDialog.refresh()
     
@@ -283,6 +295,7 @@
         
         self.__saveSettings()
         
+        self.virtualEnvironmentChanged.emit(venvName)
         if self.__virtualenvManagerDialog:
             self.__virtualenvManagerDialog.refresh()
     
@@ -368,6 +381,7 @@
                 
                 self.__saveSettings()
                 
+                self.virtualEnvironmentRemoved.emit()
                 if self.__virtualenvManagerDialog:
                     self.__virtualenvManagerDialog.refresh()
     
@@ -421,6 +435,7 @@
                 
                 self.__saveSettings()
                 
+                self.virtualEnvironmentRemoved.emit()
                 if self.__virtualenvManagerDialog:
                     self.__virtualenvManagerDialog.refresh()
     
--- a/eric6.e4p	Mon Feb 18 19:49:43 2019 +0100
+++ b/eric6.e4p	Tue Feb 19 19:56:24 2019 +0100
@@ -475,7 +475,6 @@
     <Source>PipInterface/PipDialog.py</Source>
     <Source>PipInterface/PipFileSelectionDialog.py</Source>
     <Source>PipInterface/PipFreezeDialog.py</Source>
-    <Source>PipInterface/PipListDialog.py</Source>
     <Source>PipInterface/PipPackageDetailsDialog.py</Source>
     <Source>PipInterface/PipPackagesInputDialog.py</Source>
     <Source>PipInterface/PipPackagesWidget.py</Source>
@@ -1828,7 +1827,6 @@
     <Form>PipInterface/PipDialog.ui</Form>
     <Form>PipInterface/PipFileSelectionDialog.ui</Form>
     <Form>PipInterface/PipFreezeDialog.ui</Form>
-    <Form>PipInterface/PipListDialog.ui</Form>
     <Form>PipInterface/PipPackageDetailsDialog.ui</Form>
     <Form>PipInterface/PipPackagesInputDialog.ui</Form>
     <Form>PipInterface/PipPackagesWidget.ui</Form>
@@ -2262,14 +2260,14 @@
   </Resources>
   <Others>
     <Other>.hgignore</Other>
+    <Other>APIs/Python/zope-2.10.7.api</Other>
+    <Other>APIs/Python/zope-2.11.2.api</Other>
+    <Other>APIs/Python/zope-3.3.1.api</Other>
     <Other>APIs/Python3/PyQt4.bas</Other>
     <Other>APIs/Python3/PyQt5.bas</Other>
     <Other>APIs/Python3/QScintilla2.bas</Other>
     <Other>APIs/Python3/eric6.api</Other>
     <Other>APIs/Python3/eric6.bas</Other>
-    <Other>APIs/Python/zope-2.10.7.api</Other>
-    <Other>APIs/Python/zope-2.11.2.api</Other>
-    <Other>APIs/Python/zope-3.3.1.api</Other>
     <Other>APIs/QSS/qss.api</Other>
     <Other>APIs/Ruby/Ruby-1.8.7.api</Other>
     <Other>APIs/Ruby/Ruby-1.8.7.bas</Other>

eric ide

mercurial