src/eric7/PipInterface/PipPackagesWidget.py

branch
eric7-maintenance
changeset 10222
1146cc8fbf5d
parent 10148
31ba20629af4
parent 10210
7d0e5ca7eb3e
child 10460
3b34efa2857c
equal deleted inserted replaced
10182:dce4b2b95c3f 10222:1146cc8fbf5d
272 self.__replies = [] 272 self.__replies = []
273 273
274 self.viewsStackWidget.setCurrentWidget(self.packagesPage) 274 self.viewsStackWidget.setCurrentWidget(self.packagesPage)
275 self.on_packagesList_currentItemChanged(None, None) 275 self.on_packagesList_currentItemChanged(None, None)
276 276
277 self.preferencesChanged() # perform preferences dependent configuration
278
277 @pyqtSlot() 279 @pyqtSlot()
278 def __projectOpened(self): 280 def __projectOpened(self):
279 """ 281 """
280 Private slot to handle the projectOpened signal. 282 Private slot to handle the projectOpened signal.
281 """ 283 """
290 292
291 @param shutdown flag indicating the IDE shutdown 293 @param shutdown flag indicating the IDE shutdown
292 @type bool 294 @type bool
293 """ 295 """
294 if not shutdown: 296 if not shutdown:
297 # the project entry is always at index 1
295 if self.environmentsComboBox.currentIndex() == 1: 298 if self.environmentsComboBox.currentIndex() == 1:
296 self.environmentsComboBox.setCurrentIndex(0) 299 self.environmentsComboBox.setCurrentIndex(0)
297 300
298 # the project entry is always at index 1
299 self.environmentsComboBox.removeItem(1) 301 self.environmentsComboBox.removeItem(1)
300 302
301 def __populateEnvironments(self): 303 def __populateEnvironments(self):
302 """ 304 """
303 Private method to get a list of environments and populate the selector. 305 Private method to get a list of environments and populate the selector.
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)
608 if len(self.packagesList.selectedItems()) == 0: 629 if len(self.packagesList.selectedItems()) == 0:
609 self.packageInfoWidget.clear() 630 self.packageInfoWidget.clear()
610 self.vulnerabilitiesInfoWidget.clear() 631 self.vulnerabilitiesInfoWidget.clear()
611 self.infoWidget.tabBar().hide() 632 self.infoWidget.tabBar().hide()
612 633
634 self.__updateActionButtons()
635
613 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) 636 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
614 def on_packagesList_currentItemChanged(self, curr, prev): 637 def on_packagesList_currentItemChanged(self, curr, prev):
615 """ 638 """
616 Private slot to handle a change of the current item. 639 Private slot to handle a change of the current item.
617 640
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
1362 self.__cacheSubmenuAct.setEnabled(enablePipCache) 1385 self.__cacheSubmenuAct.setEnabled(enablePipCache)
1363 1386
1364 self.__editVirtualenvConfigAct.setEnabled(enable) 1387 self.__editVirtualenvConfigAct.setEnabled(enable)
1365 1388
1366 self.__checkVulnerabilityAct.setEnabled( 1389 self.__checkVulnerabilityAct.setEnabled(
1367 enable & self.vulnerabilityCheckBox.isEnabled() 1390 enable
1391 and self.vulnerabilityCheckBox.isEnabled()
1392 and Preferences.getPip("VulnerabilityCheckEnabled")
1393 )
1394 self.__updateVulnerabilitiesAct.setEnabled(
1395 enable and Preferences.getPip("VulnerabilityCheckEnabled")
1368 ) 1396 )
1369 1397
1370 self.__cyclonedxAct.setEnabled(enable) 1398 self.__cyclonedxAct.setEnabled(enable)
1371 1399
1372 self.__showLicensesDialogAct.setEnabled(enable) 1400 self.__showLicensesDialogAct.setEnabled(enable)
1587 dlg.showConfigurationPageByName("pipPage") 1615 dlg.showConfigurationPageByName("pipPage")
1588 dlg.exec() 1616 dlg.exec()
1589 if dlg.result() == QDialog.DialogCode.Accepted: 1617 if dlg.result() == QDialog.DialogCode.Accepted:
1590 dlg.setPreferences() 1618 dlg.setPreferences()
1591 Preferences.syncPreferences() 1619 Preferences.syncPreferences()
1620 self.preferencesChanged()
1592 1621
1593 @pyqtSlot() 1622 @pyqtSlot()
1594 def __showCacheInfo(self): 1623 def __showCacheInfo(self):
1595 """ 1624 """
1596 Private slot to show information about the cache. 1625 Private slot to show information about the cache.
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
2100 2147
2101 venvName = self.environmentsComboBox.currentText() 2148 venvName = self.environmentsComboBox.currentText()
2102 if venvName == self.__pip.getProjectEnvironmentString(): 2149 if venvName == self.__pip.getProjectEnvironmentString():
2103 venvName = "<project>" 2150 venvName = "<project>"
2104 CycloneDXInterface.createCycloneDXFile(venvName) 2151 CycloneDXInterface.createCycloneDXFile(venvName)
2152
2153 ##################################################################
2154 ## Interface to preferences
2155 ##################################################################
2156
2157 @pyqtSlot()
2158 def preferencesChanged(self):
2159 """
2160 Public slot to handle a change of preferences.
2161 """
2162 enable = self.setVulnerabilityEnabled(
2163 Preferences.getPip("VulnerabilityCheckEnabled")
2164 )
2165 if enable != self.vulnerabilityCheckBox.isEnabled():
2166 # only if status changes because it is an expensive operation
2167 if self.vulnerabilityCheckBox.isChecked():
2168 self.__updateVulnerabilityData(clearFirst=True)
2169 else:
2170 self.__clearVulnerabilityInfo()

eric ide

mercurial