439 self.statusLabel.show() |
441 self.statusLabel.show() |
440 self.statusLabel.setText(self.tr("Getting installed packages...")) |
442 self.statusLabel.setText(self.tr("Getting installed packages...")) |
441 |
443 |
442 with EricOverrideCursor(): |
444 with EricOverrideCursor(): |
443 # 1. populate with installed packages |
445 # 1. populate with installed packages |
444 self.packagesList.setUpdatesEnabled(False) |
|
445 installedPackages = self.__pip.getInstalledPackages( |
446 installedPackages = self.__pip.getInstalledPackages( |
446 venvName, |
447 venvName, |
447 localPackages=self.localCheckBox.isChecked(), |
448 localPackages=self.localCheckBox.isChecked(), |
448 notRequired=self.notRequiredCheckBox.isChecked(), |
449 notRequired=self.notRequiredCheckBox.isChecked(), |
449 usersite=self.userCheckBox.isChecked(), |
450 usersite=self.userCheckBox.isChecked(), |
450 ) |
451 ) |
451 for package, version in installedPackages: |
452 for package, version in installedPackages: |
452 QTreeWidgetItem(self.packagesList, [package, version, "", ""]) |
453 QTreeWidgetItem(self.packagesList, [package, version, "", ""]) |
453 self.packagesList.setUpdatesEnabled(True) |
454 self.packagesList.sortItems( |
|
455 PipPackagesWidget.PackageColumn, Qt.SortOrder.AscendingOrder |
|
456 ) |
|
457 self.packagesList.resizeColumnToContents( |
|
458 PipPackagesWidget.PackageColumn |
|
459 ) |
|
460 self.packagesList.resizeColumnToContents( |
|
461 PipPackagesWidget.InstalledVersionColumn |
|
462 ) |
|
463 QApplication.processEvents() |
|
464 |
|
465 # 2. update with vulnerability information |
|
466 if self.vulnerabilityCheckBox.isChecked(): |
|
467 self.__updateVulnerabilityData() |
|
468 self.packagesList.resizeColumnToContents( |
|
469 PipPackagesWidget.VulnerabilityColumn |
|
470 ) |
454 self.statusLabel.setText(self.tr("Getting outdated packages...")) |
471 self.statusLabel.setText(self.tr("Getting outdated packages...")) |
455 QApplication.processEvents() |
472 QApplication.processEvents() |
456 |
473 |
457 # 2. update with update information |
474 # 3. update with update information |
458 self.packagesList.setUpdatesEnabled(False) |
475 self.__pip.getOutdatedPackages( |
459 outdatedPackages = self.__pip.getOutdatedPackages( |
|
460 venvName, |
476 venvName, |
461 localPackages=self.localCheckBox.isChecked(), |
477 localPackages=self.localCheckBox.isChecked(), |
462 notRequired=self.notRequiredCheckBox.isChecked(), |
478 notRequired=self.notRequiredCheckBox.isChecked(), |
463 usersite=self.userCheckBox.isChecked(), |
479 usersite=self.userCheckBox.isChecked(), |
|
480 callback=self.__updateOutdatedInfo, |
464 ) |
481 ) |
465 for package, _version, latest in outdatedPackages: |
482 |
466 items = self.packagesList.findItems( |
483 else: |
467 package, |
484 self.__updateActionButtons() |
468 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive, |
485 self.__updateSearchActionButtons() |
469 ) |
486 self.__updateSearchButton() |
470 if items: |
487 self.__updateSearchMoreButton(False) |
471 itm = items[0] |
488 |
472 itm.setText( |
489 def __updateOutdatedInfo(self, outdatedPackages): |
473 PipPackagesWidget.AvailableVersionColumn, latest |
490 """ |
474 ) |
491 Private method to process the list of outdated packages. |
475 |
492 |
476 self.packagesList.sortItems( |
493 @param outdatedPackages list of tuples containing the package name, |
477 PipPackagesWidget.PackageColumn, Qt.SortOrder.AscendingOrder |
494 installed version and available version |
478 ) |
495 @type list of tuple of (str, str, str) |
479 for col in range(self.packagesList.columnCount()): |
496 """ |
480 self.packagesList.resizeColumnToContents(col) |
497 for package, _version, latest in outdatedPackages: |
481 self.packagesList.setUpdatesEnabled(True) |
498 items = self.packagesList.findItems( |
482 |
499 package, |
483 # 3. update with vulnerability information |
500 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive, |
484 if self.vulnerabilityCheckBox.isChecked(): |
501 ) |
485 self.__updateVulnerabilityData() |
502 if items: |
486 self.statusLabel.hide() |
503 items[0].setText(PipPackagesWidget.AvailableVersionColumn, latest) |
|
504 self.packagesList.resizeColumnToContents( |
|
505 PipPackagesWidget.AvailableVersionColumn |
|
506 ) |
|
507 self.statusLabel.hide() |
487 |
508 |
488 self.__updateActionButtons() |
509 self.__updateActionButtons() |
489 self.__updateSearchActionButtons() |
510 self.__updateSearchActionButtons() |
490 self.__updateSearchButton() |
511 self.__updateSearchButton() |
491 self.__updateSearchMoreButton(False) |
512 self.__updateSearchMoreButton(False) |
1314 self.__pipMenu.addSeparator() |
1337 self.__pipMenu.addSeparator() |
1315 self.__checkVulnerabilityAct = self.__pipMenu.addAction( |
1338 self.__checkVulnerabilityAct = self.__pipMenu.addAction( |
1316 self.tr("Check Vulnerabilities"), self.__checkVulnerability |
1339 self.tr("Check Vulnerabilities"), self.__checkVulnerability |
1317 ) |
1340 ) |
1318 # updateVulnerabilityDbAct |
1341 # updateVulnerabilityDbAct |
1319 self.__pipMenu.addAction( |
1342 self.__updateVulnerabilitiesAct = self.__pipMenu.addAction( |
1320 self.tr("Update Vulnerability Database"), self.__updateVulnerabilityDbCache |
1343 self.tr("Update Vulnerability Database"), self.__updateVulnerabilityDbCache |
1321 ) |
1344 ) |
1322 self.__pipMenu.addSeparator() |
1345 self.__pipMenu.addSeparator() |
1323 self.__cyclonedxAct = self.__pipMenu.addAction( |
1346 self.__cyclonedxAct = self.__pipMenu.addAction( |
1324 self.tr("Create SBOM file"), self.__createSBOMFile |
1347 self.tr("Create SBOM file"), self.__createSBOMFile |
1629 ################################################################## |
1658 ################################################################## |
1630 ## Interface to the vulnerability checks below |
1659 ## Interface to the vulnerability checks below |
1631 ################################################################## |
1660 ################################################################## |
1632 |
1661 |
1633 @pyqtSlot(bool) |
1662 @pyqtSlot(bool) |
|
1663 def setVulnerabilityEnabled(self, enable): |
|
1664 """ |
|
1665 Public slot to set the enabled state of the vulnerability checks. |
|
1666 |
|
1667 @param enable vulnerability checks enabled state |
|
1668 @type bool |
|
1669 """ |
|
1670 self.vulnerabilityCheckBox.setChecked(enable) |
|
1671 self.vulnerabilityCheckBox.setEnabled(enable) |
|
1672 self.packagesList.setColumnHidden( |
|
1673 PipPackagesWidget.VulnerabilityColumn, not enable |
|
1674 ) |
|
1675 if not enable: |
|
1676 self.__clearVulnerabilityInfo() |
|
1677 |
|
1678 @pyqtSlot(bool) |
1634 def on_vulnerabilityCheckBox_clicked(self, checked): |
1679 def on_vulnerabilityCheckBox_clicked(self, checked): |
1635 """ |
1680 """ |
1636 Private slot handling a change of the automatic vulnerability checks. |
1681 Private slot handling a change of the automatic vulnerability checks. |
1637 |
1682 |
1638 @param checked flag indicating the state of the check box |
1683 @param checked flag indicating the state of the check box |
1639 @type bool |
1684 @type bool |
1640 """ |
1685 """ |
1641 if checked: |
1686 if checked: |
1642 self.__updateVulnerabilityData(clearFirst=True) |
1687 self.__updateVulnerabilityData(clearFirst=True) |
|
1688 else: |
|
1689 self.__clearVulnerabilityInfo() |
1643 |
1690 |
1644 self.packagesList.header().setSectionHidden( |
1691 self.packagesList.header().setSectionHidden( |
1645 PipPackagesWidget.VulnerabilityColumn, not checked |
1692 PipPackagesWidget.VulnerabilityColumn, not checked |
1646 ) |
1693 ) |
1647 |
1694 |
1689 name=itm.text(PipPackagesWidget.PackageColumn), |
1736 name=itm.text(PipPackagesWidget.PackageColumn), |
1690 version=itm.text(PipPackagesWidget.InstalledVersionColumn), |
1737 version=itm.text(PipPackagesWidget.InstalledVersionColumn), |
1691 ) |
1738 ) |
1692 ) |
1739 ) |
1693 |
1740 |
1694 error, vulnerabilities = self.__pip.getVulnerabilityChecker().check(packages) |
1741 if packages: |
1695 if error == VulnerabilityCheckError.OK: |
1742 error, vulnerabilities = self.__pip.getVulnerabilityChecker().check( |
1696 for package in vulnerabilities: |
1743 packages |
1697 items = self.packagesList.findItems( |
1744 ) |
1698 package, Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive |
1745 if error == VulnerabilityCheckError.OK: |
1699 ) |
1746 for package in vulnerabilities: |
1700 if items: |
1747 items = self.packagesList.findItems( |
1701 itm = items[0] |
1748 package, |
1702 itm.setData( |
1749 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive, |
1703 PipPackagesWidget.VulnerabilityColumn, |
|
1704 PipPackagesWidget.VulnerabilityRole, |
|
1705 vulnerabilities[package], |
|
1706 ) |
1750 ) |
1707 affected = {v.spec for v in vulnerabilities[package]} |
1751 if items: |
1708 itm.setText( |
1752 itm = items[0] |
1709 PipPackagesWidget.VulnerabilityColumn, ", ".join(affected) |
1753 itm.setData( |
1710 ) |
1754 PipPackagesWidget.VulnerabilityColumn, |
1711 itm.setIcon( |
1755 PipPackagesWidget.VulnerabilityRole, |
1712 PipPackagesWidget.VulnerabilityColumn, |
1756 vulnerabilities[package], |
1713 EricPixmapCache.getIcon("securityLow"), |
1757 ) |
1714 ) |
1758 affected = {v.spec for v in vulnerabilities[package]} |
1715 |
1759 itm.setText( |
1716 elif error in ( |
1760 PipPackagesWidget.VulnerabilityColumn, ", ".join(affected) |
1717 VulnerabilityCheckError.FullDbUnavailable, |
1761 ) |
1718 VulnerabilityCheckError.SummaryDbUnavailable, |
1762 itm.setIcon( |
1719 ): |
1763 PipPackagesWidget.VulnerabilityColumn, |
1720 self.vulnerabilityCheckBox.setChecked(False) |
1764 EricPixmapCache.getIcon("securityLow"), |
1721 self.vulnerabilityCheckBox.setEnabled(False) |
1765 ) |
1722 self.packagesList.setColumnHidden( |
1766 |
1723 PipPackagesWidget.VulnerabilityColumn, True |
1767 elif error in ( |
1724 ) |
1768 VulnerabilityCheckError.FullDbUnavailable, |
|
1769 VulnerabilityCheckError.SummaryDbUnavailable, |
|
1770 ): |
|
1771 self.setVulnerabilityEnabled(False) |
1725 |
1772 |
1726 @pyqtSlot() |
1773 @pyqtSlot() |
1727 def __updateVulnerabilityDbCache(self): |
1774 def __updateVulnerabilityDbCache(self): |
1728 """ |
1775 """ |
1729 Private slot to initiate an update of the local cache of the |
1776 Private slot to initiate an update of the local cache of the |