Merged with branch 'eric7' to prepare a new release. eric7-maintenance release-22.04

Sat, 02 Apr 2022 11:23:11 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 02 Apr 2022 11:23:11 +0200
branch
eric7-maintenance
changeset 9010
248ca0be0cb6
parent 8968
76a32b7b17b2 (current diff)
parent 9009
f9ed699ad123 (diff)
child 9011
429cc091bf0e

Merged with branch 'eric7' to prepare a new release.

eric7/i18n/eric7_es.ts file | annotate | diff | comparison | revisions
eric7/i18n/eric7_ru.qm file | annotate | diff | comparison | revisions
eric7/i18n/eric7_ru.ts file | annotate | diff | comparison | revisions
--- a/docs/changelog	Fri Mar 04 18:07:10 2022 +0100
+++ b/docs/changelog	Sat Apr 02 11:23:11 2022 +0200
@@ -1,5 +1,18 @@
 Change Log
 ----------
+Version 22.4:
+- bug fixes
+- General
+  -- added capability to upgrade PyQt packages eric depends on from within eric
+  -- added capability to upgrade eric from within eric
+- pip Interface
+  -- added a vulnerability check for installed packages based on "Safety DB"
+  -- added a widget to show a package dependency tree
+  -- added a button to search for more packages (i.e. one more page of results)
+- Third Party packages
+  -- upgraded coverage to 6.3.2
+  -- upgraded mccabe to version 0.7.0
+
 Version 22.3:
 - bug fixes
 - General
--- a/eric7.epj	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7.epj	Sat Apr 02 11:23:11 2022 +0200
@@ -61,12 +61,17 @@
         "CopyrightMinFileSize": 0,
         "DocstringType": "eric",
         "EnabledCheckerCategories": "C, D, E, M, N, Y, W",
-        "ExcludeFiles": "*/ThirdParty/*, */coverage/*, */Ui_*.py, */Examples/*, */*_rc.py,*/pycodestyle.py,*/pyflakes/checker.py,*/mccabe.py,*/eradicate.py,*/ast_unparse.py",
+        "ExcludeFiles": "*/ThirdParty/*, */coverage/*, */Ui_*.py, */Examples/*, */*_rc.py,*/pycodestyle.py,*/pyflakes/checker.py,*/mccabe.py,*/eradicate.py,*/ast_unparse.py,*/piplicenses.py",
         "ExcludeMessages": "C101,E265,E266,E305,E402,M201,M301,M302,M303,M304,M305,M306,M307,M308,M311,M312,M313,M314,M315,M321,M701,M702,M811,M834,N802,N803,N807,N808,N821,W293,W504,Y119,Y401,Y402",
         "FixCodes": "",
         "FixIssues": false,
         "FutureChecker": "",
         "HangClosing": false,
+        "ImportsChecker": {
+          "ApplicationPackageNames": [],
+          "BanRelativeImports": "",
+          "BannedModules": []
+        },
         "IncludeMessages": "",
         "LineComplexity": 25,
         "LineComplexityScore": 10,
@@ -718,7 +723,9 @@
       "eric7/Preferences/ConfigurationPages/InterfaceLightPage.ui",
       "eric7/HelpViewer/HelpBookmarkPropertiesDialog.ui",
       "eric7/HelpViewer/HelpBookmarksImportDialog.ui",
-      "eric7/MicroPython/BoardDataDialog.ui"
+      "eric7/MicroPython/BoardDataDialog.ui",
+      "eric7/UI/VersionsDialog.ui",
+      "eric7/PipInterface/PipLicensesDialog.ui"
     ],
     "HASH": "df7daa8781250f7664e6ecaeaf1361fa2efd39ee",
     "IDLPARAMS": {
@@ -2313,7 +2320,14 @@
       "eric7/HelpViewer/HelpBookmarkPropertiesDialog.py",
       "eric7/HelpViewer/HelpBookmarksImportDialog.py",
       "eric7/MicroPython/BoardDataDialog.py",
-      "eric7/__main__.py"
+      "eric7/__main__.py",
+      "eric7/UI/VersionsDialog.py",
+      "eric7/UI/upgrader.py",
+      "eric7/PipInterface/PipVulnerabilityChecker.py",
+      "scripts/install-dependencies.py",
+      "eric7/DebugClients/Python/coverage/lcovreport.py",
+      "eric7/PipInterface/PipLicensesDialog.py",
+      "eric7/PipInterface/piplicenses.py"
     ],
     "SPELLEXCLUDES": "Dictionaries/excludes.dic",
     "SPELLLANGUAGE": "en_US",
@@ -2391,4 +2405,4 @@
     "VCSOTHERDATA": {},
     "VERSION": "7.x"
   }
-}
+}
\ No newline at end of file
--- a/eric7/APIs/Python3/eric7.api	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/APIs/Python3/eric7.api	Sat Apr 02 11:23:11 2022 +0200
@@ -3047,18 +3047,25 @@
 eric7.PipInterface.Pip.Pip.cacheList?4(venvName)
 eric7.PipInterface.Pip.Pip.cachePurge?4(venvName)
 eric7.PipInterface.Pip.Pip.cacheRemove?4(venvName)
+eric7.PipInterface.Pip.Pip.checkPackageOutdated?4(packageStart, envName)
+eric7.PipInterface.Pip.Pip.getDependecyTree?4(envName, localPackages=True, usersite=False, reverse=False)
+eric7.PipInterface.Pip.Pip.getFrozenPackages?4(envName, localPackages=True, usersite=False, requirement=None)
 eric7.PipInterface.Pip.Pip.getIndexUrl?4()
 eric7.PipInterface.Pip.Pip.getIndexUrlPypi?4()
 eric7.PipInterface.Pip.Pip.getIndexUrlSearch?4()
 eric7.PipInterface.Pip.Pip.getInstalledPackages?4(envName, localPackages=True, notRequired=False, usersite=False)
+eric7.PipInterface.Pip.Pip.getLicenses?4(envName, localPackages=True, usersite=False, summary=False)
+eric7.PipInterface.Pip.Pip.getLicensesSummary?4(envName, localPackages=True, usersite=False)
 eric7.PipInterface.Pip.Pip.getNetworkAccessManager?4()
 eric7.PipInterface.Pip.Pip.getOutdatedPackages?4(envName, localPackages=True, notRequired=False, usersite=False)
 eric7.PipInterface.Pip.Pip.getPackageDetails?4(name, version)
+eric7.PipInterface.Pip.Pip.getPackageVersions?4(name)
 eric7.PipInterface.Pip.Pip.getProjectEnvironmentString?4()
 eric7.PipInterface.Pip.Pip.getUserConfig?4()
 eric7.PipInterface.Pip.Pip.getVirtualenvConfig?4(venvName)
 eric7.PipInterface.Pip.Pip.getVirtualenvInterpreter?4(venvName)
 eric7.PipInterface.Pip.Pip.getVirtualenvNames?4(noRemote=False, noConda=False)
+eric7.PipInterface.Pip.Pip.getVulnerabilityChecker?4()
 eric7.PipInterface.Pip.Pip.installPackages?4(packages, venvName="", userSite=False, interpreter="", forceReinstall=False)
 eric7.PipInterface.Pip.Pip.installPip?4(venvName, userSite=False)
 eric7.PipInterface.Pip.Pip.installRequirements?4(venvName)
@@ -3081,15 +3088,22 @@
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_buttonBox_clicked?4(button)
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_copyButton_clicked?4()
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_insertButton_clicked?4()
-eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_localCheckBox_clicked?4(checked)
+eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_localCheckBox_clicked?4()
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_replaceAllButton_clicked?4()
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_replaceSelectionButton_clicked?4()
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_requirementsEdit_textChanged?4()
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_requirementsFilePicker_textChanged?4(txt)
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_saveButton_clicked?4()
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_saveToButton_clicked?4()
+eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.on_userCheckBox_clicked?4()
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog.start?4(venvName)
 eric7.PipInterface.PipFreezeDialog.PipFreezeDialog?1(pip, parent=None)
+eric7.PipInterface.PipLicensesDialog.PipLicensesDialog.LicensesLicenseColumn?7
+eric7.PipInterface.PipLicensesDialog.PipLicensesDialog.LicensesPackageColumn?7
+eric7.PipInterface.PipLicensesDialog.PipLicensesDialog.LicensesVersionColumn?7
+eric7.PipInterface.PipLicensesDialog.PipLicensesDialog.SummaryCountColumn?7
+eric7.PipInterface.PipLicensesDialog.PipLicensesDialog.SummaryLicenseColumn?7
+eric7.PipInterface.PipLicensesDialog.PipLicensesDialog?1(pip, environment, localPackages=True, usersite=False, parent=None)
 eric7.PipInterface.PipPackageDetailsDialog.PipPackageDetailsDialog.ButtonInstall?7
 eric7.PipInterface.PipPackageDetailsDialog.PipPackageDetailsDialog.ButtonRemove?7
 eric7.PipInterface.PipPackageDetailsDialog.PipPackageDetailsDialog.ButtonUpgrade?7
@@ -3098,37 +3112,57 @@
 eric7.PipInterface.PipPackagesInputDialog.PipPackagesInputDialog.getData?4()
 eric7.PipInterface.PipPackagesInputDialog.PipPackagesInputDialog.on_packagesEdit_textChanged?4(txt)
 eric7.PipInterface.PipPackagesInputDialog.PipPackagesInputDialog?1(pip, title, install=True, parent=None)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.AvailableVersionColumn?7
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.DepInstalledVersionColumn?7
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.DepPackageColumn?7
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.DepRequiredVersionColumn?7
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.InstalledVersionColumn?7
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.PackageColumn?7
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.SearchVersionRole?7
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.ShowProcessClassifiersMode?7
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.ShowProcessEntryPointsMode?7
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.ShowProcessFilesListMode?7
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.ShowProcessGeneralMode?7
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.VulnerabilityColumn?7
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.VulnerabilityRole?7
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.executeInstallPackages?4(packages, userSite=False)
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.executeUninstallPackages?4(packages)
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.executeUpgradePackages?4(packages)
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.getPip?4()
-eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_environmentsComboBox_currentIndexChanged?4(index)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_dependenciesList_itemActivated?4(item, column)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_dependenciesList_itemPressed?4(item, column)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_dependenciesList_itemSelectionChanged?4()
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_environmentsComboBox_currentTextChanged?4(name)
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_installButton_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_installUserSiteButton_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_installedFilesCheckBox_clicked?4(checked)
-eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_localCheckBox_clicked?4(checked)
-eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_notRequiredCheckBox_clicked?4(checked)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_localCheckBox_clicked?4()
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_localDepCheckBox_clicked?4()
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_notRequiredCheckBox_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_packagesList_itemActivated?4(item, column)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_packagesList_itemPressed?4(item, column)
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_packagesList_itemSelectionChanged?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_refreshButton_clicked?4()
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_refreshDependenciesButton_clicked?4()
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_requiresButton_toggled?4(checked)
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_searchButton_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_searchEditName_returnPressed?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_searchEditName_textChanged?4(txt)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_searchMoreButton_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_searchResultList_itemActivated?4(item, column)
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_searchResultList_itemSelectionChanged?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_searchToggleButton_toggled?4(checked)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_showDepPackageDetailsButton_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_showDetailsButton_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_showPackageDetailsButton_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_uninstallButton_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_upgradeAllButton_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_upgradeButton_clicked?4()
-eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_userCheckBox_clicked?4(checked)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_userCheckBox_clicked?4()
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_userDepCheckBox_clicked?4()
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_verboseCheckBox_clicked?4(checked)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_viewToggleButton_toggled?4(checked)
+eric7.PipInterface.PipPackagesWidget.PipPackagesWidget.on_vulnerabilityCheckBox_clicked?4(checked)
 eric7.PipInterface.PipPackagesWidget.PipPackagesWidget?1(pip, parent=None)
 eric7.PipInterface.PipPackagesWidget.PypiSearchResultsParser.ClassPrefix?7
 eric7.PipInterface.PipPackagesWidget.PypiSearchResultsParser.getResults?4()
@@ -3136,6 +3170,52 @@
 eric7.PipInterface.PipPackagesWidget.PypiSearchResultsParser.handle_endtag?4(tag)
 eric7.PipInterface.PipPackagesWidget.PypiSearchResultsParser.handle_starttag?4(tag, attrs)
 eric7.PipInterface.PipPackagesWidget.PypiSearchResultsParser?1(data)
+eric7.PipInterface.PipVulnerabilityChecker.PipVulnerabilityChecker.FullDbFile?7
+eric7.PipInterface.PipVulnerabilityChecker.PipVulnerabilityChecker.SummaryDbFile?7
+eric7.PipInterface.PipVulnerabilityChecker.PipVulnerabilityChecker.check?4(packages)
+eric7.PipInterface.PipVulnerabilityChecker.PipVulnerabilityChecker.updateVulnerabilityDb?4()
+eric7.PipInterface.PipVulnerabilityChecker.PipVulnerabilityChecker?1(pip, parent=None)
+eric7.PipInterface.PipVulnerabilityChecker.VulnerabilityCheckError.FullDbUnavailable?7
+eric7.PipInterface.PipVulnerabilityChecker.VulnerabilityCheckError.OK?7
+eric7.PipInterface.PipVulnerabilityChecker.VulnerabilityCheckError.SummaryDbUnavailable?7
+eric7.PipInterface.piplicenses.CompatibleArgumentParser._verify_args?5(args: CustomNamespace)
+eric7.PipInterface.piplicenses.CompatibleArgumentParser.parse_args?4(args: Optional[Sequence[Text]] = None, namespace: CustomNamespace = None)
+eric7.PipInterface.piplicenses.CustomHelpFormatter._expand_help?5(action: argparse.Action)
+eric7.PipInterface.piplicenses.CustomHelpFormatter._format_action?5(action: argparse.Action)
+eric7.PipInterface.piplicenses.CustomHelpFormatter._split_lines?5(text: Text, width: int)
+eric7.PipInterface.piplicenses.CustomHelpFormatter?1(prog: Text, indent_increment: int = 2, max_help_position: int = 24, width: Optional[int] = None)
+eric7.PipInterface.piplicenses.DEFAULT_OUTPUT_FIELDS?7
+eric7.PipInterface.piplicenses.FIELDS_TO_METADATA_KEYS?7
+eric7.PipInterface.piplicenses.FIELD_NAMES?7
+eric7.PipInterface.piplicenses.FromArg.ALL?7
+eric7.PipInterface.piplicenses.FromArg.CLASSIFIER?7
+eric7.PipInterface.piplicenses.FromArg.META?7
+eric7.PipInterface.piplicenses.FromArg.MIXED?7
+eric7.PipInterface.piplicenses.LICENSE_UNKNOWN?7
+eric7.PipInterface.piplicenses.MAP_DEST_TO_ENUM?7
+eric7.PipInterface.piplicenses.METADATA_KEYS?7
+eric7.PipInterface.piplicenses.OrderArg.AUTHOR?7
+eric7.PipInterface.piplicenses.OrderArg.COUNT?7
+eric7.PipInterface.piplicenses.OrderArg.LICENSE?7
+eric7.PipInterface.piplicenses.OrderArg.NAME?7
+eric7.PipInterface.piplicenses.OrderArg.URL?7
+eric7.PipInterface.piplicenses.SUMMARY_OUTPUT_FIELDS?7
+eric7.PipInterface.piplicenses.SYSTEM_PACKAGES?7
+eric7.PipInterface.piplicenses.choices_from_enum?4(enum_cls: NoValueEnum)
+eric7.PipInterface.piplicenses.create_licenses_list?4(args: "CustomNamespace", output_fields=DEFAULT_OUTPUT_FIELDS)
+eric7.PipInterface.piplicenses.create_output_string?4(args: "CustomNamespace")
+eric7.PipInterface.piplicenses.create_parser?4()
+eric7.PipInterface.piplicenses.create_summary_list?4(args: "CustomNamespace")
+eric7.PipInterface.piplicenses.enum_key_to_value?4(enum_key: Enum)
+eric7.PipInterface.piplicenses.find_license_from_classifier?4(message)
+eric7.PipInterface.piplicenses.get_installed_distributions?4(local_only=True, user_only=False)
+eric7.PipInterface.piplicenses.get_output_fields?4(args: "CustomNamespace")
+eric7.PipInterface.piplicenses.get_packages?4(args: "CustomNamespace")
+eric7.PipInterface.piplicenses.get_pkg_included_file?4(pkg, file_names)
+eric7.PipInterface.piplicenses.get_pkg_info?4(pkg)
+eric7.PipInterface.piplicenses.main?4()
+eric7.PipInterface.piplicenses.select_license_by_source?4(from_source, license_classifier, license_meta)
+eric7.PipInterface.piplicenses.value_to_enum_key?4(value: str)
 eric7.PluginManager.PluginDetailsDialog.PluginDetailsDialog.on_activeCheckBox_clicked?4()
 eric7.PluginManager.PluginDetailsDialog.PluginDetailsDialog.on_autoactivateCheckBox_clicked?4()
 eric7.PluginManager.PluginDetailsDialog.PluginDetailsDialog?1(details, parent=None)
@@ -9829,7 +9909,7 @@
 eric7.UI.UserInterface.UserInterface.maxMenuFilePathLen?7
 eric7.UI.UserInterface.UserInterface.networkAccessManager?4()
 eric7.UI.UserInterface.UserInterface.onlineStateChanged?7
-eric7.UI.UserInterface.UserInterface.performVersionCheck?4(manual=True, alternative=0, showVersions=False)
+eric7.UI.UserInterface.UserInterface.performVersionCheck?4()
 eric7.UI.UserInterface.UserInterface.preferencesChanged?7
 eric7.UI.UserInterface.UserInterface.processArgs?4(args)
 eric7.UI.UserInterface.UserInterface.processInstallInfoFile?4()
@@ -9839,7 +9919,6 @@
 eric7.UI.UserInterface.UserInterface.removeSideWidget?4(widget)
 eric7.UI.UserInterface.UserInterface.reregisterToolbar?4(name, text, category="")
 eric7.UI.UserInterface.UserInterface.setDebugProfile?4(save=True)
-eric7.UI.UserInterface.UserInterface.showAvailableVersionsInfo?4()
 eric7.UI.UserInterface.UserInterface.showEmailDialog?4(mode, attachFile=None, deleteAttachFile=False)
 eric7.UI.UserInterface.UserInterface.showEvent?4(evt)
 eric7.UI.UserInterface.UserInterface.showFindFileByNameDialog?4()
@@ -9852,8 +9931,17 @@
 eric7.UI.UserInterface.UserInterface.showReplaceFilesWidget?4(txt="", searchDir="", openFiles=False)
 eric7.UI.UserInterface.UserInterface.showSideWidget?4(widget)
 eric7.UI.UserInterface.UserInterface.unregisterToolbar?4(name)
+eric7.UI.UserInterface.UserInterface.upgradeEric?4()
+eric7.UI.UserInterface.UserInterface.upgradeEricPyQt?4()
+eric7.UI.UserInterface.UserInterface.upgradePyQt?4()
 eric7.UI.UserInterface.UserInterface.versionIsNewer?4(required, snapshot=None)
 eric7.UI.UserInterface.UserInterface?1(app, locale, splash, plugin, disabledPlugins, noOpenAtStartup, noCrashOpenAtStartup, disableCrashSession, restartArguments, originalPathString)
+eric7.UI.VersionsDialog.VersionsDialog?1(parent, title, text)
+eric7.UI.upgrader._ericPackages?8
+eric7.UI.upgrader._pyqtPackages?8
+eric7.UI.upgrader.doUpgrade?4(packages)
+eric7.UI.upgrader.main?4()
+eric7.UI.upgrader.startEric?4(args)
 eric7.Utilities.AutoSaver.AutoSaver.AUTOSAVE_IN?7
 eric7.Utilities.AutoSaver.AutoSaver.MAXWAIT?7
 eric7.Utilities.AutoSaver.AutoSaver.changeOccurred?4()
@@ -10508,6 +10596,7 @@
 eric7.VirtualEnv.VirtualenvManager.VirtualenvManager.addVirtualEnv?4(venvName, venvDirectory, venvInterpreter="", isGlobal=False, isConda=False, isRemote=False, execPath="")
 eric7.VirtualEnv.VirtualenvManager.VirtualenvManager.createVirtualEnv?4(baseDir="")
 eric7.VirtualEnv.VirtualenvManager.VirtualenvManager.deleteVirtualEnvs?4(venvNames)
+eric7.VirtualEnv.VirtualenvManager.VirtualenvManager.environmentForInterpreter?4(interpreter)
 eric7.VirtualEnv.VirtualenvManager.VirtualenvManager.getDefaultEnvironment?4()
 eric7.VirtualEnv.VirtualenvManager.VirtualenvManager.getEnvironmentEntries?4()
 eric7.VirtualEnv.VirtualenvManager.VirtualenvManager.getVirtualEnvironmentsBaseDir?4()
@@ -12481,6 +12570,8 @@
 install-debugclients.shutilCopy?4(src, dst, perm=0o644)
 install-debugclients.sourceDir?7
 install-debugclients.usage?4(rcode=2)
+install-dependencies.main?4()
+install-dependencies.pipInstall?4(packageName)
 install-i18n.configDir?7
 install-i18n.getConfigDir?4()
 install-i18n.installTranslations?4()
--- a/eric7/APIs/Python3/eric7.bas	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/APIs/Python3/eric7.bas	Sat Apr 02 11:23:11 2022 +0200
@@ -96,6 +96,7 @@
 ColorDialogWizardDialog QDialog Ui_ColorDialogWizardDialog
 CompareDialog QWidget Ui_CompareDialog
 CompareWindow EricMainWindow
+CompatibleArgumentParser argparse.ArgumentParser
 CompleterBase QObject
 CompleterPython CompleterBase
 CompleterRuby CompleterBase
@@ -127,6 +128,8 @@
 CooperationServer QTcpServer
 CorbaPage ConfigurationPageBase Ui_CorbaPage
 CreateDialogCodeDialog QDialog Ui_CreateDialogCodeDialog
+CustomHelpFormatter argparse.HelpFormatter
+CustomNamespace argparse.Namespace
 DCTestResult TestResult
 DateTimeVisitor ast.NodeVisitor
 DebugClient DebugBase DebugClientBase ThreadExtension
@@ -336,6 +339,7 @@
 FontDialogWizard QObject
 FontDialogWizardDialog QDialog Ui_FontDialogWizardDialog
 FrameScroller QObject
+FromArg NoValueEnum
 FtpDirLineParser QObject
 FtpDirLineParserError Exception
 FtpSyncHandler SyncHandler
@@ -662,6 +666,7 @@
 NetworkUrlInterceptor QWebEngineUrlRequestInterceptor
 NewDialogClassDialog QDialog Ui_NewDialogClassDialog
 NewPythonPackageDialog QDialog Ui_NewPythonPackageDialog
+NoValueEnum Enum
 NodeTypeEnum enum.IntEnum
 NotificationFrame QFrame Ui_NotificationFrame
 NotificationTypes enum.Enum
@@ -680,6 +685,7 @@
 OpenSearchReader QXmlStreamReader
 OpenSearchWriter QXmlStreamWriter
 OperaImporter BookmarksImporter
+OrderArg NoValueEnum
 PackageDiagramBuilder UMLDiagramBuilder
 PackageItem UMLItem
 PackageModel UMLModel
@@ -699,10 +705,12 @@
 PipDialog QDialog Ui_PipDialog
 PipFileSelectionDialog QDialog Ui_PipFileSelectionDialog
 PipFreezeDialog QDialog Ui_PipFreezeDialog
+PipLicensesDialog QDialog Ui_PipLicensesDialog
 PipPackageDetailsDialog QDialog Ui_PipPackageDetailsDialog
 PipPackagesInputDialog QDialog Ui_PipPackagesInputDialog
 PipPackagesWidget QWidget Ui_PipPackagesWidget
 PipPage ConfigurationPageBase Ui_PipPage
+PipVulnerabilityChecker QObject
 PixmapDiagram EricMainWindow
 PluginActivationError PluginError
 PluginClassFormatError PluginError
@@ -830,6 +838,7 @@
 SearchReplaceWidget QWidget
 SearchWidget QWidget Ui_SearchWidget
 SecurityPage ConfigurationPageBase Ui_SecurityPage
+SelectAction argparse.Action
 SendRefererWhitelistDialog QDialog Ui_SendRefererWhitelistDialog
 Service ClbrBaseClasses.Class VisibilityMixin
 ServiceMethod ClbrBaseClasses.Function VisibilityMixin
@@ -1026,6 +1035,7 @@
 VcsStatusMonitorThread QThread
 VcsSubversionPlugin QObject
 VersionControl QObject
+VersionsDialog QDialog Ui_VersionsDialog
 ViewManager QWidget
 ViewProfileDialog QDialog
 ViewmanagerPage ConfigurationPageBase Ui_ViewmanagerPage
@@ -1045,6 +1055,7 @@
 VisibilityMixin ClbrBaseClasses.ClbrVisibilityMixinBase
 VmListspacePlugin QObject
 VmTabviewPlugin QObject
+VulnerabilityCheckError enum.Enum
 WatchPointModel QAbstractItemModel
 WatchPointViewer QTreeView
 WebBrowserAppearancePage ConfigurationPageBase Ui_WebBrowserAppearancePage
--- a/eric7/DebugClients/Python/coverage/cmdline.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/cmdline.py	Sat Apr 02 11:23:11 2022 +0200
@@ -3,7 +3,6 @@
 
 """Command-line support for coverage.py."""
 
-
 import glob
 import optparse     # pylint: disable=deprecated-module
 import os
@@ -18,16 +17,22 @@
 from coverage import env
 from coverage.collector import CTracer
 from coverage.config import CoverageConfig
+from coverage.control import DEFAULT_DATAFILE
 from coverage.data import combinable_files, debug_data_file
-from coverage.debug import info_formatter, info_header, short_stack
+from coverage.debug import info_header, short_stack, write_formatted_info
 from coverage.exceptions import _BaseCoverageException, _ExceptionDuringRun, NoSource
 from coverage.execfile import PyRunner
 from coverage.results import Numbers, should_fail_under
 
+# When adding to this file, alphabetization is important.  Look for
+# "alphabetize" comments throughout.
 
 class Opts:
     """A namespace class for individual options we'll build parsers from."""
 
+    # Keep these entries alphabetized (roughly) by the option name as it
+    # appears on the command line.
+
     append = optparse.make_option(
         '-a', '--append', action='store_true',
         help="Append coverage data to .coverage, otherwise it starts clean each time.",
@@ -52,13 +57,33 @@
         help="The context label to record for this coverage run.",
     )
     contexts = optparse.make_option(
-        '', '--contexts', action='store',
-        metavar="REGEX1,REGEX2,...",
+        '', '--contexts', action='store', metavar="REGEX1,REGEX2,...",
         help=(
             "Only display data from lines covered in the given contexts. " +
             "Accepts Python regexes, which must be quoted."
         ),
     )
+    combine_datafile = optparse.make_option(
+        '', '--data-file', action='store', metavar="DATAFILE",
+        help=(
+            "Base name of the data files to operate on. " +
+            "Defaults to '.coverage'. [env: COVERAGE_FILE]"
+        ),
+    )
+    input_datafile = optparse.make_option(
+        '', '--data-file', action='store', metavar="INFILE",
+        help=(
+            "Read coverage data for report generation from this file. " +
+            "Defaults to '.coverage'. [env: COVERAGE_FILE]"
+        ),
+    )
+    output_datafile = optparse.make_option(
+        '', '--data-file', action='store', metavar="OUTFILE",
+        help=(
+            "Write the recorded coverage data to this file. " +
+            "Defaults to '.coverage'. [env: COVERAGE_FILE]"
+        ),
+    )
     debug = optparse.make_option(
         '', '--debug', action='store', metavar="OPTS",
         help="Debug options, separated by commas. [env: COVERAGE_DEBUG]",
@@ -80,8 +105,7 @@
         help="Ignore errors while reading source files.",
     )
     include = optparse.make_option(
-        '', '--include', action='store',
-        metavar="PAT1,PAT2,...",
+        '', '--include', action='store', metavar="PAT1,PAT2,...",
         help=(
             "Include only files whose paths match one of these patterns. " +
             "Accepts shell-style wildcards, which must be quoted."
@@ -106,23 +130,24 @@
         ),
     )
     omit = optparse.make_option(
-        '', '--omit', action='store',
-        metavar="PAT1,PAT2,...",
+        '', '--omit', action='store', metavar="PAT1,PAT2,...",
         help=(
             "Omit files whose paths match one of these patterns. " +
             "Accepts shell-style wildcards, which must be quoted."
         ),
     )
     output_xml = optparse.make_option(
-        '-o', '', action='store', dest="outfile",
-        metavar="OUTFILE",
+        '-o', '', action='store', dest="outfile", metavar="OUTFILE",
         help="Write the XML report to this file. Defaults to 'coverage.xml'",
     )
     output_json = optparse.make_option(
-        '-o', '', action='store', dest="outfile",
-        metavar="OUTFILE",
+        '-o', '', action='store', dest="outfile", metavar="OUTFILE",
         help="Write the JSON report to this file. Defaults to 'coverage.json'",
     )
+    output_lcov = optparse.make_option(
+        '-o', '', action='store', dest='outfile', metavar="OUTFILE",
+        help="Write the LCOV report to this file. Defaults to 'coverage.lcov'",
+    )
     json_pretty_print = optparse.make_option(
         '', '--pretty-print', action='store_true',
         help="Format the JSON for human readers.",
@@ -131,7 +156,7 @@
         '-p', '--parallel-mode', action='store_true',
         help=(
             "Append the machine name, process id and random number to the " +
-            ".coverage data file name to simplify collecting data from " +
+            "data file name to simplify collecting data from " +
             "many processes."
         ),
     )
@@ -172,8 +197,10 @@
     )
     sort = optparse.make_option(
         '--sort', action='store', metavar='COLUMN',
-        help="Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. " +
+        help=(
+            "Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. " +
              "Default is name."
+        ),
     )
     source = optparse.make_option(
         '', '--source', action='store', metavar="SRC1,SRC2,...",
@@ -209,12 +236,14 @@
             add_help_option=False, *args, **kwargs
             )
         self.set_defaults(
+            # Keep these arguments alphabetized by their names.
             action=None,
             append=None,
             branch=None,
             concurrency=None,
             context=None,
             contexts=None,
+            data_file=None,
             debug=None,
             directory=None,
             fail_under=None,
@@ -313,6 +342,11 @@
         # Include the sub-command for this parser as part of the command.
         return f"{program_name} {self.cmd}"
 
+# In lists of Opts, keep them alphabetized by the option names as they appear
+# on the command line, since these lists determine the order of the options in
+# the help output.
+#
+# In COMMANDS, keep the keys (command names) alphabetized.
 
 GLOBAL_ARGS = [
     Opts.debug,
@@ -320,11 +354,12 @@
     Opts.rcfile,
     ]
 
-CMDS = {
+COMMANDS = {
     'annotate': CmdOptionParser(
         "annotate",
         [
             Opts.directory,
+            Opts.input_datafile,
             Opts.ignore_errors,
             Opts.include,
             Opts.omit,
@@ -340,6 +375,7 @@
         "combine",
         [
             Opts.append,
+            Opts.combine_datafile,
             Opts.keep,
             Opts.quiet,
             ] + GLOBAL_ARGS,
@@ -364,12 +400,16 @@
                 "'data' to show a summary of the collected data; " +
                 "'sys' to show installation information; " +
                 "'config' to show the configuration; " +
-                "'premain' to show what is calling coverage."
+                "'premain' to show what is calling coverage; " +
+                "'pybehave' to show internal flags describing Python behavior."
         ),
     ),
 
     'erase': CmdOptionParser(
-        "erase", GLOBAL_ARGS,
+        "erase",
+        [
+            Opts.combine_datafile
+            ] + GLOBAL_ARGS,
         description="Erase previously collected coverage data.",
     ),
 
@@ -384,6 +424,7 @@
         [
             Opts.contexts,
             Opts.directory,
+            Opts.input_datafile,
             Opts.fail_under,
             Opts.ignore_errors,
             Opts.include,
@@ -408,6 +449,7 @@
         "json",
         [
             Opts.contexts,
+            Opts.input_datafile,
             Opts.fail_under,
             Opts.ignore_errors,
             Opts.include,
@@ -418,13 +460,29 @@
             Opts.show_contexts,
             ] + GLOBAL_ARGS,
         usage="[options] [modules]",
-        description="Generate a JSON report of coverage results."
+        description="Generate a JSON report of coverage results.",
+    ),
+
+    'lcov': CmdOptionParser(
+        "lcov",
+        [
+            Opts.input_datafile,
+            Opts.fail_under,
+            Opts.ignore_errors,
+            Opts.include,
+            Opts.output_lcov,
+            Opts.omit,
+            Opts.quiet,
+        ] + GLOBAL_ARGS,
+        usage="[options] [modules]",
+        description="Generate an LCOV report of coverage results.",
     ),
 
     'report': CmdOptionParser(
         "report",
         [
             Opts.contexts,
+            Opts.input_datafile,
             Opts.fail_under,
             Opts.ignore_errors,
             Opts.include,
@@ -437,7 +495,7 @@
             Opts.skip_empty,
             ] + GLOBAL_ARGS,
         usage="[options] [modules]",
-        description="Report coverage statistics on modules."
+        description="Report coverage statistics on modules.",
     ),
 
     'run': CmdOptionParser(
@@ -447,6 +505,7 @@
             Opts.branch,
             Opts.concurrency,
             Opts.context,
+            Opts.output_datafile,
             Opts.include,
             Opts.module,
             Opts.omit,
@@ -456,12 +515,13 @@
             Opts.timid,
             ] + GLOBAL_ARGS,
         usage="[options] <pyfile> [program options]",
-        description="Run a Python program, measuring code execution."
+        description="Run a Python program, measuring code execution.",
     ),
 
     'xml': CmdOptionParser(
         "xml",
         [
+            Opts.input_datafile,
             Opts.fail_under,
             Opts.ignore_errors,
             Opts.include,
@@ -471,7 +531,7 @@
             Opts.skip_empty,
             ] + GLOBAL_ARGS,
         usage="[options] [modules]",
-        description="Generate an XML report of coverage results."
+        description="Generate an XML report of coverage results.",
     ),
 }
 
@@ -546,7 +606,7 @@
         if self.global_option:
             parser = GlobalOptionParser()
         else:
-            parser = CMDS.get(argv[0])
+            parser = COMMANDS.get(argv[0])
             if not parser:
                 show_help(f"Unknown command: {argv[0]!r}")
                 return ERR
@@ -574,6 +634,7 @@
 
         # Do something.
         self.coverage = Coverage(
+            data_file=options.data_file or DEFAULT_DATAFILE,
             data_suffix=options.parallel_mode,
             cover_pylib=options.pylib,
             timid=options.timid,
@@ -625,10 +686,10 @@
         total = None
         if options.action == "report":
             total = self.coverage.report(
+                precision=options.precision,
                 show_missing=options.show_missing,
                 skip_covered=options.skip_covered,
                 skip_empty=options.skip_empty,
-                precision=options.precision,
                 sort=options.sort,
                 **report_args
                 )
@@ -637,27 +698,31 @@
         elif options.action == "html":
             total = self.coverage.html_report(
                 directory=options.directory,
-                title=options.title,
+                precision=options.precision,
                 skip_covered=options.skip_covered,
                 skip_empty=options.skip_empty,
                 show_contexts=options.show_contexts,
-                precision=options.precision,
+                title=options.title,
                 **report_args
                 )
         elif options.action == "xml":
-            outfile = options.outfile
             total = self.coverage.xml_report(
-                outfile=outfile, skip_empty=options.skip_empty,
+                outfile=options.outfile,
+                skip_empty=options.skip_empty,
                 **report_args
                 )
         elif options.action == "json":
-            outfile = options.outfile
             total = self.coverage.json_report(
-                outfile=outfile,
+                outfile=options.outfile,
                 pretty_print=options.pretty_print,
                 show_contexts=options.show_contexts,
                 **report_args
-            )
+                )
+        elif options.action == "lcov":
+            total = self.coverage.lcov_report(
+                outfile=options.outfile,
+                **report_args
+                )
         else:
             # There are no other possible actions.
             raise AssertionError
@@ -667,6 +732,8 @@
             # value, so we can get fail_under from the config file.
             if options.fail_under is not None:
                 self.coverage.set_option("report:fail_under", options.fail_under)
+            if options.precision is not None:
+                self.coverage.set_option("report:precision", options.precision)
 
             fail_under = self.coverage.get_option("report:fail_under")
             precision = self.coverage.get_option("report:precision")
@@ -698,7 +765,7 @@
         if options.action == "help":
             if args:
                 for a in args:
-                    parser = CMDS.get(a)
+                    parser = COMMANDS.get(a)
                     if parser:
                         show_help(parser=parser)
                     else:
@@ -777,32 +844,28 @@
         """Implementation of 'coverage debug'."""
 
         if not args:
-            show_help("What information would you like: config, data, sys, premain?")
+            show_help("What information would you like: config, data, sys, premain, pybehave?")
             return ERR
         if args[1:]:
             show_help("Only one topic at a time, please")
             return ERR
 
-        if args[0] == 'sys':
-            sys_info = self.coverage.sys_info()
-            print(info_header("sys"))
-            for line in info_formatter(sys_info):
-                print(f" {line}")
-        elif args[0] == 'data':
+        if args[0] == "sys":
+            write_formatted_info(print, "sys", self.coverage.sys_info())
+        elif args[0] == "data":
             print(info_header("data"))
             data_file = self.coverage.config.data_file
             debug_data_file(data_file)
             for filename in combinable_files(data_file):
                 print("-----")
                 debug_data_file(filename)
-        elif args[0] == 'config':
-            print(info_header("config"))
-            config_info = sorted(self.coverage.config.__dict__.items())
-            for line in info_formatter(config_info):
-                print(f" {line}")
+        elif args[0] == "config":
+            write_formatted_info(print, "config", self.coverage.config.debug_info())
         elif args[0] == "premain":
             print(info_header("premain"))
             print(short_stack())
+        elif args[0] == "pybehave":
+            write_formatted_info(print, "pybehave", env.debug_info())
         else:
             show_help(f"Don't know what you mean by {args[0]!r}")
             return ERR
@@ -852,6 +915,7 @@
             help        Get help on using coverage.py.
             html        Create an HTML report.
             json        Create a JSON report of coverage results.
+            lcov        Create an LCOV report of coverage results.
             report      Report coverage stats on modules.
             run         Run a Python program and measure code execution.
             xml         Create an XML report of coverage results.
--- a/eric7/DebugClients/Python/coverage/config.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/config.py	Sat Apr 02 11:23:11 2022 +0200
@@ -11,7 +11,7 @@
 import re
 
 from coverage.exceptions import ConfigError
-from coverage.misc import contract, isolate_module, substitute_variables
+from coverage.misc import contract, isolate_module, human_sorted_items, substitute_variables
 
 from coverage.tomlconfig import TomlConfigParser, TomlDecodeError
 
@@ -227,6 +227,9 @@
         self.json_pretty_print = False
         self.json_show_contexts = False
 
+        # Defaults for [lcov]
+        self.lcov_output = "coverage.lcov"
+
         # Defaults for [paths]
         self.paths = collections.OrderedDict()
 
@@ -397,6 +400,9 @@
         ('json_output', 'json:output'),
         ('json_pretty_print', 'json:pretty_print', 'boolean'),
         ('json_show_contexts', 'json:show_contexts', 'boolean'),
+
+        # [lcov]
+        ('lcov_output', 'lcov:output'),
     ]
 
     def _set_attr_from_config_option(self, cp, attr, where, type_=''):
@@ -489,6 +495,12 @@
             for k, v in self.paths.items()
         )
 
+    def debug_info(self):
+        """Make a list of (name, value) pairs for writing debug info."""
+        return human_sorted_items(
+            (k, v) for k, v in self.__dict__.items() if not k.startswith("_")
+            )
+
 
 def config_files_to_try(config_file):
     """What config files should we try to read?
--- a/eric7/DebugClients/Python/coverage/control.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/control.py	Sat Apr 02 11:23:11 2022 +0200
@@ -9,7 +9,9 @@
 import os
 import os.path
 import platform
+import signal
 import sys
+import threading
 import time
 import warnings
 
@@ -26,7 +28,8 @@
 from coverage.html import HtmlReporter
 from coverage.inorout import InOrOut
 from coverage.jsonreport import JsonReporter
-from coverage.misc import bool_or_none, join_regex, human_sorted, human_sorted_items
+from coverage.lcovreport import LcovReporter
+from coverage.misc import bool_or_none, join_regex, human_sorted
 from coverage.misc import DefaultValue, ensure_dir_for_file, isolate_module
 from coverage.plugin import FileReporter
 from coverage.plugin_support import Plugins
@@ -60,7 +63,8 @@
         cov.config = original_config
 
 
-_DEFAULT_DATAFILE = DefaultValue("MISSING")
+DEFAULT_DATAFILE = DefaultValue("MISSING")
+_DEFAULT_DATAFILE = DEFAULT_DATAFILE  # Just in case, for backwards compatibility
 
 class Coverage:
     """Programmatic access to coverage.py.
@@ -101,7 +105,7 @@
             return None
 
     def __init__(
-        self, data_file=_DEFAULT_DATAFILE, data_suffix=None, cover_pylib=None,
+        self, data_file=DEFAULT_DATAFILE, data_suffix=None, cover_pylib=None,
         auto_data=False, timid=None, branch=None, config_file=True,
         source=None, source_pkgs=None, omit=None, include=None, debug=None,
         concurrency=None, check_preimported=False, context=None,
@@ -198,7 +202,7 @@
         # data_file=None means no disk file at all. data_file missing means
         # use the value from the config file.
         self._no_disk = data_file is None
-        if data_file is _DEFAULT_DATAFILE:
+        if data_file is DEFAULT_DATAFILE:
             data_file = None
 
         self.config = None
@@ -227,6 +231,7 @@
         self._exclude_re = None
         self._debug = None
         self._file_mapper = None
+        self._old_sigterm = None
 
         # State machine variables:
         # Have we initialized everything?
@@ -310,22 +315,25 @@
         """Write out debug info at startup if needed."""
         wrote_any = False
         with self._debug.without_callers():
-            if self._debug.should('config'):
-                config_info = human_sorted_items(self.config.__dict__.items())
-                config_info = [(k, v) for k, v in config_info if not k.startswith('_')]
-                write_formatted_info(self._debug, "config", config_info)
+            if self._debug.should("config"):
+                config_info = self.config.debug_info()
+                write_formatted_info(self._debug.write, "config", config_info)
                 wrote_any = True
 
-            if self._debug.should('sys'):
-                write_formatted_info(self._debug, "sys", self.sys_info())
+            if self._debug.should("sys"):
+                write_formatted_info(self._debug.write, "sys", self.sys_info())
                 for plugin in self._plugins:
                     header = "sys: " + plugin._coverage_plugin_name
                     info = plugin.sys_info()
-                    write_formatted_info(self._debug, header, info)
+                    write_formatted_info(self._debug.write, header, info)
+                wrote_any = True
+
+            if self._debug.should("pybehave"):
+                write_formatted_info(self._debug.write, "pybehave", env.debug_info())
                 wrote_any = True
 
         if wrote_any:
-            write_formatted_info(self._debug, "end", ())
+            write_formatted_info(self._debug.write, "end", ())
 
     def _should_trace(self, filename, frame):
         """Decide whether to trace execution in `filename`.
@@ -454,6 +462,8 @@
                 raise ConfigError(                      # pragma: only jython
                     "multiprocessing is not supported on this Python"
                 )
+            if self.config.config_file is None:
+                raise ConfigError("multiprocessing requires a configuration file")
             patch_multiprocessing(rcfile=self.config.config_file)
 
         dycon = self.config.dynamic_context
@@ -524,7 +534,14 @@
         # It's useful to write debug info after initing for start.
         self._should_write_debug = True
 
+        # Register our clean-up handlers.
         atexit.register(self._atexit)
+        is_main = (threading.current_thread() == threading.main_thread())
+        if is_main and not env.WINDOWS:
+            # The Python docs seem to imply that SIGTERM works uniformly even
+            # on Windows, but that's not my experience, and this agrees:
+            # https://stackoverflow.com/questions/35772001/x/35792192#35792192
+            self._old_sigterm = signal.signal(signal.SIGTERM, self._on_sigterm)
 
     def _init_data(self, suffix):
         """Create a data file if we don't have one yet."""
@@ -582,15 +599,23 @@
             self._collector.stop()
         self._started = False
 
-    def _atexit(self):
+    def _atexit(self, event="atexit"):
         """Clean up on process shutdown."""
         if self._debug.should("process"):
-            self._debug.write(f"atexit: pid: {os.getpid()}, instance: {self!r}")
+            self._debug.write(f"{event}: pid: {os.getpid()}, instance: {self!r}")
         if self._started:
             self.stop()
         if self._auto_save:
             self.save()
 
+    def _on_sigterm(self, signum_unused, frame_unused):
+        """A handler for signal.SIGTERM."""
+        self._atexit("sigterm")
+        # Statements after here won't be seen by metacov because we just wrote
+        # the data, and are about to kill the process.
+        signal.signal(signal.SIGTERM, self._old_sigterm)    # pragma: not covered
+        os.kill(os.getpid(), signal.SIGTERM)                # pragma: not covered
+
     def erase(self):
         """Erase previously collected coverage data.
 
@@ -1049,6 +1074,25 @@
         ):
             return render_report(self.config.json_output, JsonReporter(self), morfs, self._message)
 
+    def lcov_report(
+        self, morfs=None, outfile=None, ignore_errors=None,
+        omit=None, include=None, contexts=None,
+    ):
+        """Generate an LCOV report of coverage results.
+
+        Each module in 'morfs' is included in the report. 'outfile' is the
+        path to write the file to, "-" will write to stdout.
+
+        See :meth 'report' for other arguments.
+
+        .. versionadded:: 6.3
+        """
+        with override_config(self,
+            ignore_errors=ignore_errors, report_omit=omit, report_include=include,
+            lcov_output=outfile,  report_contexts=contexts,
+        ):
+            return render_report(self.config.lcov_output, LcovReporter(self), morfs, self._message)
+
     def sys_info(self):
         """Return a list of (key, value) pairs showing internal information."""
 
--- a/eric7/DebugClients/Python/coverage/debug.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/debug.py	Sat Apr 02 11:23:11 2022 +0200
@@ -118,7 +118,10 @@
     for label, data in info:
         if data == []:
             data = "-none-"
-        if isinstance(data, (list, set, tuple)):
+        if isinstance(data, tuple) and len(repr(tuple(data))) < 30:
+            # Convert to tuple to scrub namedtuples.
+            yield "%*s: %r" % (label_len, label, tuple(data))
+        elif isinstance(data, (list, set, tuple)):
             prefix = "%*s:" % (label_len, label)
             for e in data:
                 yield "%*s %s" % (label_len+1, prefix, e)
@@ -127,11 +130,18 @@
             yield "%*s: %s" % (label_len, label, data)
 
 
-def write_formatted_info(writer, header, info):
-    """Write a sequence of (label,data) pairs nicely."""
-    writer.write(info_header(header))
+def write_formatted_info(write, header, info):
+    """Write a sequence of (label,data) pairs nicely.
+
+    `write` is a function write(str) that accepts each line of output.
+    `header` is a string to start the section.  `info` is a sequence of
+    (label, data) pairs, where label is a str, and data can be a single
+    value, or a list/set/tuple.
+
+    """
+    write(info_header(header))
     for line in info_formatter(info):
-        writer.write(" %s" % line)
+        write(f" {line}")
 
 
 def short_stack(limit=None, skip=0):
--- a/eric7/DebugClients/Python/coverage/disposition.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/disposition.py	Sat Apr 02 11:23:11 2022 +0200
@@ -6,7 +6,9 @@
 
 class FileDisposition:
     """A simple value type for recording what to do with a file."""
-    pass
+
+    def __repr__(self):
+        return f"<FileDisposition {self.canonical_filename!r}: trace={self.trace}>"
 
 
 # FileDisposition "methods": FileDisposition is a pure value object, so it can
--- a/eric7/DebugClients/Python/coverage/doc/CHANGES.rst	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/doc/CHANGES.rst	Sat Apr 02 11:23:11 2022 +0200
@@ -9,8 +9,6 @@
 different from a strict chronological order when there are two branches in
 development at the same time, such as 4.5.x and 5.0.
 
-This list is detailed and covers changes in each pre-release version.
-
     .. When updating the "Unreleased" header to a specific version, use this
     .. format.  Don't forget the jump target:
     ..
@@ -19,6 +17,96 @@
     ..  Version 9.8.1 — 2027-07-27
     ..  --------------------------
 
+.. _changes_632:
+
+Version 6.3.2 — 2022-02-20
+--------------------------
+
+- Fix: adapt to pypy3.9's decorator tracing behavior.  It now traces function
+  decorators like CPython 3.8: both the @-line and the def-line are traced.
+  Fixes `issue 1326`_.
+
+- Debug: added ``pybehave`` to the list of :ref:`cmd_debug` and
+  :ref:`cmd_run_debug` options.
+
+- Fix: show an intelligible error message if ``--concurrency=multiprocessing``
+  is used without a configuration file.  Closes `issue 1320`_.
+
+.. _issue 1320: https://github.com/nedbat/coveragepy/issues/1320
+.. _issue 1326: https://github.com/nedbat/coveragepy/issues/1326
+
+
+.. _changes_631:
+
+Version 6.3.1 — 2022-02-01
+--------------------------
+
+- Fix: deadlocks could occur when terminating processes.  Some of these
+  deadlocks (described in `issue 1310`_) are now fixed.
+
+- Fix: a signal handler was being set from multiple threads, causing an error:
+  "ValueError: signal only works in main thread".  This is now fixed, closing
+  `issue 1312`_.
+
+- Fix: ``--precision`` on the command-line was being ignored while considering
+  ``--fail-under``.  This is now fixed, thanks to
+  `Marcelo Trylesinski <pull 1317_>`_.
+
+- Fix: releases no longer provide 3.11.0-alpha wheels. Coverage.py uses CPython
+  internal fields which are moving during the alpha phase. Fixes `issue 1316`_.
+
+.. _issue 1310: https://github.com/nedbat/coveragepy/issues/1310
+.. _issue 1312: https://github.com/nedbat/coveragepy/issues/1312
+.. _issue 1316: https://github.com/nedbat/coveragepy/issues/1316
+.. _pull 1317: https://github.com/nedbat/coveragepy/pull/1317
+
+
+.. _changes_63:
+
+Version 6.3 — 2022-01-25
+------------------------
+
+- Feature: Added the ``lcov`` command to generate reports in LCOV format.
+  Thanks, `Bradley Burns <pull 1289_>`_. Closes issues `587 <issue 587_>`_
+  and `626 <issue 626_>`_.
+
+- Feature: the coverage data file can now be specified on the command line with
+  the ``--data-file`` option in any command that reads or writes data.  This is
+  in addition to the existing ``COVERAGE_FILE`` environment variable.  Closes
+  `issue 624`_. Thanks, `Nikita Bloshchanevich <pull 1304_>`_.
+
+- Feature: coverage measurement data will now be written when a SIGTERM signal
+  is received by the process.  This includes
+  :meth:`Process.terminate <python:multiprocessing.Process.terminate>`,
+  and other ways to terminate a process.  Currently this is only on Linux and
+  Mac; Windows is not supported.  Fixes `issue 1307`_.
+
+- Dropped support for Python 3.6, which reached end-of-life on 2021-12-23.
+
+- Updated Python 3.11 support to 3.11.0a4, fixing `issue 1294`_.
+
+- Fix: the coverage data file is now created in a more robust way, to avoid
+  problems when multiple processes are trying to write data at once. Fixes
+  issues `1303 <issue 1303_>`_ and `883 <issue 883_>`_.
+
+- Fix: a .gitignore file will only be written into the HTML report output
+  directory if the directory is empty.  This should prevent certain unfortunate
+  accidents of writing the file where it is not wanted.
+
+- Releases now have MacOS arm64 wheels for Apple Silicon, fixing `issue 1288`_.
+
+.. _issue 587: https://github.com/nedbat/coveragepy/issues/587
+.. _issue 624: https://github.com/nedbat/coveragepy/issues/624
+.. _issue 626: https://github.com/nedbat/coveragepy/issues/626
+.. _issue 883: https://github.com/nedbat/coveragepy/issues/883
+.. _issue 1288: https://github.com/nedbat/coveragepy/issues/1288
+.. _issue 1294: https://github.com/nedbat/coveragepy/issues/1294
+.. _issue 1303: https://github.com/nedbat/coveragepy/issues/1303
+.. _issue 1307: https://github.com/nedbat/coveragepy/issues/1307
+.. _pull 1289: https://github.com/nedbat/coveragepy/pull/1289
+.. _pull 1304: https://github.com/nedbat/coveragepy/pull/1304
+
+
 .. _changes_62:
 
 Version 6.2 — 2021-11-26
@@ -48,16 +136,16 @@
   multiprocessing wouldn't suppress the data file suffix (`issue 989`_).  This
   is now fixed.
 
-- Debug: The `coverage debug data` command will now sniff out combinable data
+- Debug: The ``coverage debug data`` command will now sniff out combinable data
   files, and report on all of them.
 
-- Debug: The `coverage debug` command used to accept a number of topics at a
+- Debug: The ``coverage debug`` command used to accept a number of topics at a
   time, and show all of them, though this was never documented.  This no longer
   works, to allow for command-line options in the future.
 
 .. _issue 989: https://github.com/nedbat/coveragepy/issues/989
 .. _issue 1012: https://github.com/nedbat/coveragepy/issues/1012
-.. _issue 1082: https://github.com/nedbat/coveragepy/issues/1802
+.. _issue 1082: https://github.com/nedbat/coveragepy/issues/1082
 .. _issue 1203: https://github.com/nedbat/coveragepy/issues/1203
 
 
--- a/eric7/DebugClients/Python/coverage/doc/CONTRIBUTORS.txt	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/doc/CONTRIBUTORS.txt	Sat Apr 02 11:23:11 2022 +0200
@@ -24,6 +24,7 @@
 Ben Finney
 Bernát Gábor
 Bill Hart
+Bradley Burns
 Brandon Rhodes
 Brett Cannon
 Bruno P. Kinoshita
@@ -95,6 +96,7 @@
 Lex Berezhny
 Loïc Dachary
 Marc Abramowitz
+Marcelo Trylesinski
 Marcus Cobden
 Marius Gedminas
 Mark van der Wal
@@ -108,6 +110,7 @@
 Mike Fiedler
 Naveen Yadav
 Nathan Land
+Nikita Bloshchanevich
 Nils Kattenbeck
 Noel O'Boyle
 Olivier Grisel
--- a/eric7/DebugClients/Python/coverage/doc/README.rst	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/doc/README.rst	Sat Apr 02 11:23:11 2022 +0200
@@ -8,7 +8,7 @@
 Code coverage testing for Python.
 
 |  |license| |versions| |status|
-|  |test-status| |quality-status| |docs| |codecov|
+|  |test-status| |quality-status| |docs| |metacov|
 |  |kit| |downloads| |format| |repos|
 |  |stars| |forks| |contributors|
 |  |tidelift| |twitter-coveragepy| |twitter-nedbat|
@@ -19,8 +19,10 @@
 
 Coverage.py runs on these versions of Python:
 
-* CPython 3.6 through 3.11.
-* PyPy3 7.3.7.
+.. PYVERSIONS
+
+* CPython 3.7 through 3.11.0a4.
+* PyPy3 7.3.8.
 
 Documentation is on `Read the Docs`_.  Code repository and issue tracker are on
 `GitHub`_.
@@ -29,8 +31,9 @@
 .. _GitHub: https://github.com/nedbat/coveragepy
 
 
-**New in 6.x:** dropped support for Python 2.7 and 3.5; added support for 3.10
-match/case statements.
+**New in 6.x:** dropped support for Python 2.7, 3.5, and 3.6;
+write data on SIGTERM;
+added support for 3.10 match/case statements.
 
 
 For Enterprise
@@ -121,9 +124,9 @@
 .. |license| image:: https://img.shields.io/pypi/l/coverage.svg
     :target: https://pypi.org/project/coverage/
     :alt: License
-.. |codecov| image:: https://codecov.io/github/nedbat/coveragepy/coverage.svg?branch=master&precision=2
-    :target: https://codecov.io/github/nedbat/coveragepy?branch=master
-    :alt: Coverage!
+.. |metacov| image:: https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/nedbat/8c6980f77988a327348f9b02bbaf67f5/raw/metacov.json
+    :target: https://nedbat.github.io/coverage-reports/latest.html
+    :alt: Coverage reports
 .. |repos| image:: https://repology.org/badge/tiny-repos/python:coverage.svg
     :target: https://repology.org/project/python:coverage/versions
     :alt: Packaging status
--- a/eric7/DebugClients/Python/coverage/env.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/env.py	Sat Apr 02 11:23:11 2022 +0200
@@ -39,36 +39,26 @@
     else:
         optimize_if_debug = not pep626
 
-    # Is "if not __debug__" optimized away?
-    optimize_if_not_debug = (not PYPY) and (PYVERSION >= (3, 7, 0, 'alpha', 4))
+    # Is "if not __debug__" optimized away? The exact details have changed
+    # across versions.
     if pep626:
-        optimize_if_not_debug = False
-    if PYPY:
-        optimize_if_not_debug = True
-
-    # Is "if not __debug__" optimized away even better?
-    optimize_if_not_debug2 = (not PYPY) and (PYVERSION >= (3, 8, 0, 'beta', 1))
-    if pep626:
-        optimize_if_not_debug2 = False
-
-    # Yet another way to optimize "if not __debug__"?
-    optimize_if_not_debug3 = (PYPY and PYVERSION >= (3, 8))
+        optimize_if_not_debug = 1
+    elif PYPY:
+        if PYVERSION >= (3, 9):
+            optimize_if_not_debug = 2
+        elif PYVERSION[:2] == (3, 8):
+            optimize_if_not_debug = 3
+        else:
+            optimize_if_not_debug = 1
+    else:
+        if PYVERSION >= (3, 8, 0, 'beta', 1):
+            optimize_if_not_debug = 2
+        else:
+            optimize_if_not_debug = 1
 
     # Can co_lnotab have negative deltas?
     negative_lnotab = not (PYPY and PYPYVERSION < (7, 2))
 
-    # Do .pyc files conform to PEP 552? Hash-based pyc's.
-    hashed_pyc_pep552 = (PYVERSION >= (3, 7, 0, 'alpha', 4))
-
-    # Python 3.7.0b3 changed the behavior of the sys.path[0] entry for -m. It
-    # used to be an empty string (meaning the current directory). It changed
-    # to be the actual path to the current directory, so that os.chdir wouldn't
-    # affect the outcome.
-    actual_syspath0_dash_m = (
-        (CPYTHON and (PYVERSION >= (3, 7, 0, 'beta', 3))) or
-        (PYPY and (PYPYVERSION >= (7, 3, 4)))
-        )
-
     # 3.7 changed how functions with only docstrings are numbered.
     docstring_only_function = (not PYPY) and ((3, 7, 0, 'beta', 5) <= PYVERSION <= (3, 10))
 
@@ -81,13 +71,21 @@
     # When a function is decorated, does the trace function get called for the
     # @-line and also the def-line (new behavior in 3.8)? Or just the @-line
     # (old behavior)?
-    trace_decorated_def = (CPYTHON and PYVERSION >= (3, 8))
+    trace_decorated_def = (CPYTHON and PYVERSION >= (3, 8)) or (PYPY and PYVERSION >= (3, 9))
+
+    # Functions are no longer claimed to start at their earliest decorator even though
+    # the decorators are traced?
+    def_ast_no_decorator = (PYPY and PYVERSION >= (3, 9))
+
+    # CPython 3.11 now jumps to the decorator line again while executing
+    # the decorator.
+    trace_decorator_line_again = (CPYTHON and PYVERSION > (3, 11, 0, 'alpha', 3, 0))
 
     # Are while-true loops optimized into absolute jumps with no loop setup?
     nix_while_true = (PYVERSION >= (3, 8))
 
-    # Python 3.9a1 made sys.argv[0] and other reported files absolute paths.
-    report_absolute_files = (PYVERSION >= (3, 9))
+    # CPython 3.9a1 made sys.argv[0] and other reported files absolute paths.
+    report_absolute_files = (CPYTHON and PYVERSION >= (3, 9))
 
     # Lines after break/continue/return/raise are no longer compiled into the
     # bytecode.  They used to be marked as missing, now they aren't executable.
@@ -129,4 +127,22 @@
 # Environment COVERAGE_NO_CONTRACTS=1 can turn off contracts while debugging
 # tests to remove noise from stack traces.
 # $set_env.py: COVERAGE_NO_CONTRACTS - Disable PyContracts to simplify stack traces.
-USE_CONTRACTS = TESTING and not bool(int(os.environ.get("COVERAGE_NO_CONTRACTS", 0)))
+USE_CONTRACTS = (
+    TESTING
+    and not bool(int(os.environ.get("COVERAGE_NO_CONTRACTS", 0)))
+    and (PYVERSION < (3, 11))
+)
+
+def debug_info():
+    """Return a list of (name, value) pairs for printing debug information."""
+    info = [
+        (name, value) for name, value in globals().items()
+        if not name.startswith("_") and
+            name not in {"PYBEHAVIOR", "debug_info"} and
+            not isinstance(value, type(os))
+    ]
+    info += [
+        (name, value) for name, value in PYBEHAVIOR.__dict__.items()
+        if not name.startswith("_")
+    ]
+    return sorted(info)
--- a/eric7/DebugClients/Python/coverage/execfile.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/execfile.py	Sat Apr 02 11:23:11 2022 +0200
@@ -80,10 +80,7 @@
         This needs to happen before any importing, and without importing anything.
         """
         if self.as_module:
-            if env.PYBEHAVIOR.actual_syspath0_dash_m:
-                path0 = os.getcwd()
-            else:
-                path0 = ""
+            path0 = os.getcwd()
         elif os.path.isdir(self.arg0):
             # Running a directory means running the __main__.py file in that
             # directory.
@@ -295,18 +292,14 @@
         if magic != PYC_MAGIC_NUMBER:
             raise NoCode(f"Bad magic number in .pyc file: {magic!r} != {PYC_MAGIC_NUMBER!r}")
 
-        date_based = True
-        if env.PYBEHAVIOR.hashed_pyc_pep552:
-            flags = struct.unpack('<L', fpyc.read(4))[0]
-            hash_based = flags & 0x01
-            if hash_based:
-                fpyc.read(8)    # Skip the hash.
-                date_based = False
-        if date_based:
+        flags = struct.unpack('<L', fpyc.read(4))[0]
+        hash_based = flags & 0x01
+        if hash_based:
+            fpyc.read(8)    # Skip the hash.
+        else:
             # Skip the junk in the header that we don't need.
-            fpyc.read(4)            # Skip the moddate.
-            # 3.3 added another long to the header (size), skip it.
-            fpyc.read(4)
+            fpyc.read(4)    # Skip the moddate.
+            fpyc.read(4)    # Skip the size.
 
         # The rest of the file is the code object we want.
         code = marshal.load(fpyc)
--- a/eric7/DebugClients/Python/coverage/files.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/files.py	Sat Apr 02 11:23:11 2022 +0200
@@ -145,13 +145,7 @@
 @contract(returns='unicode')
 def abs_file(path):
     """Return the absolute normalized form of `path`."""
-    try:
-        path = os.path.realpath(path)
-    except UnicodeError:
-        pass
-    path = os.path.abspath(path)
-    path = actual_path(path)
-    return path
+    return actual_path(os.path.abspath(os.path.realpath(path)))
 
 
 def python_reported_file(filename):
--- a/eric7/DebugClients/Python/coverage/html.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/html.py	Sat Apr 02 11:23:11 2022 +0200
@@ -164,6 +164,7 @@
         self.incr = IncrementalChecker(self.directory)
         self.datagen = HtmlDataGeneration(self.coverage)
         self.totals = Numbers(precision=self.config.precision)
+        self.directory_was_empty = False
 
         self.template_globals = {
             # Functions available in the templates.
@@ -224,11 +225,11 @@
         for static in self.STATIC_FILES:
             shutil.copyfile(data_filename(static), os.path.join(self.directory, static))
 
+        # Only write the .gitignore file if the directory was originally empty.
         # .gitignore can't be copied from the source tree because it would
         # prevent the static files from being checked in.
-        gitigore_path = os.path.join(self.directory, ".gitignore")
-        if not os.path.exists(gitigore_path):
-            with open(gitigore_path, "w") as fgi:
+        if self.directory_was_empty:
+            with open(os.path.join(self.directory, ".gitignore"), "w") as fgi:
                 fgi.write("# Created by coverage.py\n*\n")
 
         # The user may have extra CSS they want copied.
@@ -240,6 +241,8 @@
         rootname = flat_rootname(fr.relative_filename())
         html_filename = rootname + ".html"
         ensure_dir(self.directory)
+        if not os.listdir(self.directory):
+            self.directory_was_empty = True
         html_path = os.path.join(self.directory, html_filename)
 
         # Get the numbers for this file.
--- a/eric7/DebugClients/Python/coverage/inorout.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/inorout.py	Sat Apr 02 11:23:11 2022 +0200
@@ -124,8 +124,7 @@
         pass
     else:
         if spec is not None:
-            if spec.origin != "namespace":
-                filename = spec.origin
+            filename = spec.origin
             path = list(spec.submodule_search_locations or ())
     return filename, path
 
--- a/eric7/DebugClients/Python/coverage/jsonreport.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/jsonreport.py	Sat Apr 02 11:23:11 2022 +0200
@@ -2,6 +2,7 @@
 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
 
 """Json reporting for coverage.py"""
+
 import datetime
 import json
 import sys
@@ -27,7 +28,7 @@
 
         `morfs` is a list of modules or file names.
 
-        `outfile` is a file object to write the json to
+        `outfile` is a file object to write the json to.
 
         """
         outfile = outfile or sys.stdout
@@ -75,7 +76,7 @@
         return self.total.n_statements and self.total.pc_covered
 
     def report_one_file(self, coverage_data, analysis):
-        """Extract the relevant report data for a single file"""
+        """Extract the relevant report data for a single file."""
         nums = analysis.numbers
         self.total += nums
         summary = {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/DebugClients/Python/coverage/lcovreport.py	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,106 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt
+
+"""LCOV reporting for coverage.py."""
+
+import sys
+import base64
+from hashlib import md5
+
+from coverage.report import get_analysis_to_report
+
+
+class LcovReporter:
+    """A reporter for writing LCOV coverage reports."""
+
+    report_type = "LCOV report"
+
+    def __init__(self, coverage):
+        self.coverage = coverage
+        self.config = self.coverage.config
+
+    def report(self, morfs, outfile=None):
+        """Renders the full lcov report.
+
+        'morfs' is a list of modules or filenames
+
+        outfile is the file object to write the file into.
+        """
+
+        self.coverage.get_data()
+        outfile = outfile or sys.stdout
+
+        for fr, analysis in get_analysis_to_report(self.coverage, morfs):
+            self.get_lcov(fr, analysis, outfile)
+
+    def get_lcov(self, fr, analysis, outfile=None):
+        """Produces the lcov data for a single file.
+
+        This currently supports both line and branch coverage,
+        however function coverage is not supported.
+        """
+        outfile.write("TN:\n")
+        outfile.write(f"SF:{fr.relative_filename()}\n")
+        source_lines = fr.source().splitlines()
+
+        for covered in sorted(analysis.executed):
+            # Note: Coverage.py currently only supports checking *if* a line
+            # has been executed, not how many times, so we set this to 1 for
+            # nice output even if it's technically incorrect.
+
+            # The lines below calculate a 64-bit encoded md5 hash of the line
+            # corresponding to the DA lines in the lcov file, for either case
+            # of the line being covered or missed in coverage.py. The final two
+            # characters of the encoding ("==") are removed from the hash to
+            # allow genhtml to run on the resulting lcov file.
+            if source_lines:
+                line = source_lines[covered-1].encode("utf-8")
+            else:
+                line = b""
+            hashed = base64.b64encode(md5(line).digest()).decode().rstrip("=")
+            outfile.write(f"DA:{covered},1,{hashed}\n")
+
+        for missed in sorted(analysis.missing):
+            assert source_lines
+            line = source_lines[missed-1].encode("utf-8")
+            hashed = base64.b64encode(md5(line).digest()).decode().rstrip("=")
+            outfile.write(f"DA:{missed},0,{hashed}\n")
+
+        outfile.write(f"LF:{len(analysis.statements)}\n")
+        outfile.write(f"LH:{len(analysis.executed)}\n")
+
+        # More information dense branch coverage data.
+        missing_arcs = analysis.missing_branch_arcs()
+        executed_arcs = analysis.executed_branch_arcs()
+        for block_number, block_line_number in enumerate(
+            sorted(analysis.branch_stats().keys())
+        ):
+            for branch_number, line_number in enumerate(
+                sorted(missing_arcs[block_line_number])
+            ):
+                # The exit branches have a negative line number,
+                # this will not produce valid lcov. Setting
+                # the line number of the exit branch to 0 will allow
+                # for valid lcov, while preserving the data.
+                line_number = max(line_number, 0)
+                outfile.write(f"BRDA:{line_number},{block_number},{branch_number},-\n")
+
+            # The start value below allows for the block number to be
+            # preserved between these two for loops (stopping the loop from
+            # resetting the value of the block number to 0).
+            for branch_number, line_number in enumerate(
+                sorted(executed_arcs[block_line_number]),
+                start=len(missing_arcs[block_line_number]),
+            ):
+                line_number = max(line_number, 0)
+                outfile.write(f"BRDA:{line_number},{block_number},{branch_number},1\n")
+
+        # Summary of the branch coverage.
+        if analysis.has_arcs():
+            branch_stats = analysis.branch_stats()
+            brf = sum(t for t, k in branch_stats.values())
+            brh = brf - sum(t - k for t, k in branch_stats.values())
+            outfile.write(f"BRF:{brf}\n")
+            outfile.write(f"BRH:{brh}\n")
+
+        outfile.write("end_of_record\n")
--- a/eric7/DebugClients/Python/coverage/multiproc.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/multiproc.py	Sat Apr 02 11:23:11 2022 +0200
@@ -27,7 +27,7 @@
         """Wrapper around _bootstrap to start coverage."""
         try:
             from coverage import Coverage       # avoid circular import
-            cov = Coverage(data_suffix=True)
+            cov = Coverage(data_suffix=True, auto_data=True)
             cov._warn_preimported_source = False
             cov.start()
             debug = cov._debug
--- a/eric7/DebugClients/Python/coverage/parser.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/parser.py	Sat Apr 02 11:23:11 2022 +0200
@@ -644,7 +644,7 @@
         self.missing_arc_fragments = collections.defaultdict(list)
         self.block_stack = []
 
-        # $set_env.py: COVERAGE_TRACK_ARCS - Trace every arc added while parsing code.
+        # $set_env.py: COVERAGE_TRACK_ARCS - Trace possible arcs added while parsing code.
         self.debug = bool(int(os.environ.get("COVERAGE_TRACK_ARCS", 0)))
 
     def analyze(self):
@@ -664,8 +664,8 @@
     def add_arc(self, start, end, smsg=None, emsg=None):
         """Add an arc, including message fragments to use if it is missing."""
         if self.debug:                      # pragma: debugging
-            print(f"\nAdding arc: ({start}, {end}): {smsg!r}, {emsg!r}")
-            print(short_stack(limit=6))
+            print(f"\nAdding possible arc: ({start}, {end}): {smsg!r}, {emsg!r}")
+            print(short_stack(limit=10))
         self.arcs.add((start, end))
 
         if smsg is not None or emsg is not None:
@@ -692,7 +692,7 @@
     def _line_decorated(self, node):
         """Compute first line number for things that can be decorated (classes and functions)."""
         lineno = node.lineno
-        if env.PYBEHAVIOR.trace_decorated_def:
+        if env.PYBEHAVIOR.trace_decorated_def or env.PYBEHAVIOR.def_ast_no_decorator:
             if node.decorator_list:
                 lineno = node.decorator_list[0].lineno
         return lineno
@@ -944,10 +944,11 @@
     def _handle_decorated(self, node):
         """Add arcs for things that can be decorated (classes and functions)."""
         main_line = last = node.lineno
-        if node.decorator_list:
-            if env.PYBEHAVIOR.trace_decorated_def:
+        decs = node.decorator_list
+        if decs:
+            if env.PYBEHAVIOR.trace_decorated_def or env.PYBEHAVIOR.def_ast_no_decorator:
                 last = None
-            for dec_node in node.decorator_list:
+            for dec_node in decs:
                 dec_start = self.line_for_node(dec_node)
                 if last is not None and dec_start != last:
                     self.add_arc(last, dec_start)
@@ -955,6 +956,11 @@
             if env.PYBEHAVIOR.trace_decorated_def:
                 self.add_arc(last, main_line)
                 last = main_line
+            if env.PYBEHAVIOR.trace_decorator_line_again:
+                for top, bot in zip(decs, decs[1:]):
+                    self.add_arc(self.line_for_node(bot), self.line_for_node(top))
+                self.add_arc(self.line_for_node(decs[0]), main_line)
+                self.add_arc(main_line, self.line_for_node(decs[-1]))
             # The definition line may have been missed, but we should have it
             # in `self.statements`.  For some constructs, `line_for_node` is
             # not what we'd think of as the first line in the statement, so map
--- a/eric7/DebugClients/Python/coverage/pytracer.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/pytracer.py	Sat Apr 02 11:23:11 2022 +0200
@@ -10,14 +10,18 @@
 from coverage import env
 
 # We need the YIELD_VALUE opcode below, in a comparison-friendly form.
-YIELD_VALUE = dis.opmap['YIELD_VALUE']
+RESUME = dis.opmap.get('RESUME')
+RETURN_VALUE = dis.opmap['RETURN_VALUE']
+if RESUME is None:
+    YIELD_VALUE = dis.opmap['YIELD_VALUE']
+    YIELD_FROM = dis.opmap['YIELD_FROM']
+    YIELD_FROM_OFFSET = 0 if env.PYPY else 2
 
 # When running meta-coverage, this file can try to trace itself, which confuses
 # everything.  Don't trace ourselves.
 
 THIS_FILE = __file__.rstrip("co")
 
-
 class PyTracer:
     """Python implementation of the raw data tracer."""
 
@@ -64,7 +68,7 @@
         atexit.register(setattr, self, 'in_atexit', True)
 
     def __repr__(self):
-        return "<PyTracer at {}: {} lines in {} files>".format(
+        return "<PyTracer at 0x{:x}: {} lines in {} files>".format(
             id(self),
             sum(len(v) for v in self.data.values()),
             len(self.data),
@@ -78,13 +82,13 @@
                 id(self),
                 len(self.data_stack),
             ))
-            if 0:
+            if 0:   # if you want thread ids..
                 f.write(".{:x}.{:x}".format(
                     self.thread.ident,
                     self.threading.current_thread().ident,
                 ))
             f.write(" {}".format(" ".join(map(str, args))))
-            if 0:
+            if 0:   # if you want callers..
                 f.write(" | ")
                 stack = " / ".join(
                     (fname or "???").rpartition("/")[-1]
@@ -132,8 +136,7 @@
             else:
                 self.started_context = False
 
-            # Entering a new frame.  Decide if we should trace
-            # in this file.
+            # Entering a new frame.  Decide if we should trace in this file.
             self._activity = True
             self.data_stack.append(
                 (
@@ -160,7 +163,14 @@
             # function calls and re-entering generators.  The f_lasti field is
             # -1 for calls, and a real offset for generators.  Use <0 as the
             # line number for calls, and the real line number for generators.
-            if getattr(frame, 'f_lasti', -1) < 0:
+            if RESUME is not None:
+                # The current opcode is guaranteed to be RESUME. The argument
+                # determines what kind of resume it is.
+                oparg = frame.f_code.co_code[frame.f_lasti + 1]
+                real_call = (oparg == 0)
+            else:
+                real_call = (getattr(frame, 'f_lasti', -1) < 0)
+            if real_call:
                 self.last_line = -frame.f_code.co_firstlineno
             else:
                 self.last_line = frame.f_lineno
@@ -178,9 +188,27 @@
             if self.trace_arcs and self.cur_file_data:
                 # Record an arc leaving the function, but beware that a
                 # "return" event might just mean yielding from a generator.
-                # Jython seems to have an empty co_code, so just assume return.
                 code = frame.f_code.co_code
-                if (not code) or code[frame.f_lasti] != YIELD_VALUE:
+                lasti = frame.f_lasti
+                if RESUME is not None:
+                    if len(code) == lasti + 2:
+                        # A return from the end of a code object is a real return.
+                        real_return = True
+                    else:
+                        # it's a real return.
+                        real_return = (code[lasti + 2] != RESUME)
+                else:
+                    if code[lasti] == RETURN_VALUE:
+                        real_return = True
+                    elif code[lasti] == YIELD_VALUE:
+                        real_return = False
+                    elif len(code) <= lasti + YIELD_FROM_OFFSET:
+                        real_return = True
+                    elif code[lasti + YIELD_FROM_OFFSET] == YIELD_FROM:
+                        real_return = False
+                    else:
+                        real_return = True
+                if real_return:
                     first = frame.f_code.co_firstlineno
                     self.cur_file_data.add((self.last_line, -first))
             # Leaving this function, pop the filename stack.
@@ -238,8 +266,10 @@
             # has changed to None.
             dont_warn = (env.PYPY and env.PYPYVERSION >= (5, 4) and self.in_atexit and tf is None)
             if (not dont_warn) and tf != self._trace:   # pylint: disable=comparison-with-callable
-                msg = f"Trace function changed, measurement is likely wrong: {tf!r}"
-                self.warn(msg, slug="trace-changed")
+                self.warn(
+                    f"Trace function changed, data is likely wrong: {tf!r} != {self._trace!r}",
+                    slug="trace-changed",
+                )
 
     def activity(self):
         """Has there been any activity?"""
--- a/eric7/DebugClients/Python/coverage/results.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/results.py	Sat Apr 02 11:23:11 2022 +0200
@@ -136,6 +136,21 @@
                 mba[l1].append(l2)
         return mba
 
+    @contract(returns='dict(int: list(int))')
+    def executed_branch_arcs(self):
+        """Return arcs that were executed from branch lines.
+
+        Returns {l1:[l2a,l2b,...], ...}
+
+        """
+        executed = self.arcs_executed()
+        branch_lines = set(self._branch_lines())
+        eba = collections.defaultdict(list)
+        for l1, l2 in executed:
+            if l1 in branch_lines:
+                eba[l1].append(l2)
+        return eba
+
     @contract(returns='dict(int: tuple(int, int))')
     def branch_stats(self):
         """Get stats about branches.
--- a/eric7/DebugClients/Python/coverage/sqldata.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/sqldata.py	Sat Apr 02 11:23:11 2022 +0200
@@ -215,7 +215,7 @@
         self._dbs = {}
         self._pid = os.getpid()
         # Synchronize the operations used during collection.
-        self._lock = threading.Lock()
+        self._lock = threading.RLock()
 
         # Are we in sync with the data file?
         self._have_used = False
@@ -231,7 +231,11 @@
         """A decorator for methods that should hold self._lock."""
         @functools.wraps(method)
         def _wrapped(self, *args, **kwargs):
+            if self._debug.should("lock"):
+                self._debug.write(f"Locking {self._lock!r} for {method.__name__}")
             with self._lock:
+                if self._debug.should("lock"):
+                    self._debug.write(f"Locked  {self._lock!r} for {method.__name__}")
                 # pylint: disable=not-callable
                 return method(self, *args, **kwargs)
         return _wrapped
@@ -256,26 +260,6 @@
         self._have_used = False
         self._current_context_id = None
 
-    def _create_db(self):
-        """Create a db file that doesn't exist yet.
-
-        Initializes the schema and certain metadata.
-        """
-        if self._debug.should("dataio"):
-            self._debug.write(f"Creating data file {self._filename!r}")
-        self._dbs[threading.get_ident()] = db = SqliteDb(self._filename, self._debug)
-        with db:
-            db.executescript(SCHEMA)
-            db.execute("insert into coverage_schema (version) values (?)", (SCHEMA_VERSION,))
-            db.executemany(
-                "insert into meta (key, value) values (?, ?)",
-                [
-                    ("sys_argv", str(getattr(sys, "argv", None))),
-                    ("version", __version__),
-                    ("when", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
-                ]
-            )
-
     def _open_db(self):
         """Open an existing db file, and read its metadata."""
         if self._debug.should("dataio"):
@@ -289,11 +273,14 @@
             try:
                 schema_version, = db.execute_one("select version from coverage_schema")
             except Exception as exc:
-                raise DataError(
-                    "Data file {!r} doesn't seem to be a coverage data file: {}".format(
-                        self._filename, exc
-                    )
-                ) from exc
+                if "no such table: coverage_schema" in str(exc):
+                    self._init_db(db)
+                else:
+                    raise DataError(
+                        "Data file {!r} doesn't seem to be a coverage data file: {}".format(
+                            self._filename, exc
+                        )
+                    ) from exc
             else:
                 if schema_version != SCHEMA_VERSION:
                     raise DataError(
@@ -309,13 +296,25 @@
             for path, file_id in db.execute("select path, id from file"):
                 self._file_map[path] = file_id
 
+    def _init_db(self, db):
+        """Write the initial contents of the database."""
+        if self._debug.should("dataio"):
+            self._debug.write(f"Initing data file {self._filename!r}")
+        db.executescript(SCHEMA)
+        db.execute("insert into coverage_schema (version) values (?)", (SCHEMA_VERSION,))
+        db.executemany(
+            "insert or ignore into meta (key, value) values (?, ?)",
+            [
+                ("sys_argv", str(getattr(sys, "argv", None))),
+                ("version", __version__),
+                ("when", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
+            ]
+        )
+
     def _connect(self):
         """Get the SqliteDb object to use."""
         if threading.get_ident() not in self._dbs:
-            if os.path.exists(self._filename):
-                self._open_db()
-            else:
-                self._create_db()
+            self._open_db()
         return self._dbs[threading.get_ident()]
 
     def __bool__(self):
@@ -349,7 +348,8 @@
         if self._debug.should("dataio"):
             self._debug.write(f"Dumping data from data file {self._filename!r}")
         with self._connect() as con:
-            return b"z" + zlib.compress(con.dump().encode("utf-8"))
+            script = con.dump()
+            return b"z" + zlib.compress(script.encode("utf-8"))
 
     @contract(data="bytes")
     def loads(self, data):
@@ -501,6 +501,9 @@
             self._set_context_id()
             for filename, arcs in arc_data.items():
                 file_id = self._file_id(filename, add=True)
+                from coverage import env
+                if env.PYVERSION == (3, 11, 0, "alpha", 4, 0):
+                    arcs = [(a, b) for a, b in arcs if a is not None and b is not None]
                 data = [(file_id, self._current_context_id, fromno, tono) for fromno, tono in arcs]
                 con.executemany(
                     "insert or ignore into arc " +
@@ -513,15 +516,19 @@
         assert lines or arcs
         assert not (lines and arcs)
         if lines and self._has_arcs:
+            if self._debug.should("dataop"):
+                self._debug.write("Error: Can't add line measurements to existing branch data")
             raise DataError("Can't add line measurements to existing branch data")
         if arcs and self._has_lines:
+            if self._debug.should("dataop"):
+                self._debug.write("Error: Can't add branch measurements to existing line data")
             raise DataError("Can't add branch measurements to existing line data")
         if not self._has_arcs and not self._has_lines:
             self._has_lines = lines
             self._has_arcs = arcs
             with self._connect() as con:
                 con.execute(
-                    "insert into meta (key, value) values (?, ?)",
+                    "insert or ignore into meta (key, value) values (?, ?)",
                     ("has_arcs", str(int(arcs)))
                 )
 
--- a/eric7/DebugClients/Python/coverage/version.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/DebugClients/Python/coverage/version.py	Sat Apr 02 11:23:11 2022 +0200
@@ -5,7 +5,7 @@
 # This file is exec'ed in setup.py, don't import anything!
 
 # Same semantics as sys.version_info.
-version_info = (6, 2, 0, "final", 0)
+version_info = (6, 3, 2, "final", 0)
 
 
 def _make_version(major, minor, micro, releaselevel, serial):
Binary file eric7/Documentation/Help/source.qch has changed
--- a/eric7/Documentation/Help/source.qhp	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Help/source.qhp	Sat Apr 02 11:23:11 2022 +0200
@@ -297,9 +297,12 @@
             <section title="eric7.PipInterface.PipDialog" ref="eric7.PipInterface.PipDialog.html" />
             <section title="eric7.PipInterface.PipFileSelectionDialog" ref="eric7.PipInterface.PipFileSelectionDialog.html" />
             <section title="eric7.PipInterface.PipFreezeDialog" ref="eric7.PipInterface.PipFreezeDialog.html" />
+            <section title="eric7.PipInterface.PipLicensesDialog" ref="eric7.PipInterface.PipLicensesDialog.html" />
             <section title="eric7.PipInterface.PipPackageDetailsDialog" ref="eric7.PipInterface.PipPackageDetailsDialog.html" />
             <section title="eric7.PipInterface.PipPackagesInputDialog" ref="eric7.PipInterface.PipPackagesInputDialog.html" />
             <section title="eric7.PipInterface.PipPackagesWidget" ref="eric7.PipInterface.PipPackagesWidget.html" />
+            <section title="eric7.PipInterface.PipVulnerabilityChecker" ref="eric7.PipInterface.PipVulnerabilityChecker.html" />
+            <section title="eric7.PipInterface.piplicenses" ref="eric7.PipInterface.piplicenses.html" />
           </section>
           <section title="eric7.PluginManager" ref="index-eric7.PluginManager.html">
             <section title="eric7.PluginManager.PluginDetailsDialog" ref="eric7.PluginManager.PluginDetailsDialog.html" />
@@ -1091,6 +1094,8 @@
             <section title="eric7.UI.SplashScreen" ref="eric7.UI.SplashScreen.html" />
             <section title="eric7.UI.SymbolsWidget" ref="eric7.UI.SymbolsWidget.html" />
             <section title="eric7.UI.UserInterface" ref="eric7.UI.UserInterface.html" />
+            <section title="eric7.UI.VersionsDialog" ref="eric7.UI.VersionsDialog.html" />
+            <section title="eric7.UI.upgrader" ref="eric7.UI.upgrader.html" />
           </section>
           <section title="eric7.Utilities" ref="index-eric7.Utilities.html">
             <section title="eric7.Utilities.ClassBrowsers" ref="index-eric7.Utilities.ClassBrowsers.html">
@@ -1435,6 +1440,7 @@
         <section title="create_windows_links" ref="create_windows_links.html" />
         <section title="install" ref="install.html" />
         <section title="install-debugclients" ref="install-debugclients.html" />
+        <section title="install-dependencies" ref="install-dependencies.html" />
         <section title="install-i18n" ref="install-i18n.html" />
         <section title="setup" ref="setup.html" />
         <section title="uninstall" ref="uninstall.html" />
@@ -2876,6 +2882,9 @@
       <keyword name="CompareWindow" id="CompareWindow" ref="eric7.UI.CompareDialog.html#CompareWindow" />
       <keyword name="CompareWindow (Constructor)" id="CompareWindow (Constructor)" ref="eric7.UI.CompareDialog.html#CompareWindow.__init__" />
       <keyword name="CompareWindow.eventFilter" id="CompareWindow.eventFilter" ref="eric7.UI.CompareDialog.html#CompareWindow.eventFilter" />
+      <keyword name="CompatibleArgumentParser" id="CompatibleArgumentParser" ref="eric7.PipInterface.piplicenses.html#CompatibleArgumentParser" />
+      <keyword name="CompatibleArgumentParser._verify_args" id="CompatibleArgumentParser._verify_args" ref="eric7.PipInterface.piplicenses.html#CompatibleArgumentParser._verify_args" />
+      <keyword name="CompatibleArgumentParser.parse_args" id="CompatibleArgumentParser.parse_args" ref="eric7.PipInterface.piplicenses.html#CompatibleArgumentParser.parse_args" />
       <keyword name="Completer" id="Completer" ref="eric7.DebugClients.Python.FlexCompleter.html#Completer" />
       <keyword name="Completer (Constructor)" id="Completer (Constructor)" ref="eric7.DebugClients.Python.FlexCompleter.html#Completer.__init__" />
       <keyword name="Completer._callable_postfix" id="Completer._callable_postfix" ref="eric7.DebugClients.Python.FlexCompleter.html#Completer._callable_postfix" />
@@ -3259,6 +3268,12 @@
       <keyword name="CreateDialogCodeDialog.on_classNameCombo_activated" id="CreateDialogCodeDialog.on_classNameCombo_activated" ref="eric7.Project.CreateDialogCodeDialog.html#CreateDialogCodeDialog.on_classNameCombo_activated" />
       <keyword name="CreateDialogCodeDialog.on_filterEdit_textChanged" id="CreateDialogCodeDialog.on_filterEdit_textChanged" ref="eric7.Project.CreateDialogCodeDialog.html#CreateDialogCodeDialog.on_filterEdit_textChanged" />
       <keyword name="CreateDialogCodeDialog.on_newButton_clicked" id="CreateDialogCodeDialog.on_newButton_clicked" ref="eric7.Project.CreateDialogCodeDialog.html#CreateDialogCodeDialog.on_newButton_clicked" />
+      <keyword name="CustomHelpFormatter" id="CustomHelpFormatter" ref="eric7.PipInterface.piplicenses.html#CustomHelpFormatter" />
+      <keyword name="CustomHelpFormatter (Constructor)" id="CustomHelpFormatter (Constructor)" ref="eric7.PipInterface.piplicenses.html#CustomHelpFormatter.__init__" />
+      <keyword name="CustomHelpFormatter._expand_help" id="CustomHelpFormatter._expand_help" ref="eric7.PipInterface.piplicenses.html#CustomHelpFormatter._expand_help" />
+      <keyword name="CustomHelpFormatter._format_action" id="CustomHelpFormatter._format_action" ref="eric7.PipInterface.piplicenses.html#CustomHelpFormatter._format_action" />
+      <keyword name="CustomHelpFormatter._split_lines" id="CustomHelpFormatter._split_lines" ref="eric7.PipInterface.piplicenses.html#CustomHelpFormatter._split_lines" />
+      <keyword name="CustomNamespace" id="CustomNamespace" ref="eric7.PipInterface.piplicenses.html#CustomNamespace" />
       <keyword name="DCTestResult" id="DCTestResult" ref="eric7.DebugClients.Python.DCTestResult.html#DCTestResult" />
       <keyword name="DCTestResult (Constructor)" id="DCTestResult (Constructor)" ref="eric7.DebugClients.Python.DCTestResult.html#DCTestResult.__init__" />
       <keyword name="DCTestResult (Module)" id="DCTestResult (Module)" ref="eric7.DebugClients.Python.DCTestResult.html" />
@@ -6088,6 +6103,7 @@
       <keyword name="FrameScroller.setScrollDivider" id="FrameScroller.setScrollDivider" ref="eric7.WebBrowser.AutoScroll.FrameScroller.html#FrameScroller.setScrollDivider" />
       <keyword name="FrameScroller.startScrolling" id="FrameScroller.startScrolling" ref="eric7.WebBrowser.AutoScroll.FrameScroller.html#FrameScroller.startScrolling" />
       <keyword name="FrameScroller.stopScrolling" id="FrameScroller.stopScrolling" ref="eric7.WebBrowser.AutoScroll.FrameScroller.html#FrameScroller.stopScrolling" />
+      <keyword name="FromArg" id="FromArg" ref="eric7.PipInterface.piplicenses.html#FromArg" />
       <keyword name="FtpDirLineParser" id="FtpDirLineParser" ref="eric7.Utilities.FtpUtilities.html#FtpDirLineParser" />
       <keyword name="FtpDirLineParser (Constructor)" id="FtpDirLineParser (Constructor)" ref="eric7.Utilities.FtpUtilities.html#FtpDirLineParser.__init__" />
       <keyword name="FtpDirLineParser.__ignoreLine" id="FtpDirLineParser.__ignoreLine" ref="eric7.Utilities.FtpUtilities.html#FtpDirLineParser.__ignoreLine" />
@@ -10922,6 +10938,8 @@
       <keyword name="NewPythonPackageDialog (Module)" id="NewPythonPackageDialog (Module)" ref="eric7.Project.NewPythonPackageDialog.html" />
       <keyword name="NewPythonPackageDialog.getData" id="NewPythonPackageDialog.getData" ref="eric7.Project.NewPythonPackageDialog.html#NewPythonPackageDialog.getData" />
       <keyword name="NewPythonPackageDialog.on_packageEdit_textChanged" id="NewPythonPackageDialog.on_packageEdit_textChanged" ref="eric7.Project.NewPythonPackageDialog.html#NewPythonPackageDialog.on_packageEdit_textChanged" />
+      <keyword name="NoValueEnum" id="NoValueEnum" ref="eric7.PipInterface.piplicenses.html#NoValueEnum" />
+      <keyword name="NoValueEnum.__repr__" id="NoValueEnum.__repr__" ref="eric7.PipInterface.piplicenses.html#NoValueEnum.__repr__" />
       <keyword name="NodeTypeEnum" id="NodeTypeEnum" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Imports.ImportsEnums.html#NodeTypeEnum" />
       <keyword name="NoneSplashScreen" id="NoneSplashScreen" ref="eric7.UI.SplashScreen.html#NoneSplashScreen" />
       <keyword name="NoneSplashScreen (Constructor)" id="NoneSplashScreen (Constructor)" ref="eric7.UI.SplashScreen.html#NoneSplashScreen.__init__" />
@@ -11121,6 +11139,7 @@
       <keyword name="OperaImporter.importedBookmarks" id="OperaImporter.importedBookmarks" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.OperaImporter.html#OperaImporter.importedBookmarks" />
       <keyword name="OperaImporter.open" id="OperaImporter.open" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.OperaImporter.html#OperaImporter.open" />
       <keyword name="OperaImporter.setPath" id="OperaImporter.setPath" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.OperaImporter.html#OperaImporter.setPath" />
+      <keyword name="OrderArg" id="OrderArg" ref="eric7.PipInterface.piplicenses.html#OrderArg" />
       <keyword name="PDFObjectTracker" id="PDFObjectTracker" ref="eric7.QScintilla.Exporters.ExporterPDF.html#PDFObjectTracker" />
       <keyword name="PDFObjectTracker (Constructor)" id="PDFObjectTracker (Constructor)" ref="eric7.QScintilla.Exporters.ExporterPDF.html#PDFObjectTracker.__init__" />
       <keyword name="PDFObjectTracker.add" id="PDFObjectTracker.add" ref="eric7.QScintilla.Exporters.ExporterPDF.html#PDFObjectTracker.add" />
@@ -11139,6 +11158,7 @@
       <keyword name="PDFRender.startPage" id="PDFRender.startPage" ref="eric7.QScintilla.Exporters.ExporterPDF.html#PDFRender.startPage" />
       <keyword name="PDFStyle" id="PDFStyle" ref="eric7.QScintilla.Exporters.ExporterPDF.html#PDFStyle" />
       <keyword name="PDFStyle (Constructor)" id="PDFStyle (Constructor)" ref="eric7.QScintilla.Exporters.ExporterPDF.html#PDFStyle.__init__" />
+      <keyword name="Package" id="Package" ref="eric7.PipInterface.PipVulnerabilityChecker.html#Package" />
       <keyword name="PackageDiagramBuilder" id="PackageDiagramBuilder" ref="eric7.Graphics.PackageDiagramBuilder.html#PackageDiagramBuilder" />
       <keyword name="PackageDiagramBuilder (Constructor)" id="PackageDiagramBuilder (Constructor)" ref="eric7.Graphics.PackageDiagramBuilder.html#PackageDiagramBuilder.__init__" />
       <keyword name="PackageDiagramBuilder (Module)" id="PackageDiagramBuilder (Module)" ref="eric7.Graphics.PackageDiagramBuilder.html" />
@@ -11316,22 +11336,30 @@
       <keyword name="Pip" id="Pip" ref="eric7.PipInterface.Pip.html#Pip" />
       <keyword name="Pip (Constructor)" id="Pip (Constructor)" ref="eric7.PipInterface.Pip.html#Pip.__init__" />
       <keyword name="Pip (Module)" id="Pip (Module)" ref="eric7.PipInterface.Pip.html" />
+      <keyword name="Pip.__checkUpgradeEric" id="Pip.__checkUpgradeEric" ref="eric7.PipInterface.Pip.html#Pip.__checkUpgradeEric" />
       <keyword name="Pip.__checkUpgradePyQt" id="Pip.__checkUpgradePyQt" ref="eric7.PipInterface.Pip.html#Pip.__checkUpgradePyQt" />
       <keyword name="Pip.cacheList" id="Pip.cacheList" ref="eric7.PipInterface.Pip.html#Pip.cacheList" />
       <keyword name="Pip.cachePurge" id="Pip.cachePurge" ref="eric7.PipInterface.Pip.html#Pip.cachePurge" />
       <keyword name="Pip.cacheRemove" id="Pip.cacheRemove" ref="eric7.PipInterface.Pip.html#Pip.cacheRemove" />
+      <keyword name="Pip.checkPackageOutdated" id="Pip.checkPackageOutdated" ref="eric7.PipInterface.Pip.html#Pip.checkPackageOutdated" />
+      <keyword name="Pip.getDependecyTree" id="Pip.getDependecyTree" ref="eric7.PipInterface.Pip.html#Pip.getDependecyTree" />
+      <keyword name="Pip.getFrozenPackages" id="Pip.getFrozenPackages" ref="eric7.PipInterface.Pip.html#Pip.getFrozenPackages" />
       <keyword name="Pip.getIndexUrl" id="Pip.getIndexUrl" ref="eric7.PipInterface.Pip.html#Pip.getIndexUrl" />
       <keyword name="Pip.getIndexUrlPypi" id="Pip.getIndexUrlPypi" ref="eric7.PipInterface.Pip.html#Pip.getIndexUrlPypi" />
       <keyword name="Pip.getIndexUrlSearch" id="Pip.getIndexUrlSearch" ref="eric7.PipInterface.Pip.html#Pip.getIndexUrlSearch" />
       <keyword name="Pip.getInstalledPackages" id="Pip.getInstalledPackages" ref="eric7.PipInterface.Pip.html#Pip.getInstalledPackages" />
+      <keyword name="Pip.getLicenses" id="Pip.getLicenses" ref="eric7.PipInterface.Pip.html#Pip.getLicenses" />
+      <keyword name="Pip.getLicensesSummary" id="Pip.getLicensesSummary" ref="eric7.PipInterface.Pip.html#Pip.getLicensesSummary" />
       <keyword name="Pip.getNetworkAccessManager" id="Pip.getNetworkAccessManager" ref="eric7.PipInterface.Pip.html#Pip.getNetworkAccessManager" />
       <keyword name="Pip.getOutdatedPackages" id="Pip.getOutdatedPackages" ref="eric7.PipInterface.Pip.html#Pip.getOutdatedPackages" />
       <keyword name="Pip.getPackageDetails" id="Pip.getPackageDetails" ref="eric7.PipInterface.Pip.html#Pip.getPackageDetails" />
+      <keyword name="Pip.getPackageVersions" id="Pip.getPackageVersions" ref="eric7.PipInterface.Pip.html#Pip.getPackageVersions" />
       <keyword name="Pip.getProjectEnvironmentString" id="Pip.getProjectEnvironmentString" ref="eric7.PipInterface.Pip.html#Pip.getProjectEnvironmentString" />
       <keyword name="Pip.getUserConfig" id="Pip.getUserConfig" ref="eric7.PipInterface.Pip.html#Pip.getUserConfig" />
       <keyword name="Pip.getVirtualenvConfig" id="Pip.getVirtualenvConfig" ref="eric7.PipInterface.Pip.html#Pip.getVirtualenvConfig" />
       <keyword name="Pip.getVirtualenvInterpreter" id="Pip.getVirtualenvInterpreter" ref="eric7.PipInterface.Pip.html#Pip.getVirtualenvInterpreter" />
       <keyword name="Pip.getVirtualenvNames" id="Pip.getVirtualenvNames" ref="eric7.PipInterface.Pip.html#Pip.getVirtualenvNames" />
+      <keyword name="Pip.getVulnerabilityChecker" id="Pip.getVulnerabilityChecker" ref="eric7.PipInterface.Pip.html#Pip.getVulnerabilityChecker" />
       <keyword name="Pip.installPackages" id="Pip.installPackages" ref="eric7.PipInterface.Pip.html#Pip.installPackages" />
       <keyword name="Pip.installPip" id="Pip.installPip" ref="eric7.PipInterface.Pip.html#Pip.installPip" />
       <keyword name="Pip.installRequirements" id="Pip.installRequirements" ref="eric7.PipInterface.Pip.html#Pip.installRequirements" />
@@ -11376,8 +11404,13 @@
       <keyword name="PipFreezeDialog.on_requirementsFilePicker_textChanged" id="PipFreezeDialog.on_requirementsFilePicker_textChanged" ref="eric7.PipInterface.PipFreezeDialog.html#PipFreezeDialog.on_requirementsFilePicker_textChanged" />
       <keyword name="PipFreezeDialog.on_saveButton_clicked" id="PipFreezeDialog.on_saveButton_clicked" ref="eric7.PipInterface.PipFreezeDialog.html#PipFreezeDialog.on_saveButton_clicked" />
       <keyword name="PipFreezeDialog.on_saveToButton_clicked" id="PipFreezeDialog.on_saveToButton_clicked" ref="eric7.PipInterface.PipFreezeDialog.html#PipFreezeDialog.on_saveToButton_clicked" />
+      <keyword name="PipFreezeDialog.on_userCheckBox_clicked" id="PipFreezeDialog.on_userCheckBox_clicked" ref="eric7.PipInterface.PipFreezeDialog.html#PipFreezeDialog.on_userCheckBox_clicked" />
       <keyword name="PipFreezeDialog.start" id="PipFreezeDialog.start" ref="eric7.PipInterface.PipFreezeDialog.html#PipFreezeDialog.start" />
       <keyword name="PipInterface (Package)" id="PipInterface (Package)" ref="index-eric7.PipInterface.html" />
+      <keyword name="PipLicensesDialog" id="PipLicensesDialog" ref="eric7.PipInterface.PipLicensesDialog.html#PipLicensesDialog" />
+      <keyword name="PipLicensesDialog (Constructor)" id="PipLicensesDialog (Constructor)" ref="eric7.PipInterface.PipLicensesDialog.html#PipLicensesDialog.__init__" />
+      <keyword name="PipLicensesDialog (Module)" id="PipLicensesDialog (Module)" ref="eric7.PipInterface.PipLicensesDialog.html" />
+      <keyword name="PipLicensesDialog.__refreshLicenses" id="PipLicensesDialog.__refreshLicenses" ref="eric7.PipInterface.PipLicensesDialog.html#PipLicensesDialog.__refreshLicenses" />
       <keyword name="PipPackageDetailsDialog" id="PipPackageDetailsDialog" ref="eric7.PipInterface.PipPackageDetailsDialog.html#PipPackageDetailsDialog" />
       <keyword name="PipPackageDetailsDialog (Constructor)" id="PipPackageDetailsDialog (Constructor)" ref="eric7.PipInterface.PipPackageDetailsDialog.html#PipPackageDetailsDialog.__init__" />
       <keyword name="PipPackageDetailsDialog (Module)" id="PipPackageDetailsDialog (Module)" ref="eric7.PipInterface.PipPackageDetailsDialog.html" />
@@ -11397,8 +11430,10 @@
       <keyword name="PipPackagesWidget (Constructor)" id="PipPackagesWidget (Constructor)" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__init__" />
       <keyword name="PipPackagesWidget (Module)" id="PipPackagesWidget (Module)" ref="eric7.PipInterface.PipPackagesWidget.html" />
       <keyword name="PipPackagesWidget.__aboutToShowPipMenu" id="PipPackagesWidget.__aboutToShowPipMenu" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__aboutToShowPipMenu" />
+      <keyword name="PipPackagesWidget.__addDependency" id="PipPackagesWidget.__addDependency" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__addDependency" />
       <keyword name="PipPackagesWidget.__allUpdateableItems" id="PipPackagesWidget.__allUpdateableItems" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__allUpdateableItems" />
       <keyword name="PipPackagesWidget.__availablePipVersion" id="PipPackagesWidget.__availablePipVersion" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__availablePipVersion" />
+      <keyword name="PipPackagesWidget.__clearVulnerabilityInfo" id="PipPackagesWidget.__clearVulnerabilityInfo" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__clearVulnerabilityInfo" />
       <keyword name="PipPackagesWidget.__editConfiguration" id="PipPackagesWidget.__editConfiguration" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__editConfiguration" />
       <keyword name="PipPackagesWidget.__editUserConfiguration" id="PipPackagesWidget.__editUserConfiguration" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__editUserConfiguration" />
       <keyword name="PipPackagesWidget.__editVirtualenvConfiguration" id="PipPackagesWidget.__editVirtualenvConfiguration" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__editVirtualenvConfiguration" />
@@ -11414,52 +11449,84 @@
       <keyword name="PipPackagesWidget.__pipConfigure" id="PipPackagesWidget.__pipConfigure" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__pipConfigure" />
       <keyword name="PipPackagesWidget.__populateEnvironments" id="PipPackagesWidget.__populateEnvironments" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__populateEnvironments" />
       <keyword name="PipPackagesWidget.__projectClosed" id="PipPackagesWidget.__projectClosed" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__projectClosed" />
+      <keyword name="PipPackagesWidget.__projectOpened" id="PipPackagesWidget.__projectOpened" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__projectOpened" />
       <keyword name="PipPackagesWidget.__purgeCache" id="PipPackagesWidget.__purgeCache" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__purgeCache" />
+      <keyword name="PipPackagesWidget.__refreshDependencyTree" id="PipPackagesWidget.__refreshDependencyTree" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__refreshDependencyTree" />
       <keyword name="PipPackagesWidget.__refreshPackagesList" id="PipPackagesWidget.__refreshPackagesList" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__refreshPackagesList" />
       <keyword name="PipPackagesWidget.__reinstallPackages" id="PipPackagesWidget.__reinstallPackages" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__reinstallPackages" />
       <keyword name="PipPackagesWidget.__removeCachedFiles" id="PipPackagesWidget.__removeCachedFiles" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__removeCachedFiles" />
       <keyword name="PipPackagesWidget.__repairPip" id="PipPackagesWidget.__repairPip" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__repairPip" />
       <keyword name="PipPackagesWidget.__search" id="PipPackagesWidget.__search" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__search" />
+      <keyword name="PipPackagesWidget.__searchFirst" id="PipPackagesWidget.__searchFirst" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__searchFirst" />
       <keyword name="PipPackagesWidget.__searchResponse" id="PipPackagesWidget.__searchResponse" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__searchResponse" />
       <keyword name="PipPackagesWidget.__selectedUpdateableItems" id="PipPackagesWidget.__selectedUpdateableItems" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__selectedUpdateableItems" />
       <keyword name="PipPackagesWidget.__showCacheInfo" id="PipPackagesWidget.__showCacheInfo" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__showCacheInfo" />
       <keyword name="PipPackagesWidget.__showCacheList" id="PipPackagesWidget.__showCacheList" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__showCacheList" />
+      <keyword name="PipPackagesWidget.__showLicensesDialog" id="PipPackagesWidget.__showLicensesDialog" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__showLicensesDialog" />
       <keyword name="PipPackagesWidget.__showPackageDetails" id="PipPackagesWidget.__showPackageDetails" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__showPackageDetails" />
+      <keyword name="PipPackagesWidget.__showPackageInformation" id="PipPackagesWidget.__showPackageInformation" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__showPackageInformation" />
       <keyword name="PipPackagesWidget.__showSearchedDetails" id="PipPackagesWidget.__showSearchedDetails" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__showSearchedDetails" />
+      <keyword name="PipPackagesWidget.__showVulnerabilityInformation" id="PipPackagesWidget.__showVulnerabilityInformation" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__showVulnerabilityInformation" />
       <keyword name="PipPackagesWidget.__uninstallRequirements" id="PipPackagesWidget.__uninstallRequirements" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__uninstallRequirements" />
       <keyword name="PipPackagesWidget.__updateActionButtons" id="PipPackagesWidget.__updateActionButtons" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__updateActionButtons" />
+      <keyword name="PipPackagesWidget.__updateDepActionButtons" id="PipPackagesWidget.__updateDepActionButtons" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__updateDepActionButtons" />
       <keyword name="PipPackagesWidget.__updateSearchActionButtons" id="PipPackagesWidget.__updateSearchActionButtons" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__updateSearchActionButtons" />
       <keyword name="PipPackagesWidget.__updateSearchButton" id="PipPackagesWidget.__updateSearchButton" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__updateSearchButton" />
+      <keyword name="PipPackagesWidget.__updateSearchMoreButton" id="PipPackagesWidget.__updateSearchMoreButton" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__updateSearchMoreButton" />
+      <keyword name="PipPackagesWidget.__updateVulnerabilityData" id="PipPackagesWidget.__updateVulnerabilityData" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__updateVulnerabilityData" />
+      <keyword name="PipPackagesWidget.__updateVulnerabilityDbCache" id="PipPackagesWidget.__updateVulnerabilityDbCache" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.__updateVulnerabilityDbCache" />
       <keyword name="PipPackagesWidget.executeInstallPackages" id="PipPackagesWidget.executeInstallPackages" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.executeInstallPackages" />
       <keyword name="PipPackagesWidget.executeUninstallPackages" id="PipPackagesWidget.executeUninstallPackages" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.executeUninstallPackages" />
       <keyword name="PipPackagesWidget.executeUpgradePackages" id="PipPackagesWidget.executeUpgradePackages" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.executeUpgradePackages" />
       <keyword name="PipPackagesWidget.getPip" id="PipPackagesWidget.getPip" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.getPip" />
-      <keyword name="PipPackagesWidget.on_environmentsComboBox_currentIndexChanged" id="PipPackagesWidget.on_environmentsComboBox_currentIndexChanged" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_environmentsComboBox_currentIndexChanged" />
+      <keyword name="PipPackagesWidget.on_dependenciesList_itemActivated" id="PipPackagesWidget.on_dependenciesList_itemActivated" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_dependenciesList_itemActivated" />
+      <keyword name="PipPackagesWidget.on_dependenciesList_itemPressed" id="PipPackagesWidget.on_dependenciesList_itemPressed" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_dependenciesList_itemPressed" />
+      <keyword name="PipPackagesWidget.on_dependenciesList_itemSelectionChanged" id="PipPackagesWidget.on_dependenciesList_itemSelectionChanged" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_dependenciesList_itemSelectionChanged" />
+      <keyword name="PipPackagesWidget.on_environmentsComboBox_currentTextChanged" id="PipPackagesWidget.on_environmentsComboBox_currentTextChanged" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_environmentsComboBox_currentTextChanged" />
       <keyword name="PipPackagesWidget.on_installButton_clicked" id="PipPackagesWidget.on_installButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_installButton_clicked" />
       <keyword name="PipPackagesWidget.on_installUserSiteButton_clicked" id="PipPackagesWidget.on_installUserSiteButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_installUserSiteButton_clicked" />
       <keyword name="PipPackagesWidget.on_installedFilesCheckBox_clicked" id="PipPackagesWidget.on_installedFilesCheckBox_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_installedFilesCheckBox_clicked" />
       <keyword name="PipPackagesWidget.on_localCheckBox_clicked" id="PipPackagesWidget.on_localCheckBox_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_localCheckBox_clicked" />
+      <keyword name="PipPackagesWidget.on_localDepCheckBox_clicked" id="PipPackagesWidget.on_localDepCheckBox_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_localDepCheckBox_clicked" />
       <keyword name="PipPackagesWidget.on_notRequiredCheckBox_clicked" id="PipPackagesWidget.on_notRequiredCheckBox_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_notRequiredCheckBox_clicked" />
       <keyword name="PipPackagesWidget.on_packagesList_itemActivated" id="PipPackagesWidget.on_packagesList_itemActivated" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_packagesList_itemActivated" />
+      <keyword name="PipPackagesWidget.on_packagesList_itemPressed" id="PipPackagesWidget.on_packagesList_itemPressed" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_packagesList_itemPressed" />
       <keyword name="PipPackagesWidget.on_packagesList_itemSelectionChanged" id="PipPackagesWidget.on_packagesList_itemSelectionChanged" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_packagesList_itemSelectionChanged" />
       <keyword name="PipPackagesWidget.on_refreshButton_clicked" id="PipPackagesWidget.on_refreshButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_refreshButton_clicked" />
+      <keyword name="PipPackagesWidget.on_refreshDependenciesButton_clicked" id="PipPackagesWidget.on_refreshDependenciesButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_refreshDependenciesButton_clicked" />
+      <keyword name="PipPackagesWidget.on_requiresButton_toggled" id="PipPackagesWidget.on_requiresButton_toggled" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_requiresButton_toggled" />
       <keyword name="PipPackagesWidget.on_searchButton_clicked" id="PipPackagesWidget.on_searchButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_searchButton_clicked" />
       <keyword name="PipPackagesWidget.on_searchEditName_returnPressed" id="PipPackagesWidget.on_searchEditName_returnPressed" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_searchEditName_returnPressed" />
       <keyword name="PipPackagesWidget.on_searchEditName_textChanged" id="PipPackagesWidget.on_searchEditName_textChanged" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_searchEditName_textChanged" />
+      <keyword name="PipPackagesWidget.on_searchMoreButton_clicked" id="PipPackagesWidget.on_searchMoreButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_searchMoreButton_clicked" />
       <keyword name="PipPackagesWidget.on_searchResultList_itemActivated" id="PipPackagesWidget.on_searchResultList_itemActivated" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_searchResultList_itemActivated" />
       <keyword name="PipPackagesWidget.on_searchResultList_itemSelectionChanged" id="PipPackagesWidget.on_searchResultList_itemSelectionChanged" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_searchResultList_itemSelectionChanged" />
       <keyword name="PipPackagesWidget.on_searchToggleButton_toggled" id="PipPackagesWidget.on_searchToggleButton_toggled" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_searchToggleButton_toggled" />
+      <keyword name="PipPackagesWidget.on_showDepPackageDetailsButton_clicked" id="PipPackagesWidget.on_showDepPackageDetailsButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_showDepPackageDetailsButton_clicked" />
       <keyword name="PipPackagesWidget.on_showDetailsButton_clicked" id="PipPackagesWidget.on_showDetailsButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_showDetailsButton_clicked" />
       <keyword name="PipPackagesWidget.on_showPackageDetailsButton_clicked" id="PipPackagesWidget.on_showPackageDetailsButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_showPackageDetailsButton_clicked" />
       <keyword name="PipPackagesWidget.on_uninstallButton_clicked" id="PipPackagesWidget.on_uninstallButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_uninstallButton_clicked" />
       <keyword name="PipPackagesWidget.on_upgradeAllButton_clicked" id="PipPackagesWidget.on_upgradeAllButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_upgradeAllButton_clicked" />
       <keyword name="PipPackagesWidget.on_upgradeButton_clicked" id="PipPackagesWidget.on_upgradeButton_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_upgradeButton_clicked" />
       <keyword name="PipPackagesWidget.on_userCheckBox_clicked" id="PipPackagesWidget.on_userCheckBox_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_userCheckBox_clicked" />
+      <keyword name="PipPackagesWidget.on_userDepCheckBox_clicked" id="PipPackagesWidget.on_userDepCheckBox_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_userDepCheckBox_clicked" />
       <keyword name="PipPackagesWidget.on_verboseCheckBox_clicked" id="PipPackagesWidget.on_verboseCheckBox_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_verboseCheckBox_clicked" />
+      <keyword name="PipPackagesWidget.on_viewToggleButton_toggled" id="PipPackagesWidget.on_viewToggleButton_toggled" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_viewToggleButton_toggled" />
+      <keyword name="PipPackagesWidget.on_vulnerabilityCheckBox_clicked" id="PipPackagesWidget.on_vulnerabilityCheckBox_clicked" ref="eric7.PipInterface.PipPackagesWidget.html#PipPackagesWidget.on_vulnerabilityCheckBox_clicked" />
       <keyword name="PipPage" id="PipPage" ref="eric7.Preferences.ConfigurationPages.PipPage.html#PipPage" />
       <keyword name="PipPage (Constructor)" id="PipPage (Constructor)" ref="eric7.Preferences.ConfigurationPages.PipPage.html#PipPage.__init__" />
       <keyword name="PipPage (Module)" id="PipPage (Module)" ref="eric7.Preferences.ConfigurationPages.PipPage.html" />
       <keyword name="PipPage.save" id="PipPage.save" ref="eric7.Preferences.ConfigurationPages.PipPage.html#PipPage.save" />
+      <keyword name="PipVulnerabilityChecker" id="PipVulnerabilityChecker" ref="eric7.PipInterface.PipVulnerabilityChecker.html#PipVulnerabilityChecker" />
+      <keyword name="PipVulnerabilityChecker (Constructor)" id="PipVulnerabilityChecker (Constructor)" ref="eric7.PipInterface.PipVulnerabilityChecker.html#PipVulnerabilityChecker.__init__" />
+      <keyword name="PipVulnerabilityChecker (Module)" id="PipVulnerabilityChecker (Module)" ref="eric7.PipInterface.PipVulnerabilityChecker.html" />
+      <keyword name="PipVulnerabilityChecker.__createCacheFile" id="PipVulnerabilityChecker.__createCacheFile" ref="eric7.PipInterface.PipVulnerabilityChecker.html#PipVulnerabilityChecker.__createCacheFile" />
+      <keyword name="PipVulnerabilityChecker.__fetchVulnerabilityDatabase" id="PipVulnerabilityChecker.__fetchVulnerabilityDatabase" ref="eric7.PipInterface.PipVulnerabilityChecker.html#PipVulnerabilityChecker.__fetchVulnerabilityDatabase" />
+      <keyword name="PipVulnerabilityChecker.__getDataFromCache" id="PipVulnerabilityChecker.__getDataFromCache" ref="eric7.PipInterface.PipVulnerabilityChecker.html#PipVulnerabilityChecker.__getDataFromCache" />
+      <keyword name="PipVulnerabilityChecker.__getVulnerabilities" id="PipVulnerabilityChecker.__getVulnerabilities" ref="eric7.PipInterface.PipVulnerabilityChecker.html#PipVulnerabilityChecker.__getVulnerabilities" />
+      <keyword name="PipVulnerabilityChecker.__writeDataToCache" id="PipVulnerabilityChecker.__writeDataToCache" ref="eric7.PipInterface.PipVulnerabilityChecker.html#PipVulnerabilityChecker.__writeDataToCache" />
+      <keyword name="PipVulnerabilityChecker.check" id="PipVulnerabilityChecker.check" ref="eric7.PipInterface.PipVulnerabilityChecker.html#PipVulnerabilityChecker.check" />
+      <keyword name="PipVulnerabilityChecker.updateVulnerabilityDb" id="PipVulnerabilityChecker.updateVulnerabilityDb" ref="eric7.PipInterface.PipVulnerabilityChecker.html#PipVulnerabilityChecker.updateVulnerabilityDb" />
       <keyword name="PixmapCache" id="PixmapCache" ref="eric7.UI.PixmapCache.html#PixmapCache" />
       <keyword name="PixmapCache (Constructor)" id="PixmapCache (Constructor)" ref="eric7.UI.PixmapCache.html#PixmapCache.__init__" />
       <keyword name="PixmapCache (Module)" id="PixmapCache (Module)" ref="eric7.UI.PixmapCache.html" />
@@ -13479,6 +13546,8 @@
       <keyword name="SecurityPage.save" id="SecurityPage.save" ref="eric7.Preferences.ConfigurationPages.SecurityPage.html#SecurityPage.save" />
       <keyword name="SecurityPage.setMode" id="SecurityPage.setMode" ref="eric7.Preferences.ConfigurationPages.SecurityPage.html#SecurityPage.setMode" />
       <keyword name="SecurityUtils (Module)" id="SecurityUtils (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.SecurityUtils.html" />
+      <keyword name="SelectAction" id="SelectAction" ref="eric7.PipInterface.piplicenses.html#SelectAction" />
+      <keyword name="SelectAction.__call__" id="SelectAction.__call__" ref="eric7.PipInterface.piplicenses.html#SelectAction.__call__" />
       <keyword name="SendRefererWhitelistDialog" id="SendRefererWhitelistDialog" ref="eric7.WebBrowser.Network.SendRefererWhitelistDialog.html#SendRefererWhitelistDialog" />
       <keyword name="SendRefererWhitelistDialog (Constructor)" id="SendRefererWhitelistDialog (Constructor)" ref="eric7.WebBrowser.Network.SendRefererWhitelistDialog.html#SendRefererWhitelistDialog.__init__" />
       <keyword name="SendRefererWhitelistDialog (Module)" id="SendRefererWhitelistDialog (Module)" ref="eric7.WebBrowser.Network.SendRefererWhitelistDialog.html" />
@@ -16335,6 +16404,7 @@
       <keyword name="UserInterface.__openHexEditor" id="UserInterface.__openHexEditor" ref="eric7.UI.UserInterface.html#UserInterface.__openHexEditor" />
       <keyword name="UserInterface.__openMiniEditor" id="UserInterface.__openMiniEditor" ref="eric7.UI.UserInterface.html#UserInterface.__openMiniEditor" />
       <keyword name="UserInterface.__openOnStartup" id="UserInterface.__openOnStartup" ref="eric7.UI.UserInterface.html#UserInterface.__openOnStartup" />
+      <keyword name="UserInterface.__performUpgrade" id="UserInterface.__performUpgrade" ref="eric7.UI.UserInterface.html#UserInterface.__performUpgrade" />
       <keyword name="UserInterface.__pluginInstallFinished" id="UserInterface.__pluginInstallFinished" ref="eric7.UI.UserInterface.html#UserInterface.__pluginInstallFinished" />
       <keyword name="UserInterface.__pluginsConfigure" id="UserInterface.__pluginsConfigure" ref="eric7.UI.UserInterface.html#UserInterface.__pluginsConfigure" />
       <keyword name="UserInterface.__populateToolbarsMenu" id="UserInterface.__populateToolbarsMenu" ref="eric7.UI.UserInterface.html#UserInterface.__populateToolbarsMenu" />
@@ -16357,7 +16427,6 @@
       <keyword name="UserInterface.__setEditProfile" id="UserInterface.__setEditProfile" ref="eric7.UI.UserInterface.html#UserInterface.__setEditProfile" />
       <keyword name="UserInterface.__setWindowCaption" id="UserInterface.__setWindowCaption" ref="eric7.UI.UserInterface.html#UserInterface.__setWindowCaption" />
       <keyword name="UserInterface.__setupDockWindow" id="UserInterface.__setupDockWindow" ref="eric7.UI.UserInterface.html#UserInterface.__setupDockWindow" />
-      <keyword name="UserInterface.__showAvailableVersionInfos" id="UserInterface.__showAvailableVersionInfos" ref="eric7.UI.UserInterface.html#UserInterface.__showAvailableVersionInfos" />
       <keyword name="UserInterface.__showCertificatesDialog" id="UserInterface.__showCertificatesDialog" ref="eric7.UI.UserInterface.html#UserInterface.__showCertificatesDialog" />
       <keyword name="UserInterface.__showEricDoc" id="UserInterface.__showEricDoc" ref="eric7.UI.UserInterface.html#UserInterface.__showEricDoc" />
       <keyword name="UserInterface.__showErrorLog" id="UserInterface.__showErrorLog" ref="eric7.UI.UserInterface.html#UserInterface.__showErrorLog" />
@@ -16414,11 +16483,7 @@
       <keyword name="UserInterface.__unittestScript" id="UserInterface.__unittestScript" ref="eric7.UI.UserInterface.html#UserInterface.__unittestScript" />
       <keyword name="UserInterface.__unittestStopped" id="UserInterface.__unittestStopped" ref="eric7.UI.UserInterface.html#UserInterface.__unittestStopped" />
       <keyword name="UserInterface.__updateExternalToolsActions" id="UserInterface.__updateExternalToolsActions" ref="eric7.UI.UserInterface.html#UserInterface.__updateExternalToolsActions" />
-      <keyword name="UserInterface.__updateVersionsUrls" id="UserInterface.__updateVersionsUrls" ref="eric7.UI.UserInterface.html#UserInterface.__updateVersionsUrls" />
-      <keyword name="UserInterface.__versionCheckResult" id="UserInterface.__versionCheckResult" ref="eric7.UI.UserInterface.html#UserInterface.__versionCheckResult" />
       <keyword name="UserInterface.__versionToTuple" id="UserInterface.__versionToTuple" ref="eric7.UI.UserInterface.html#UserInterface.__versionToTuple" />
-      <keyword name="UserInterface.__versionsDownloadCanceled" id="UserInterface.__versionsDownloadCanceled" ref="eric7.UI.UserInterface.html#UserInterface.__versionsDownloadCanceled" />
-      <keyword name="UserInterface.__versionsDownloadDone" id="UserInterface.__versionsDownloadDone" ref="eric7.UI.UserInterface.html#UserInterface.__versionsDownloadDone" />
       <keyword name="UserInterface.__webBrowser" id="UserInterface.__webBrowser" ref="eric7.UI.UserInterface.html#UserInterface.__webBrowser" />
       <keyword name="UserInterface.__webBrowserFinished" id="UserInterface.__webBrowserFinished" ref="eric7.UI.UserInterface.html#UserInterface.__webBrowserFinished" />
       <keyword name="UserInterface.__webBrowserShutdown" id="UserInterface.__webBrowserShutdown" ref="eric7.UI.UserInterface.html#UserInterface.__webBrowserShutdown" />
@@ -16470,7 +16535,6 @@
       <keyword name="UserInterface.removeSideWidget" id="UserInterface.removeSideWidget" ref="eric7.UI.UserInterface.html#UserInterface.removeSideWidget" />
       <keyword name="UserInterface.reregisterToolbar" id="UserInterface.reregisterToolbar" ref="eric7.UI.UserInterface.html#UserInterface.reregisterToolbar" />
       <keyword name="UserInterface.setDebugProfile" id="UserInterface.setDebugProfile" ref="eric7.UI.UserInterface.html#UserInterface.setDebugProfile" />
-      <keyword name="UserInterface.showAvailableVersionsInfo" id="UserInterface.showAvailableVersionsInfo" ref="eric7.UI.UserInterface.html#UserInterface.showAvailableVersionsInfo" />
       <keyword name="UserInterface.showEmailDialog" id="UserInterface.showEmailDialog" ref="eric7.UI.UserInterface.html#UserInterface.showEmailDialog" />
       <keyword name="UserInterface.showEvent" id="UserInterface.showEvent" ref="eric7.UI.UserInterface.html#UserInterface.showEvent" />
       <keyword name="UserInterface.showFindFileByNameDialog" id="UserInterface.showFindFileByNameDialog" ref="eric7.UI.UserInterface.html#UserInterface.showFindFileByNameDialog" />
@@ -16482,6 +16546,9 @@
       <keyword name="UserInterface.showReplaceFilesWidget" id="UserInterface.showReplaceFilesWidget" ref="eric7.UI.UserInterface.html#UserInterface.showReplaceFilesWidget" />
       <keyword name="UserInterface.showSideWidget" id="UserInterface.showSideWidget" ref="eric7.UI.UserInterface.html#UserInterface.showSideWidget" />
       <keyword name="UserInterface.unregisterToolbar" id="UserInterface.unregisterToolbar" ref="eric7.UI.UserInterface.html#UserInterface.unregisterToolbar" />
+      <keyword name="UserInterface.upgradeEric" id="UserInterface.upgradeEric" ref="eric7.UI.UserInterface.html#UserInterface.upgradeEric" />
+      <keyword name="UserInterface.upgradeEricPyQt" id="UserInterface.upgradeEricPyQt" ref="eric7.UI.UserInterface.html#UserInterface.upgradeEricPyQt" />
+      <keyword name="UserInterface.upgradePyQt" id="UserInterface.upgradePyQt" ref="eric7.UI.UserInterface.html#UserInterface.upgradePyQt" />
       <keyword name="UserInterface.versionIsNewer" id="UserInterface.versionIsNewer" ref="eric7.UI.UserInterface.html#UserInterface.versionIsNewer" />
       <keyword name="UserProjectFile" id="UserProjectFile" ref="eric7.Project.UserProjectFile.html#UserProjectFile" />
       <keyword name="UserProjectFile (Constructor)" id="UserProjectFile (Constructor)" ref="eric7.Project.UserProjectFile.html#UserProjectFile.__init__" />
@@ -16739,6 +16806,10 @@
       <keyword name="VersionControl.vcsSwitch" id="VersionControl.vcsSwitch" ref="eric7.VCS.VersionControl.html#VersionControl.vcsSwitch" />
       <keyword name="VersionControl.vcsTag" id="VersionControl.vcsTag" ref="eric7.VCS.VersionControl.html#VersionControl.vcsTag" />
       <keyword name="VersionControl.vcsUpdate" id="VersionControl.vcsUpdate" ref="eric7.VCS.VersionControl.html#VersionControl.vcsUpdate" />
+      <keyword name="VersionsDialog" id="VersionsDialog" ref="eric7.UI.VersionsDialog.html#VersionsDialog" />
+      <keyword name="VersionsDialog (Constructor)" id="VersionsDialog (Constructor)" ref="eric7.UI.VersionsDialog.html#VersionsDialog.__init__" />
+      <keyword name="VersionsDialog (Module)" id="VersionsDialog (Module)" ref="eric7.UI.VersionsDialog.html" />
+      <keyword name="VersionsDialog.__checkForUpdate" id="VersionsDialog.__checkForUpdate" ref="eric7.UI.VersionsDialog.html#VersionsDialog.__checkForUpdate" />
       <keyword name="ViewManager" id="ViewManager" ref="eric7.ViewManager.ViewManager.html#ViewManager" />
       <keyword name="ViewManager (Constructor)" id="ViewManager (Constructor)" ref="eric7.ViewManager.ViewManager.html#ViewManager.__init__" />
       <keyword name="ViewManager (Module)" id="ViewManager (Module)" ref="eric7.ViewManager.ViewManager.html" />
@@ -17014,6 +17085,7 @@
       <keyword name="VirtualenvAddEditDialog" id="VirtualenvAddEditDialog" ref="eric7.VirtualEnv.VirtualenvAddEditDialog.html#VirtualenvAddEditDialog" />
       <keyword name="VirtualenvAddEditDialog (Constructor)" id="VirtualenvAddEditDialog (Constructor)" ref="eric7.VirtualEnv.VirtualenvAddEditDialog.html#VirtualenvAddEditDialog.__init__" />
       <keyword name="VirtualenvAddEditDialog (Module)" id="VirtualenvAddEditDialog (Module)" ref="eric7.VirtualEnv.VirtualenvAddEditDialog.html" />
+      <keyword name="VirtualenvAddEditDialog.__detectPythonInterpreter" id="VirtualenvAddEditDialog.__detectPythonInterpreter" ref="eric7.VirtualEnv.VirtualenvAddEditDialog.html#VirtualenvAddEditDialog.__detectPythonInterpreter" />
       <keyword name="VirtualenvAddEditDialog.__updateOk" id="VirtualenvAddEditDialog.__updateOk" ref="eric7.VirtualEnv.VirtualenvAddEditDialog.html#VirtualenvAddEditDialog.__updateOk" />
       <keyword name="VirtualenvAddEditDialog.getData" id="VirtualenvAddEditDialog.getData" ref="eric7.VirtualEnv.VirtualenvAddEditDialog.html#VirtualenvAddEditDialog.getData" />
       <keyword name="VirtualenvAddEditDialog.on_anacondaCheckBox_clicked" id="VirtualenvAddEditDialog.on_anacondaCheckBox_clicked" ref="eric7.VirtualEnv.VirtualenvAddEditDialog.html#VirtualenvAddEditDialog.on_anacondaCheckBox_clicked" />
@@ -17075,6 +17147,7 @@
       <keyword name="VirtualenvManager.addVirtualEnv" id="VirtualenvManager.addVirtualEnv" ref="eric7.VirtualEnv.VirtualenvManager.html#VirtualenvManager.addVirtualEnv" />
       <keyword name="VirtualenvManager.createVirtualEnv" id="VirtualenvManager.createVirtualEnv" ref="eric7.VirtualEnv.VirtualenvManager.html#VirtualenvManager.createVirtualEnv" />
       <keyword name="VirtualenvManager.deleteVirtualEnvs" id="VirtualenvManager.deleteVirtualEnvs" ref="eric7.VirtualEnv.VirtualenvManager.html#VirtualenvManager.deleteVirtualEnvs" />
+      <keyword name="VirtualenvManager.environmentForInterpreter" id="VirtualenvManager.environmentForInterpreter" ref="eric7.VirtualEnv.VirtualenvManager.html#VirtualenvManager.environmentForInterpreter" />
       <keyword name="VirtualenvManager.getDefaultEnvironment" id="VirtualenvManager.getDefaultEnvironment" ref="eric7.VirtualEnv.VirtualenvManager.html#VirtualenvManager.getDefaultEnvironment" />
       <keyword name="VirtualenvManager.getEnvironmentEntries" id="VirtualenvManager.getEnvironmentEntries" ref="eric7.VirtualEnv.VirtualenvManager.html#VirtualenvManager.getEnvironmentEntries" />
       <keyword name="VirtualenvManager.getVirtualEnvironmentsBaseDir" id="VirtualenvManager.getVirtualEnvironmentsBaseDir" ref="eric7.VirtualEnv.VirtualenvManager.html#VirtualenvManager.getVirtualEnvironmentsBaseDir" />
@@ -17180,6 +17253,8 @@
       <keyword name="VmTabviewPlugin (Constructor)" id="VmTabviewPlugin (Constructor)" ref="eric7.Plugins.PluginVmTabview.html#VmTabviewPlugin.__init__" />
       <keyword name="VmTabviewPlugin.activate" id="VmTabviewPlugin.activate" ref="eric7.Plugins.PluginVmTabview.html#VmTabviewPlugin.activate" />
       <keyword name="VmTabviewPlugin.deactivate" id="VmTabviewPlugin.deactivate" ref="eric7.Plugins.PluginVmTabview.html#VmTabviewPlugin.deactivate" />
+      <keyword name="Vulnerability" id="Vulnerability" ref="eric7.PipInterface.PipVulnerabilityChecker.html#Vulnerability" />
+      <keyword name="VulnerabilityCheckError" id="VulnerabilityCheckError" ref="eric7.PipInterface.PipVulnerabilityChecker.html#VulnerabilityCheckError" />
       <keyword name="Watch" id="Watch" ref="eric7.DebugClients.Python.BreakpointWatch.html#Watch" />
       <keyword name="Watch (Constructor)" id="Watch (Constructor)" ref="eric7.DebugClients.Python.BreakpointWatch.html#Watch.__init__" />
       <keyword name="Watch.clear_all_watches" id="Watch.clear_all_watches" ref="eric7.DebugClients.Python.BreakpointWatch.html#Watch.clear_all_watches" />
@@ -18131,6 +18206,7 @@
       <keyword name="checkTryExceptPass" id="checkTryExceptPass" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.tryExcept.html#checkTryExceptPass" />
       <keyword name="checkWeakCryptographicKey" id="checkWeakCryptographicKey" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.weakCryptographicKey.html#checkWeakCryptographicKey" />
       <keyword name="checkYamlLoad" id="checkYamlLoad" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.yamlLoad.html#checkYamlLoad" />
+      <keyword name="choices_from_enum" id="choices_from_enum" ref="eric7.PipInterface.piplicenses.html#choices_from_enum" />
       <keyword name="className" id="className" ref="eric7.Project.UicLoadUi5.html#className" />
       <keyword name="className" id="className" ref="eric7.Project.UicLoadUi6.html#className" />
       <keyword name="cleanUp" id="cleanUp" ref="install-debugclients.html#cleanUp" />
@@ -18295,6 +18371,10 @@
       <keyword name="createWindowsShortcut" id="createWindowsShortcut" ref="create_windows_links.html#createWindowsShortcut" />
       <keyword name="createWindowsShortcut" id="createWindowsShortcut" ref="eric7.eric7_post_install.html#createWindowsShortcut" />
       <keyword name="createWindowsShortcut" id="createWindowsShortcut" ref="install.html#createWindowsShortcut" />
+      <keyword name="create_licenses_list" id="create_licenses_list" ref="eric7.PipInterface.piplicenses.html#create_licenses_list" />
+      <keyword name="create_output_string" id="create_output_string" ref="eric7.PipInterface.piplicenses.html#create_output_string" />
+      <keyword name="create_parser" id="create_parser" ref="eric7.PipInterface.piplicenses.html#create_parser" />
+      <keyword name="create_summary_list" id="create_summary_list" ref="eric7.PipInterface.piplicenses.html#create_summary_list" />
       <keyword name="create_windows_links (Module)" id="create_windows_links (Module)" ref="create_windows_links.html" />
       <keyword name="critical" id="critical" ref="eric7.EricWidgets.EricMessageBox.html#critical" />
       <keyword name="crypto (Package)" id="crypto (Package)" ref="index-eric7.Utilities.crypto.html" />
@@ -18323,6 +18403,7 @@
       <keyword name="djangoSqlInjection (Module)" id="djangoSqlInjection (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.djangoSqlInjection.html" />
       <keyword name="djangoXssVulnerability (Module)" id="djangoXssVulnerability (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.djangoXssVulnerability.html" />
       <keyword name="doDependancyChecks" id="doDependancyChecks" ref="install.html#doDependancyChecks" />
+      <keyword name="doUpgrade" id="doUpgrade" ref="eric7.UI.upgrader.html#doUpgrade" />
       <keyword name="drawPolygon" id="drawPolygon" ref="eric7.Snapshot.SnapshotFreehandGrabber.html#drawPolygon" />
       <keyword name="drawRect" id="drawRect" ref="eric7.Snapshot.SnapshotRegionGrabber.html#drawRect" />
       <keyword name="editMessageFilters" id="editMessageFilters" ref="eric7.EricWidgets.EricErrorMessage.html#editMessageFilters" />
@@ -18330,6 +18411,7 @@
       <keyword name="encryptData" id="encryptData" ref="eric7.Utilities.crypto.py3AES.html#encryptData" />
       <keyword name="engineDisplayName" id="engineDisplayName" ref="eric7.Plugins.UiExtensionPlugins.Translator.TranslatorEngines.__init__.html#engineDisplayName" />
       <keyword name="ensureUniqueFilename" id="ensureUniqueFilename" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#ensureUniqueFilename" />
+      <keyword name="enum_key_to_value" id="enum_key_to_value" ref="eric7.PipInterface.piplicenses.html#enum_key_to_value" />
       <keyword name="eradicate (Module)" id="eradicate (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Miscellaneous.eradicate.html" />
       <keyword name="eric6SettingsName" id="eric6SettingsName" ref="eric7.Preferences.__init__.html#eric6SettingsName" />
       <keyword name="eric7 (Module)" id="eric7 (Module)" ref="eric7.eric7.html" />
@@ -18393,6 +18475,7 @@
       <keyword name="filterCharsFromFilename" id="filterCharsFromFilename" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#filterCharsFromFilename" />
       <keyword name="filterMessage" id="filterMessage" ref="eric7.EricWidgets.EricErrorMessage.html#filterMessage" />
       <keyword name="findVolume" id="findVolume" ref="eric7.Utilities.__init__.html#findVolume" />
+      <keyword name="find_license_from_classifier" id="find_license_from_classifier" ref="eric7.PipInterface.piplicenses.html#find_license_from_classifier" />
       <keyword name="find_module" id="find_module" ref="eric7.Utilities.ClassBrowsers.__init__.html#find_module" />
       <keyword name="find_module" id="find_module" ref="eric7.Utilities.ModuleParser.html#find_module" />
       <keyword name="flaskDebug (Module)" id="flaskDebug (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.flaskDebug.html" />
@@ -18616,7 +18699,12 @@
       <keyword name="get_class_members" id="get_class_members" ref="eric7.DebugClients.Python.FlexCompleter.html#get_class_members" />
       <keyword name="get_coding" id="get_coding" ref="eric7.Utilities.__init__.html#get_coding" />
       <keyword name="get_codingBytes" id="get_codingBytes" ref="eric7.Utilities.__init__.html#get_codingBytes" />
+      <keyword name="get_installed_distributions" id="get_installed_distributions" ref="eric7.PipInterface.piplicenses.html#get_installed_distributions" />
+      <keyword name="get_output_fields" id="get_output_fields" ref="eric7.PipInterface.piplicenses.html#get_output_fields" />
+      <keyword name="get_packages" id="get_packages" ref="eric7.PipInterface.piplicenses.html#get_packages" />
       <keyword name="get_parser" id="get_parser" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#get_parser" />
+      <keyword name="get_pkg_included_file" id="get_pkg_included_file" ref="eric7.PipInterface.piplicenses.html#get_pkg_included_file" />
+      <keyword name="get_pkg_info" id="get_pkg_info" ref="eric7.PipInterface.piplicenses.html#get_pkg_info" />
       <keyword name="getargvalues" id="getargvalues" ref="eric7.DebugClients.Python.DebugUtilities.html#getargvalues" />
       <keyword name="getpass" id="getpass" ref="eric7.DebugClients.Python.getpass.html#getpass" />
       <keyword name="getpass (Module)" id="getpass (Module)" ref="eric7.DebugClients.Python.getpass.html" />
@@ -18673,6 +18761,7 @@
       <keyword name="insecureSslTls (Module)" id="insecureSslTls (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.insecureSslTls.html" />
       <keyword name="install (Module)" id="install (Module)" ref="install.html" />
       <keyword name="install-debugclients (Module)" id="install-debugclients (Module)" ref="install-debugclients.html" />
+      <keyword name="install-dependencies (Module)" id="install-dependencies (Module)" ref="install-dependencies.html" />
       <keyword name="install-i18n (Module)" id="install-i18n (Module)" ref="install-i18n.html" />
       <keyword name="installEric" id="installEric" ref="install.html#installEric" />
       <keyword name="installEricDebugClients" id="installEricDebugClients" ref="install-debugclients.html#installEricDebugClients" />
@@ -18737,9 +18826,11 @@
       <keyword name="main" id="main" ref="cleanupSource.html#main" />
       <keyword name="main" id="main" ref="compileUiFiles.html#main" />
       <keyword name="main" id="main" ref="create_windows_links.html#main" />
+      <keyword name="main" id="main" ref="eric7.PipInterface.piplicenses.html#main" />
       <keyword name="main" id="main" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Miscellaneous.eradicate.html#main" />
       <keyword name="main" id="main" ref="eric7.Plugins.VcsPlugins.vcsMercurial.HisteditExtension.HgHisteditEditor.html#main" />
       <keyword name="main" id="main" ref="eric7.Plugins.WizardPlugins.QRegularExpressionWizard.QRegularExpressionWizardServer.html#main" />
+      <keyword name="main" id="main" ref="eric7.UI.upgrader.html#main" />
       <keyword name="main" id="main" ref="eric7.eric7.html#main" />
       <keyword name="main" id="main" ref="eric7.eric7_api.html#main" />
       <keyword name="main" id="main" ref="eric7.eric7_browser.html#main" />
@@ -18765,6 +18856,7 @@
       <keyword name="main" id="main" ref="eric7.eric7_unittest.html#main" />
       <keyword name="main" id="main" ref="eric7.eric7_virtualenv.html#main" />
       <keyword name="main" id="main" ref="install-debugclients.html#main" />
+      <keyword name="main" id="main" ref="install-dependencies.html#main" />
       <keyword name="main" id="main" ref="install-i18n.html#main" />
       <keyword name="main" id="main" ref="install.html#main" />
       <keyword name="main" id="main" ref="uninstall-debugclients.html#main" />
@@ -18823,7 +18915,9 @@
       <keyword name="patchQProcess" id="patchQProcess" ref="eric7.DebugClients.Python.QProcessExtension.html#patchQProcess" />
       <keyword name="patchSubprocess" id="patchSubprocess" ref="eric7.DebugClients.Python.SubprocessExtension.html#patchSubprocess" />
       <keyword name="pbkdf2" id="pbkdf2" ref="eric7.Utilities.crypto.py3PBKDF2.html#pbkdf2" />
+      <keyword name="pipInstall" id="pipInstall" ref="install-dependencies.html#pipInstall" />
       <keyword name="pipInstall" id="pipInstall" ref="install.html#pipInstall" />
+      <keyword name="piplicenses (Module)" id="piplicenses (Module)" ref="eric7.PipInterface.piplicenses.html" />
       <keyword name="pixmapFileToDataUrl" id="pixmapFileToDataUrl" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#pixmapFileToDataUrl" />
       <keyword name="pixmapFromByteArray" id="pixmapFromByteArray" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#pixmapFromByteArray" />
       <keyword name="pixmapToByteArray" id="pixmapToByteArray" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#pixmapToByteArray" />
@@ -18932,6 +19026,7 @@
       <keyword name="schemeFromProxyType" id="schemeFromProxyType" ref="eric7.EricNetwork.EricNetworkProxyFactory.html#schemeFromProxyType" />
       <keyword name="scrollToAnchor" id="scrollToAnchor" ref="eric7.WebBrowser.Tools.Scripts.html#scrollToAnchor" />
       <keyword name="securityOk" id="securityOk" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.CodeStyleChecker.html#securityOk" />
+      <keyword name="select_license_by_source" id="select_license_by_source" ref="eric7.PipInterface.piplicenses.html#select_license_by_source" />
       <keyword name="sendPostData" id="sendPostData" ref="eric7.WebBrowser.Tools.Scripts.html#sendPostData" />
       <keyword name="sessionType" id="sessionType" ref="eric7.Globals.__init__.html#sessionType" />
       <keyword name="setActions" id="setActions" ref="eric7.Preferences.Shortcuts.html#setActions" />
@@ -19007,6 +19102,7 @@
       <keyword name="splitPath" id="splitPath" ref="eric7.Utilities.__init__.html#splitPath" />
       <keyword name="sshNoHostKeyVerification (Module)" id="sshNoHostKeyVerification (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.sshNoHostKeyVerification.html" />
       <keyword name="startDebugger" id="startDebugger" ref="eric7.DebugClients.Python.eric7dbgstub.html#startDebugger" />
+      <keyword name="startEric" id="startEric" ref="eric7.UI.upgrader.html#startEric" />
       <keyword name="startsWithShebang" id="startsWithShebang" ref="eric7.DebugClients.Python.DebugUtilities.html#startsWithShebang" />
       <keyword name="startswithPath" id="startswithPath" ref="eric7.Utilities.__init__.html#startswithPath" />
       <keyword name="stdin_get_value" id="stdin_get_value" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#stdin_get_value" />
@@ -19070,6 +19166,7 @@
       <keyword name="updatePip" id="updatePip" ref="install.html#updatePip" />
       <keyword name="updateTypeMap" id="updateTypeMap" ref="eric7.DebugClients.Python.DebugVariables.html#updateTypeMap" />
       <keyword name="update_counts" id="update_counts" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#update_counts" />
+      <keyword name="upgrader (Module)" id="upgrader (Module)" ref="eric7.UI.upgrader.html" />
       <keyword name="usage" id="usage" ref="eric7.Toolbox.Startup.html#usage" />
       <keyword name="usage" id="usage" ref="eric7.eric7_api.html#usage" />
       <keyword name="usage" id="usage" ref="eric7.eric7_doc.html#usage" />
@@ -19079,6 +19176,7 @@
       <keyword name="usage" id="usage" ref="uninstall-debugclients.html#usage" />
       <keyword name="usage" id="usage" ref="uninstall.html#usage" />
       <keyword name="userConfiguration" id="userConfiguration" ref="eric7.CondaInterface.__init__.html#userConfiguration" />
+      <keyword name="value_to_enum_key" id="value_to_enum_key" ref="eric7.PipInterface.piplicenses.html#value_to_enum_key" />
       <keyword name="vcsGit (Package)" id="vcsGit (Package)" ref="index-eric7.Plugins.VcsPlugins.vcsGit.html" />
       <keyword name="vcsMercurial (Package)" id="vcsMercurial (Package)" ref="index-eric7.Plugins.VcsPlugins.vcsMercurial.html" />
       <keyword name="vcsPySvn (Package)" id="vcsPySvn (Package)" ref="index-eric7.Plugins.VcsPlugins.vcsPySvn.html" />
@@ -19363,9 +19461,12 @@
       <file>eric7.PipInterface.PipDialog.html</file>
       <file>eric7.PipInterface.PipFileSelectionDialog.html</file>
       <file>eric7.PipInterface.PipFreezeDialog.html</file>
+      <file>eric7.PipInterface.PipLicensesDialog.html</file>
       <file>eric7.PipInterface.PipPackageDetailsDialog.html</file>
       <file>eric7.PipInterface.PipPackagesInputDialog.html</file>
       <file>eric7.PipInterface.PipPackagesWidget.html</file>
+      <file>eric7.PipInterface.PipVulnerabilityChecker.html</file>
+      <file>eric7.PipInterface.piplicenses.html</file>
       <file>eric7.PluginManager.PluginDetailsDialog.html</file>
       <file>eric7.PluginManager.PluginExceptions.html</file>
       <file>eric7.PluginManager.PluginInfoDialog.html</file>
@@ -20005,6 +20106,8 @@
       <file>eric7.UI.SplashScreen.html</file>
       <file>eric7.UI.SymbolsWidget.html</file>
       <file>eric7.UI.UserInterface.html</file>
+      <file>eric7.UI.VersionsDialog.html</file>
+      <file>eric7.UI.upgrader.html</file>
       <file>eric7.Utilities.AutoSaver.html</file>
       <file>eric7.Utilities.BackgroundClient.html</file>
       <file>eric7.Utilities.BackgroundService.html</file>
@@ -20407,6 +20510,7 @@
       <file>index-eric7.html</file>
       <file>index.html</file>
       <file>install-debugclients.html</file>
+      <file>install-dependencies.html</file>
       <file>install-i18n.html</file>
       <file>install.html</file>
       <file>setup.html</file>
--- a/eric7/Documentation/Source/eric7.PipInterface.Pip.html	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Source/eric7.PipInterface.Pip.html	Sat Apr 02 11:23:11 2022 +0200
@@ -59,6 +59,10 @@
 <td>Constructor</td>
 </tr>
 <tr>
+<td><a href="#Pip.__checkUpgradeEric">__checkUpgradeEric</a></td>
+<td>Private method to check, if an upgrade of the eric-ide package is attempted.</td>
+</tr>
+<tr>
 <td><a href="#Pip.__checkUpgradePyQt">__checkUpgradePyQt</a></td>
 <td>Private method to check, if an upgrade of PyQt packages is attempted.</td>
 </tr>
@@ -75,6 +79,18 @@
 <td>Public method to remove files from the pip cache.</td>
 </tr>
 <tr>
+<td><a href="#Pip.checkPackageOutdated">checkPackageOutdated</a></td>
+<td>Public method to check, if a group of packages is outdated.</td>
+</tr>
+<tr>
+<td><a href="#Pip.getDependecyTree">getDependecyTree</a></td>
+<td>Public method to get the dependency tree of installed packages.</td>
+</tr>
+<tr>
+<td><a href="#Pip.getFrozenPackages">getFrozenPackages</a></td>
+<td>Public method to get the list of package specifiers to freeze them.</td>
+</tr>
+<tr>
 <td><a href="#Pip.getIndexUrl">getIndexUrl</a></td>
 <td>Public method to get the index URL for PyPI.</td>
 </tr>
@@ -91,6 +107,14 @@
 <td>Public method to get the list of installed packages.</td>
 </tr>
 <tr>
+<td><a href="#Pip.getLicenses">getLicenses</a></td>
+<td>Public method to get the licenses per package for a given environment.</td>
+</tr>
+<tr>
+<td><a href="#Pip.getLicensesSummary">getLicensesSummary</a></td>
+<td>Public method to get a summary of licenses found in a given environment.</td>
+</tr>
+<tr>
 <td><a href="#Pip.getNetworkAccessManager">getNetworkAccessManager</a></td>
 <td>Public method to get a reference to the network access manager object.</td>
 </tr>
@@ -103,6 +127,10 @@
 <td>Public method to get package details using the PyPI JSON interface.</td>
 </tr>
 <tr>
+<td><a href="#Pip.getPackageVersions">getPackageVersions</a></td>
+<td>Public method to get a list of versions available for the given package.</td>
+</tr>
+<tr>
 <td><a href="#Pip.getProjectEnvironmentString">getProjectEnvironmentString</a></td>
 <td>Public method to get the string for the project environment.</td>
 </tr>
@@ -123,6 +151,10 @@
 <td>Public method to get a sorted list of virtual environment names.</td>
 </tr>
 <tr>
+<td><a href="#Pip.getVulnerabilityChecker">getVulnerabilityChecker</a></td>
+<td>Public method to get a reference to the vulnerability checker object.</td>
+</tr>
+<tr>
 <td><a href="#Pip.installPackages">installPackages</a></td>
 <td>Public method to install the given list of packages.</td>
 </tr>
@@ -176,7 +208,34 @@
 
 <dt><i>parent</i> (QObject)</dt>
 <dd>
-parent
+reference to the user interface object
+</dd>
+</dl>
+<a NAME="Pip.__checkUpgradeEric" ID="Pip.__checkUpgradeEric"></a>
+<h4>Pip.__checkUpgradeEric</h4>
+<b>__checkUpgradeEric</b>(<i>packages</i>)
+
+<p>
+        Private method to check, if an upgrade of the eric-ide package is
+        attempted.
+</p>
+<dl>
+
+<dt><i>packages</i> (list of str)</dt>
+<dd>
+list of packages to upgrade
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating an eric-ide upgrade
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
 </dd>
 </dl>
 <a NAME="Pip.__checkUpgradePyQt" ID="Pip.__checkUpgradePyQt"></a>
@@ -196,7 +255,7 @@
 <dl>
 <dt>Return:</dt>
 <dd>
-flag indicating to abort the upgrade attempt
+flag indicating a PyQt upgrade
 </dd>
 </dl>
 <dl>
@@ -247,6 +306,122 @@
 name of the virtual environment to be used
 </dd>
 </dl>
+<a NAME="Pip.checkPackageOutdated" ID="Pip.checkPackageOutdated"></a>
+<h4>Pip.checkPackageOutdated</h4>
+<b>checkPackageOutdated</b>(<i>packageStart, envName</i>)
+
+<p>
+        Public method to check, if a group of packages is outdated.
+</p>
+<dl>
+
+<dt><i>packageStart</i> (str)</dt>
+<dd>
+start string for package names to be checked
+            (case insensitive)
+</dd>
+<dt><i>envName</i> (str)</dt>
+<dd>
+name of the environment to get the packages for
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating outdated packages and the
+            list of tuples containing the package name, installed version
+            and available version
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, (str, str, str))
+</dd>
+</dl>
+<a NAME="Pip.getDependecyTree" ID="Pip.getDependecyTree"></a>
+<h4>Pip.getDependecyTree</h4>
+<b>getDependecyTree</b>(<i>envName, localPackages=True, usersite=False, reverse=False</i>)
+
+<p>
+        Public method to get the dependency tree of installed packages.
+</p>
+<dl>
+
+<dt><i>envName</i> (str)</dt>
+<dd>
+name of the environment to get the packages for
+</dd>
+<dt><i>localPackages</i> (bool)</dt>
+<dd>
+flag indicating to get the tree for local
+            packages only
+</dd>
+<dt><i>usersite</i> (bool)</dt>
+<dd>
+flag indicating to get the tree for packages
+            installed in user-site directory only
+</dd>
+<dt><i>reverse</i> (bool)</dt>
+<dd>
+flag indicating to get the dependency tree in
+            reverse order (i.e. list packages needed by other)
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of nested dictionaries resembling the requested
+            dependency tree
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+list of dict
+</dd>
+</dl>
+<a NAME="Pip.getFrozenPackages" ID="Pip.getFrozenPackages"></a>
+<h4>Pip.getFrozenPackages</h4>
+<b>getFrozenPackages</b>(<i>envName, localPackages=True, usersite=False, requirement=None</i>)
+
+<p>
+        Public method to get the list of package specifiers to freeze them.
+</p>
+<dl>
+
+<dt><i>envName</i> (str)</dt>
+<dd>
+name of the environment to get the package specifiers
+            for
+</dd>
+<dt><i>localPackages</i> (bool)</dt>
+<dd>
+flag indicating to get package specifiers for
+            local packages only
+</dd>
+<dt><i>usersite</i> (bool)</dt>
+<dd>
+flag indicating to get package specifiers for packages
+            installed in user-site only
+</dd>
+<dt><i>requirement</i> (str)</dt>
+<dd>
+name of a requirements file
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of package specifiers
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+list of str
+</dd>
+</dl>
 <a NAME="Pip.getIndexUrl" ID="Pip.getIndexUrl"></a>
 <h4>Pip.getIndexUrl</h4>
 <b>getIndexUrl</b>(<i></i>)
@@ -344,6 +519,86 @@
 list of tuple of (str, str)
 </dd>
 </dl>
+<a NAME="Pip.getLicenses" ID="Pip.getLicenses"></a>
+<h4>Pip.getLicenses</h4>
+<b>getLicenses</b>(<i>envName, localPackages=True, usersite=False, summary=False</i>)
+
+<p>
+        Public method to get the licenses per package for a given environment.
+</p>
+<dl>
+
+<dt><i>envName</i> (str)</dt>
+<dd>
+name of the environment to get the licenses for
+</dd>
+<dt><i>localPackages</i> (bool)</dt>
+<dd>
+flag indicating to get the licenses for local
+            packages only
+</dd>
+<dt><i>usersite</i> (bool)</dt>
+<dd>
+flag indicating to get the licenses for packages
+            installed in user-site directory only
+</dd>
+<dt><i>summary</i> (bool (optional))</dt>
+<dd>
+flag indicating to get a summary listing (defaults to
+            False)
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of dictionaries containing the license and version per
+            package
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+dict
+</dd>
+</dl>
+<a NAME="Pip.getLicensesSummary" ID="Pip.getLicensesSummary"></a>
+<h4>Pip.getLicensesSummary</h4>
+<b>getLicensesSummary</b>(<i>envName, localPackages=True, usersite=False</i>)
+
+<p>
+        Public method to get a summary of licenses found in a given
+        environment.
+</p>
+<dl>
+
+<dt><i>envName</i> (str)</dt>
+<dd>
+name of the environment to get the licenses summary for
+</dd>
+<dt><i>localPackages</i> (bool)</dt>
+<dd>
+flag indicating to get the licenses summary for
+            local packages only
+</dd>
+<dt><i>usersite</i> (bool)</dt>
+<dd>
+flag indicating to get the licenses summary for
+            packages installed in user-site directory only
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of dictionaries containing the license and the count of
+            packages
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+dict
+</dd>
+</dl>
 <a NAME="Pip.getNetworkAccessManager" ID="Pip.getNetworkAccessManager"></a>
 <h4>Pip.getNetworkAccessManager</h4>
 <b>getNetworkAccessManager</b>(<i></i>)
@@ -434,6 +689,33 @@
 dict
 </dd>
 </dl>
+<a NAME="Pip.getPackageVersions" ID="Pip.getPackageVersions"></a>
+<h4>Pip.getPackageVersions</h4>
+<b>getPackageVersions</b>(<i>name</i>)
+
+<p>
+        Public method to get a list of versions available for the given
+        package.
+</p>
+<dl>
+
+<dt><i>name</i> (str)</dt>
+<dd>
+package name
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of available versions
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+list of str
+</dd>
+</dl>
 <a NAME="Pip.getProjectEnvironmentString" ID="Pip.getProjectEnvironmentString"></a>
 <h4>Pip.getProjectEnvironmentString</h4>
 <b>getProjectEnvironmentString</b>(<i></i>)
@@ -555,6 +837,25 @@
 list of str
 </dd>
 </dl>
+<a NAME="Pip.getVulnerabilityChecker" ID="Pip.getVulnerabilityChecker"></a>
+<h4>Pip.getVulnerabilityChecker</h4>
+<b>getVulnerabilityChecker</b>(<i></i>)
+
+<p>
+        Public method to get a reference to the vulnerability checker object.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+reference to the vulnerability checker object
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+PipVulnerabilityChecker
+</dd>
+</dl>
 <a NAME="Pip.installPackages" ID="Pip.installPackages"></a>
 <h4>Pip.installPackages</h4>
 <b>installPackages</b>(<i>packages, venvName="", userSite=False, interpreter="", forceReinstall=False</i>)
--- a/eric7/Documentation/Source/eric7.PipInterface.PipFreezeDialog.html	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Source/eric7.PipInterface.PipFreezeDialog.html	Sat Apr 02 11:23:11 2022 +0200
@@ -115,6 +115,10 @@
 <td>Private slot to write the requirements text to a new file.</td>
 </tr>
 <tr>
+<td><a href="#PipFreezeDialog.on_userCheckBox_clicked">on_userCheckBox_clicked</a></td>
+<td>Private slot handling the switching of the user-site mode.</td>
+</tr>
+<tr>
 <td><a href="#PipFreezeDialog.start">start</a></td>
 <td>Public method to start the command.</td>
 </tr>
@@ -216,18 +220,11 @@
 </p>
 <a NAME="PipFreezeDialog.on_localCheckBox_clicked" ID="PipFreezeDialog.on_localCheckBox_clicked"></a>
 <h4>PipFreezeDialog.on_localCheckBox_clicked</h4>
-<b>on_localCheckBox_clicked</b>(<i>checked</i>)
+<b>on_localCheckBox_clicked</b>(<i></i>)
 
 <p>
         Private slot handling the switching of the local mode.
 </p>
-<dl>
-
-<dt><i>checked</i> (bool)</dt>
-<dd>
-state of the local check box
-</dd>
-</dl>
 <a NAME="PipFreezeDialog.on_replaceAllButton_clicked" ID="PipFreezeDialog.on_replaceAllButton_clicked"></a>
 <h4>PipFreezeDialog.on_replaceAllButton_clicked</h4>
 <b>on_replaceAllButton_clicked</b>(<i></i>)
@@ -279,6 +276,13 @@
 <p>
         Private slot to write the requirements text to a new file.
 </p>
+<a NAME="PipFreezeDialog.on_userCheckBox_clicked" ID="PipFreezeDialog.on_userCheckBox_clicked"></a>
+<h4>PipFreezeDialog.on_userCheckBox_clicked</h4>
+<b>on_userCheckBox_clicked</b>(<i></i>)
+
+<p>
+        Private slot handling the switching of the user-site mode.
+</p>
 <a NAME="PipFreezeDialog.start" ID="PipFreezeDialog.start"></a>
 <h4>PipFreezeDialog.start</h4>
 <b>start</b>(<i>venvName</i>)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/Documentation/Source/eric7.PipInterface.PipLicensesDialog.html	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.PipInterface.PipLicensesDialog</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.PipInterface.PipLicensesDialog</h1>
+
+<p>
+Module implementing a dialog to show the licenses of an environment.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#PipLicensesDialog">PipLicensesDialog</a></td>
+<td>Class implementing a dialog to show the licenses of an environment.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="PipLicensesDialog" ID="PipLicensesDialog"></a>
+<h2>PipLicensesDialog</h2>
+
+<p>
+    Class implementing a dialog to show the licenses of an environment.
+</p>
+<h3>Derived from</h3>
+QDialog, Ui_PipLicensesDialog
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>LicensesLicenseColumn</td></tr><tr><td>LicensesPackageColumn</td></tr><tr><td>LicensesVersionColumn</td></tr><tr><td>SummaryCountColumn</td></tr><tr><td>SummaryLicenseColumn</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#PipLicensesDialog.__init__">PipLicensesDialog</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#PipLicensesDialog.__refreshLicenses">__refreshLicenses</a></td>
+<td>Private slot to refresh the license lists.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="PipLicensesDialog.__init__" ID="PipLicensesDialog.__init__"></a>
+<h4>PipLicensesDialog (Constructor)</h4>
+<b>PipLicensesDialog</b>(<i>pip, environment, localPackages=True, usersite=False, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>pip</i> (Pip)</dt>
+<dd>
+reference to the pip interface object
+</dd>
+<dt><i>environment</i> (str)</dt>
+<dd>
+name of the environment to show the licenses for
+</dd>
+<dt><i>localPackages</i> (bool)</dt>
+<dd>
+flag indicating to show the licenses for local
+            packages only
+</dd>
+<dt><i>usersite</i> (bool)</dt>
+<dd>
+flag indicating to show the licenses for packages
+            installed in user-site directory only
+</dd>
+<dt><i>parent</i> (QWidget (optional))</dt>
+<dd>
+reference to the parent widget (defaults to None)
+</dd>
+</dl>
+<a NAME="PipLicensesDialog.__refreshLicenses" ID="PipLicensesDialog.__refreshLicenses"></a>
+<h4>PipLicensesDialog.__refreshLicenses</h4>
+<b>__refreshLicenses</b>(<i></i>)
+
+<p>
+        Private slot to refresh the license lists.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- a/eric7/Documentation/Source/eric7.PipInterface.PipPackagesWidget.html	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Source/eric7.PipInterface.PipPackagesWidget.html	Sat Apr 02 11:23:11 2022 +0200
@@ -47,7 +47,7 @@
 <h3>Class Attributes</h3>
 
 <table>
-<tr><td>SearchVersionRole</td></tr><tr><td>ShowProcessClassifiersMode</td></tr><tr><td>ShowProcessEntryPointsMode</td></tr><tr><td>ShowProcessFilesListMode</td></tr><tr><td>ShowProcessGeneralMode</td></tr>
+<tr><td>AvailableVersionColumn</td></tr><tr><td>DepInstalledVersionColumn</td></tr><tr><td>DepPackageColumn</td></tr><tr><td>DepRequiredVersionColumn</td></tr><tr><td>InstalledVersionColumn</td></tr><tr><td>PackageColumn</td></tr><tr><td>SearchVersionRole</td></tr><tr><td>ShowProcessClassifiersMode</td></tr><tr><td>ShowProcessEntryPointsMode</td></tr><tr><td>ShowProcessFilesListMode</td></tr><tr><td>ShowProcessGeneralMode</td></tr><tr><td>VulnerabilityColumn</td></tr><tr><td>VulnerabilityRole</td></tr>
 </table>
 <h3>Class Methods</h3>
 
@@ -67,6 +67,10 @@
 <td>Private slot to set the action enabled status.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__addDependency">__addDependency</a></td>
+<td>Private method to add a dependency branch to a given parent.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.__allUpdateableItems">__allUpdateableItems</a></td>
 <td>Private method to get a list of all items that can be updated.</td>
 </tr>
@@ -75,6 +79,10 @@
 <td>Private method to get the pip version of the selected environment.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__clearVulnerabilityInfo">__clearVulnerabilityInfo</a></td>
+<td>Private slot to clear the vulnerability info.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.__editConfiguration">__editConfiguration</a></td>
 <td>Private method to edit a configuration.</td>
 </tr>
@@ -135,12 +143,20 @@
 <td>Private slot to handle the projectClosed signal.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__projectOpened">__projectOpened</a></td>
+<td>Private slot to handle the projectOpened signal.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.__purgeCache">__purgeCache</a></td>
 <td>Private slot to empty the pip cache.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__refreshDependencyTree">__refreshDependencyTree</a></td>
+<td>Private method to refresh the dependency tree.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.__refreshPackagesList">__refreshPackagesList</a></td>
-<td>Private method to referesh the packages list.</td>
+<td>Private method to refresh the packages list.</td>
 </tr>
 <tr>
 <td><a href="#PipPackagesWidget.__reinstallPackages">__reinstallPackages</a></td>
@@ -159,6 +175,10 @@
 <td>Private method to perform the search by calling the PyPI search URL.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__searchFirst">__searchFirst</a></td>
+<td>Private method to perform the search for packages.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.__searchResponse">__searchResponse</a></td>
 <td>Private method to extract the search result data from the response.</td>
 </tr>
@@ -175,14 +195,26 @@
 <td>Private slot to show a list of cached files.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__showLicensesDialog">__showLicensesDialog</a></td>
+<td>Private slot to show a dialog with the licenses of the selected environment.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.__showPackageDetails">__showPackageDetails</a></td>
 <td>Private method to populate the package details dialog.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__showPackageInformation">__showPackageInformation</a></td>
+<td>Private method to show information for a package.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.__showSearchedDetails">__showSearchedDetails</a></td>
 <td>Private slot to show details about the selected search result package.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__showVulnerabilityInformation">__showVulnerabilityInformation</a></td>
+<td>Private method to show the detected vulnerability data.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.__uninstallRequirements">__uninstallRequirements</a></td>
 <td>Private slot to uninstall packages as given in a requirements file.</td>
 </tr>
@@ -191,6 +223,10 @@
 <td>Private method to set the state of the action buttons.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__updateDepActionButtons">__updateDepActionButtons</a></td>
+<td>Private method to set the state of the dependency page action buttons.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.__updateSearchActionButtons">__updateSearchActionButtons</a></td>
 <td>Private method to update the action button states of the search widget.</td>
 </tr>
@@ -199,6 +235,18 @@
 <td>Private method to update the state of the search button.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.__updateSearchMoreButton">__updateSearchMoreButton</a></td>
+<td>Private method to update the state of the search more button.</td>
+</tr>
+<tr>
+<td><a href="#PipPackagesWidget.__updateVulnerabilityData">__updateVulnerabilityData</a></td>
+<td>Private slot to update the shown vulnerability info.</td>
+</tr>
+<tr>
+<td><a href="#PipPackagesWidget.__updateVulnerabilityDbCache">__updateVulnerabilityDbCache</a></td>
+<td>Private slot to initiate an update of the local cache of the vulnerability database.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.executeInstallPackages">executeInstallPackages</a></td>
 <td>Public method to install the given list of packages.</td>
 </tr>
@@ -215,7 +263,19 @@
 <td>Public method to get a reference to the pip interface object.</td>
 </tr>
 <tr>
-<td><a href="#PipPackagesWidget.on_environmentsComboBox_currentIndexChanged">on_environmentsComboBox_currentIndexChanged</a></td>
+<td><a href="#PipPackagesWidget.on_dependenciesList_itemActivated">on_dependenciesList_itemActivated</a></td>
+<td>Private slot reacting on a package item of the dependency tree being activated.</td>
+</tr>
+<tr>
+<td><a href="#PipPackagesWidget.on_dependenciesList_itemPressed">on_dependenciesList_itemPressed</a></td>
+<td>Private slot reacting on a package item of the dependency tree being pressed.</td>
+</tr>
+<tr>
+<td><a href="#PipPackagesWidget.on_dependenciesList_itemSelectionChanged">on_dependenciesList_itemSelectionChanged</a></td>
+<td>Private slot reacting on a change of selected items of the dependency tree.</td>
+</tr>
+<tr>
+<td><a href="#PipPackagesWidget.on_environmentsComboBox_currentTextChanged">on_environmentsComboBox_currentTextChanged</a></td>
 <td>Private slot handling the selection of a Python environment.</td>
 </tr>
 <tr>
@@ -235,22 +295,38 @@
 <td>Private slot handling the switching of the local mode.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.on_localDepCheckBox_clicked">on_localDepCheckBox_clicked</a></td>
+<td>Private slot handling the switching of the local mode.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.on_notRequiredCheckBox_clicked">on_notRequiredCheckBox_clicked</a></td>
 <td>Private slot handling the switching of the 'not required' mode.</td>
 </tr>
 <tr>
 <td><a href="#PipPackagesWidget.on_packagesList_itemActivated">on_packagesList_itemActivated</a></td>
-<td>Private slot reacting on a package item activation.</td>
+<td>Private slot reacting on a package item being activated.</td>
+</tr>
+<tr>
+<td><a href="#PipPackagesWidget.on_packagesList_itemPressed">on_packagesList_itemPressed</a></td>
+<td>Private slot reacting on a package item being pressed.</td>
 </tr>
 <tr>
 <td><a href="#PipPackagesWidget.on_packagesList_itemSelectionChanged">on_packagesList_itemSelectionChanged</a></td>
-<td>Private slot handling the selection of a package.</td>
+<td>Private slot reacting on a change of selected items.</td>
 </tr>
 <tr>
 <td><a href="#PipPackagesWidget.on_refreshButton_clicked">on_refreshButton_clicked</a></td>
 <td>Private slot to refresh the display.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.on_refreshDependenciesButton_clicked">on_refreshDependenciesButton_clicked</a></td>
+<td>Private slot to refresh the dependency tree.</td>
+</tr>
+<tr>
+<td><a href="#PipPackagesWidget.on_requiresButton_toggled">on_requiresButton_toggled</a></td>
+<td>Private slot handling the selection of the view type.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.on_searchButton_clicked">on_searchButton_clicked</a></td>
 <td>Private slot handling a press of the search button.</td>
 </tr>
@@ -263,6 +339,10 @@
 <td>Private slot handling a change of the search term.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.on_searchMoreButton_clicked">on_searchMoreButton_clicked</a></td>
+<td>Private slot handling a press of the search more button.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.on_searchResultList_itemActivated">on_searchResultList_itemActivated</a></td>
 <td>Private slot reacting on an search result item activation.</td>
 </tr>
@@ -275,6 +355,10 @@
 <td>Private slot to togle the search widget.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.on_showDepPackageDetailsButton_clicked">on_showDepPackageDetailsButton_clicked</a></td>
+<td>Private slot to show information for the selected package of the dependency tree.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.on_showDetailsButton_clicked">on_showDetailsButton_clicked</a></td>
 <td>Private slot to handle pressing the Show Details button.</td>
 </tr>
@@ -299,9 +383,21 @@
 <td>Private slot handling the switching of the 'user-site' mode.</td>
 </tr>
 <tr>
+<td><a href="#PipPackagesWidget.on_userDepCheckBox_clicked">on_userDepCheckBox_clicked</a></td>
+<td>Private slot handling the switching of the 'user-site' mode.</td>
+</tr>
+<tr>
 <td><a href="#PipPackagesWidget.on_verboseCheckBox_clicked">on_verboseCheckBox_clicked</a></td>
 <td>Private slot to handle a change of the verbose package information checkbox.</td>
 </tr>
+<tr>
+<td><a href="#PipPackagesWidget.on_viewToggleButton_toggled">on_viewToggleButton_toggled</a></td>
+<td>Private slot handling the view selection.</td>
+</tr>
+<tr>
+<td><a href="#PipPackagesWidget.on_vulnerabilityCheckBox_clicked">on_vulnerabilityCheckBox_clicked</a></td>
+<td>Private slot handling a change of the automatic vulnerability checks.</td>
+</tr>
 </table>
 <h3>Static Methods</h3>
 
@@ -334,6 +430,24 @@
 <p>
         Private slot to set the action enabled status.
 </p>
+<a NAME="PipPackagesWidget.__addDependency" ID="PipPackagesWidget.__addDependency"></a>
+<h4>PipPackagesWidget.__addDependency</h4>
+<b>__addDependency</b>(<i>dependency, parent</i>)
+
+<p>
+        Private method to add a dependency branch to a given parent.
+</p>
+<dl>
+
+<dt><i>dependency</i> (dict)</dt>
+<dd>
+dependency to be added
+</dd>
+<dt><i>parent</i> (QTreeWidget or QTreeWidgetItem)</dt>
+<dd>
+reference to the parent item
+</dd>
+</dl>
 <a NAME="PipPackagesWidget.__allUpdateableItems" ID="PipPackagesWidget.__allUpdateableItems"></a>
 <h4>PipPackagesWidget.__allUpdateableItems</h4>
 <b>__allUpdateableItems</b>(<i></i>)
@@ -373,6 +487,13 @@
 tuple of int
 </dd>
 </dl>
+<a NAME="PipPackagesWidget.__clearVulnerabilityInfo" ID="PipPackagesWidget.__clearVulnerabilityInfo"></a>
+<h4>PipPackagesWidget.__clearVulnerabilityInfo</h4>
+<b>__clearVulnerabilityInfo</b>(<i></i>)
+
+<p>
+        Private slot to clear the vulnerability info.
+</p>
 <a NAME="PipPackagesWidget.__editConfiguration" ID="PipPackagesWidget.__editConfiguration"></a>
 <h4>PipPackagesWidget.__editConfiguration</h4>
 <b>__editConfiguration</b>(<i>venvName=""</i>)
@@ -507,6 +628,13 @@
 flag indicating the IDE shutdown
 </dd>
 </dl>
+<a NAME="PipPackagesWidget.__projectOpened" ID="PipPackagesWidget.__projectOpened"></a>
+<h4>PipPackagesWidget.__projectOpened</h4>
+<b>__projectOpened</b>(<i></i>)
+
+<p>
+        Private slot to handle the projectOpened signal.
+</p>
 <a NAME="PipPackagesWidget.__purgeCache" ID="PipPackagesWidget.__purgeCache"></a>
 <h4>PipPackagesWidget.__purgeCache</h4>
 <b>__purgeCache</b>(<i></i>)
@@ -514,12 +642,19 @@
 <p>
         Private slot to empty the pip cache.
 </p>
+<a NAME="PipPackagesWidget.__refreshDependencyTree" ID="PipPackagesWidget.__refreshDependencyTree"></a>
+<h4>PipPackagesWidget.__refreshDependencyTree</h4>
+<b>__refreshDependencyTree</b>(<i></i>)
+
+<p>
+        Private method to refresh the dependency tree.
+</p>
 <a NAME="PipPackagesWidget.__refreshPackagesList" ID="PipPackagesWidget.__refreshPackagesList"></a>
 <h4>PipPackagesWidget.__refreshPackagesList</h4>
 <b>__refreshPackagesList</b>(<i></i>)
 
 <p>
-        Private method to referesh the packages list.
+        Private method to refresh the packages list.
 </p>
 <a NAME="PipPackagesWidget.__reinstallPackages" ID="PipPackagesWidget.__reinstallPackages"></a>
 <h4>PipPackagesWidget.__reinstallPackages</h4>
@@ -545,11 +680,25 @@
 </p>
 <a NAME="PipPackagesWidget.__search" ID="PipPackagesWidget.__search"></a>
 <h4>PipPackagesWidget.__search</h4>
-<b>__search</b>(<i></i>)
+<b>__search</b>(<i>page=1</i>)
 
 <p>
         Private method to perform the search by calling the PyPI search URL.
 </p>
+<dl>
+
+<dt><i>page</i> (int (optional))</dt>
+<dd>
+search page to retrieve (defaults to 1)
+</dd>
+</dl>
+<a NAME="PipPackagesWidget.__searchFirst" ID="PipPackagesWidget.__searchFirst"></a>
+<h4>PipPackagesWidget.__searchFirst</h4>
+<b>__searchFirst</b>(<i></i>)
+
+<p>
+        Private method to perform the search for packages.
+</p>
 <a NAME="PipPackagesWidget.__searchResponse" ID="PipPackagesWidget.__searchResponse"></a>
 <h4>PipPackagesWidget.__searchResponse</h4>
 <b>__searchResponse</b>(<i>reply</i>)
@@ -597,6 +746,14 @@
 <p>
         Private slot to show a list of cached files.
 </p>
+<a NAME="PipPackagesWidget.__showLicensesDialog" ID="PipPackagesWidget.__showLicensesDialog"></a>
+<h4>PipPackagesWidget.__showLicensesDialog</h4>
+<b>__showLicensesDialog</b>(<i></i>)
+
+<p>
+        Private slot to show a dialog with the licenses of the selected
+        environment.
+</p>
 <a NAME="PipPackagesWidget.__showPackageDetails" ID="PipPackagesWidget.__showPackageDetails"></a>
 <h4>PipPackagesWidget.__showPackageDetails</h4>
 <b>__showPackageDetails</b>(<i>packageName, packageVersion, upgradable=False, installable=False</i>)
@@ -625,6 +782,24 @@
             (defaults to False)
 </dd>
 </dl>
+<a NAME="PipPackagesWidget.__showPackageInformation" ID="PipPackagesWidget.__showPackageInformation"></a>
+<h4>PipPackagesWidget.__showPackageInformation</h4>
+<b>__showPackageInformation</b>(<i>packageName, infoWidget</i>)
+
+<p>
+        Private method to show information for a package.
+</p>
+<dl>
+
+<dt><i>packageName</i> (str)</dt>
+<dd>
+name of the package
+</dd>
+<dt><i>infoWidget</i> (QTreeWidget)</dt>
+<dd>
+reference to the widget to contain the information
+</dd>
+</dl>
 <a NAME="PipPackagesWidget.__showSearchedDetails" ID="PipPackagesWidget.__showSearchedDetails"></a>
 <h4>PipPackagesWidget.__showSearchedDetails</h4>
 <b>__showSearchedDetails</b>(<i>item=None</i>)
@@ -639,6 +814,28 @@
 reference to the search result item to show details for
 </dd>
 </dl>
+<a NAME="PipPackagesWidget.__showVulnerabilityInformation" ID="PipPackagesWidget.__showVulnerabilityInformation"></a>
+<h4>PipPackagesWidget.__showVulnerabilityInformation</h4>
+<b>__showVulnerabilityInformation</b>(<i>packageName, packageVersion, vulnerabilities</i>)
+
+<p>
+        Private method to show the detected vulnerability data.
+</p>
+<dl>
+
+<dt><i>packageName</i> (str)</dt>
+<dd>
+name of the package
+</dd>
+<dt><i>packageVersion</i> (str)</dt>
+<dd>
+installed version number
+</dd>
+<dt><i>vulnerabilities</i> (list of Vulnerability)</dt>
+<dd>
+list of vulnerabilities
+</dd>
+</dl>
 <a NAME="PipPackagesWidget.__uninstallRequirements" ID="PipPackagesWidget.__uninstallRequirements"></a>
 <h4>PipPackagesWidget.__uninstallRequirements</h4>
 <b>__uninstallRequirements</b>(<i></i>)
@@ -653,6 +850,13 @@
 <p>
         Private method to set the state of the action buttons.
 </p>
+<a NAME="PipPackagesWidget.__updateDepActionButtons" ID="PipPackagesWidget.__updateDepActionButtons"></a>
+<h4>PipPackagesWidget.__updateDepActionButtons</h4>
+<b>__updateDepActionButtons</b>(<i></i>)
+
+<p>
+        Private method to set the state of the dependency page action buttons.
+</p>
 <a NAME="PipPackagesWidget.__updateSearchActionButtons" ID="PipPackagesWidget.__updateSearchActionButtons"></a>
 <h4>PipPackagesWidget.__updateSearchActionButtons</h4>
 <b>__updateSearchActionButtons</b>(<i></i>)
@@ -667,6 +871,43 @@
 <p>
         Private method to update the state of the search button.
 </p>
+<a NAME="PipPackagesWidget.__updateSearchMoreButton" ID="PipPackagesWidget.__updateSearchMoreButton"></a>
+<h4>PipPackagesWidget.__updateSearchMoreButton</h4>
+<b>__updateSearchMoreButton</b>(<i>enable</i>)
+
+<p>
+        Private method to update the state of the search more button.
+</p>
+<dl>
+
+<dt><i>enable</i> (bool)</dt>
+<dd>
+flag indicating the desired enable state
+</dd>
+</dl>
+<a NAME="PipPackagesWidget.__updateVulnerabilityData" ID="PipPackagesWidget.__updateVulnerabilityData"></a>
+<h4>PipPackagesWidget.__updateVulnerabilityData</h4>
+<b>__updateVulnerabilityData</b>(<i>clearFirst=True</i>)
+
+<p>
+        Private slot to update the shown vulnerability info.
+</p>
+<dl>
+
+<dt><i>clearFirst</i> (bool (optional))</dt>
+<dd>
+flag indicating to clear the vulnerability info first
+            (defaults to True)
+</dd>
+</dl>
+<a NAME="PipPackagesWidget.__updateVulnerabilityDbCache" ID="PipPackagesWidget.__updateVulnerabilityDbCache"></a>
+<h4>PipPackagesWidget.__updateVulnerabilityDbCache</h4>
+<b>__updateVulnerabilityDbCache</b>(<i></i>)
+
+<p>
+        Private slot to initiate an update of the local cache of the
+        vulnerability database.
+</p>
 <a NAME="PipPackagesWidget.executeInstallPackages" ID="PipPackagesWidget.executeInstallPackages"></a>
 <h4>PipPackagesWidget.executeInstallPackages</h4>
 <b>executeInstallPackages</b>(<i>packages, userSite=False</i>)
@@ -732,18 +973,64 @@
 Pip
 </dd>
 </dl>
-<a NAME="PipPackagesWidget.on_environmentsComboBox_currentIndexChanged" ID="PipPackagesWidget.on_environmentsComboBox_currentIndexChanged"></a>
-<h4>PipPackagesWidget.on_environmentsComboBox_currentIndexChanged</h4>
-<b>on_environmentsComboBox_currentIndexChanged</b>(<i>index</i>)
+<a NAME="PipPackagesWidget.on_dependenciesList_itemActivated" ID="PipPackagesWidget.on_dependenciesList_itemActivated"></a>
+<h4>PipPackagesWidget.on_dependenciesList_itemActivated</h4>
+<b>on_dependenciesList_itemActivated</b>(<i>item, column</i>)
+
+<p>
+        Private slot reacting on a package item of the dependency tree being
+        activated.
+</p>
+<dl>
+
+<dt><i>item</i> (QTreeWidgetItem)</dt>
+<dd>
+reference to the activated item
+</dd>
+<dt><i>column</i> (int)</dt>
+<dd>
+activated column
+</dd>
+</dl>
+<a NAME="PipPackagesWidget.on_dependenciesList_itemPressed" ID="PipPackagesWidget.on_dependenciesList_itemPressed"></a>
+<h4>PipPackagesWidget.on_dependenciesList_itemPressed</h4>
+<b>on_dependenciesList_itemPressed</b>(<i>item, column</i>)
+
+<p>
+        Private slot reacting on a package item of the dependency tree being
+        pressed.
+</p>
+<dl>
+
+<dt><i>item</i> (QTreeWidgetItem)</dt>
+<dd>
+reference to the pressed item
+</dd>
+<dt><i>column</i> (int)</dt>
+<dd>
+pressed column
+</dd>
+</dl>
+<a NAME="PipPackagesWidget.on_dependenciesList_itemSelectionChanged" ID="PipPackagesWidget.on_dependenciesList_itemSelectionChanged"></a>
+<h4>PipPackagesWidget.on_dependenciesList_itemSelectionChanged</h4>
+<b>on_dependenciesList_itemSelectionChanged</b>(<i></i>)
+
+<p>
+        Private slot reacting on a change of selected items of the dependency
+        tree.
+</p>
+<a NAME="PipPackagesWidget.on_environmentsComboBox_currentTextChanged" ID="PipPackagesWidget.on_environmentsComboBox_currentTextChanged"></a>
+<h4>PipPackagesWidget.on_environmentsComboBox_currentTextChanged</h4>
+<b>on_environmentsComboBox_currentTextChanged</b>(<i>name</i>)
 
 <p>
         Private slot handling the selection of a Python environment.
 </p>
 <dl>
 
-<dt><i>index</i> (int)</dt>
+<dt><i>name</i> (str)</dt>
 <dd>
-index of the selected Python environment
+name of the selected Python environment
 </dd>
 </dl>
 <a NAME="PipPackagesWidget.on_installButton_clicked" ID="PipPackagesWidget.on_installButton_clicked"></a>
@@ -777,38 +1064,31 @@
 </dl>
 <a NAME="PipPackagesWidget.on_localCheckBox_clicked" ID="PipPackagesWidget.on_localCheckBox_clicked"></a>
 <h4>PipPackagesWidget.on_localCheckBox_clicked</h4>
-<b>on_localCheckBox_clicked</b>(<i>checked</i>)
+<b>on_localCheckBox_clicked</b>(<i></i>)
 
 <p>
         Private slot handling the switching of the local mode.
 </p>
-<dl>
+<a NAME="PipPackagesWidget.on_localDepCheckBox_clicked" ID="PipPackagesWidget.on_localDepCheckBox_clicked"></a>
+<h4>PipPackagesWidget.on_localDepCheckBox_clicked</h4>
+<b>on_localDepCheckBox_clicked</b>(<i></i>)
 
-<dt><i>checked</i> (bool)</dt>
-<dd>
-state of the local check box
-</dd>
-</dl>
+<p>
+        Private slot handling the switching of the local mode.
+</p>
 <a NAME="PipPackagesWidget.on_notRequiredCheckBox_clicked" ID="PipPackagesWidget.on_notRequiredCheckBox_clicked"></a>
 <h4>PipPackagesWidget.on_notRequiredCheckBox_clicked</h4>
-<b>on_notRequiredCheckBox_clicked</b>(<i>checked</i>)
+<b>on_notRequiredCheckBox_clicked</b>(<i></i>)
 
 <p>
         Private slot handling the switching of the 'not required' mode.
 </p>
-<dl>
-
-<dt><i>checked</i> (bool)</dt>
-<dd>
-state of the 'not required' check box
-</dd>
-</dl>
 <a NAME="PipPackagesWidget.on_packagesList_itemActivated" ID="PipPackagesWidget.on_packagesList_itemActivated"></a>
 <h4>PipPackagesWidget.on_packagesList_itemActivated</h4>
 <b>on_packagesList_itemActivated</b>(<i>item, column</i>)
 
 <p>
-        Private slot reacting on a package item activation.
+        Private slot reacting on a package item being activated.
 </p>
 <dl>
 
@@ -821,12 +1101,30 @@
 activated column
 </dd>
 </dl>
+<a NAME="PipPackagesWidget.on_packagesList_itemPressed" ID="PipPackagesWidget.on_packagesList_itemPressed"></a>
+<h4>PipPackagesWidget.on_packagesList_itemPressed</h4>
+<b>on_packagesList_itemPressed</b>(<i>item, column</i>)
+
+<p>
+        Private slot reacting on a package item being pressed.
+</p>
+<dl>
+
+<dt><i>item</i> (QTreeWidgetItem)</dt>
+<dd>
+reference to the pressed item
+</dd>
+<dt><i>column</i> (int)</dt>
+<dd>
+pressed column
+</dd>
+</dl>
 <a NAME="PipPackagesWidget.on_packagesList_itemSelectionChanged" ID="PipPackagesWidget.on_packagesList_itemSelectionChanged"></a>
 <h4>PipPackagesWidget.on_packagesList_itemSelectionChanged</h4>
 <b>on_packagesList_itemSelectionChanged</b>(<i></i>)
 
 <p>
-        Private slot handling the selection of a package.
+        Private slot reacting on a change of selected items.
 </p>
 <a NAME="PipPackagesWidget.on_refreshButton_clicked" ID="PipPackagesWidget.on_refreshButton_clicked"></a>
 <h4>PipPackagesWidget.on_refreshButton_clicked</h4>
@@ -835,6 +1133,27 @@
 <p>
         Private slot to refresh the display.
 </p>
+<a NAME="PipPackagesWidget.on_refreshDependenciesButton_clicked" ID="PipPackagesWidget.on_refreshDependenciesButton_clicked"></a>
+<h4>PipPackagesWidget.on_refreshDependenciesButton_clicked</h4>
+<b>on_refreshDependenciesButton_clicked</b>(<i></i>)
+
+<p>
+        Private slot to refresh the dependency tree.
+</p>
+<a NAME="PipPackagesWidget.on_requiresButton_toggled" ID="PipPackagesWidget.on_requiresButton_toggled"></a>
+<h4>PipPackagesWidget.on_requiresButton_toggled</h4>
+<b>on_requiresButton_toggled</b>(<i>checked</i>)
+
+<p>
+        Private slot handling the selection of the view type.
+</p>
+<dl>
+
+<dt><i>checked</i> (bool)</dt>
+<dd>
+state of the radio button (unused)
+</dd>
+</dl>
 <a NAME="PipPackagesWidget.on_searchButton_clicked" ID="PipPackagesWidget.on_searchButton_clicked"></a>
 <h4>PipPackagesWidget.on_searchButton_clicked</h4>
 <b>on_searchButton_clicked</b>(<i></i>)
@@ -863,6 +1182,13 @@
 search term
 </dd>
 </dl>
+<a NAME="PipPackagesWidget.on_searchMoreButton_clicked" ID="PipPackagesWidget.on_searchMoreButton_clicked"></a>
+<h4>PipPackagesWidget.on_searchMoreButton_clicked</h4>
+<b>on_searchMoreButton_clicked</b>(<i></i>)
+
+<p>
+        Private slot handling a press of the search more button.
+</p>
 <a NAME="PipPackagesWidget.on_searchResultList_itemActivated" ID="PipPackagesWidget.on_searchResultList_itemActivated"></a>
 <h4>PipPackagesWidget.on_searchResultList_itemActivated</h4>
 <b>on_searchResultList_itemActivated</b>(<i>item, column</i>)
@@ -902,6 +1228,14 @@
 state of the search widget button
 </dd>
 </dl>
+<a NAME="PipPackagesWidget.on_showDepPackageDetailsButton_clicked" ID="PipPackagesWidget.on_showDepPackageDetailsButton_clicked"></a>
+<h4>PipPackagesWidget.on_showDepPackageDetailsButton_clicked</h4>
+<b>on_showDepPackageDetailsButton_clicked</b>(<i></i>)
+
+<p>
+        Private slot to show information for the selected package of the
+        dependency tree.
+</p>
 <a NAME="PipPackagesWidget.on_showDetailsButton_clicked" ID="PipPackagesWidget.on_showDetailsButton_clicked"></a>
 <h4>PipPackagesWidget.on_showDetailsButton_clicked</h4>
 <b>on_showDetailsButton_clicked</b>(<i></i>)
@@ -939,18 +1273,18 @@
 </p>
 <a NAME="PipPackagesWidget.on_userCheckBox_clicked" ID="PipPackagesWidget.on_userCheckBox_clicked"></a>
 <h4>PipPackagesWidget.on_userCheckBox_clicked</h4>
-<b>on_userCheckBox_clicked</b>(<i>checked</i>)
+<b>on_userCheckBox_clicked</b>(<i></i>)
 
 <p>
         Private slot handling the switching of the 'user-site' mode.
 </p>
-<dl>
+<a NAME="PipPackagesWidget.on_userDepCheckBox_clicked" ID="PipPackagesWidget.on_userDepCheckBox_clicked"></a>
+<h4>PipPackagesWidget.on_userDepCheckBox_clicked</h4>
+<b>on_userDepCheckBox_clicked</b>(<i></i>)
 
-<dt><i>checked</i> (bool)</dt>
-<dd>
-state of the 'user-site' check box
-</dd>
-</dl>
+<p>
+        Private slot handling the switching of the 'user-site' mode.
+</p>
 <a NAME="PipPackagesWidget.on_verboseCheckBox_clicked" ID="PipPackagesWidget.on_verboseCheckBox_clicked"></a>
 <h4>PipPackagesWidget.on_verboseCheckBox_clicked</h4>
 <b>on_verboseCheckBox_clicked</b>(<i>checked</i>)
@@ -966,6 +1300,34 @@
 state of the checkbox
 </dd>
 </dl>
+<a NAME="PipPackagesWidget.on_viewToggleButton_toggled" ID="PipPackagesWidget.on_viewToggleButton_toggled"></a>
+<h4>PipPackagesWidget.on_viewToggleButton_toggled</h4>
+<b>on_viewToggleButton_toggled</b>(<i>checked</i>)
+
+<p>
+        Private slot handling the view selection.
+</p>
+<dl>
+
+<dt><i>checked</i> (bool)</dt>
+<dd>
+state of the toggle button
+</dd>
+</dl>
+<a NAME="PipPackagesWidget.on_vulnerabilityCheckBox_clicked" ID="PipPackagesWidget.on_vulnerabilityCheckBox_clicked"></a>
+<h4>PipPackagesWidget.on_vulnerabilityCheckBox_clicked</h4>
+<b>on_vulnerabilityCheckBox_clicked</b>(<i>checked</i>)
+
+<p>
+        Private slot handling a change of the automatic vulnerability checks.
+</p>
+<dl>
+
+<dt><i>checked</i> (bool)</dt>
+<dd>
+flag indicating the state of the check box
+</dd>
+</dl>
 <div align="right"><a href="#top">Up</a></div>
 <hr />
 <hr />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/Documentation/Source/eric7.PipInterface.PipVulnerabilityChecker.html	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,393 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.PipInterface.PipVulnerabilityChecker</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.PipInterface.PipVulnerabilityChecker</h1>
+
+<p>
+Module implementing a Python package vulnerability checker.
+</p>
+<p>
+The vulnerability data is provided by the open Python vulnerability database
+<a href="https://github.com/pyupio/safety-db">Safety DB</a>.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#Package">Package</a></td>
+<td>Class containing the package data.</td>
+</tr>
+<tr>
+<td><a href="#PipVulnerabilityChecker">PipVulnerabilityChecker</a></td>
+<td>Class implementing a Python package vulnerability checker.</td>
+</tr>
+<tr>
+<td><a href="#Vulnerability">Vulnerability</a></td>
+<td>Class containing the vulnerability data.</td>
+</tr>
+<tr>
+<td><a href="#VulnerabilityCheckError">VulnerabilityCheckError</a></td>
+<td>Class defining various vulnerability check error states.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="Package" ID="Package"></a>
+<h2>Package</h2>
+
+<p>
+    Class containing the package data.
+</p>
+<h3>Derived from</h3>
+None
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="PipVulnerabilityChecker" ID="PipVulnerabilityChecker"></a>
+<h2>PipVulnerabilityChecker</h2>
+
+<p>
+    Class implementing a Python package vulnerability checker.
+</p>
+<h3>Derived from</h3>
+QObject
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>FullDbFile</td></tr><tr><td>SummaryDbFile</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#PipVulnerabilityChecker.__init__">PipVulnerabilityChecker</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#PipVulnerabilityChecker.__createCacheFile">__createCacheFile</a></td>
+<td>Private method to create the cache file.</td>
+</tr>
+<tr>
+<td><a href="#PipVulnerabilityChecker.__fetchVulnerabilityDatabase">__fetchVulnerabilityDatabase</a></td>
+<td>Private method to get the data of the vulnerability database.</td>
+</tr>
+<tr>
+<td><a href="#PipVulnerabilityChecker.__getDataFromCache">__getDataFromCache</a></td>
+<td>Private method to get the vulnerability database from the cache.</td>
+</tr>
+<tr>
+<td><a href="#PipVulnerabilityChecker.__getVulnerabilities">__getVulnerabilities</a></td>
+<td>Private method to get the vulnerabilities for a package.</td>
+</tr>
+<tr>
+<td><a href="#PipVulnerabilityChecker.__writeDataToCache">__writeDataToCache</a></td>
+<td>Private method to write the vulnerability data for a database to the cache.</td>
+</tr>
+<tr>
+<td><a href="#PipVulnerabilityChecker.check">check</a></td>
+<td>Public method to check the given packages for vulnerabilities.</td>
+</tr>
+<tr>
+<td><a href="#PipVulnerabilityChecker.updateVulnerabilityDb">updateVulnerabilityDb</a></td>
+<td>Public method to update the cache of the vulnerability databases.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="PipVulnerabilityChecker.__init__" ID="PipVulnerabilityChecker.__init__"></a>
+<h4>PipVulnerabilityChecker (Constructor)</h4>
+<b>PipVulnerabilityChecker</b>(<i>pip, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>pip</i> (Pip)</dt>
+<dd>
+reference to the global pip interface
+</dd>
+<dt><i>parent</i> (QWidget (optional))</dt>
+<dd>
+reference to the parent widget (defaults to None)
+</dd>
+</dl>
+<a NAME="PipVulnerabilityChecker.__createCacheFile" ID="PipVulnerabilityChecker.__createCacheFile"></a>
+<h4>PipVulnerabilityChecker.__createCacheFile</h4>
+<b>__createCacheFile</b>(<i></i>)
+
+<p>
+        Private method to create the cache file.
+</p>
+<p>
+        The cache file has the following structure.
+        {
+          "insecure.json": {
+              "cachedAt": 12345678
+              "db": {}
+          },
+          "insecure_full.json": {
+              "cachedAt": 12345678
+              "db": {}
+          },
+        }
+</p>
+<a NAME="PipVulnerabilityChecker.__fetchVulnerabilityDatabase" ID="PipVulnerabilityChecker.__fetchVulnerabilityDatabase"></a>
+<h4>PipVulnerabilityChecker.__fetchVulnerabilityDatabase</h4>
+<b>__fetchVulnerabilityDatabase</b>(<i>full=False, forceUpdate=False</i>)
+
+<p>
+        Private method to get the data of the vulnerability database.
+</p>
+<p>
+        If the cached data is still valid, this data will be used.
+        Otherwise a copy of the requested database will be downloaded
+        and cached.
+</p>
+<dl>
+
+<dt><i>full</i> (bool (optional))</dt>
+<dd>
+flag indicating to get the database containing the full
+            data set (defaults to False)
+</dd>
+<dt><i>forceUpdate</i> (bool (optional))</dt>
+<dd>
+flag indicating an update of the cache is required
+            (defaults to False)
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+dictionary containing the vulnerability data (full data set or
+            just package name and version specifier)
+</dd>
+</dl>
+<a NAME="PipVulnerabilityChecker.__getDataFromCache" ID="PipVulnerabilityChecker.__getDataFromCache"></a>
+<h4>PipVulnerabilityChecker.__getDataFromCache</h4>
+<b>__getDataFromCache</b>(<i>dbName</i>)
+
+<p>
+        Private method to get the vulnerability database from the cache.
+</p>
+<dl>
+
+<dt><i>dbName</i> (str)</dt>
+<dd>
+name of the vulnerability database
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+dictionary containing the requested vulnerability data
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+dict
+</dd>
+</dl>
+<a NAME="PipVulnerabilityChecker.__getVulnerabilities" ID="PipVulnerabilityChecker.__getVulnerabilities"></a>
+<h4>PipVulnerabilityChecker.__getVulnerabilities</h4>
+<b>__getVulnerabilities</b>(<i>package, specifier, db</i>)
+
+<p>
+        Private method to get the vulnerabilities for a package.
+</p>
+<dl>
+
+<dt><i>package</i> (str)</dt>
+<dd>
+name of the package
+</dd>
+<dt><i>specifier</i> (Specifier)</dt>
+<dd>
+package specifier
+</dd>
+<dt><i>db</i> (dict)</dt>
+<dd>
+vulnerability data
+</dd>
+</dl>
+<dl>
+<dt>Yield:</dt>
+<dd>
+dictionary containing the vulnerability data for the package
+</dd>
+</dl>
+<dl>
+<dt>Yield Type:</dt>
+<dd>
+dict
+</dd>
+</dl>
+<a NAME="PipVulnerabilityChecker.__writeDataToCache" ID="PipVulnerabilityChecker.__writeDataToCache"></a>
+<h4>PipVulnerabilityChecker.__writeDataToCache</h4>
+<b>__writeDataToCache</b>(<i>dbName, data</i>)
+
+<p>
+        Private method to write the vulnerability data for a database to the
+        cache.
+</p>
+<dl>
+
+<dt><i>dbName</i> (str)</dt>
+<dd>
+name of the vulnerability database
+</dd>
+<dt><i>data</i> (dict)</dt>
+<dd>
+dictionary containing the vulnerability data
+</dd>
+</dl>
+<a NAME="PipVulnerabilityChecker.check" ID="PipVulnerabilityChecker.check"></a>
+<h4>PipVulnerabilityChecker.check</h4>
+<b>check</b>(<i>packages</i>)
+
+<p>
+        Public method to check the given packages for vulnerabilities.
+</p>
+<dl>
+
+<dt><i>packages</i> (Package)</dt>
+<dd>
+list of packages
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing an error status and a dictionary containing
+            detected vulnerable packages keyed by package name
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (VulnerabilityCheckError, list of Vulnerability)
+</dd>
+</dl>
+<a NAME="PipVulnerabilityChecker.updateVulnerabilityDb" ID="PipVulnerabilityChecker.updateVulnerabilityDb"></a>
+<h4>PipVulnerabilityChecker.updateVulnerabilityDb</h4>
+<b>updateVulnerabilityDb</b>(<i></i>)
+
+<p>
+        Public method to update the cache of the vulnerability databases.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="Vulnerability" ID="Vulnerability"></a>
+<h2>Vulnerability</h2>
+
+<p>
+    Class containing the vulnerability data.
+</p>
+<h3>Derived from</h3>
+None
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="VulnerabilityCheckError" ID="VulnerabilityCheckError"></a>
+<h2>VulnerabilityCheckError</h2>
+
+<p>
+    Class defining various vulnerability check error states.
+</p>
+<h3>Derived from</h3>
+enum.Enum
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>FullDbUnavailable</td></tr><tr><td>OK</td></tr><tr><td>SummaryDbUnavailable</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/Documentation/Source/eric7.PipInterface.piplicenses.html	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,521 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.PipInterface.piplicenses</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.PipInterface.piplicenses</h1>
+
+<p>
+pip-licenses
+</p>
+<p>
+MIT License
+</p>
+<p>
+Copyright (c) 2018 raimon
+</p>
+<p>
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+</p>
+<p>
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+</p>
+<p>
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>DEFAULT_OUTPUT_FIELDS</td></tr><tr><td>FIELDS_TO_METADATA_KEYS</td></tr><tr><td>FIELD_NAMES</td></tr><tr><td>LICENSE_UNKNOWN</td></tr><tr><td>MAP_DEST_TO_ENUM</td></tr><tr><td>METADATA_KEYS</td></tr><tr><td>SUMMARY_OUTPUT_FIELDS</td></tr><tr><td>SYSTEM_PACKAGES</td></tr><tr><td>__author__</td></tr><tr><td>__license__</td></tr><tr><td>__pkgname__</td></tr><tr><td>__summary__</td></tr><tr><td>__url__</td></tr><tr><td>__version__</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#CompatibleArgumentParser">CompatibleArgumentParser</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#CustomHelpFormatter">CustomHelpFormatter</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#CustomNamespace">CustomNamespace</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#FromArg">FromArg</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#NoValueEnum">NoValueEnum</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#OrderArg">OrderArg</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#SelectAction">SelectAction</a></td>
+<td></td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#choices_from_enum">choices_from_enum</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#create_licenses_list">create_licenses_list</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#create_output_string">create_output_string</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#create_parser">create_parser</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#create_summary_list">create_summary_list</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#enum_key_to_value">enum_key_to_value</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#find_license_from_classifier">find_license_from_classifier</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#get_installed_distributions">get_installed_distributions</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#get_output_fields">get_output_fields</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#get_packages">get_packages</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#get_pkg_included_file">get_pkg_included_file</a></td>
+<td>Attempt to find the package's included file on disk and return the tuple (included_file_path, included_file_contents).</td>
+</tr>
+<tr>
+<td><a href="#get_pkg_info">get_pkg_info</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#main">main</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#select_license_by_source">select_license_by_source</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#value_to_enum_key">value_to_enum_key</a></td>
+<td></td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="CompatibleArgumentParser" ID="CompatibleArgumentParser"></a>
+<h2>CompatibleArgumentParser</h2>
+
+<h3>Derived from</h3>
+argparse.ArgumentParser
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#CompatibleArgumentParser._verify_args">_verify_args</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#CompatibleArgumentParser.parse_args">parse_args</a></td>
+<td></td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="CompatibleArgumentParser._verify_args" ID="CompatibleArgumentParser._verify_args"></a>
+<h4>CompatibleArgumentParser._verify_args</h4>
+<b>_verify_args</b>(<i>args: CustomNamespace</i>)
+
+<a NAME="CompatibleArgumentParser.parse_args" ID="CompatibleArgumentParser.parse_args"></a>
+<h4>CompatibleArgumentParser.parse_args</h4>
+<b>parse_args</b>(<i>args: Optional[Sequence[Text]] = None, namespace: CustomNamespace = None</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="CustomHelpFormatter" ID="CustomHelpFormatter"></a>
+<h2>CustomHelpFormatter</h2>
+
+<h3>Derived from</h3>
+argparse.HelpFormatter
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#CustomHelpFormatter.__init__">CustomHelpFormatter</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#CustomHelpFormatter._expand_help">_expand_help</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#CustomHelpFormatter._format_action">_format_action</a></td>
+<td></td>
+</tr>
+<tr>
+<td><a href="#CustomHelpFormatter._split_lines">_split_lines</a></td>
+<td></td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="CustomHelpFormatter.__init__" ID="CustomHelpFormatter.__init__"></a>
+<h4>CustomHelpFormatter (Constructor)</h4>
+<b>CustomHelpFormatter</b>(<i>prog: Text, indent_increment: int = 2, max_help_position: int = 24, width: Optional[int] = None</i>)
+
+<a NAME="CustomHelpFormatter._expand_help" ID="CustomHelpFormatter._expand_help"></a>
+<h4>CustomHelpFormatter._expand_help</h4>
+<b>_expand_help</b>(<i>action: argparse.Action</i>)
+
+<a NAME="CustomHelpFormatter._format_action" ID="CustomHelpFormatter._format_action"></a>
+<h4>CustomHelpFormatter._format_action</h4>
+<b>_format_action</b>(<i>action: argparse.Action</i>)
+
+<a NAME="CustomHelpFormatter._split_lines" ID="CustomHelpFormatter._split_lines"></a>
+<h4>CustomHelpFormatter._split_lines</h4>
+<b>_split_lines</b>(<i>text: Text, width: int</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="CustomNamespace" ID="CustomNamespace"></a>
+<h2>CustomNamespace</h2>
+
+<h3>Derived from</h3>
+argparse.Namespace
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="FromArg" ID="FromArg"></a>
+<h2>FromArg</h2>
+
+<h3>Derived from</h3>
+NoValueEnum
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>ALL</td></tr><tr><td>CLASSIFIER</td></tr><tr><td>META</td></tr><tr><td>MIXED</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="NoValueEnum" ID="NoValueEnum"></a>
+<h2>NoValueEnum</h2>
+
+<h3>Derived from</h3>
+Enum
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#NoValueEnum.__repr__">__repr__</a></td>
+<td></td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="NoValueEnum.__repr__" ID="NoValueEnum.__repr__"></a>
+<h4>NoValueEnum.__repr__</h4>
+<b>__repr__</b>(<i></i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="OrderArg" ID="OrderArg"></a>
+<h2>OrderArg</h2>
+
+<h3>Derived from</h3>
+NoValueEnum
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>AUTHOR</td></tr><tr><td>COUNT</td></tr><tr><td>LICENSE</td></tr><tr><td>NAME</td></tr><tr><td>URL</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="SelectAction" ID="SelectAction"></a>
+<h2>SelectAction</h2>
+
+<h3>Derived from</h3>
+argparse.Action
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#SelectAction.__call__">__call__</a></td>
+<td></td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="SelectAction.__call__" ID="SelectAction.__call__"></a>
+<h4>SelectAction.__call__</h4>
+<b>__call__</b>(<i>parser: argparse.ArgumentParser, namespace: argparse.Namespace, values: Text, option_string: Optional[Text] = None, </i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="choices_from_enum" ID="choices_from_enum"></a>
+<h2>choices_from_enum</h2>
+<b>choices_from_enum</b>(<i>enum_cls: NoValueEnum</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="create_licenses_list" ID="create_licenses_list"></a>
+<h2>create_licenses_list</h2>
+<b>create_licenses_list</b>(<i>args: "CustomNamespace", output_fields=DEFAULT_OUTPUT_FIELDS</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="create_output_string" ID="create_output_string"></a>
+<h2>create_output_string</h2>
+<b>create_output_string</b>(<i>args: "CustomNamespace"</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="create_parser" ID="create_parser"></a>
+<h2>create_parser</h2>
+<b>create_parser</b>(<i></i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="create_summary_list" ID="create_summary_list"></a>
+<h2>create_summary_list</h2>
+<b>create_summary_list</b>(<i>args: "CustomNamespace"</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="enum_key_to_value" ID="enum_key_to_value"></a>
+<h2>enum_key_to_value</h2>
+<b>enum_key_to_value</b>(<i>enum_key: Enum</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="find_license_from_classifier" ID="find_license_from_classifier"></a>
+<h2>find_license_from_classifier</h2>
+<b>find_license_from_classifier</b>(<i>message</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="get_installed_distributions" ID="get_installed_distributions"></a>
+<h2>get_installed_distributions</h2>
+<b>get_installed_distributions</b>(<i>local_only=True, user_only=False</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="get_output_fields" ID="get_output_fields"></a>
+<h2>get_output_fields</h2>
+<b>get_output_fields</b>(<i>args: "CustomNamespace"</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="get_packages" ID="get_packages"></a>
+<h2>get_packages</h2>
+<b>get_packages</b>(<i>args: "CustomNamespace"</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="get_pkg_included_file" ID="get_pkg_included_file"></a>
+<h2>get_pkg_included_file</h2>
+<b>get_pkg_included_file</b>(<i>pkg, file_names</i>)
+
+<p>
+        Attempt to find the package's included file on disk and return the
+        tuple (included_file_path, included_file_contents).
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="get_pkg_info" ID="get_pkg_info"></a>
+<h2>get_pkg_info</h2>
+<b>get_pkg_info</b>(<i>pkg</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="main" ID="main"></a>
+<h2>main</h2>
+<b>main</b>(<i></i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="select_license_by_source" ID="select_license_by_source"></a>
+<h2>select_license_by_source</h2>
+<b>select_license_by_source</b>(<i>from_source, license_classifier, license_meta</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="value_to_enum_key" ID="value_to_enum_key"></a>
+<h2>value_to_enum_key</h2>
+<b>value_to_enum_key</b>(<i>value: str</i>)
+
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- a/eric7/Documentation/Source/eric7.UI.UserInterface.html	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Source/eric7.UI.UserInterface.html	Sat Apr 02 11:23:11 2022 +0200
@@ -561,6 +561,10 @@
 <td>Private method to open the last file, project or multiproject.</td>
 </tr>
 <tr>
+<td><a href="#UserInterface.__performUpgrade">__performUpgrade</a></td>
+<td>Private method to perform the requested upgrade operation.</td>
+</tr>
+<tr>
 <td><a href="#UserInterface.__pluginInstallFinished">__pluginInstallFinished</a></td>
 <td>Private slot to handle the finishing of the plugin install dialog.</td>
 </tr>
@@ -649,10 +653,6 @@
 <td>Private method to configure the dock window created with __createDockWindow().</td>
 </tr>
 <tr>
-<td><a href="#UserInterface.__showAvailableVersionInfos">__showAvailableVersionInfos</a></td>
-<td>Private method to show the versions available for download.</td>
-</tr>
-<tr>
 <td><a href="#UserInterface.__showCertificatesDialog">__showCertificatesDialog</a></td>
 <td>Private slot to show the certificates management dialog.</td>
 </tr>
@@ -877,26 +877,10 @@
 <td>Private method to update the external tools actions for the current tool group.</td>
 </tr>
 <tr>
-<td><a href="#UserInterface.__updateVersionsUrls">__updateVersionsUrls</a></td>
-<td>Private method to update the URLs from which to retrieve the versions file.</td>
-</tr>
-<tr>
-<td><a href="#UserInterface.__versionCheckResult">__versionCheckResult</a></td>
-<td>Private method to show the result of the version check action.</td>
-</tr>
-<tr>
 <td><a href="#UserInterface.__versionToTuple">__versionToTuple</a></td>
 <td>Private method to convert a version string into a tuple.</td>
 </tr>
 <tr>
-<td><a href="#UserInterface.__versionsDownloadCanceled">__versionsDownloadCanceled</a></td>
-<td>Private slot called to cancel the version check.</td>
-</tr>
-<tr>
-<td><a href="#UserInterface.__versionsDownloadDone">__versionsDownloadDone</a></td>
-<td>Private slot called, after the versions file has been downloaded from the internet.</td>
-</tr>
-<tr>
 <td><a href="#UserInterface.__webBrowser">__webBrowser</a></td>
 <td>Private slot to start the eric web browser.</td>
 </tr>
@@ -1070,7 +1054,7 @@
 </tr>
 <tr>
 <td><a href="#UserInterface.performVersionCheck">performVersionCheck</a></td>
-<td>Public method to check the internet for an eric update.</td>
+<td>Public method to check for an update even if not installed via PyPI.</td>
 </tr>
 <tr>
 <td><a href="#UserInterface.processArgs">processArgs</a></td>
@@ -1101,10 +1085,6 @@
 <td>Public slot to activate the debug view profile.</td>
 </tr>
 <tr>
-<td><a href="#UserInterface.showAvailableVersionsInfo">showAvailableVersionsInfo</a></td>
-<td>Public method to show the eric versions available for download.</td>
-</tr>
-<tr>
 <td><a href="#UserInterface.showEmailDialog">showEmailDialog</a></td>
 <td>Public slot to show the email dialog in a given mode.</td>
 </tr>
@@ -1149,6 +1129,18 @@
 <td>Public method to unregister a toolbar.</td>
 </tr>
 <tr>
+<td><a href="#UserInterface.upgradeEric">upgradeEric</a></td>
+<td>Public slot to upgrade the eric-ide package of the eric7 environment.</td>
+</tr>
+<tr>
+<td><a href="#UserInterface.upgradeEricPyQt">upgradeEricPyQt</a></td>
+<td>Public slot to upgrade the eric-ide and Pyqt packages of the eric7 environment.</td>
+</tr>
+<tr>
+<td><a href="#UserInterface.upgradePyQt">upgradePyQt</a></td>
+<td>Public slot to upgrade the PyQt packages of the eric7 environment.</td>
+</tr>
+<tr>
 <td><a href="#UserInterface.versionIsNewer">versionIsNewer</a></td>
 <td>Public method to check, if the eric version is good compared to the required version.</td>
 </tr>
@@ -2057,6 +2049,26 @@
             "Nothing", "File", "Project", "MultiProject" or "Session")
 </dd>
 </dl>
+<a NAME="UserInterface.__performUpgrade" ID="UserInterface.__performUpgrade"></a>
+<h4>UserInterface.__performUpgrade</h4>
+<b>__performUpgrade</b>(<i>upgradeType</i>)
+
+<p>
+        Private method to perform the requested upgrade operation.
+</p>
+<p>
+        This action needs to shut down eric first, start a non-PyQt application
+        performing the upgrade of the PyQt packages via pip and restart eric
+        with the passed arguments. The upgrade process is not visible.
+</p>
+<dl>
+
+<dt><i>upgradeType</i> (str)</dt>
+<dd>
+upgrade operation (one of 'eric', 'ericpyqt',
+            'pyqt')
+</dd>
+</dl>
 <a NAME="UserInterface.__pluginInstallFinished" ID="UserInterface.__pluginInstallFinished"></a>
 <h4>UserInterface.__pluginInstallFinished</h4>
 <b>__pluginInstallFinished</b>(<i></i>)
@@ -2313,21 +2325,6 @@
 caption of the dock window (string)
 </dd>
 </dl>
-<a NAME="UserInterface.__showAvailableVersionInfos" ID="UserInterface.__showAvailableVersionInfos"></a>
-<h4>UserInterface.__showAvailableVersionInfos</h4>
-<b>__showAvailableVersionInfos</b>(<i>versions</i>)
-
-<p>
-        Private method to show the versions available for download.
-</p>
-<dl>
-
-<dt><i>versions</i></dt>
-<dd>
-contents of the downloaded versions file (list of
-            strings)
-</dd>
-</dl>
 <a NAME="UserInterface.__showCertificatesDialog" ID="UserInterface.__showCertificatesDialog"></a>
 <h4>UserInterface.__showCertificatesDialog</h4>
 <b>__showCertificatesDialog</b>(<i></i>)
@@ -2863,37 +2860,6 @@
         Private method to update the external tools actions for the current
         tool group.
 </p>
-<a NAME="UserInterface.__updateVersionsUrls" ID="UserInterface.__updateVersionsUrls"></a>
-<h4>UserInterface.__updateVersionsUrls</h4>
-<b>__updateVersionsUrls</b>(<i>versions</i>)
-
-<p>
-        Private method to update the URLs from which to retrieve the versions
-        file.
-</p>
-<dl>
-
-<dt><i>versions</i></dt>
-<dd>
-contents of the downloaded versions file (list of
-            strings)
-</dd>
-</dl>
-<a NAME="UserInterface.__versionCheckResult" ID="UserInterface.__versionCheckResult"></a>
-<h4>UserInterface.__versionCheckResult</h4>
-<b>__versionCheckResult</b>(<i>versions</i>)
-
-<p>
-        Private method to show the result of the version check action.
-</p>
-<dl>
-
-<dt><i>versions</i></dt>
-<dd>
-contents of the downloaded versions file (list of
-            strings)
-</dd>
-</dl>
 <a NAME="UserInterface.__versionToTuple" ID="UserInterface.__versionToTuple"></a>
 <h4>UserInterface.__versionToTuple</h4>
 <b>__versionToTuple</b>(<i>version</i>)
@@ -2920,28 +2886,6 @@
 tuple of int
 </dd>
 </dl>
-<a NAME="UserInterface.__versionsDownloadCanceled" ID="UserInterface.__versionsDownloadCanceled"></a>
-<h4>UserInterface.__versionsDownloadCanceled</h4>
-<b>__versionsDownloadCanceled</b>(<i></i>)
-
-<p>
-        Private slot called to cancel the version check.
-</p>
-<a NAME="UserInterface.__versionsDownloadDone" ID="UserInterface.__versionsDownloadDone"></a>
-<h4>UserInterface.__versionsDownloadDone</h4>
-<b>__versionsDownloadDone</b>(<i>reply</i>)
-
-<p>
-        Private slot called, after the versions file has been downloaded
-        from the internet.
-</p>
-<dl>
-
-<dt><i>reply</i> (QNetworkReply)</dt>
-<dd>
-reference to the network reply
-</dd>
-</dl>
 <a NAME="UserInterface.__webBrowser" ID="UserInterface.__webBrowser"></a>
 <h4>UserInterface.__webBrowser</h4>
 <b>__webBrowser</b>(<i>home=""</i>)
@@ -3567,26 +3511,11 @@
 </dl>
 <a NAME="UserInterface.performVersionCheck" ID="UserInterface.performVersionCheck"></a>
 <h4>UserInterface.performVersionCheck</h4>
-<b>performVersionCheck</b>(<i>manual=True, alternative=0, showVersions=False</i>)
+<b>performVersionCheck</b>(<i></i>)
 
 <p>
-        Public method to check the internet for an eric update.
+        Public method to check for an update even if not installed via PyPI.
 </p>
-<dl>
-
-<dt><i>manual</i></dt>
-<dd>
-flag indicating an invocation via the menu (boolean)
-</dd>
-<dt><i>alternative</i></dt>
-<dd>
-index of server to download from (integer)
-</dd>
-<dt><i>showVersions</i></dt>
-<dd>
-flag indicating the show versions mode (boolean)
-</dd>
-</dl>
 <a NAME="UserInterface.processArgs" ID="UserInterface.processArgs"></a>
 <h4>UserInterface.processArgs</h4>
 <b>processArgs</b>(<i>args</i>)
@@ -3723,13 +3652,6 @@
             be saved (boolean)
 </dd>
 </dl>
-<a NAME="UserInterface.showAvailableVersionsInfo" ID="UserInterface.showAvailableVersionsInfo"></a>
-<h4>UserInterface.showAvailableVersionsInfo</h4>
-<b>showAvailableVersionsInfo</b>(<i></i>)
-
-<p>
-        Public method to show the eric versions available for download.
-</p>
 <a NAME="UserInterface.showEmailDialog" ID="UserInterface.showEmailDialog"></a>
 <h4>UserInterface.showEmailDialog</h4>
 <b>showEmailDialog</b>(<i>mode, attachFile=None, deleteAttachFile=False</i>)
@@ -3907,6 +3829,64 @@
 name of the toolbar (string).
 </dd>
 </dl>
+<a NAME="UserInterface.upgradeEric" ID="UserInterface.upgradeEric"></a>
+<h4>UserInterface.upgradeEric</h4>
+<b>upgradeEric</b>(<i></i>)
+
+<p>
+        Public slot to upgrade the eric-ide package of the eric7 environment.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a successful upgrade
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="UserInterface.upgradeEricPyQt" ID="UserInterface.upgradeEricPyQt"></a>
+<h4>UserInterface.upgradeEricPyQt</h4>
+<b>upgradeEricPyQt</b>(<i></i>)
+
+<p>
+        Public slot to upgrade the eric-ide and Pyqt packages of the eric7
+        environment.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a successful upgrade
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="UserInterface.upgradePyQt" ID="UserInterface.upgradePyQt"></a>
+<h4>UserInterface.upgradePyQt</h4>
+<b>upgradePyQt</b>(<i></i>)
+
+<p>
+        Public slot to upgrade the PyQt packages of the eric7 environment.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a successful upgrade
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
 <a NAME="UserInterface.versionIsNewer" ID="UserInterface.versionIsNewer"></a>
 <h4>UserInterface.versionIsNewer</h4>
 <b>versionIsNewer</b>(<i>required, snapshot=None</i>)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/Documentation/Source/eric7.UI.VersionsDialog.html	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.UI.VersionsDialog</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.UI.VersionsDialog</h1>
+
+<p>
+Module implementing a dialog to show the versions of various components.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#VersionsDialog">VersionsDialog</a></td>
+<td>Class implementing a dialog to show the versions of various components.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="VersionsDialog" ID="VersionsDialog"></a>
+<h2>VersionsDialog</h2>
+
+<p>
+    Class implementing a dialog to show the versions of various components.
+</p>
+<h3>Derived from</h3>
+QDialog, Ui_VersionsDialog
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#VersionsDialog.__init__">VersionsDialog</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#VersionsDialog.__checkForUpdate">__checkForUpdate</a></td>
+<td>Private slot to check, if updates of PyQt6 packages or the eric-ide package are available.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="VersionsDialog.__init__" ID="VersionsDialog.__init__"></a>
+<h4>VersionsDialog (Constructor)</h4>
+<b>VersionsDialog</b>(<i>parent, title, text</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>parent</i> (UserInterface)</dt>
+<dd>
+reference to the parent widget
+</dd>
+<dt><i>title</i> (str)</dt>
+<dd>
+dialog title
+</dd>
+<dt><i>text</i> (str)</dt>
+<dd>
+versions text to be shown
+</dd>
+</dl>
+<a NAME="VersionsDialog.__checkForUpdate" ID="VersionsDialog.__checkForUpdate"></a>
+<h4>VersionsDialog.__checkForUpdate</h4>
+<b>__checkForUpdate</b>(<i></i>)
+
+<p>
+        Private slot to check, if updates of PyQt6 packages or the eric-ide
+        package are available.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/Documentation/Source/eric7.UI.upgrader.html	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.UI.upgrader</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.UI.upgrader</h1>
+
+<p>
+Script to upgrade the packages eric depends on.
+</p>
+<p>
+This process must be performed while eric is closed. The script will upgrade
+the requested packages and will restart eric.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>_ericPackages</td></tr><tr><td>_pyqtPackages</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#doUpgrade">doUpgrade</a></td>
+<td>Function to upgrade the given packages via pip.</td>
+</tr>
+<tr>
+<td><a href="#main">main</a></td>
+<td>Main entry point into the upgrader.</td>
+</tr>
+<tr>
+<td><a href="#startEric">startEric</a></td>
+<td>Function to start eric with the given arguments.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="doUpgrade" ID="doUpgrade"></a>
+<h2>doUpgrade</h2>
+<b>doUpgrade</b>(<i>packages</i>)
+
+<p>
+    Function to upgrade the given packages via pip.
+</p>
+<dl>
+
+<dt><i>packages</i> (list of str)</dt>
+<dd>
+list of packages to be upgraded
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a successful installation
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="main" ID="main"></a>
+<h2>main</h2>
+<b>main</b>(<i></i>)
+
+<p>
+    Main entry point into the upgrader.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="startEric" ID="startEric"></a>
+<h2>startEric</h2>
+<b>startEric</b>(<i>args</i>)
+
+<p>
+    Function to start eric with the given arguments.
+</p>
+<dl>
+
+<dt><i>args</i> (list of str)</dt>
+<dd>
+list containing the start arguments
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- a/eric7/Documentation/Source/eric7.VirtualEnv.VirtualenvAddEditDialog.html	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Source/eric7.VirtualEnv.VirtualenvAddEditDialog.html	Sat Apr 02 11:23:11 2022 +0200
@@ -59,6 +59,10 @@
 <td>Constructor</td>
 </tr>
 <tr>
+<td><a href="#VirtualenvAddEditDialog.__detectPythonInterpreter">__detectPythonInterpreter</a></td>
+<td>Private method to search for a suitable Python interpreter inside an environment.</td>
+</tr>
+<tr>
 <td><a href="#VirtualenvAddEditDialog.__updateOk">__updateOk</a></td>
 <td>Private slot to update the state of the OK button.</td>
 </tr>
@@ -148,6 +152,33 @@
 reference to the parent widget
 </dd>
 </dl>
+<a NAME="VirtualenvAddEditDialog.__detectPythonInterpreter" ID="VirtualenvAddEditDialog.__detectPythonInterpreter"></a>
+<h4>VirtualenvAddEditDialog.__detectPythonInterpreter</h4>
+<b>__detectPythonInterpreter</b>(<i>venvDirectory</i>)
+
+<p>
+        Private method to search for a suitable Python interpreter inside an
+        environment.
+</p>
+<dl>
+
+<dt><i>venvDirectory</i> (str)</dt>
+<dd>
+directory for the virtual environment
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+detected Python interpreter or empty string
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
 <a NAME="VirtualenvAddEditDialog.__updateOk" ID="VirtualenvAddEditDialog.__updateOk"></a>
 <h4>VirtualenvAddEditDialog.__updateOk</h4>
 <b>__updateOk</b>(<i></i>)
--- a/eric7/Documentation/Source/eric7.VirtualEnv.VirtualenvManager.html	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Source/eric7.VirtualEnv.VirtualenvManager.html	Sat Apr 02 11:23:11 2022 +0200
@@ -107,6 +107,10 @@
 <td>Public method to delete virtual environments from the list and disk.</td>
 </tr>
 <tr>
+<td><a href="#VirtualenvManager.environmentForInterpreter">environmentForInterpreter</a></td>
+<td>Public method to get the environment a given interpreter belongs to.</td>
+</tr>
+<tr>
 <td><a href="#VirtualenvManager.getDefaultEnvironment">getDefaultEnvironment</a></td>
 <td>Public method to get the default virtual environment.</td>
 </tr>
@@ -299,6 +303,33 @@
 list of logical names for the virtual environments
 </dd>
 </dl>
+<a NAME="VirtualenvManager.environmentForInterpreter" ID="VirtualenvManager.environmentForInterpreter"></a>
+<h4>VirtualenvManager.environmentForInterpreter</h4>
+<b>environmentForInterpreter</b>(<i>interpreter</i>)
+
+<p>
+        Public method to get the environment a given interpreter belongs to.
+</p>
+<dl>
+
+<dt><i>interpreter</i> (str)</dt>
+<dd>
+path of the interpreter
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing the environment name and a dictionary
+            containing a copy of the default virtual environment
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (str, dict)
+</dd>
+</dl>
 <a NAME="VirtualenvManager.getDefaultEnvironment" ID="VirtualenvManager.getDefaultEnvironment"></a>
 <h4>VirtualenvManager.getDefaultEnvironment</h4>
 <b>getDefaultEnvironment</b>(<i></i>)
--- a/eric7/Documentation/Source/index-eric7.PipInterface.html	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Source/index-eric7.PipInterface.html	Sat Apr 02 11:23:11 2022 +0200
@@ -32,6 +32,10 @@
 <td>Module implementing a dialog to generate a requirements file.</td>
 </tr>
 <tr>
+<td><a href="eric7.PipInterface.PipLicensesDialog.html">PipLicensesDialog</a></td>
+<td>Module implementing a dialog to show the licenses of an environment.</td>
+</tr>
+<tr>
 <td><a href="eric7.PipInterface.PipPackageDetailsDialog.html">PipPackageDetailsDialog</a></td>
 <td>Module implementing a dialog to show details about a package.</td>
 </tr>
@@ -43,5 +47,13 @@
 <td><a href="eric7.PipInterface.PipPackagesWidget.html">PipPackagesWidget</a></td>
 <td>Module implementing the pip packages management widget.</td>
 </tr>
+<tr>
+<td><a href="eric7.PipInterface.PipVulnerabilityChecker.html">PipVulnerabilityChecker</a></td>
+<td>Module implementing a Python package vulnerability checker.</td>
+</tr>
+<tr>
+<td><a href="eric7.PipInterface.piplicenses.html">piplicenses</a></td>
+<td>pip-licenses</td>
+</tr>
 </table>
 </body></html>
\ No newline at end of file
--- a/eric7/Documentation/Source/index-eric7.UI.html	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Source/index-eric7.UI.html	Sat Apr 02 11:23:11 2022 +0200
@@ -147,5 +147,13 @@
 <td><a href="eric7.UI.UserInterface.html">UserInterface</a></td>
 <td>Module implementing the main user interface.</td>
 </tr>
+<tr>
+<td><a href="eric7.UI.VersionsDialog.html">VersionsDialog</a></td>
+<td>Module implementing a dialog to show the versions of various components.</td>
+</tr>
+<tr>
+<td><a href="eric7.UI.upgrader.html">upgrader</a></td>
+<td>Script to upgrade the packages eric depends on.</td>
+</tr>
 </table>
 </body></html>
\ No newline at end of file
--- a/eric7/Documentation/Source/index.html	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/Documentation/Source/index.html	Sat Apr 02 11:23:11 2022 +0200
@@ -41,6 +41,10 @@
 <td>Installation script for the eric debug clients.</td>
 </tr>
 <tr>
+<td><a href="install-dependencies.html">install-dependencies</a></td>
+<td>Installation script for the eric IDE dependencies.</td>
+</tr>
+<tr>
 <td><a href="install-i18n.html">install-i18n</a></td>
 <td>Installation script for the eric IDE translation files.</td>
 </tr>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/Documentation/Source/install-dependencies.html	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html><head>
+<title>install-dependencies</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>install-dependencies</h1>
+
+<p>
+Installation script for the eric IDE dependencies.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#main">main</a></td>
+<td>Function to install the eric dependencies.</td>
+</tr>
+<tr>
+<td><a href="#pipInstall">pipInstall</a></td>
+<td>Install the given package via pip.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="main" ID="main"></a>
+<h2>main</h2>
+<b>main</b>(<i></i>)
+
+<p>
+    Function to install the eric dependencies.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="pipInstall" ID="pipInstall"></a>
+<h2>pipInstall</h2>
+<b>pipInstall</b>(<i>packageName</i>)
+
+<p>
+    Install the given package via pip.
+</p>
+<dl>
+
+<dt><i>packageName</i> (str)</dt>
+<dd>
+name of the package to be installed
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a successful installation
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- a/eric7/PipInterface/Pip.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/PipInterface/Pip.py	Sat Apr 02 11:23:11 2022 +0200
@@ -31,6 +31,7 @@
     SSL_AVAILABLE = False
 
 from .PipDialog import PipDialog
+from .PipVulnerabilityChecker import PipVulnerabilityChecker
 
 import Preferences
 import Globals
@@ -49,11 +50,13 @@
         """
         Constructor
         
-        @param parent parent
+        @param parent reference to the user interface object
         @type QObject
         """
         super().__init__(parent)
         
+        self.__ui = parent
+        
         # attributes for the network objects
         self.__networkManager = QNetworkAccessManager(self)
         self.__networkManager.proxyAuthenticationRequired.connect(
@@ -63,6 +66,8 @@
             self.__networkManager.sslErrors.connect(
                 self.__sslErrorHandler.sslErrorsReply)
         self.__replies = []
+        
+        self.__vulnerabilityChecker = PipVulnerabilityChecker(self, self)
     
     def getNetworkAccessManager(self):
         """
@@ -73,6 +78,15 @@
         """
         return self.__networkManager
     
+    def getVulnerabilityChecker(self):
+        """
+        Public method to get a reference to the vulnerability checker object.
+        
+        @return reference to the vulnerability checker object
+        @rtype PipVulnerabilityChecker
+        """
+        return self.__vulnerabilityChecker
+    
     ##########################################################################
     ## Methods below implement some utility functions
     ##########################################################################
@@ -294,7 +308,7 @@
         
         @param packages list of packages to upgrade
         @type list of str
-        @return flag indicating to abort the upgrade attempt
+        @return flag indicating a PyQt upgrade
         @rtype bool
         """
         pyqtPackages = [
@@ -304,21 +318,22 @@
                 "pyqt6-charts-qt6"
             ]
         ]
+        return bool(pyqtPackages)
+    
+    def __checkUpgradeEric(self, packages):
+        """
+        Private method to check, if an upgrade of the eric-ide package is
+        attempted.
         
-        abort = (
-            not EricMessageBox.yesNo(
-                None,
-                self.tr("Upgrade Packages"),
-                self.tr(
-                    """You are trying to upgrade PyQt packages. This might"""
-                    """ not work for the current instance of Python ({0})."""
-                    """ Do you want to continue?""").format(sys.executable),
-                icon=EricMessageBox.Critical)
-            if bool(pyqtPackages) else
-            False
-        )
-        
-        return abort
+        @param packages list of packages to upgrade
+        @type list of str
+        @return flag indicating an eric-ide upgrade
+        @rtype bool
+        """
+        ericPackages = [
+            p for p in packages if p.lower() == "eric-ide"
+        ]
+        return bool(ericPackages)
     
     def upgradePackages(self, packages, venvName, userSite=False):
         """
@@ -337,11 +352,20 @@
         if not venvName:
             return False
         
-        if (
-            self.getVirtualenvInterpreter(venvName) == sys.executable and
-            self.__checkUpgradePyQt(packages)
-        ):
-            return False
+        if self.getVirtualenvInterpreter(venvName) == sys.executable:
+            upgradePyQt = self.__checkUpgradePyQt(packages)
+            upgradeEric = self.__checkUpgradeEric(packages)
+            if upgradeEric or upgradePyQt:
+                try:
+                    if upgradeEric and upgradePyQt:
+                        self.__ui.upgradeEricPyQt()
+                    elif upgradeEric:
+                        self.__ui.upgradeEric()
+                    elif upgradePyQt:
+                        self.__ui.upgradePyQt()
+                    return None     # should not be reached; play it safe
+                except AttributeError:
+                    return False
         
         interpreter = self.getVirtualenvInterpreter(venvName)
         if not interpreter:
@@ -671,6 +695,31 @@
            
         return packages
     
+    def checkPackageOutdated(self, packageStart, envName):
+        """
+        Public method to check, if a group of packages is outdated.
+        
+        @param packageStart start string for package names to be checked
+            (case insensitive)
+        @type str
+        @param envName name of the environment to get the packages for
+        @type str
+        @return tuple containing a flag indicating outdated packages and the
+            list of tuples containing the package name, installed version
+            and available version
+        @rtype tuple of (bool, (str, str, str))
+        """
+        filteredPackages = []
+        
+        if bool(envName) and bool(packageStart):
+            packages = self.getOutdatedPackages(envName)
+            filterStr = packageStart.lower()
+            filteredPackages = [
+                p for p in packages
+                if p[0].lower().startswith(filterStr)]
+        
+        return bool(filteredPackages), filteredPackages
+    
     def getPackageDetails(self, name, version):
         """
         Public method to get package details using the PyPI JSON interface.
@@ -703,6 +752,80 @@
         
         return result
     
+    def getPackageVersions(self, name):
+        """
+        Public method to get a list of versions available for the given
+        package.
+        
+        @param name package name
+        @type str
+        @return list of available versions
+        @rtype list of str
+        """
+        result = []
+        
+        if name:
+            url = "{0}/{1}/json".format(self.getIndexUrlPypi(), name)
+            request = QNetworkRequest(QUrl(url))
+            reply = self.__networkManager.get(request)
+            while not reply.isFinished():
+                QCoreApplication.processEvents()
+                QThread.msleep(100)
+            
+            reply.deleteLater()
+            if reply.error() == QNetworkReply.NetworkError.NoError:
+                dataStr = str(reply.readAll(),
+                              Preferences.getSystem("IOEncoding"),
+                              'replace')
+                with contextlib.suppress(Exception):
+                    data = json.loads(dataStr)
+                    result = list(data["releases"].keys())
+        
+        return result
+    
+    def getFrozenPackages(self, envName, localPackages=True, usersite=False,
+                          requirement=None):
+        """
+        Public method to get the list of package specifiers to freeze them.
+        
+        @param envName name of the environment to get the package specifiers
+            for
+        @type str
+        @param localPackages flag indicating to get package specifiers for
+            local packages only
+        @type bool
+        @param usersite flag indicating to get package specifiers for packages
+            installed in user-site only
+        @type bool
+        @param requirement name of a requirements file
+        @type str
+        @return list of package specifiers
+        @rtype list of str
+        """
+        specifiers = []
+        
+        if envName:
+            interpreter = self.getVirtualenvInterpreter(envName)
+            if interpreter:
+                args = [
+                    "-m", "pip",
+                    "freeze",
+                ]
+                if localPackages:
+                    args.append("--local")
+                if usersite:
+                    args.append("--user")
+                if requirement and os.path.exists(requirement):
+                    args.append("--requirement")
+                    args.append(requirement)
+                
+                success, output = self.runProcess(args, interpreter)
+                if success and output:
+                    specifiers = [spec.strip() for spec in output.splitlines()
+                                  if spec.strip()]
+        
+        return specifiers
+    
     #######################################################################
     ## Cache handling methods below
     #######################################################################
@@ -795,3 +918,132 @@
                                            showArgs=False)
                     if res:
                         dia.exec()
+    
+    #######################################################################
+    ## Dependency tree handling methods below
+    #######################################################################
+    
+    def getDependecyTree(self, envName, localPackages=True, usersite=False,
+                         reverse=False):
+        """
+        Public method to get the dependency tree of installed packages.
+        
+        @param envName name of the environment to get the packages for
+        @type str
+        @param localPackages flag indicating to get the tree for local
+            packages only
+        @type bool
+        @param usersite flag indicating to get the tree for packages
+            installed in user-site directory only
+        @type bool
+        @param reverse flag indicating to get the dependency tree in
+            reverse order (i.e. list packages needed by other)
+        @type bool
+        @return list of nested dictionaries resembling the requested
+            dependency tree
+        @rtype list of dict
+        """
+        dependencies = []
+        
+        if envName:
+            interpreter = self.getVirtualenvInterpreter(envName)
+            if interpreter:
+                args = [
+                    "-m", "pipdeptree",
+                    "--json-tree",
+                    "--python", interpreter,
+                ]
+                if localPackages:
+                    args.append("--local-only")
+                if usersite:
+                    args.append("--user-only")
+                if reverse:
+                    args.append("--reverse")
+                
+                proc = QProcess()
+                proc.start(sys.executable.replace("w.exe", ".exe"), args)
+                if proc.waitForStarted(15000) and proc.waitForFinished(30000):
+                    output = str(proc.readAllStandardOutput(),
+                                 Preferences.getSystem("IOEncoding"),
+                                 'replace').strip()
+                    with contextlib.suppress(json.JSONDecodeError):
+                        dependencies = json.loads(output)
+        
+        return dependencies
+    
+    #######################################################################
+    ## License handling methods below
+    #######################################################################
+    
+    def getLicenses(self, envName, localPackages=True, usersite=False,
+                    summary=False):
+        """
+        Public method to get the licenses per package for a given environment.
+        
+        @param envName name of the environment to get the licenses for
+        @type str
+        @param localPackages flag indicating to get the licenses for local
+            packages only
+        @type bool
+        @param usersite flag indicating to get the licenses for packages
+            installed in user-site directory only
+        @type bool
+        @param summary flag indicating to get a summary listing (defaults to
+            False)
+        @type bool (optional)
+        @return list of dictionaries containing the license and version per
+            package
+        @rtype dict
+        """
+        licenses = []
+        
+        if envName:
+            interpreter = self.getVirtualenvInterpreter(envName)
+            if interpreter:
+                from . import piplicenses
+                with open(piplicenses.__file__, "r") as f:
+                    content = f.read()
+                args = [
+                    "-c",
+                    content,
+                    "--from",
+                    "mixed",
+                    "--with-system",
+                ]
+                if localPackages:
+                    args.append("--local-only")
+                if usersite:
+                    args.append("--user-only")
+                if summary:
+                    args.append("--summary")
+                
+                proc = QProcess()
+                proc.start(interpreter, args)
+                if proc.waitForStarted(15000) and proc.waitForFinished(30000):
+                    output = str(proc.readAllStandardOutput(),
+                                 Preferences.getSystem("IOEncoding"),
+                                 'replace').strip()
+                    with contextlib.suppress(json.JSONDecodeError):
+                        licenses = json.loads(output)
+        
+        return licenses
+    
+    def getLicensesSummary(self, envName, localPackages=True, usersite=False):
+        """
+        Public method to get a summary of licenses found in a given
+        environment.
+        
+        @param envName name of the environment to get the licenses summary for
+        @type str
+        @param localPackages flag indicating to get the licenses summary for
+            local packages only
+        @type bool
+        @param usersite flag indicating to get the licenses summary for
+            packages installed in user-site directory only
+        @type bool
+        @return list of dictionaries containing the license and the count of
+            packages
+        @rtype dict
+        """
+        return self.getLicenses(envName, localPackages=localPackages,
+                                usersite=usersite, summary=True)
--- a/eric7/PipInterface/PipFreezeDialog.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/PipInterface/PipFreezeDialog.py	Sat Apr 02 11:23:11 2022 +0200
@@ -66,13 +66,17 @@
         """
         e.accept()
     
-    @pyqtSlot(bool)
-    def on_localCheckBox_clicked(self, checked):
+    @pyqtSlot()
+    def on_localCheckBox_clicked(self):
         """
         Private slot handling the switching of the local mode.
-        
-        @param checked state of the local check box
-        @type bool
+        """
+        self.__refresh()
+    
+    @pyqtSlot()
+    def on_userCheckBox_clicked(self):
+        """
+        Private slot handling the switching of the user-site mode.
         """
         self.__refresh()
     
@@ -135,29 +139,25 @@
         self.__requirementsAvailable = False
         self.__environmentName = venvName
         
-        interpreter = self.__pip.getVirtualenvInterpreter(venvName)
-        if not interpreter:
-            return
-        
-        args = ["-m", "pip", "freeze"]
-        if self.localCheckBox.isChecked():
-            args.append("--local")
-        if self.requirementsFilePicker.text():
-            fileName = Utilities.toNativeSeparators(
-                self.requirementsFilePicker.text())
-            if os.path.exists(fileName):
-                args.append("--requirement")
-                args.append(fileName)
+        fileName = (
+            Utilities.toNativeSeparators(self.requirementsFilePicker.text())
+            if self.requirementsFilePicker.text() else
+            ""
+        )
         
         with EricOverrideCursor():
-            success, output = self.__pip.runProcess(args, interpreter)
+            specifiers = self.__pip.getFrozenPackages(
+                venvName, localPackages=self.localCheckBox.isChecked(),
+                usersite=self.userCheckBox.isChecked(), requirement=fileName)
             
-            if success:
-                self.requirementsEdit.setPlainText(output)
+            if specifiers:
+                self.requirementsEdit.setPlainText(
+                    "\n".join(specifiers) + "\n")
                 self.__requirementsAvailable = True
             else:
-                self.requirementsEdit.setPlainText(
-                    self.tr("No output generated by 'pip freeze'."))
+                self.requirementsEdit.setPlainText(self.tr(
+                    "No package specifiers generated by 'pip freeze'.")
+                )
         
         self.__updateButtons()
         
--- a/eric7/PipInterface/PipFreezeDialog.ui	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/PipInterface/PipFreezeDialog.ui	Sat Apr 02 11:23:11 2022 +0200
@@ -21,17 +21,44 @@
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
-    <widget class="QCheckBox" name="localCheckBox">
-     <property name="toolTip">
-      <string>Select to show requirements for locally-installed packages only</string>
-     </property>
-     <property name="text">
-      <string>Local packages only</string>
-     </property>
-     <property name="checked">
-      <bool>true</bool>
-     </property>
-    </widget>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QCheckBox" name="localCheckBox">
+       <property name="toolTip">
+        <string>Select to show requirements for locally-installed packages only</string>
+       </property>
+       <property name="text">
+        <string>Local packages only</string>
+       </property>
+       <property name="checked">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QCheckBox" name="userCheckBox">
+       <property name="toolTip">
+        <string>Select to show requirements for packages installed to the user-site only</string>
+       </property>
+       <property name="text">
+        <string>User-Site only</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <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>
+    </layout>
    </item>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
@@ -160,6 +187,7 @@
  </customwidgets>
  <tabstops>
   <tabstop>localCheckBox</tabstop>
+  <tabstop>userCheckBox</tabstop>
   <tabstop>requirementsFilePicker</tabstop>
   <tabstop>requirementsEdit</tabstop>
   <tabstop>saveButton</tabstop>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/PipInterface/PipLicensesDialog.py	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show the licenses of an environment.
+"""
+
+from PyQt6.QtCore import pyqtSlot, Qt
+from PyQt6.QtWidgets import QDialog, QTreeWidgetItem
+
+from EricGui.EricOverrideCursor import EricOverrideCursor
+
+from .Ui_PipLicensesDialog import Ui_PipLicensesDialog
+
+
+class PipLicensesDialog(QDialog, Ui_PipLicensesDialog):
+    """
+    Class implementing a dialog to show the licenses of an environment.
+    """
+    LicensesPackageColumn = 0
+    LicensesVersionColumn = 1
+    LicensesLicenseColumn = 2
+    
+    SummaryCountColumn = 0
+    SummaryLicenseColumn = 1
+    
+    def __init__(self, pip, environment, localPackages=True, usersite=False,
+                 parent=None):
+        """
+        Constructor
+        
+        @param pip reference to the pip interface object
+        @type Pip
+        @param environment name of the environment to show the licenses for
+        @type str
+        @param localPackages flag indicating to show the licenses for local
+            packages only
+        @type bool
+        @param usersite flag indicating to show the licenses for packages
+            installed in user-site directory only
+        @type bool
+        @param parent reference to the parent widget (defaults to None)
+        @type QWidget (optional)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        
+        self.__pip = pip
+        self.__environment = environment
+        
+        self.localCheckBox.setChecked(localPackages)
+        self.userCheckBox.setChecked(usersite)
+        
+        self.localCheckBox.toggled.connect(self.__refreshLicenses)
+        self.userCheckBox.toggled.connect(self.__refreshLicenses)
+        
+        if environment:
+            self.environmentLabel.setText("<b>{0}</b>".format(
+                self.tr('Licenses of "{0}"').format(environment)
+            ))
+        else:
+            # That should never happen; play it safe.
+            self.environmentLabel.setText(self.tr("No environment specified."))
+        
+        self.__refreshLicenses()
+        
+    @pyqtSlot()
+    def __refreshLicenses(self):
+        """
+        Private slot to refresh the license lists.
+        """
+        with EricOverrideCursor():
+            self.licensesList.clear()
+            self.summaryList.clear()
+            
+            # step 1: show the licenses per package
+            self.licensesList.setUpdatesEnabled(False)
+            licenses = self.__pip.getLicenses(
+                self.__environment,
+                localPackages=self.localCheckBox.isChecked(),
+                usersite=self.userCheckBox.isChecked(),
+            )
+            for lic in licenses:
+                QTreeWidgetItem(self.licensesList, [
+                    lic["Name"],
+                    lic["Version"],
+                    lic["License"].replace("; ", "\n"),
+                ])
+            
+            self.licensesList.sortItems(
+                PipLicensesDialog.LicensesPackageColumn,
+                Qt.SortOrder.AscendingOrder)
+            for col in range(self.licensesList.columnCount()):
+                self.licensesList.resizeColumnToContents(col)
+            self.licensesList.setUpdatesEnabled(True)
+            
+            # step 2: show the licenses summary
+            self.summaryList.setUpdatesEnabled(False)
+            licenses = self.__pip.getLicensesSummary(
+                self.__environment,
+                localPackages=self.localCheckBox.isChecked(),
+                usersite=self.userCheckBox.isChecked(),
+            )
+            for lic in licenses:
+                QTreeWidgetItem(self.summaryList, [
+                    "{0:4d}".format(lic["Count"]),
+                    lic["License"].replace("; ", "\n"),
+                ])
+            
+            self.summaryList.sortItems(
+                PipLicensesDialog.SummaryLicenseColumn,
+                Qt.SortOrder.AscendingOrder)
+            for col in range(self.summaryList.columnCount()):
+                self.summaryList.resizeColumnToContents(col)
+            self.summaryList.setUpdatesEnabled(True)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/PipInterface/PipLicensesDialog.ui	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PipLicensesDialog</class>
+ <widget class="QDialog" name="PipLicensesDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>750</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Package Licenses</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="environmentLabel"/>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
+      <widget class="QCheckBox" name="localCheckBox">
+       <property name="toolTip">
+        <string>Select to show only licenses of locally installed packages</string>
+       </property>
+       <property name="text">
+        <string>Local packages only</string>
+       </property>
+       <property name="checked">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QCheckBox" name="userCheckBox">
+       <property name="toolTip">
+        <string>Select to show only licenses of packages installed to the user-site</string>
+       </property>
+       <property name="text">
+        <string>User-Site only</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QTreeWidget" name="licensesList">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>7</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="sortingEnabled">
+      <bool>true</bool>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+     <column>
+      <property name="text">
+       <string>Package</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Version</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>License</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTreeWidget" name="summaryList">
+     <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="rootIsDecorated">
+      <bool>false</bool>
+     </property>
+     <property name="itemsExpandable">
+      <bool>false</bool>
+     </property>
+     <property name="sortingEnabled">
+      <bool>true</bool>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+     <column>
+      <property name="text">
+       <string>Count</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>License</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>localCheckBox</tabstop>
+  <tabstop>userCheckBox</tabstop>
+  <tabstop>licensesList</tabstop>
+  <tabstop>summaryList</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>PipLicensesDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>PipLicensesDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- a/eric7/PipInterface/PipPackagesWidget.py	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/PipInterface/PipPackagesWidget.py	Sat Apr 02 11:23:11 2022 +0200
@@ -12,17 +12,21 @@
 import html.parser
 import contextlib
 
+from packaging.specifiers import SpecifierSet
+
 from PyQt6.QtCore import pyqtSlot, Qt, QUrl, QUrlQuery
+from PyQt6.QtGui import QIcon
 from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest
 from PyQt6.QtWidgets import (
     QWidget, QToolButton, QApplication, QHeaderView, QTreeWidgetItem,
-    QMenu, QDialog
+    QMenu, QDialog, QAbstractItemView
 )
 
 from EricWidgets.EricApplication import ericApp
 from EricWidgets import EricMessageBox
 from EricGui.EricOverrideCursor import EricOverrideCursor
 
+from .PipVulnerabilityChecker import Package, VulnerabilityCheckError
 from .Ui_PipPackagesWidget import Ui_PipPackagesWidget
 
 import UI.PixmapCache
@@ -148,6 +152,16 @@
     ShowProcessFilesListMode = 3
     
     SearchVersionRole = Qt.ItemDataRole.UserRole + 1
+    VulnerabilityRole = Qt.ItemDataRole.UserRole + 2
+    
+    PackageColumn = 0
+    InstalledVersionColumn = 1
+    AvailableVersionColumn = 2
+    VulnerabilityColumn = 3
+    
+    DepPackageColumn = 0
+    DepInstalledVersionColumn = 1
+    DepRequiredVersionColumn = 2
     
     def __init__(self, pip, parent=None):
         """
@@ -163,6 +177,8 @@
         
         self.layout().setContentsMargins(0, 3, 0, 0)
         
+        self.viewToggleButton.setIcon(UI.PixmapCache.getIcon("viewListTree"))
+        
         self.pipMenuButton.setObjectName(
             "pip_supermenu_button")
         self.pipMenuButton.setIcon(UI.PixmapCache.getIcon("superMenu"))
@@ -175,21 +191,40 @@
         self.pipMenuButton.setAutoRaise(True)
         self.pipMenuButton.setShowMenuInside(True)
         
-        self.refreshButton.setIcon(UI.PixmapCache.getIcon("reload"))
-        self.upgradeButton.setIcon(UI.PixmapCache.getIcon("1uparrow"))
-        self.upgradeAllButton.setIcon(UI.PixmapCache.getIcon("2uparrow"))
-        self.uninstallButton.setIcon(UI.PixmapCache.getIcon("minus"))
-        self.showPackageDetailsButton.setIcon(UI.PixmapCache.getIcon("info"))
-        self.searchToggleButton.setIcon(UI.PixmapCache.getIcon("find"))
-        self.searchButton.setIcon(UI.PixmapCache.getIcon("findNext"))
-        self.installButton.setIcon(UI.PixmapCache.getIcon("plus"))
-        self.installUserSiteButton.setIcon(UI.PixmapCache.getIcon("addUser"))
-        self.showDetailsButton.setIcon(UI.PixmapCache.getIcon("info"))
+        self.refreshButton.setIcon(
+            UI.PixmapCache.getIcon("reload"))
+        self.upgradeButton.setIcon(
+            UI.PixmapCache.getIcon("1uparrow"))
+        self.upgradeAllButton.setIcon(
+            UI.PixmapCache.getIcon("2uparrow"))
+        self.uninstallButton.setIcon(
+            UI.PixmapCache.getIcon("minus"))
+        self.showPackageDetailsButton.setIcon(
+            UI.PixmapCache.getIcon("info"))
+        self.searchToggleButton.setIcon(
+            UI.PixmapCache.getIcon("find"))
+        self.searchButton.setIcon(
+            UI.PixmapCache.getIcon("findNext"))
+        self.searchMoreButton.setIcon(
+            UI.PixmapCache.getIcon("plus"))
+        self.installButton.setIcon(
+            UI.PixmapCache.getIcon("plus"))
+        self.installUserSiteButton.setIcon(
+            UI.PixmapCache.getIcon("addUser"))
+        self.showDetailsButton.setIcon(
+            UI.PixmapCache.getIcon("info"))
+        
+        self.refreshDependenciesButton.setIcon(
+            UI.PixmapCache.getIcon("reload"))
+        self.showDepPackageDetailsButton.setIcon(
+            UI.PixmapCache.getIcon("info"))
         
         self.__pip = pip
         
         self.packagesList.header().setSortIndicator(
-            0, Qt.SortOrder.AscendingOrder)
+            PipPackagesWidget.PackageColumn, Qt.SortOrder.AscendingOrder)
+        self.dependenciesList.header().setSortIndicator(
+            PipPackagesWidget.DepPackageColumn, Qt.SortOrder.AscendingOrder)
         
         self.__infoLabels = {
             "name": self.tr("Name:"),
@@ -208,25 +243,29 @@
             "files": self.tr("Files:"),
         }
         self.infoWidget.setHeaderLabels(["Key", "Value"])
+        self.dependencyInfoWidget.setHeaderLabels(["Key", "Value"])
         
         venvManager = ericApp().getObject("VirtualEnvManager")
         venvManager.virtualEnvironmentAdded.connect(
             self.on_refreshButton_clicked)
         venvManager.virtualEnvironmentRemoved.connect(
             self.on_refreshButton_clicked)
+        self.__selectedEnvironment = None
         
         project = ericApp().getObject("Project")
         project.projectOpened.connect(
-            self.on_refreshButton_clicked)
+            self.__projectOpened)
         project.projectClosed.connect(
             self.__projectClosed)
         
         self.__initPipMenu()
         self.__populateEnvironments()
         self.__updateActionButtons()
+        self.__updateDepActionButtons()
         
         self.statusLabel.hide()
         self.searchWidget.hide()
+        self.__lastSearchPage = 0
         
         self.__queryName = []
         self.__querySummary = []
@@ -234,6 +273,17 @@
         self.__replies = []
         
         self.__packageDetailsDialog = None
+        
+        self.viewsStackWidget.setCurrentWidget(self.packagesPage)
+    
+    @pyqtSlot()
+    def __projectOpened(self):
+        """
+        Private slot to handle the projectOpened signal.
+        """
+        projectVenv = self.__pip.getProjectEnvironmentString()
+        if projectVenv:
+            self.environmentsComboBox.insertItem(1, projectVenv)
     
     @pyqtSlot(bool)
     def __projectClosed(self, shutdown):
@@ -244,7 +294,8 @@
         @type bool
         """
         if not shutdown:
-            self.on_refreshButton_clicked()
+            # the project entry is always at index 1
+            self.environmentsComboBox.removeItem(1)
     
     def __populateEnvironments(self):
         """
@@ -298,7 +349,8 @@
                 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive
             )
             if len(pipList) > 0:
-                pipVersionTuple = Globals.versionToTuple(pipList[0].text(1))
+                pipVersionTuple = Globals.versionToTuple(
+                    pipList[0].text(PipPackagesWidget.InstalledVersionColumn))
         
         return pipVersionTuple
     
@@ -324,7 +376,7 @@
         """
         return [
             itm for itm in self.packagesList.selectedItems()
-            if bool(itm.text(2))
+            if bool(itm.text(PipPackagesWidget.AvailableVersionColumn))
         ]
     
     def __allUpdateableItems(self):
@@ -337,7 +389,7 @@
         updateableItems = []
         for index in range(self.packagesList.topLevelItemCount()):
             itm = self.packagesList.topLevelItem(index)
-            if itm.text(2):
+            if itm.text(PipPackagesWidget.AvailableVersionColumn):
                 updateableItems.append(itm)
         
         return updateableItems
@@ -363,7 +415,7 @@
     
     def __refreshPackagesList(self):
         """
-        Private method to referesh the packages list.
+        Private method to refresh the packages list.
         """
         self.packagesList.clear()
         venvName = self.environmentsComboBox.currentText()
@@ -384,7 +436,8 @@
                         usersite=self.userCheckBox.isChecked(),
                     )
                     for package, version in installedPackages:
-                        QTreeWidgetItem(self.packagesList, [package, version])
+                        QTreeWidgetItem(self.packagesList,
+                                        [package, version, "", ""])
                     self.packagesList.setUpdatesEnabled(True)
                     self.statusLabel.setText(
                         self.tr("Getting outdated packages..."))
@@ -406,146 +459,190 @@
                         )
                         if items:
                             itm = items[0]
-                            itm.setText(2, latest)
+                            itm.setText(
+                                PipPackagesWidget.AvailableVersionColumn,
+                                latest)
                     
-                    self.packagesList.sortItems(0, Qt.SortOrder.AscendingOrder)
+                    self.packagesList.sortItems(
+                        PipPackagesWidget.PackageColumn,
+                        Qt.SortOrder.AscendingOrder)
                     for col in range(self.packagesList.columnCount()):
                         self.packagesList.resizeColumnToContents(col)
                     self.packagesList.setUpdatesEnabled(True)
+                    
+                    # 3. update with vulnerability information
+                    if self.vulnerabilityCheckBox.isChecked():
+                        self.__updateVulnerabilityData()
                 self.statusLabel.hide()
         
         self.__updateActionButtons()
         self.__updateSearchActionButtons()
         self.__updateSearchButton()
+        self.__updateSearchMoreButton(False)
     
-    @pyqtSlot(int)
-    def on_environmentsComboBox_currentIndexChanged(self, index):
+    @pyqtSlot(str)
+    def on_environmentsComboBox_currentTextChanged(self, name):
         """
         Private slot handling the selection of a Python environment.
         
-        @param index index of the selected Python environment
-        @type int
+        @param name name of the selected Python environment
+        @type str
+        """
+        if name != self.__selectedEnvironment:
+            if self.viewToggleButton.isChecked():
+                self.__refreshDependencyTree()
+            else:
+                self.__refreshPackagesList()
+            self.__selectedEnvironment = name
+    
+    @pyqtSlot()
+    def on_localCheckBox_clicked(self):
+        """
+        Private slot handling the switching of the local mode.
+        """
+        self.__refreshPackagesList()
+    
+    @pyqtSlot()
+    def on_notRequiredCheckBox_clicked(self):
+        """
+        Private slot handling the switching of the 'not required' mode.
+        """
+        self.__refreshPackagesList()
+    
+    @pyqtSlot()
+    def on_userCheckBox_clicked(self):
+        """
+        Private slot handling the switching of the 'user-site' mode.
         """
         self.__refreshPackagesList()
     
-    @pyqtSlot(bool)
-    def on_localCheckBox_clicked(self, checked):
+    def __showPackageInformation(self, packageName, infoWidget):
         """
-        Private slot handling the switching of the local mode.
+        Private method to show information for a package.
         
-        @param checked state of the local check box
-        @type bool
+        @param packageName name of the package
+        @type str
+        @param infoWidget reference to the widget to contain the information
+        @type QTreeWidget
         """
-        self.__refreshPackagesList()
-    
-    @pyqtSlot(bool)
-    def on_notRequiredCheckBox_clicked(self, checked):
-        """
-        Private slot handling the switching of the 'not required' mode.
+        environment = self.environmentsComboBox.currentText()
+        interpreter = self.__pip.getVirtualenvInterpreter(environment)
+        if not interpreter:
+            return
+        
+        args = ["-m", "pip", "show"]
+        if self.verboseCheckBox.isChecked():
+            args.append("--verbose")
+        if self.installedFilesCheckBox.isChecked():
+            args.append("--files")
+        args.append(packageName)
         
-        @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()
+        with EricOverrideCursor():
+            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(
+                                    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(
+                                    infoWidget,
+                                    [self.__infoLabels[label], info])
+                            if label == "files":
+                                mode = self.ShowProcessFilesListMode
+                            elif label == "classifiers":
+                                mode = self.ShowProcessClassifiersMode
+                            elif label == "entry-points":
+                                mode = self.ShowProcessEntryPointsMode
+                infoWidget.scrollToTop()
+            
+            header = infoWidget.header()
+            header.setStretchLastSection(False)
+            header.resizeSections(QHeaderView.ResizeMode.ResizeToContents)
+            if (
+                header.sectionSize(0) + header.sectionSize(1) <
+                header.width()
+            ):
+                header.setStretchLastSection(True)
     
     @pyqtSlot()
     def on_packagesList_itemSelectionChanged(self):
         """
-        Private slot handling the selection of a package.
+        Private slot reacting on a change of selected items.
+        """
+        if len(self.packagesList.selectedItems()) == 0:
+            self.infoWidget.clear()
+    
+    @pyqtSlot(QTreeWidgetItem, int)
+    def on_packagesList_itemPressed(self, item, column):
+        """
+        Private slot reacting on a package item being pressed.
+        
+        @param item reference to the pressed item
+        @type QTreeWidgetItem
+        @param column pressed column
+        @type int
         """
         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
-            
-            args = ["-m", "pip", "show"]
-            if self.verboseCheckBox.isChecked():
-                args.append("--verbose")
-            if self.installedFilesCheckBox.isChecked():
-                args.append("--files")
-            args.append(itm.text(0))
-            
-            with EricOverrideCursor():
-                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.ResizeMode.ResizeToContents)
-                if (
-                    header.sectionSize(0) + header.sectionSize(1) <
-                    header.width()
-                ):
-                    header.setStretchLastSection(True)
+        if item is not None:
+            if (
+                column == PipPackagesWidget.VulnerabilityColumn and
+                bool(item.text(PipPackagesWidget.VulnerabilityColumn))
+            ):
+                self.__showVulnerabilityInformation(
+                    item.text(PipPackagesWidget.PackageColumn),
+                    item.text(PipPackagesWidget.InstalledVersionColumn),
+                    item.data(PipPackagesWidget.VulnerabilityColumn,
+                              PipPackagesWidget.VulnerabilityRole)
+                )
+            else:
+                self.__showPackageInformation(
+                    item.text(PipPackagesWidget.PackageColumn),
+                    self.infoWidget
+                )
         
         self.__updateActionButtons()
     
     @pyqtSlot(QTreeWidgetItem, int)
     def on_packagesList_itemActivated(self, item, column):
         """
-        Private slot reacting on a package item activation.
+        Private slot reacting on a package item being activated.
         
         @param item reference to the activated item
         @type QTreeWidgetItem
         @param column activated column
         @type int
         """
-        packageName = item.text(0)
-        upgradable = bool(item.text(2))
-        if column == 1:
+        packageName = item.text(PipPackagesWidget.PackageColumn)
+        upgradable = bool(item.text(PipPackagesWidget.AvailableVersionColumn))
+        if column == PipPackagesWidget.InstalledVersionColumn:
             # show details for installed version
-            packageVersion = item.text(1)
+            packageVersion = item.text(
+                PipPackagesWidget.InstalledVersionColumn)
         else:
             # show details for available version or installed one
-            if item.text(2):
-                packageVersion = item.text(2)
+            if item.text(PipPackagesWidget.AvailableVersionColumn):
+                packageVersion = item.text(
+                    PipPackagesWidget.AvailableVersionColumn)
             else:
-                packageVersion = item.text(1)
+                packageVersion = item.text(
+                    PipPackagesWidget.InstalledVersionColumn)
         
         self.__showPackageDetails(packageName, packageVersion,
                                   upgradable=upgradable)
@@ -559,7 +656,8 @@
         @param checked state of the checkbox
         @type bool
         """
-        self.on_packagesList_itemSelectionChanged()
+        self.on_packagesList_itemClicked(self.packagesList.currentItem(),
+                                         self.packagesList.currentColumn())
     
     @pyqtSlot(bool)
     def on_installedFilesCheckBox_clicked(self, checked):
@@ -570,7 +668,8 @@
         @param checked state of the checkbox
         @type bool
         """
-        self.on_packagesList_itemSelectionChanged()
+        self.on_packagesList_itemClicked(self.packagesList.currentItem(),
+                                         self.packagesList.currentColumn())
     
     @pyqtSlot()
     def on_refreshButton_clicked(self):
@@ -598,7 +697,8 @@
         """
         Private slot to upgrade selected packages of the selected environment.
         """
-        packages = [itm.text(0) for itm in self.__selectedUpdateableItems()]
+        packages = [itm.text(PipPackagesWidget.PackageColumn)
+                    for itm in self.__selectedUpdateableItems()]
         if packages:
             self.executeUpgradePackages(packages)
     
@@ -607,7 +707,8 @@
         """
         Private slot to upgrade all packages of the selected environment.
         """
-        packages = [itm.text(0) for itm in self.__allUpdateableItems()]
+        packages = [itm.text(PipPackagesWidget.PackageColumn)
+                    for itm in self.__allUpdateableItems()]
         if packages:
             self.executeUpgradePackages(packages)
     
@@ -616,7 +717,8 @@
         """
         Private slot to remove selected packages of the selected environment.
         """
-        packages = [itm.text(0) for itm in self.packagesList.selectedItems()]
+        packages = [itm.text(PipPackagesWidget.PackageColumn)
+                    for itm in self.packagesList.selectedItems()]
         self.executeUninstallPackages(packages)
     
     def executeUninstallPackages(self, packages):
@@ -653,13 +755,16 @@
         """
         item = self.packagesList.selectedItems()[0]
         if item:
-            packageName = item.text(0)
-            upgradable = bool(item.text(2))
+            packageName = item.text(PipPackagesWidget.PackageColumn)
+            upgradable = bool(item.text(
+                PipPackagesWidget.AvailableVersionColumn))
             # show details for available version or installed one
-            if item.text(2):
-                packageVersion = item.text(2)
+            if item.text(PipPackagesWidget.AvailableVersionColumn):
+                packageVersion = item.text(
+                    PipPackagesWidget.AvailableVersionColumn)
             else:
-                packageVersion = item.text(1)
+                packageVersion = item.text(
+                    PipPackagesWidget.InstalledVersionColumn)
             
             self.__showPackageDetails(packageName, packageVersion,
                                       upgradable=upgradable)
@@ -694,6 +799,19 @@
             self.__isPipAvailable()
         )
     
+    def __updateSearchMoreButton(self, enable):
+        """
+        Private method to update the state of the search more button.
+        
+        @param enable flag indicating the desired enable state
+        @type bool
+        """
+        self.searchMoreButton.setEnabled(
+            enable and
+            bool(self.searchEditName.text()) and
+            self.__isPipAvailable()
+        )
+    
     @pyqtSlot(bool)
     def on_searchToggleButton_toggled(self, checked):
         """
@@ -710,6 +828,7 @@
             
             self.__updateSearchActionButtons()
             self.__updateSearchButton()
+            self.__updateSearchMoreButton(False)
     
     @pyqtSlot(str)
     def on_searchEditName_textChanged(self, txt):
@@ -730,14 +849,21 @@
             bool(self.searchEditName.text()) and
             self.__isPipAvailable()
         ):
-            self.__search()
+            self.__searchFirst()
     
     @pyqtSlot()
     def on_searchButton_clicked(self):
         """
         Private slot handling a press of the search button.
         """
-        self.__search()
+        self.__searchFirst()
+    
+    @pyqtSlot()
+    def on_searchMoreButton_clicked(self):
+        """
+        Private slot handling a press of the search more button.
+        """
+        self.__search(self.__lastSearchPage + 1)
     
     @pyqtSlot()
     def on_searchResultList_itemSelectionChanged(self):
@@ -746,19 +872,33 @@
         """
         self.__updateSearchActionButtons()
     
-    def __search(self):
+    def __searchFirst(self):
         """
-        Private method to perform the search by calling the PyPI search URL.
+        Private method to perform the search for packages.
         """
         self.searchResultList.clear()
         self.searchInfoLabel.clear()
         
+        self.__updateSearchMoreButton(False)
+        
+        self.__search()
+    
+    def __search(self, page=1):
+        """
+        Private method to perform the search by calling the PyPI search URL.
+        
+        @param page search page to retrieve (defaults to 1)
+        @type int (optional)
+        """
+        self.__lastSearchPage = page
+        
         self.searchButton.setEnabled(False)
         
         searchTerm = self.searchEditName.text().strip()
         searchTerm = bytes(QUrl.toPercentEncoding(searchTerm)).decode()
         urlQuery = QUrlQuery()
         urlQuery.addQueryItem("q", searchTerm)
+        urlQuery.addQueryItem("page", str(page))
         url = QUrl(self.__pip.getIndexUrlSearch())
         url.setQuery(urlQuery)
         
@@ -801,18 +941,39 @@
         
         results = PypiSearchResultsParser(data).getResults()
         if results:
+            # PyPI returns max. 20 entries per page
             if len(results) < 20:
-                msg = self.tr("%n package(s) found.", "", len(results))
+                msg = self.tr("%n package(s) found.", "",
+                              (self.__lastSearchPage - 1) * 20 + len(results))
+                self.__updateSearchMoreButton(False)
             else:
-                msg = self.tr("Showing first 20 packages found.")
+                msg = self.tr("Showing first {0} packages found.").format(
+                    self.__lastSearchPage * 20)
+                self.__updateSearchMoreButton(True)
             self.searchInfoLabel.setText(msg)
+            lastItem = self.searchResultList.topLevelItem(
+                self.searchResultList.topLevelItemCount() - 1)
         else:
-            EricMessageBox.warning(
-                self,
-                self.tr("Search PyPI"),
-                self.tr("""<p>There were no results for <b>{0}</b>.</p>"""))
-            self.searchInfoLabel.setText(
-                self.tr("""<p>There were no results for <b>{0}</b>.</p>"""))
+            self.__updateSearchMoreButton(False)
+            if self.__lastSearchPage == 1:
+                EricMessageBox.warning(
+                    self,
+                    self.tr("Search PyPI"),
+                    self.tr("""<p>There were no results for <b>{0}</b>.</p>""")
+                    .format(searchTerm)
+                )
+                self.searchInfoLabel.setText(
+                    self.tr("""<p>There were no results for <b>{0}</b>.</p>""")
+                    .format(searchTerm)
+                )
+            else:
+                EricMessageBox.warning(
+                    self,
+                    self.tr("Search PyPI"),
+                    self.tr("""<p>There were no more results for"""
+                            """ <b>{0}</b>.</p>""").format(searchTerm)
+                )
+            lastItem = None
         
         wrapper = textwrap.TextWrapper(width=80)
         for result in results:
@@ -832,6 +993,11 @@
                 ])
             itm.setData(0, self.SearchVersionRole, result['version'])
         
+        if lastItem:
+            self.searchResultList.scrollToItem(
+                lastItem,
+                QAbstractItemView.ScrollHint.PositionAtTop)
+        
         header = self.searchResultList.header()
         header.setStretchLastSection(False)
         header.resizeSections(QHeaderView.ResizeMode.ResizeToContents)
@@ -1016,6 +1182,18 @@
             self.tr("Generate Requirements..."),
             self.__generateRequirements)
         self.__pipMenu.addSeparator()
+        self.__showLicensesDialogAct = self.__pipMenu.addAction(
+            self.tr("Show Licenses..."),
+            self.__showLicensesDialog)
+        self.__pipMenu.addSeparator()
+        self.__checkVulnerabilityAct = self.__pipMenu.addAction(
+            self.tr("Check Vulnerabilities"),
+            self.__updateVulnerabilityData)
+        # updateVulnerabilityDbAct
+        self.__pipMenu.addAction(
+            self.tr("Update Vulnerability Database"),
+            self.__updateVulnerabilityDbCache)
+        self.__pipMenu.addSeparator()
         self.__cacheInfoAct = self.__pipMenu.addAction(
             self.tr("Show Cache Info..."),
             self.__showCacheInfo)
@@ -1072,6 +1250,11 @@
         self.__cachePurgeAct.setEnabled(enablePipCache)
         
         self.__editVirtualenvConfigAct.setEnabled(enable)
+        
+        self.__checkVulnerabilityAct.setEnabled(
+            enable & self.vulnerabilityCheckBox.isEnabled())
+        
+        self.__showLicensesDialogAct.setEnabled(enable)
     
     @pyqtSlot()
     def __installPip(self):
@@ -1137,7 +1320,8 @@
         """
         Private slot to force a re-installation of the selected packages.
         """
-        packages = [itm.text(0) for itm in self.packagesList.selectedItems()]
+        packages = [itm.text(PipPackagesWidget.PackageColumn)
+                    for itm in self.packagesList.selectedItems()]
         venvName = self.environmentsComboBox.currentText()
         if venvName and packages:
             self.__pip.installPackages(packages, venvName=venvName,
@@ -1283,3 +1467,378 @@
         venvName = self.environmentsComboBox.currentText()
         if venvName:
             self.__pip.cachePurge(venvName)
+    
+    ##################################################################
+    ## Interface to the vulnerability checks below
+    ##################################################################
+    
+    @pyqtSlot(bool)
+    def on_vulnerabilityCheckBox_clicked(self, checked):
+        """
+        Private slot handling a change of the automatic vulnerability checks.
+        
+        @param checked flag indicating the state of the check box
+        @type bool
+        """
+        if checked:
+            self.__updateVulnerabilityData(clearFirst=True)
+    
+    @pyqtSlot()
+    def __clearVulnerabilityInfo(self):
+        """
+        Private slot to clear the vulnerability info.
+        """
+        for row in range(self.packagesList.topLevelItemCount()):
+            itm = self.packagesList.topLevelItem(row)
+            itm.setText(PipPackagesWidget.VulnerabilityColumn, "")
+            itm.setToolTip(PipPackagesWidget.VulnerabilityColumn, "")
+            itm.setIcon(PipPackagesWidget.VulnerabilityColumn, QIcon())
+            itm.setData(PipPackagesWidget.VulnerabilityColumn,
+                        PipPackagesWidget.VulnerabilityRole,
+                        None)
+    
+    @pyqtSlot()
+    def __updateVulnerabilityData(self, clearFirst=True):
+        """
+        Private slot to update the shown vulnerability info.
+        
+        @param clearFirst flag indicating to clear the vulnerability info first
+            (defaults to True)
+        @type bool (optional)
+        """
+        if clearFirst:
+            self.__clearVulnerabilityInfo()
+        
+        packages = []
+        for row in range(self.packagesList.topLevelItemCount()):
+            itm = self.packagesList.topLevelItem(row)
+            packages.append(Package(
+                name=itm.text(PipPackagesWidget.PackageColumn),
+                version=itm.text(PipPackagesWidget.InstalledVersionColumn)
+            ))
+        
+        error, vulnerabilities = (
+            self.__pip.getVulnerabilityChecker().check(packages)
+        )
+        if error == VulnerabilityCheckError.OK:
+            for package in vulnerabilities:
+                items = self.packagesList.findItems(
+                    package,
+                    Qt.MatchFlag.MatchExactly |
+                    Qt.MatchFlag.MatchCaseSensitive
+                )
+                if items:
+                    itm = items[0]
+                    itm.setData(
+                        PipPackagesWidget.VulnerabilityColumn,
+                        PipPackagesWidget.VulnerabilityRole,
+                        vulnerabilities[package]
+                    )
+                    affected = {v.spec for v in vulnerabilities[package]}
+                    itm.setText(
+                        PipPackagesWidget.VulnerabilityColumn,
+                        ', '.join(affected)
+                    )
+                    itm.setIcon(
+                        PipPackagesWidget.VulnerabilityColumn,
+                        UI.PixmapCache.getIcon("securityLow")
+                    )
+        
+        elif error in (VulnerabilityCheckError.FullDbUnavailable,
+                       VulnerabilityCheckError.SummaryDbUnavailable):
+            self.vulnerabilityCheckBox.setChecked(False)
+            self.vulnerabilityCheckBox.setEnabled(False)
+            self.packagesList.setColumnHidden(
+                PipPackagesWidget.VulnerabilityColumn, True)
+    
+    @pyqtSlot()
+    def __updateVulnerabilityDbCache(self):
+        """
+        Private slot to initiate an update of the local cache of the
+        vulnerability database.
+        """
+        with EricOverrideCursor():
+            self.__pip.getVulnerabilityChecker().updateVulnerabilityDb()
+    
+    def __showVulnerabilityInformation(self, packageName, packageVersion,
+                                       vulnerabilities):
+        """
+        Private method to show the detected vulnerability data.
+        
+        @param packageName name of the package
+        @type str
+        @param packageVersion installed version number
+        @type str
+        @param vulnerabilities list of vulnerabilities
+        @type list of Vulnerability
+        """
+        header = (
+            self.tr("{0} {1}", "package name, package version")
+            .format(packageName, packageVersion)
+        )
+        topItem = QTreeWidgetItem(self.infoWidget, [header])
+        topItem.setFirstColumnSpanned(True)
+        topItem.setExpanded(True)
+        font = topItem.font(0)
+        font.setBold(True)
+        topItem.setFont(0, font)
+        
+        for vulnerability in vulnerabilities:
+            title = (
+                vulnerability.cve
+                if vulnerability.cve else
+                vulnerability.vulnerabilityId
+            )
+            titleItem = QTreeWidgetItem(topItem, [title])
+            titleItem.setFirstColumnSpanned(True)
+            titleItem.setExpanded(True)
+            
+            QTreeWidgetItem(
+                titleItem,
+                [self.tr("Affected Version:"), vulnerability.spec])
+            itm = QTreeWidgetItem(
+                titleItem,
+                [self.tr("Advisory:"), vulnerability.advisory])
+            itm.setToolTip(1, "<p>{0}</p>".format(
+                vulnerability.advisory.replace("\r\n", "<br/>")
+            ))
+        
+        self.infoWidget.scrollToTop()
+        self.infoWidget.resizeColumnToContents(0)
+        
+        header = self.infoWidget.header()
+        header.setStretchLastSection(True)
+    
+    #######################################################################
+    ## Dependency tree related methods below
+    #######################################################################
+    
+    @pyqtSlot(bool)
+    def on_viewToggleButton_toggled(self, checked):
+        """
+        Private slot handling the view selection.
+        
+        @param checked state of the toggle button
+        @type bool
+        """
+        if checked:
+            self.viewsStackWidget.setCurrentWidget(
+                self.dependenciesPage)
+            self.__refreshDependencyTree()
+        else:
+            self.viewsStackWidget.setCurrentWidget(
+                self.packagesPage)
+            self.__refreshPackagesList()
+    
+    @pyqtSlot(bool)
+    def on_requiresButton_toggled(self, checked):
+        """
+        Private slot handling the selection of the view type.
+        
+        @param checked state of the radio button (unused)
+        @type bool
+        """
+        self.__refreshDependencyTree()
+    
+    @pyqtSlot()
+    def on_localDepCheckBox_clicked(self):
+        """
+        Private slot handling the switching of the local mode.
+        """
+        self.__refreshDependencyTree()
+    
+    @pyqtSlot()
+    def on_userDepCheckBox_clicked(self):
+        """
+        Private slot handling the switching of the 'user-site' mode.
+        """
+        self.__refreshDependencyTree()
+    
+    def __refreshDependencyTree(self):
+        """
+        Private method to refresh the dependency tree.
+        """
+        self.dependenciesList.clear()
+        venvName = self.environmentsComboBox.currentText()
+        if venvName:
+            interpreter = self.__pip.getVirtualenvInterpreter(venvName)
+            if interpreter:
+                with EricOverrideCursor():
+                    dependencies = self.__pip.getDependecyTree(
+                        venvName,
+                        localPackages=self.localDepCheckBox.isChecked(),
+                        usersite=self.userDepCheckBox.isChecked(),
+                        reverse=self.requiredByButton.isChecked(),
+                    )
+                    
+                    self.dependenciesList.setUpdatesEnabled(False)
+                    for dependency in dependencies:
+                        self.__addDependency(dependency, self.dependenciesList)
+                    
+                    self.dependenciesList.sortItems(
+                        PipPackagesWidget.DepPackageColumn,
+                        Qt.SortOrder.AscendingOrder)
+                    for col in range(self.dependenciesList.columnCount()):
+                        self.dependenciesList.resizeColumnToContents(col)
+                    self.dependenciesList.setUpdatesEnabled(True)
+        
+        self.__updateDepActionButtons()
+    
+    def __addDependency(self, dependency, parent):
+        """
+        Private method to add a dependency branch to a given parent.
+        
+        @param dependency dependency to be added
+        @type dict
+        @param parent reference to the parent item
+        @type QTreeWidget or QTreeWidgetItem
+        """
+        itm = QTreeWidgetItem(parent, [
+            dependency["package_name"],
+            dependency["installed_version"],
+            dependency["required_version"],
+        ])
+        itm.setExpanded(True)
+        
+        if dependency["required_version"].lower() != "any":
+            spec = (
+                "=={0}".format(dependency["required_version"])
+                if dependency["required_version"][0] in "0123456789" else
+                dependency["required_version"]
+            )
+            specifierSet = SpecifierSet(specifiers=spec)
+            if not specifierSet.contains(dependency["installed_version"]):
+                itm.setIcon(PipPackagesWidget.DepRequiredVersionColumn,
+                            UI.PixmapCache.getIcon("warning"))
+        
+        if dependency["required_version"].lower() == "any":
+            itm.setText(PipPackagesWidget.DepRequiredVersionColumn,
+                        self.tr("any"))
+        
+        # recursively add sub-dependencies
+        for dep in dependency["dependencies"]:
+            self.__addDependency(dep, itm)
+    
+    @pyqtSlot(QTreeWidgetItem, int)
+    def on_dependenciesList_itemActivated(self, item, column):
+        """
+        Private slot reacting on a package item of the dependency tree being
+        activated.
+        
+        @param item reference to the activated item
+        @type QTreeWidgetItem
+        @param column activated column
+        @type int
+        """
+        packageName = item.text(PipPackagesWidget.DepPackageColumn)
+        packageVersion = item.text(
+            PipPackagesWidget.DepInstalledVersionColumn)
+        
+        self.__showPackageDetails(packageName, packageVersion)
+    
+    @pyqtSlot()
+    def on_dependenciesList_itemSelectionChanged(self):
+        """
+        Private slot reacting on a change of selected items of the dependency
+        tree.
+        """
+        if len(self.dependenciesList.selectedItems()) == 0:
+            self.dependencyInfoWidget.clear()
+    
+    @pyqtSlot(QTreeWidgetItem, int)
+    def on_dependenciesList_itemPressed(self, item, column):
+        """
+        Private slot reacting on a package item of the dependency tree being
+        pressed.
+        
+        @param item reference to the pressed item
+        @type QTreeWidgetItem
+        @param column pressed column
+        @type int
+        """
+        self.dependencyInfoWidget.clear()
+        
+        if item is not None:
+            self.__showPackageInformation(
+                item.text(PipPackagesWidget.DepPackageColumn),
+                self.dependencyInfoWidget
+            )
+        
+        self.__updateDepActionButtons()
+    
+    @pyqtSlot()
+    def on_refreshDependenciesButton_clicked(self):
+        """
+        Private slot to refresh the dependency tree.
+        """
+        currentEnvironment = self.environmentsComboBox.currentText()
+        self.environmentsComboBox.clear()
+        self.dependenciesList.clear()
+        
+        with EricOverrideCursor():
+            self.__populateEnvironments()
+            
+            index = self.environmentsComboBox.findText(
+                currentEnvironment,
+                Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive
+            )
+            if index != -1:
+                self.environmentsComboBox.setCurrentIndex(index)
+        
+        self.__updateDepActionButtons()
+    
+    @pyqtSlot()
+    def on_showDepPackageDetailsButton_clicked(self):
+        """
+        Private slot to show information for the selected package of the
+        dependency tree.
+        """
+        item = self.dependenciesList.selectedItems()[0]
+        if item:
+            packageName = item.text(PipPackagesWidget.DepPackageColumn)
+            packageVersion = item.text(
+                PipPackagesWidget.DepInstalledVersionColumn)
+            
+            self.__showPackageDetails(packageName, packageVersion)
+    
+    def __updateDepActionButtons(self):
+        """
+        Private method to set the state of the dependency page action buttons.
+        """
+        self.showDepPackageDetailsButton.setEnabled(
+            len(self.dependenciesList.selectedItems()) == 1 and
+            self.__isPipAvailable()
+        )
+    
+    ##################################################################
+    ## Interface to show the licenses dialog below
+    ##################################################################
+    
+    @pyqtSlot()
+    def __showLicensesDialog(self):
+        """
+        Private slot to show a dialog with the licenses of the selected
+        environment.
+        """
+        # TODO: not yet implemented
+        from .PipLicensesDialog import PipLicensesDialog
+        
+        environment = self.environmentsComboBox.currentText()
+        localPackages = (
+            self.localDepCheckBox.isChecked()
+            if self.viewToggleButton.isChecked() else
+            self.localCheckBox.isChecked()
+        )
+        usersite = (
+            self.userDepCheckBox.isChecked()
+            if self.viewToggleButton.isChecked() else
+            self.userCheckBox.isChecked()
+        )
+        dlg = PipLicensesDialog(
+            self.__pip,
+            environment,
+            localPackages=localPackages,
+            usersite=usersite,
+            parent=self
+        )
+        dlg.exec()
--- a/eric7/PipInterface/PipPackagesWidget.ui	Fri Mar 04 18:07:10 2022 +0100
+++ b/eric7/PipInterface/PipPackagesWidget.ui	Sat Apr 02 11:23:11 2022 +0200
@@ -7,129 +7,64 @@
     <x>0</x>
     <y>0</y>
     <width>503</width>
-    <height>700</height>
+    <height>1180</height>
    </rect>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout_5">
+  <layout class="QVBoxLayout" name="verticalLayout_6">
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>3</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
    <item>
-    <widget class="QWidget" name="baseWidget" native="true">
-     <layout class="QVBoxLayout" name="verticalLayout_4">
-      <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">
-        <item>
-         <widget class="QComboBox" name="environmentsComboBox"/>
-        </item>
-        <item>
-         <widget class="EricToolButton" name="pipMenuButton"/>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QGridLayout" name="gridLayout_2">
-        <item row="0" column="0">
-         <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="1">
-         <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="0">
-         <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="QLabel" name="statusLabel"/>
-      </item>
-      <item>
-       <widget class="QSplitter" name="splitter">
-        <property name="orientation">
-         <enum>Qt::Vertical</enum>
-        </property>
-        <widget class="QTreeWidget" name="packagesList">
-         <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>
-         <attribute name="headerDefaultSectionSize">
-          <number>150</number>
-         </attribute>
-         <column>
-          <property name="text">
-           <string>Package</string>
-          </property>
-         </column>
-         <column>
-          <property name="text">
-           <string>Installed Version</string>
-          </property>
-         </column>
-         <column>
-          <property name="text">
-           <string>Available Version</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_3">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QToolButton" name="viewToggleButton">
+       <property name="toolTip">
+        <string>Toggle to show or hide the dependency tree view</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="environmentsComboBox"/>
+     </item>
+     <item>
+      <widget class="EricToolButton" name="pipMenuButton"/>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QStackedWidget" name="viewsStackWidget">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="packagesPage">
+      <layout class="QVBoxLayout" name="verticalLayout_5">
+       <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>
+        <widget class="QWidget" name="baseWidget" native="true">
+         <layout class="QVBoxLayout" name="verticalLayout_4">
           <property name="leftMargin">
            <number>0</number>
           </property>
@@ -143,40 +78,361 @@
            <number>0</number>
           </property>
           <item>
-           <layout class="QHBoxLayout" name="horizontalLayout_7">
-            <item>
-             <widget class="QCheckBox" name="verboseCheckBox">
+           <layout class="QGridLayout" name="gridLayout_2">
+            <item row="0" column="0">
+             <widget class="QCheckBox" name="localCheckBox">
               <property name="toolTip">
-               <string>Select to show verbose package information</string>
+               <string>Select to show only locally-installed packages</string>
               </property>
               <property name="text">
-               <string>Verbose Information</string>
+               <string>Local packages only</string>
+              </property>
+              <property name="checked">
+               <bool>true</bool>
               </property>
              </widget>
             </item>
-            <item>
-             <widget class="QCheckBox" name="installedFilesCheckBox">
+            <item row="0" column="1">
+             <widget class="QCheckBox" name="notRequiredCheckBox">
               <property name="toolTip">
-               <string>Select to show information about installed files</string>
+               <string>Select to list packages that are not dependencies of installed packages</string>
               </property>
               <property name="text">
-               <string>Installed Files</string>
+               <string>Not required Packages</string>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="0">
+             <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>
+            <item row="1" column="1">
+             <widget class="QCheckBox" name="vulnerabilityCheckBox">
+              <property name="toolTip">
+               <string>Perform vulnerability checks based on &quot;Safety DB&quot;.</string>
+              </property>
+              <property name="text">
+               <string>Vulnerability Check</string>
+              </property>
+              <property name="checked">
+               <bool>true</bool>
               </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>
+           <widget class="QLabel" name="statusLabel"/>
+          </item>
+          <item>
+           <widget class="QSplitter" name="splitter">
+            <property name="orientation">
+             <enum>Qt::Vertical</enum>
             </property>
+            <widget class="QTreeWidget" name="packagesList">
+             <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>
+             <attribute name="headerDefaultSectionSize">
+              <number>150</number>
+             </attribute>
+             <column>
+              <property name="text">
+               <string>Package</string>
+              </property>
+             </column>
+             <column>
+              <property name="text">
+               <string>Installed</string>
+              </property>
+             </column>
+             <column>
+              <property name="text">
+               <string>Available</string>
+              </property>
+             </column>
+             <column>
+              <property name="text">
+               <string>Affected</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_3">
+              <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_7">
+                <item>
+                 <widget class="QCheckBox" name="verboseCheckBox">
+                  <property name="toolTip">
+                   <string>Select to show verbose package information</string>
+                  </property>
+                  <property name="text">
+                   <string>Verbose 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</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>
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <item>
+             <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>
+             <widget class="QToolButton" name="refreshButton">
+              <property name="toolTip">
+               <string>Press to refresh the lists</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="upgradeButton">
+              <property name="toolTip">
+               <string>Press to upgrade the selected packages</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="upgradeAllButton">
+              <property name="toolTip">
+               <string>Press to upgrade all listed packages</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="uninstallButton">
+              <property name="toolTip">
+               <string>Press to uninstall the selected package</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="showPackageDetailsButton">
+              <property name="toolTip">
+               <string>Press to show details for the selected entry</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer_2">
+              <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>
+             <widget class="QToolButton" name="searchToggleButton">
+              <property name="toolTip">
+               <string>Toggle to show or hide the search window</string>
+              </property>
+              <property name="checkable">
+               <bool>true</bool>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QWidget" name="searchWidget" native="true">
+         <layout class="QVBoxLayout" name="verticalLayout_2">
+          <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_8">
+            <item>
+             <widget class="QLabel" name="label">
+              <property name="text">
+               <string>Package</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLineEdit" name="searchEditName">
+              <property name="toolTip">
+               <string>Enter the search term for the package name</string>
+              </property>
+              <property name="placeholderText">
+               <string>Enter search term</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="searchButton">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="toolTip">
+               <string>Press to start the search</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="searchMoreButton">
+              <property name="enabled">
+               <bool>false</bool>
+              </property>
+              <property name="toolTip">
+               <string>Press to search for more packages</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <widget class="QWidget" name="searchOptionsWidget" native="true">
+            <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>
+            </layout>
+           </widget>
+          </item>
+          <item>
+           <widget class="QTreeWidget" name="searchResultList">
             <property name="alternatingRowColors">
              <bool>true</bool>
             </property>
+            <property name="selectionMode">
+             <enum>QAbstractItemView::ExtendedSelection</enum>
+            </property>
             <property name="rootIsDecorated">
              <bool>false</bool>
             </property>
@@ -189,270 +445,278 @@
             <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>Package</string>
+             </property>
+            </column>
             <column>
              <property name="text">
-              <string notr="true">1</string>
+              <string>Version</string>
+             </property>
+            </column>
+            <column>
+             <property name="text">
+              <string>Released</string>
              </property>
             </column>
             <column>
              <property name="text">
-              <string notr="true">2</string>
+              <string>Description</string>
              </property>
             </column>
            </widget>
           </item>
+          <item>
+           <widget class="QLabel" name="searchInfoLabel"/>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_3">
+            <item>
+             <spacer name="horizontalSpacer_3">
+              <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>
+             <widget class="QToolButton" name="installButton">
+              <property name="toolTip">
+               <string>Press to install the selected package</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="installUserSiteButton">
+              <property name="toolTip">
+               <string>Press to install the selected package to the user site</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QToolButton" name="showDetailsButton">
+              <property name="toolTip">
+               <string>Press to show details for the selected entry</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer_4">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="dependenciesPage">
+      <layout class="QVBoxLayout" name="verticalLayout_8">
+       <item>
+        <widget class="QGroupBox" name="groupBox">
+         <property name="title">
+          <string>View Type</string>
+         </property>
+         <layout class="QHBoxLayout" name="horizontalLayout_5">
+          <item>
+           <widget class="QRadioButton" name="requiresButton">
+            <property name="toolTip">
+             <string>Select to show which package requires other packages</string>
+            </property>
+            <property name="text">
+             <string>Requires</string>
+            </property>
+            <property name="checked">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QRadioButton" name="requiredByButton">
+            <property name="toolTip">
+             <string>Select to show which package is required by others</string>
+            </property>
+            <property name="text">
+             <string>Required By</string>
+            </property>
+           </widget>
+          </item>
          </layout>
         </widget>
-       </widget>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_2">
-        <item>
-         <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>
-         <widget class="QToolButton" name="refreshButton">
-          <property name="toolTip">
-           <string>Press to refresh the lists</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QToolButton" name="upgradeButton">
-          <property name="toolTip">
-           <string>Press to upgrade the selected packages</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QToolButton" name="upgradeAllButton">
-          <property name="toolTip">
-           <string>Press to upgrade all listed packages</string>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <item>
+          <widget class="QCheckBox" name="localDepCheckBox">
+           <property name="toolTip">
+            <string>Select to show only dependencies of locally installed packages</string>
+           </property>
+           <property name="text">
+            <string>Local packages only</string>
+           </property>
+           <property name="checked">
+            <bool>true</bool>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="userDepCheckBox">
+           <property name="toolTip">
+            <string>Select to show only dependencies of 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_2">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <widget class="QTreeWidget" name="dependenciesList">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+            <horstretch>0</horstretch>
+            <verstretch>3</verstretch>
+           </sizepolicy>
           </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QToolButton" name="uninstallButton">
-          <property name="toolTip">
-           <string>Press to uninstall the selected package</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QToolButton" name="showPackageDetailsButton">
-          <property name="toolTip">
-           <string>Press to show details for the selected entry</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <spacer name="horizontalSpacer_2">
-          <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>
-         <widget class="QToolButton" name="searchToggleButton">
-          <property name="toolTip">
-           <string>Toggle to show or hide the search window</string>
-          </property>
-          <property name="checkable">
+          <property name="alternatingRowColors">
            <bool>true</bool>
           </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-   <item>
-    <widget class="QWidget" name="searchWidget" native="true">
-     <layout class="QVBoxLayout" name="verticalLayout_2">
-      <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="QGridLayout" name="gridLayout">
-        <item row="0" column="2" rowspan="2">
-         <widget class="QToolButton" name="searchButton">
-          <property name="enabled">
+          <property name="sortingEnabled">
+           <bool>true</bool>
+          </property>
+          <property name="expandsOnDoubleClick">
            <bool>false</bool>
           </property>
-          <property name="toolTip">
-           <string>Press to start the search</string>
-          </property>
+          <attribute name="headerDefaultSectionSize">
+           <number>150</number>
+          </attribute>
+          <column>
+           <property name="text">
+            <string>Package</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>Installed</string>
+           </property>
+          </column>
+          <column>
+           <property name="text">
+            <string>Required</string>
+           </property>
+          </column>
          </widget>
-        </item>
-        <item row="0" column="0">
-         <widget class="QLabel" name="label">
-          <property name="text">
-           <string>Package</string>
+         <widget class="QTreeWidget" name="dependencyInfoWidget">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+            <horstretch>0</horstretch>
+            <verstretch>1</verstretch>
+           </sizepolicy>
           </property>
-         </widget>
-        </item>
-        <item row="0" column="1">
-         <widget class="QLineEdit" name="searchEditName">
-          <property name="toolTip">
-           <string>Enter the search term for the package name</string>
+          <property name="alternatingRowColors">
+           <bool>true</bool>
+          </property>
+          <property name="rootIsDecorated">
+           <bool>false</bool>
+          </property>
+          <property name="itemsExpandable">
+           <bool>false</bool>
           </property>
-          <property name="placeholderText">
-           <string>Enter search term</string>
+          <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>
-      </item>
-      <item>
-       <widget class="QWidget" name="searchOptionsWidget" native="true">
-        <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>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_6">
+         <item>
+          <spacer name="horizontalSpacer_5">
+           <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>
+          <widget class="QToolButton" name="refreshDependenciesButton">
+           <property name="toolTip">
+            <string>Press to refresh the dependency tree</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QToolButton" name="showDepPackageDetailsButton">
+           <property name="toolTip">
+            <string>Press to show details for the selected entry</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_6">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
         </layout>
-       </widget>
-      </item>
-      <item>
-       <widget class="QTreeWidget" name="searchResultList">
-        <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="allColumnsShowFocus">
-         <bool>true</bool>
-        </property>
-        <property name="wordWrap">
-         <bool>true</bool>
-        </property>
-        <column>
-         <property name="text">
-          <string>Package</string>
-         </property>
-        </column>
-        <column>
-         <property name="text">
-          <string>Version</string>
-         </property>
-        </column>
-        <column>
-         <property name="text">
-          <string>Released</string>
-         </property>
-        </column>
-        <column>
-         <property name="text">
-          <string>Description</string>
-         </property>
-        </column>
-       </widget>
-      </item>
-      <item>
-       <widget class="QLabel" name="searchInfoLabel"/>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_3">
-        <item>
-         <spacer name="horizontalSpacer_3">
-          <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>
-         <widget class="QToolButton" name="installButton">
-          <property name="toolTip">
-           <string>Press to install the selected package</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QToolButton" name="installUserSiteButton">
-          <property name="toolTip">
-           <string>Press to install the selected package to the user site</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QToolButton" name="showDetailsButton">
-          <property name="toolTip">
-           <string>Press to show details for the selected entry</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <spacer name="horizontalSpacer_4">
-          <property name="orientation">
-           <enum>Qt::Horizontal</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>40</width>
-            <height>20</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-       </layout>
-      </item>
-     </layout>
+       </item>
+      </layout>
+     </widget>
     </widget>
    </item>
   </layout>
@@ -465,11 +729,13 @@
   </customwidget>
  </customwidgets>
  <tabstops>
+  <tabstop>viewToggleButton</tabstop>
   <tabstop>environmentsComboBox</tabstop>
   <tabstop>pipMenuButton</tabstop>
   <tabstop>localCheckBox</tabstop>
   <tabstop>notRequiredCheckBox</tabstop>
   <tabstop>userCheckBox</tabstop>
+  <tabstop>vulnerabilityCheckBox</tabstop>
   <tabstop>packagesList</tabstop>
   <tabstop>verboseCheckBox</tabstop>
   <tabstop>installedFilesCheckBox</tabstop>
@@ -482,10 +748,19 @@
   <tabstop>searchToggleButton</tabstop>
   <tabstop>searchEditName</tabstop>
   <tabstop>searchButton</tabstop>
+  <tabstop>searchMoreButton</tabstop>
   <tabstop>searchResultList</tabstop>
   <tabstop>installButton</tabstop>
   <tabstop>installUserSiteButton</tabstop>
   <tabstop>showDetailsButton</tabstop>
+  <tabstop>requiresButton</tabstop>
+  <tabstop>requiredByButton</tabstop>
+  <tabstop>localDepCheckBox</tabstop>
+  <tabstop>userDepCheckBox</tabstop>
+  <tabstop>dependenciesList</tabstop>
+  <tabstop>dependencyInfoWidget</tabstop>
+  <tabstop>refreshDependenciesButton</tabstop>
+  <tabstop>showDepPackageDetailsButton</tabstop>
  </tabstops>
  <resources/>
  <connections/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/PipInterface/PipVulnerabilityChecker.py	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,300 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a Python package vulnerability checker.
+
+The vulnerability data is provided by the open Python vulnerability database
+<a href="https://github.com/pyupio/safety-db">Safety DB</a>.
+"""
+
+import collections
+import contextlib
+import enum
+import json
+import os
+import time
+from dataclasses import dataclass
+
+from packaging.specifiers import SpecifierSet
+
+from PyQt6.QtCore import QCoreApplication, QObject, QThread, QUrl
+from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest
+
+from EricWidgets import EricMessageBox
+
+import Globals
+import Preferences
+
+
+@dataclass
+class Package:
+    """
+    Class containing the package data.
+    """
+    name: str               # package name
+    version: str            # version
+
+
+@dataclass
+class Vulnerability:
+    """
+    Class containing the vulnerability data.
+    """
+    name: str               # package name
+    spec: dict              # package specification record
+    version: str            # package version
+    cve: str                # CVE ID
+    advisory: str           # CVE advisory text
+    vulnerabilityId: str    # vulnerability ID
+
+
+class VulnerabilityCheckError(enum.Enum):
+    """
+    Class defining various vulnerability check error states.
+    """
+    OK = 0
+    SummaryDbUnavailable = 1
+    FullDbUnavailable = 2
+
+
+class PipVulnerabilityChecker(QObject):
+    """
+    Class implementing a Python package vulnerability checker.
+    """
+    FullDbFile = "insecure_full.json"
+    SummaryDbFile = "insecure.json"
+    
+    def __init__(self, pip, parent=None):
+        """
+        Constructor
+        
+        @param pip reference to the global pip interface
+        @type Pip
+        @param parent reference to the parent widget (defaults to None)
+        @type QWidget (optional)
+        """
+        super().__init__(parent)
+        
+        self.__pip = pip
+        
+        securityDir = os.path.join(Globals.getConfigDir(), "security")
+        os.makedirs(securityDir, mode=0o700, exist_ok=True)
+        self.__cacheFile = os.path.join(securityDir,
+                                        "vulnerability_cache.json")
+        if not os.path.exists(self.__cacheFile):
+            self.__createCacheFile()
+    
+    def __createCacheFile(self):
+        """
+        Private method to create the cache file.
+        
+        The cache file has the following structure.
+        {
+          "insecure.json": {
+              "cachedAt": 12345678
+              "db": {}
+          },
+          "insecure_full.json": {
+              "cachedAt": 12345678
+              "db": {}
+          },
+        }
+        """
+        structure = {
+            "insecure.json": {
+                "cachedAt": 0,
+                "db": {},
+            },
+            "insecure_full.json": {
+                "cachedAt": 0,
+                "db": {},
+            },
+        }
+        with open(self.__cacheFile, "w") as f:
+            json.dump(structure, f, indent=2)
+    
+    def __getDataFromCache(self, dbName):
+        """
+        Private method to get the vulnerability database from the cache.
+        
+        @param dbName name of the vulnerability database
+        @type str
+        @return dictionary containing the requested vulnerability data
+        @rtype dict
+        """
+        if os.path.exists(self.__cacheFile):
+            with open(self.__cacheFile, "r") as f:  # __IGNORE_WARNING_Y117__
+                with contextlib.suppress(json.JSONDecodeError, OSError):
+                    cachedData = json.load(f)
+                    if (
+                        dbName in cachedData and
+                        "cachedAt" in cachedData[dbName]
+                    ):
+                        cacheValidPeriod = Preferences.getPip(
+                            "VulnerabilityDbCacheValidity")
+                        if (
+                            cachedData[dbName]["cachedAt"] + cacheValidPeriod >
+                            time.time()
+                        ):
+                            return cachedData[dbName]["db"]
+        
+        return {}
+    
+    def __writeDataToCache(self, dbName, data):
+        """
+        Private method to write the vulnerability data for a database to the
+        cache.
+        
+        @param dbName name of the vulnerability database
+        @type str
+        @param data dictionary containing the vulnerability data
+        @type dict
+        """
+        if not os.path.exists(self.__cacheFile):
+            self.__createCacheFile()
+        
+        with open(self.__cacheFile, "r") as f:
+            try:
+                cache = json.load(f)
+            except json.JSONDecodeError:
+                cache = {}
+        
+        cache[dbName] = {
+            "cachedAt": time.time(),
+            "db": data,
+        }
+        with open(self.__cacheFile, "w") as f:
+            json.dump(cache, f, indent=2)
+    
+    def __fetchVulnerabilityDatabase(self, full=False, forceUpdate=False):
+        """
+        Private method to get the data of the vulnerability database.
+        
+        If the cached data is still valid, this data will be used.
+        Otherwise a copy of the requested database will be downloaded
+        and cached.
+        
+        @param full flag indicating to get the database containing the full
+            data set (defaults to False)
+        @type bool (optional)
+        @param forceUpdate flag indicating an update of the cache is required
+            (defaults to False)
+        @type bool (optional)
+        @return dictionary containing the vulnerability data (full data set or
+            just package name and version specifier)
+        """
+        dbName = (
+            PipVulnerabilityChecker.FullDbFile
+            if full else
+            PipVulnerabilityChecker.SummaryDbFile
+        )
+        
+        if not forceUpdate:
+            cachedData = self.__getDataFromCache(dbName)
+            if cachedData:
+                return cachedData
+        
+        url = Preferences.getPip("VulnerabilityDbMirror") + dbName
+        request = QNetworkRequest(QUrl(url))
+        reply = self.__pip.getNetworkAccessManager().get(request)
+        while not reply.isFinished():
+            QCoreApplication.processEvents()
+            QThread.msleep(100)
+        
+        reply.deleteLater()
+        if reply.error() == QNetworkReply.NetworkError.NoError:
+            data = str(reply.readAll(),
+                       Preferences.getSystem("IOEncoding"),
+                       'replace')
+            with contextlib.suppress(json.JSONDecodeError):
+                data = json.loads(data)
+                self.__writeDataToCache(dbName, data)
+                return data
+        
+        EricMessageBox.critical(
+            None,
+            self.tr("Fetching Vulnerability Database"),
+            self.tr("""<p>The vulnerability database <b>{0}</b> could not"""
+                    """ be loaded from <b>{1}</b>.</p><p>The vulnerability"""
+                    """ check is not available.</p>""")
+        )
+        return {}
+    
+    def __getVulnerabilities(self, package, specifier, db):
+        """
+        Private method to get the vulnerabilities for a package.
+        
+        @param package name of the package
+        @type str
+        @param specifier package specifier
+        @type Specifier
+        @param db vulnerability data
+        @type dict
+        @yield dictionary containing the vulnerability data for the package
+        @ytype dict
+        """
+        for entry in db[package]:
+            for entrySpec in entry["specs"]:
+                if entrySpec == specifier:
+                    yield entry
+    
+    def check(self, packages):
+        """
+        Public method to check the given packages for vulnerabilities.
+        
+        @param packages list of packages
+        @type Package
+        @return tuple containing an error status and a dictionary containing
+            detected vulnerable packages keyed by package name
+        @rtype tuple of (VulnerabilityCheckError, list of Vulnerability)
+        """
+        db = self.__fetchVulnerabilityDatabase()
+        if not db:
+            return VulnerabilityCheckError.SummaryDbUnavailable, []
+        
+        fullDb = None
+        vulnerablePackages = frozenset(db.keys())
+        vulnerabilities = collections.defaultdict(list)
+        
+        for package in packages:
+            # normalize the package name, the safety-db is converting
+            # underscores to dashes and uses lowercase
+            name = package.name.replace("_", "-").lower()
+        
+            if name in vulnerablePackages:
+                # we have a candidate here, build the spec set
+                for specifier in db[name]:
+                    specifierSet = SpecifierSet(specifiers=specifier)
+                    if specifierSet.contains(package.version):
+                        if not fullDb:
+                            fullDb = self.__fetchVulnerabilityDatabase(
+                                full=True)
+                        for data in self.__getVulnerabilities(
+                            package=name, specifier=specifier, db=fullDb
+                        ):
+                            vulnarabilityId = (
+                                data.get("id").replace("pyup.io-", "")
+                            )
+                            cveId = data.get("cve", "")
+                            if cveId:
+                                cveId = cveId.split(",", 1)[0].strip()
+                            vulnerabilities[package.name].append(Vulnerability(
+                                name=name,
+                                spec=specifier,
+                                version=package.version,
+                                cve=cveId,
+                                advisory=data.get("advisory", ""),
+                                vulnerabilityId=vulnarabilityId
+                            ))
+        
+        return VulnerabilityCheckError.OK, vulnerabilities
+    
+    def updateVulnerabilityDb(self):
+        """
+        Public method to update the cache of the vulnerability databases.
+        """
+        self.__fetchVulnerabilityDatabase(full=False, forceUpdate=True)
+        self.__fetchVulnerabilityDatabase(full=True, forceUpdate=True)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/PipInterface/piplicenses.py	Sat Apr 02 11:23:11 2022 +0200
@@ -0,0 +1,664 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim:fenc=utf-8 ff=unix ft=python ts=4 sw=4 sts=4 si et
+"""
+pip-licenses
+
+MIT License
+
+Copyright (c) 2018 raimon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+"""
+
+#
+# Modified to be used within the eric-ide project.
+#
+# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+import argparse
+import codecs
+import glob
+import json
+import os
+import sys
+from collections import Counter
+from email import message_from_string
+from email.parser import FeedParser
+from enum import Enum, auto
+from typing import List, Optional, Sequence, Text
+
+
+def get_installed_distributions(local_only=True, user_only=False):
+    try:
+        from pip._internal.metadata import get_environment
+    except ImportError:
+        # For backward compatibility with pip version 20.3.4
+        from pip._internal.utils import misc
+        return misc.get_installed_distributions(
+            local_only=local_only,
+            user_only=user_only
+        )
+    else:
+        from pip._internal.utils.compat import stdlib_pkgs
+        dists = get_environment(None).iter_installed_distributions(
+            local_only=local_only,
+            user_only=user_only,
+            skip=stdlib_pkgs,
+            include_editables=True,
+            editables_only=False,
+        )
+        return [d._dist for d in dists]
+
+
+__pkgname__ = 'pip-licenses'
+__version__ = '3.5.3'
+__author__ = 'raimon'
+__license__ = 'MIT'
+__summary__ = ('Dump the software license list of '
+               'Python packages installed with pip.')
+__url__ = 'https://github.com/raimon49/pip-licenses'
+
+
+FIELD_NAMES = (
+    'Name',
+    'Version',
+    'License',
+    'LicenseFile',
+    'LicenseText',
+    'NoticeFile',
+    'NoticeText',
+    'Author',
+    'Description',
+    'URL',
+)
+
+
+DEFAULT_OUTPUT_FIELDS = (
+    'Name',
+    'Version',
+)
+
+
+SUMMARY_OUTPUT_FIELDS = (
+    'Count',
+    'License',
+)
+
+
+METADATA_KEYS = (
+    'home-page',
+    'author',
+    'license',
+    'summary',
+    'license_classifier',
+)
+
+# Mapping of FIELD_NAMES to METADATA_KEYS where they differ by more than case
+FIELDS_TO_METADATA_KEYS = {
+    'URL': 'home-page',
+    'Description': 'summary',
+    'License-Metadata': 'license',
+    'License-Classifier': 'license_classifier',
+}
+
+
+SYSTEM_PACKAGES = (
+    __pkgname__,
+    'pip',
+    'setuptools',
+    'wheel',
+)
+
+LICENSE_UNKNOWN = 'UNKNOWN'
+
+
+def get_packages(args: "CustomNamespace"):
+
+    def get_pkg_included_file(pkg, file_names):
+        """
+        Attempt to find the package's included file on disk and return the
+        tuple (included_file_path, included_file_contents).
+        """
+        included_file = LICENSE_UNKNOWN
+        included_text = LICENSE_UNKNOWN
+        pkg_dirname = "{}-{}.dist-info".format(
+            pkg.project_name.replace("-", "_"), pkg.version)
+        patterns = []
+        [patterns.extend(sorted(glob.glob(os.path.join(pkg.location,
+                                                       pkg_dirname,
+                                                       f))))
+         for f in file_names]
+        for test_file in patterns:
+            if os.path.exists(test_file):
+                included_file = test_file
+                with open(test_file, encoding='utf-8',
+                          errors='backslashreplace') as included_file_handle:
+                    included_text = included_file_handle.read()
+                break
+        return (included_file, included_text)
+
+    def get_pkg_info(pkg):
+        (license_file, license_text) = get_pkg_included_file(
+            pkg,
+            ('LICENSE*', 'LICENCE*', 'COPYING*')
+        )
+        (notice_file, notice_text) = get_pkg_included_file(
+            pkg,
+            ('NOTICE*',)
+        )
+        pkg_info = {
+            'name': pkg.project_name,
+            'version': pkg.version,
+            'namever': str(pkg),
+            'licensefile': license_file,
+            'licensetext': license_text,
+            'noticefile': notice_file,
+            'noticetext': notice_text,
+        }
+        metadata = None
+        if pkg.has_metadata('METADATA'):
+            metadata = pkg.get_metadata('METADATA')
+
+        if pkg.has_metadata('PKG-INFO') and metadata is None:
+            metadata = pkg.get_metadata('PKG-INFO')
+
+        if metadata is None:
+            for key in METADATA_KEYS:
+                pkg_info[key] = LICENSE_UNKNOWN
+
+            return pkg_info
+
+        feed_parser = FeedParser()
+        feed_parser.feed(metadata)
+        parsed_metadata = feed_parser.close()
+
+        for key in METADATA_KEYS:
+            pkg_info[key] = parsed_metadata.get(key, LICENSE_UNKNOWN)
+
+        if metadata is not None:
+            message = message_from_string(metadata)
+            pkg_info['license_classifier'] = \
+                find_license_from_classifier(message)
+
+        if args.filter_strings:
+            for k in pkg_info:
+                if isinstance(pkg_info[k], list):
+                    for i, item in enumerate(pkg_info[k]):
+                        pkg_info[k][i] = item. \
+                            encode(args.filter_code_page, errors="ignore"). \
+                            decode(args.filter_code_page)
+                else:
+                    pkg_info[k] = pkg_info[k]. \
+                        encode(args.filter_code_page, errors="ignore"). \
+                        decode(args.filter_code_page)
+
+        return pkg_info
+
+    pkgs = get_installed_distributions(
+        local_only=args.local_only,
+        user_only=args.user_only,
+    )
+    ignore_pkgs_as_lower = [pkg.lower() for pkg in args.ignore_packages]
+    pkgs_as_lower = [pkg.lower() for pkg in args.packages]
+
+    fail_on_licenses = set()
+    if args.fail_on:
+        fail_on_licenses = set(map(str.strip, args.fail_on.split(";")))
+
+    allow_only_licenses = set()
+    if args.allow_only:
+        allow_only_licenses = set(map(str.strip, args.allow_only.split(";")))
+
+    for pkg in pkgs:
+        pkg_name = pkg.project_name
+
+        if pkg_name.lower() in ignore_pkgs_as_lower:
+            continue
+
+        if pkgs_as_lower and pkg_name.lower() not in pkgs_as_lower:
+            continue
+
+        if not args.with_system and pkg_name in SYSTEM_PACKAGES:
+            continue
+
+        pkg_info = get_pkg_info(pkg)
+
+        license_names = select_license_by_source(
+            args.from_,
+            pkg_info['license_classifier'],
+            pkg_info['license'])
+
+        if fail_on_licenses:
+            failed_licenses = license_names.intersection(fail_on_licenses)
+            if failed_licenses:
+                sys.stderr.write(
+                    "fail-on license {} was found for package "
+                    "{}:{}".format(
+                        '; '.join(sorted(failed_licenses)),
+                        pkg_info['name'],
+                        pkg_info['version'])
+                )
+                sys.exit(1)
+
+        if allow_only_licenses:
+            uncommon_licenses = license_names.difference(allow_only_licenses)
+            if len(uncommon_licenses) == len(license_names):
+                sys.stderr.write(
+                    "license {} not in allow-only licenses was found"
+                    " for package {}:{}".format(
+                        '; '.join(sorted(uncommon_licenses)),
+                        pkg_info['name'],
+                        pkg_info['version'])
+                )
+                sys.exit(1)
+
+        yield pkg_info
+
+
+def create_licenses_list(
+        args: "CustomNamespace", output_fields=DEFAULT_OUTPUT_FIELDS):
+    
+    licenses = []
+    for pkg in get_packages(args):
+        row = {}
+        for field in output_fields:
+            if field == 'License':
+                license_set = select_license_by_source(
+                    args.from_, pkg['license_classifier'], pkg['license'])
+                license_str = '; '.join(sorted(license_set))
+                row[field] = license_str
+            elif field == 'License-Classifier':
+                row[field] = ('; '.join(sorted(pkg['license_classifier']))
+                           or LICENSE_UNKNOWN)
+            elif field.lower() in pkg:
+                row[field] = pkg[field.lower()]
+            else:
+                row[field] = pkg[FIELDS_TO_METADATA_KEYS[field]]
+        licenses.append(row)
+
+    return licenses
+
+
+def create_summary_list(args: "CustomNamespace"):
+    counts = Counter(
+        '; '.join(sorted(select_license_by_source(
+            args.from_, pkg['license_classifier'], pkg['license'])))
+        for pkg in get_packages(args))
+
+    licenses = []
+    for license, count in counts.items():
+        licenses.append({
+            "Count": count,
+            "License": license,
+        })
+    
+    return licenses
+
+
+def find_license_from_classifier(message):
+    licenses = []
+    for k, v in message.items():
+        if k == 'Classifier' and v.startswith('License'):
+            license = v.split(' :: ')[-1]
+
+            # Through the declaration of 'Classifier: License :: OSI Approved'
+            if license != 'OSI Approved':
+                licenses.append(license)
+
+    return licenses
+
+
+def select_license_by_source(from_source, license_classifier, license_meta):
+    license_classifier_set = set(license_classifier) or {LICENSE_UNKNOWN}
+    if (from_source == FromArg.CLASSIFIER or
+            from_source == FromArg.MIXED and len(license_classifier) > 0):
+        return license_classifier_set
+    else:
+        return {license_meta}
+
+
+def get_output_fields(args: "CustomNamespace"):
+    if args.summary:
+        return list(SUMMARY_OUTPUT_FIELDS)
+
+    output_fields = list(DEFAULT_OUTPUT_FIELDS)
+
+    if args.from_ == FromArg.ALL:
+        output_fields.append('License-Metadata')
+        output_fields.append('License-Classifier')
+    else:
+        output_fields.append('License')
+
+    if args.with_authors:
+        output_fields.append('Author')
+
+    if args.with_urls:
+        output_fields.append('URL')
+
+    if args.with_description:
+        output_fields.append('Description')
+
+    if args.with_license_file:
+        if not args.no_license_path:
+            output_fields.append('LicenseFile')
+
+        output_fields.append('LicenseText')
+
+        if args.with_notice_file:
+            output_fields.append('NoticeText')
+            if not args.no_license_path:
+                output_fields.append('NoticeFile')
+
+    return output_fields
+
+
+def create_output_string(args: "CustomNamespace"):
+    output_fields = get_output_fields(args)
+
+    if args.summary:
+        licenses = create_summary_list(args)
+    else:
+        licenses = create_licenses_list(args, output_fields)
+    
+    return json.dumps(licenses)
+
+
+class CustomHelpFormatter(argparse.HelpFormatter):  # pragma: no cover
+    def __init__(
+        self, prog: Text, indent_increment: int = 2,
+        max_help_position: int = 24, width: Optional[int] = None
+    ) -> None:
+        max_help_position = 30
+        super().__init__(
+            prog, indent_increment=indent_increment,
+            max_help_position=max_help_position, width=width)
+
+    def _format_action(self, action: argparse.Action) -> str:
+        flag_indent_argument: bool = False
+        text = self._expand_help(action)
+        separator_pos = text[:3].find('|')
+        if separator_pos != -1 and 'I' in text[:separator_pos]:
+            self._indent()
+            flag_indent_argument = True
+        help_str = super()._format_action(action)
+        if flag_indent_argument:
+            self._dedent()
+        return help_str
+
+    def _expand_help(self, action: argparse.Action) -> str:
+        if isinstance(action.default, Enum):
+            default_value = enum_key_to_value(action.default)
+            return self._get_help_string(action) % {'default': default_value}
+        return super()._expand_help(action)
+
+    def _split_lines(self, text: Text, width: int) -> List[str]:
+        separator_pos = text[:3].find('|')
+        if separator_pos != -1:
+            flag_splitlines: bool = 'R' in text[:separator_pos]
+            text = text[separator_pos + 1:]
+            if flag_splitlines:
+                return text.splitlines()
+        return super()._split_lines(text, width)
+
+
+class CustomNamespace(argparse.Namespace):
+    from_: "FromArg"
+    order: "OrderArg"
+    summary: bool
+    local_only: bool
+    user_only:bool
+    output_file: str
+    ignore_packages: List[str]
+    packages: List[str]
+    with_system: bool
+    with_authors: bool
+    with_urls: bool
+    with_description: bool
+    with_license_file: bool
+    no_license_path: bool
+    with_notice_file: bool
+    filter_strings: bool
+    filter_code_page: str
+    fail_on: Optional[str]
+    allow_only: Optional[str]
+
+
+class CompatibleArgumentParser(argparse.ArgumentParser):
+    def parse_args(self, args: Optional[Sequence[Text]] = None,
+                   namespace: CustomNamespace = None) -> CustomNamespace:
+        args = super().parse_args(args, namespace)
+        self._verify_args(args)
+        return args
+
+    def _verify_args(self, args: CustomNamespace):
+        if args.with_license_file is False and (
+                args.no_license_path is True or
+                args.with_notice_file is True):
+            self.error(
+                "'--no-license-path' and '--with-notice-file' require "
+                "the '--with-license-file' option to be set")
+        if args.filter_strings is False and \
+                args.filter_code_page != 'latin1':
+            self.error(
+                "'--filter-code-page' requires the '--filter-strings' "
+                "option to be set")
+        try:
+            codecs.lookup(args.filter_code_page)
+        except LookupError:
+            self.error(
+                "invalid code page '%s' given for '--filter-code-page, "
+                "check https://docs.python.org/3/library/codecs.html"
+                "#standard-encodings for valid code pages"
+                % args.filter_code_page)
+
+
+class NoValueEnum(Enum):
+    def __repr__(self):  # pragma: no cover
+        return '<%s.%s>' % (self.__class__.__name__, self.name)
+
+
+class FromArg(NoValueEnum):
+    META = M = auto()
+    CLASSIFIER = C = auto()
+    MIXED = MIX = auto()
+    ALL = auto()
+
+
+class OrderArg(NoValueEnum):
+    COUNT = C = auto()
+    LICENSE = L = auto()
+    NAME = N = auto()
+    AUTHOR = A = auto()
+    URL = U = auto()
+
+
+def value_to_enum_key(value: str) -> str:
+    return value.replace('-', '_').upper()
+
+
+def enum_key_to_value(enum_key: Enum) -> str:
+    return enum_key.name.replace('_', '-').lower()
+
+
+def choices_from_enum(enum_cls: NoValueEnum) -> List[str]:
+    return [key.replace('_', '-').lower()