Sat, 02 Apr 2022 11:23:11 +0200
Merged with branch 'eric7' to prepare a new release.
--- 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):
--- 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 "Safety DB".</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()