110 attributeName = self.__activeClass.replace(self.ClassPrefix, "") |
119 attributeName = self.__activeClass.replace(self.ClassPrefix, "") |
111 self.__results[-1][attributeName] = self.__getDate(attrs) |
120 self.__results[-1][attributeName] = self.__getDate(attrs) |
112 self.__activeClass = None |
121 self.__activeClass = None |
113 else: |
122 else: |
114 self.__activeClass = None |
123 self.__activeClass = None |
115 |
124 |
116 def handle_data(self, data): |
125 def handle_data(self, data): |
117 """ |
126 """ |
118 Public method process arbitrary data. |
127 Public method process arbitrary data. |
119 |
128 |
120 @param data data to be processed |
129 @param data data to be processed |
121 @type str |
130 @type str |
122 """ |
131 """ |
123 if self.__activeClass is not None: |
132 if self.__activeClass is not None: |
124 attributeName = self.__activeClass.replace(self.ClassPrefix, "") |
133 attributeName = self.__activeClass.replace(self.ClassPrefix, "") |
125 self.__results[-1][attributeName] = data |
134 self.__results[-1][attributeName] = data |
126 |
135 |
127 def handle_endtag(self, tag): |
136 def handle_endtag(self, tag): |
128 """ |
137 """ |
129 Public method to process the end tag. |
138 Public method to process the end tag. |
130 |
139 |
131 @param tag tag name (all lowercase) |
140 @param tag tag name (all lowercase) |
132 @type str |
141 @type str |
133 """ |
142 """ |
134 self.__activeClass = None |
143 self.__activeClass = None |
135 |
144 |
136 def getResults(self): |
145 def getResults(self): |
137 """ |
146 """ |
138 Public method to get the extracted search results. |
147 Public method to get the extracted search results. |
139 |
148 |
140 @return extracted result data |
149 @return extracted result data |
141 @rtype list of dict |
150 @rtype list of dict |
142 """ |
151 """ |
143 return self.__results |
152 return self.__results |
144 |
153 |
145 |
154 |
146 class PipPackagesWidget(QWidget, Ui_PipPackagesWidget): |
155 class PipPackagesWidget(QWidget, Ui_PipPackagesWidget): |
147 """ |
156 """ |
148 Class implementing the pip packages management widget. |
157 Class implementing the pip packages management widget. |
149 """ |
158 """ |
|
159 |
150 ShowProcessGeneralMode = 0 |
160 ShowProcessGeneralMode = 0 |
151 ShowProcessClassifiersMode = 1 |
161 ShowProcessClassifiersMode = 1 |
152 ShowProcessEntryPointsMode = 2 |
162 ShowProcessEntryPointsMode = 2 |
153 ShowProcessFilesListMode = 3 |
163 ShowProcessFilesListMode = 3 |
154 |
164 |
155 SearchVersionRole = Qt.ItemDataRole.UserRole + 1 |
165 SearchVersionRole = Qt.ItemDataRole.UserRole + 1 |
156 VulnerabilityRole = Qt.ItemDataRole.UserRole + 2 |
166 VulnerabilityRole = Qt.ItemDataRole.UserRole + 2 |
157 |
167 |
158 PackageColumn = 0 |
168 PackageColumn = 0 |
159 InstalledVersionColumn = 1 |
169 InstalledVersionColumn = 1 |
160 AvailableVersionColumn = 2 |
170 AvailableVersionColumn = 2 |
161 VulnerabilityColumn = 3 |
171 VulnerabilityColumn = 3 |
162 |
172 |
163 DepPackageColumn = 0 |
173 DepPackageColumn = 0 |
164 DepInstalledVersionColumn = 1 |
174 DepInstalledVersionColumn = 1 |
165 DepRequiredVersionColumn = 2 |
175 DepRequiredVersionColumn = 2 |
166 |
176 |
167 def __init__(self, pip, parent=None): |
177 def __init__(self, pip, parent=None): |
168 """ |
178 """ |
169 Constructor |
179 Constructor |
170 |
180 |
171 @param pip reference to the global pip interface |
181 @param pip reference to the global pip interface |
172 @type Pip |
182 @type Pip |
173 @param parent reference to the parent widget |
183 @param parent reference to the parent widget |
174 @type QWidget |
184 @type QWidget |
175 """ |
185 """ |
176 super().__init__(parent) |
186 super().__init__(parent) |
177 self.setupUi(self) |
187 self.setupUi(self) |
178 |
188 |
179 self.layout().setContentsMargins(0, 3, 0, 0) |
189 self.layout().setContentsMargins(0, 3, 0, 0) |
180 |
190 |
181 self.viewToggleButton.setIcon(UI.PixmapCache.getIcon("viewListTree")) |
191 self.viewToggleButton.setIcon(UI.PixmapCache.getIcon("viewListTree")) |
182 |
192 |
183 self.pipMenuButton.setObjectName( |
193 self.pipMenuButton.setObjectName("pip_supermenu_button") |
184 "pip_supermenu_button") |
|
185 self.pipMenuButton.setIcon(UI.PixmapCache.getIcon("superMenu")) |
194 self.pipMenuButton.setIcon(UI.PixmapCache.getIcon("superMenu")) |
186 self.pipMenuButton.setToolTip(self.tr("pip Menu")) |
195 self.pipMenuButton.setToolTip(self.tr("pip Menu")) |
187 self.pipMenuButton.setPopupMode( |
196 self.pipMenuButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) |
188 QToolButton.ToolButtonPopupMode.InstantPopup) |
197 self.pipMenuButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly) |
189 self.pipMenuButton.setToolButtonStyle( |
|
190 Qt.ToolButtonStyle.ToolButtonIconOnly) |
|
191 self.pipMenuButton.setFocusPolicy(Qt.FocusPolicy.NoFocus) |
198 self.pipMenuButton.setFocusPolicy(Qt.FocusPolicy.NoFocus) |
192 self.pipMenuButton.setAutoRaise(True) |
199 self.pipMenuButton.setAutoRaise(True) |
193 self.pipMenuButton.setShowMenuInside(True) |
200 self.pipMenuButton.setShowMenuInside(True) |
194 |
201 |
195 self.refreshButton.setIcon( |
202 self.refreshButton.setIcon(UI.PixmapCache.getIcon("reload")) |
196 UI.PixmapCache.getIcon("reload")) |
203 self.upgradeButton.setIcon(UI.PixmapCache.getIcon("1uparrow")) |
197 self.upgradeButton.setIcon( |
204 self.upgradeAllButton.setIcon(UI.PixmapCache.getIcon("2uparrow")) |
198 UI.PixmapCache.getIcon("1uparrow")) |
205 self.uninstallButton.setIcon(UI.PixmapCache.getIcon("minus")) |
199 self.upgradeAllButton.setIcon( |
206 self.showPackageDetailsButton.setIcon(UI.PixmapCache.getIcon("info")) |
200 UI.PixmapCache.getIcon("2uparrow")) |
207 self.searchToggleButton.setIcon(UI.PixmapCache.getIcon("find")) |
201 self.uninstallButton.setIcon( |
208 self.searchButton.setIcon(UI.PixmapCache.getIcon("findNext")) |
202 UI.PixmapCache.getIcon("minus")) |
209 self.searchMoreButton.setIcon(UI.PixmapCache.getIcon("plus")) |
203 self.showPackageDetailsButton.setIcon( |
210 self.installButton.setIcon(UI.PixmapCache.getIcon("plus")) |
204 UI.PixmapCache.getIcon("info")) |
211 self.installUserSiteButton.setIcon(UI.PixmapCache.getIcon("addUser")) |
205 self.searchToggleButton.setIcon( |
212 self.showDetailsButton.setIcon(UI.PixmapCache.getIcon("info")) |
206 UI.PixmapCache.getIcon("find")) |
213 |
207 self.searchButton.setIcon( |
214 self.refreshDependenciesButton.setIcon(UI.PixmapCache.getIcon("reload")) |
208 UI.PixmapCache.getIcon("findNext")) |
215 self.showDepPackageDetailsButton.setIcon(UI.PixmapCache.getIcon("info")) |
209 self.searchMoreButton.setIcon( |
216 |
210 UI.PixmapCache.getIcon("plus")) |
|
211 self.installButton.setIcon( |
|
212 UI.PixmapCache.getIcon("plus")) |
|
213 self.installUserSiteButton.setIcon( |
|
214 UI.PixmapCache.getIcon("addUser")) |
|
215 self.showDetailsButton.setIcon( |
|
216 UI.PixmapCache.getIcon("info")) |
|
217 |
|
218 self.refreshDependenciesButton.setIcon( |
|
219 UI.PixmapCache.getIcon("reload")) |
|
220 self.showDepPackageDetailsButton.setIcon( |
|
221 UI.PixmapCache.getIcon("info")) |
|
222 |
|
223 self.__pip = pip |
217 self.__pip = pip |
224 |
218 |
225 self.packagesList.header().setSortIndicator( |
219 self.packagesList.header().setSortIndicator( |
226 PipPackagesWidget.PackageColumn, Qt.SortOrder.AscendingOrder) |
220 PipPackagesWidget.PackageColumn, Qt.SortOrder.AscendingOrder |
|
221 ) |
227 self.dependenciesList.header().setSortIndicator( |
222 self.dependenciesList.header().setSortIndicator( |
228 PipPackagesWidget.DepPackageColumn, Qt.SortOrder.AscendingOrder) |
223 PipPackagesWidget.DepPackageColumn, Qt.SortOrder.AscendingOrder |
229 |
224 ) |
|
225 |
230 self.__infoLabels = { |
226 self.__infoLabels = { |
231 "name": self.tr("Name:"), |
227 "name": self.tr("Name:"), |
232 "version": self.tr("Version:"), |
228 "version": self.tr("Version:"), |
233 "location": self.tr("Location:"), |
229 "location": self.tr("Location:"), |
234 "requires": self.tr("Requires:"), |
230 "requires": self.tr("Requires:"), |
243 "entry-points": self.tr("Entry Points:"), |
239 "entry-points": self.tr("Entry Points:"), |
244 "files": self.tr("Files:"), |
240 "files": self.tr("Files:"), |
245 } |
241 } |
246 self.infoWidget.setHeaderLabels(["Key", "Value"]) |
242 self.infoWidget.setHeaderLabels(["Key", "Value"]) |
247 self.dependencyInfoWidget.setHeaderLabels(["Key", "Value"]) |
243 self.dependencyInfoWidget.setHeaderLabels(["Key", "Value"]) |
248 |
244 |
249 venvManager = ericApp().getObject("VirtualEnvManager") |
245 venvManager = ericApp().getObject("VirtualEnvManager") |
250 venvManager.virtualEnvironmentAdded.connect( |
246 venvManager.virtualEnvironmentAdded.connect(self.on_refreshButton_clicked) |
251 self.on_refreshButton_clicked) |
247 venvManager.virtualEnvironmentRemoved.connect(self.on_refreshButton_clicked) |
252 venvManager.virtualEnvironmentRemoved.connect( |
|
253 self.on_refreshButton_clicked) |
|
254 self.__selectedEnvironment = None |
248 self.__selectedEnvironment = None |
255 |
249 |
256 project = ericApp().getObject("Project") |
250 project = ericApp().getObject("Project") |
257 project.projectOpened.connect( |
251 project.projectOpened.connect(self.__projectOpened) |
258 self.__projectOpened) |
252 project.projectClosed.connect(self.__projectClosed) |
259 project.projectClosed.connect( |
253 |
260 self.__projectClosed) |
|
261 |
|
262 self.__initPipMenu() |
254 self.__initPipMenu() |
263 self.__populateEnvironments() |
255 self.__populateEnvironments() |
264 self.__updateActionButtons() |
256 self.__updateActionButtons() |
265 self.__updateDepActionButtons() |
257 self.__updateDepActionButtons() |
266 |
258 |
267 self.statusLabel.hide() |
259 self.statusLabel.hide() |
268 self.searchWidget.hide() |
260 self.searchWidget.hide() |
269 self.__lastSearchPage = 0 |
261 self.__lastSearchPage = 0 |
270 |
262 |
271 self.__queryName = [] |
263 self.__queryName = [] |
272 self.__querySummary = [] |
264 self.__querySummary = [] |
273 |
265 |
274 self.__replies = [] |
266 self.__replies = [] |
275 |
267 |
276 self.__packageDetailsDialog = None |
268 self.__packageDetailsDialog = None |
277 |
269 |
278 self.viewsStackWidget.setCurrentWidget(self.packagesPage) |
270 self.viewsStackWidget.setCurrentWidget(self.packagesPage) |
279 |
271 |
280 @pyqtSlot() |
272 @pyqtSlot() |
281 def __projectOpened(self): |
273 def __projectOpened(self): |
282 """ |
274 """ |
283 Private slot to handle the projectOpened signal. |
275 Private slot to handle the projectOpened signal. |
284 """ |
276 """ |
285 projectVenv = self.__pip.getProjectEnvironmentString() |
277 projectVenv = self.__pip.getProjectEnvironmentString() |
286 if projectVenv: |
278 if projectVenv: |
287 self.environmentsComboBox.insertItem(1, projectVenv) |
279 self.environmentsComboBox.insertItem(1, projectVenv) |
288 |
280 |
289 @pyqtSlot(bool) |
281 @pyqtSlot(bool) |
290 def __projectClosed(self, shutdown): |
282 def __projectClosed(self, shutdown): |
291 """ |
283 """ |
292 Private slot to handle the projectClosed signal. |
284 Private slot to handle the projectClosed signal. |
293 |
285 |
294 @param shutdown flag indicating the IDE shutdown |
286 @param shutdown flag indicating the IDE shutdown |
295 @type bool |
287 @type bool |
296 """ |
288 """ |
297 if not shutdown: |
289 if not shutdown: |
298 # the project entry is always at index 1 |
290 # the project entry is always at index 1 |
299 self.environmentsComboBox.removeItem(1) |
291 self.environmentsComboBox.removeItem(1) |
300 |
292 |
301 def __populateEnvironments(self): |
293 def __populateEnvironments(self): |
302 """ |
294 """ |
303 Private method to get a list of environments and populate the selector. |
295 Private method to get a list of environments and populate the selector. |
304 """ |
296 """ |
305 self.environmentsComboBox.addItem("") |
297 self.environmentsComboBox.addItem("") |
306 projectVenv = self.__pip.getProjectEnvironmentString() |
298 projectVenv = self.__pip.getProjectEnvironmentString() |
307 if projectVenv: |
299 if projectVenv: |
308 self.environmentsComboBox.addItem(projectVenv) |
300 self.environmentsComboBox.addItem(projectVenv) |
309 self.environmentsComboBox.addItems( |
301 self.environmentsComboBox.addItems( |
310 self.__pip.getVirtualenvNames( |
302 self.__pip.getVirtualenvNames( |
311 noRemote=True, |
303 noRemote=True, noConda=Preferences.getPip("ExcludeCondaEnvironments") |
312 noConda=Preferences.getPip("ExcludeCondaEnvironments") |
304 ) |
313 ) |
305 ) |
314 ) |
306 |
315 |
|
316 def __isPipAvailable(self): |
307 def __isPipAvailable(self): |
317 """ |
308 """ |
318 Private method to check, if the pip package is available for the |
309 Private method to check, if the pip package is available for the |
319 selected environment. |
310 selected environment. |
320 |
311 |
321 @return flag indicating availability |
312 @return flag indicating availability |
322 @rtype bool |
313 @rtype bool |
323 """ |
314 """ |
324 available = False |
315 available = False |
325 |
316 |
326 venvName = self.environmentsComboBox.currentText() |
317 venvName = self.environmentsComboBox.currentText() |
327 if venvName: |
318 if venvName: |
328 available = ( |
319 available = ( |
329 len(self.packagesList.findItems( |
320 len( |
330 "pip", |
321 self.packagesList.findItems( |
331 Qt.MatchFlag.MatchExactly | |
322 "pip", |
332 Qt.MatchFlag.MatchCaseSensitive)) == 1 |
323 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive, |
333 ) |
324 ) |
334 |
325 ) |
|
326 == 1 |
|
327 ) |
|
328 |
335 return available |
329 return available |
336 |
330 |
337 def __availablePipVersion(self): |
331 def __availablePipVersion(self): |
338 """ |
332 """ |
339 Private method to get the pip version of the selected environment. |
333 Private method to get the pip version of the selected environment. |
340 |
334 |
341 @return tuple containing the version number or tuple with all zeros |
335 @return tuple containing the version number or tuple with all zeros |
342 in case pip is not available |
336 in case pip is not available |
343 @rtype tuple of int |
337 @rtype tuple of int |
344 """ |
338 """ |
345 pipVersionTuple = (0, 0, 0) |
339 pipVersionTuple = (0, 0, 0) |
346 venvName = self.environmentsComboBox.currentText() |
340 venvName = self.environmentsComboBox.currentText() |
347 if venvName: |
341 if venvName: |
348 pipList = self.packagesList.findItems( |
342 pipList = self.packagesList.findItems( |
349 "pip", |
343 "pip", Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive |
350 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive |
|
351 ) |
344 ) |
352 if len(pipList) > 0: |
345 if len(pipList) > 0: |
353 pipVersionTuple = Globals.versionToTuple( |
346 pipVersionTuple = Globals.versionToTuple( |
354 pipList[0].text(PipPackagesWidget.InstalledVersionColumn)) |
347 pipList[0].text(PipPackagesWidget.InstalledVersionColumn) |
355 |
348 ) |
|
349 |
356 return pipVersionTuple |
350 return pipVersionTuple |
357 |
351 |
358 def getPip(self): |
352 def getPip(self): |
359 """ |
353 """ |
360 Public method to get a reference to the pip interface object. |
354 Public method to get a reference to the pip interface object. |
361 |
355 |
362 @return reference to the pip interface object |
356 @return reference to the pip interface object |
363 @rtype Pip |
357 @rtype Pip |
364 """ |
358 """ |
365 return self.__pip |
359 return self.__pip |
366 |
360 |
367 ####################################################################### |
361 ####################################################################### |
368 ## Slots handling widget signals below |
362 ## Slots handling widget signals below |
369 ####################################################################### |
363 ####################################################################### |
370 |
364 |
371 def __selectedUpdateableItems(self): |
365 def __selectedUpdateableItems(self): |
372 """ |
366 """ |
373 Private method to get a list of selected items that can be updated. |
367 Private method to get a list of selected items that can be updated. |
374 |
368 |
375 @return list of selected items that can be updated |
369 @return list of selected items that can be updated |
376 @rtype list of QTreeWidgetItem |
370 @rtype list of QTreeWidgetItem |
377 """ |
371 """ |
378 return [ |
372 return [ |
379 itm for itm in self.packagesList.selectedItems() |
373 itm |
|
374 for itm in self.packagesList.selectedItems() |
380 if bool(itm.text(PipPackagesWidget.AvailableVersionColumn)) |
375 if bool(itm.text(PipPackagesWidget.AvailableVersionColumn)) |
381 ] |
376 ] |
382 |
377 |
383 def __allUpdateableItems(self): |
378 def __allUpdateableItems(self): |
384 """ |
379 """ |
385 Private method to get a list of all items that can be updated. |
380 Private method to get a list of all items that can be updated. |
386 |
381 |
387 @return list of all items that can be updated |
382 @return list of all items that can be updated |
388 @rtype list of QTreeWidgetItem |
383 @rtype list of QTreeWidgetItem |
389 """ |
384 """ |
390 updateableItems = [] |
385 updateableItems = [] |
391 for index in range(self.packagesList.topLevelItemCount()): |
386 for index in range(self.packagesList.topLevelItemCount()): |
392 itm = self.packagesList.topLevelItem(index) |
387 itm = self.packagesList.topLevelItem(index) |
393 if itm.text(PipPackagesWidget.AvailableVersionColumn): |
388 if itm.text(PipPackagesWidget.AvailableVersionColumn): |
394 updateableItems.append(itm) |
389 updateableItems.append(itm) |
395 |
390 |
396 return updateableItems |
391 return updateableItems |
397 |
392 |
398 def __updateActionButtons(self): |
393 def __updateActionButtons(self): |
399 """ |
394 """ |
400 Private method to set the state of the action buttons. |
395 Private method to set the state of the action buttons. |
401 """ |
396 """ |
402 if self.__isPipAvailable(): |
397 if self.__isPipAvailable(): |
403 self.upgradeButton.setEnabled( |
398 self.upgradeButton.setEnabled(bool(self.__selectedUpdateableItems())) |
404 bool(self.__selectedUpdateableItems())) |
399 self.uninstallButton.setEnabled(bool(self.packagesList.selectedItems())) |
405 self.uninstallButton.setEnabled( |
400 self.upgradeAllButton.setEnabled(bool(self.__allUpdateableItems())) |
406 bool(self.packagesList.selectedItems())) |
|
407 self.upgradeAllButton.setEnabled( |
|
408 bool(self.__allUpdateableItems())) |
|
409 self.showPackageDetailsButton.setEnabled( |
401 self.showPackageDetailsButton.setEnabled( |
410 len(self.packagesList.selectedItems()) == 1) |
402 len(self.packagesList.selectedItems()) == 1 |
|
403 ) |
411 else: |
404 else: |
412 self.upgradeButton.setEnabled(False) |
405 self.upgradeButton.setEnabled(False) |
413 self.uninstallButton.setEnabled(False) |
406 self.uninstallButton.setEnabled(False) |
414 self.upgradeAllButton.setEnabled(False) |
407 self.upgradeAllButton.setEnabled(False) |
415 self.showPackageDetailsButton.setEnabled(False) |
408 self.showPackageDetailsButton.setEnabled(False) |
416 |
409 |
417 def __refreshPackagesList(self): |
410 def __refreshPackagesList(self): |
418 """ |
411 """ |
419 Private method to refresh the packages list. |
412 Private method to refresh the packages list. |
420 """ |
413 """ |
421 self.packagesList.clear() |
414 self.packagesList.clear() |
422 venvName = self.environmentsComboBox.currentText() |
415 venvName = self.environmentsComboBox.currentText() |
423 if venvName: |
416 if venvName: |
424 interpreter = self.__pip.getVirtualenvInterpreter(venvName) |
417 interpreter = self.__pip.getVirtualenvInterpreter(venvName) |
425 if interpreter: |
418 if interpreter: |
426 self.statusLabel.show() |
419 self.statusLabel.show() |
427 self.statusLabel.setText( |
420 self.statusLabel.setText(self.tr("Getting installed packages...")) |
428 self.tr("Getting installed packages...")) |
421 |
429 |
|
430 with EricOverrideCursor(): |
422 with EricOverrideCursor(): |
431 # 1. populate with installed packages |
423 # 1. populate with installed packages |
432 self.packagesList.setUpdatesEnabled(False) |
424 self.packagesList.setUpdatesEnabled(False) |
433 installedPackages = self.__pip.getInstalledPackages( |
425 installedPackages = self.__pip.getInstalledPackages( |
434 venvName, |
426 venvName, |
435 localPackages=self.localCheckBox.isChecked(), |
427 localPackages=self.localCheckBox.isChecked(), |
436 notRequired=self.notRequiredCheckBox.isChecked(), |
428 notRequired=self.notRequiredCheckBox.isChecked(), |
437 usersite=self.userCheckBox.isChecked(), |
429 usersite=self.userCheckBox.isChecked(), |
438 ) |
430 ) |
439 for package, version in installedPackages: |
431 for package, version in installedPackages: |
440 QTreeWidgetItem(self.packagesList, |
432 QTreeWidgetItem(self.packagesList, [package, version, "", ""]) |
441 [package, version, "", ""]) |
|
442 self.packagesList.setUpdatesEnabled(True) |
433 self.packagesList.setUpdatesEnabled(True) |
443 self.statusLabel.setText( |
434 self.statusLabel.setText(self.tr("Getting outdated packages...")) |
444 self.tr("Getting outdated packages...")) |
|
445 QApplication.processEvents() |
435 QApplication.processEvents() |
446 |
436 |
447 # 2. update with update information |
437 # 2. update with update information |
448 self.packagesList.setUpdatesEnabled(False) |
438 self.packagesList.setUpdatesEnabled(False) |
449 outdatedPackages = self.__pip.getOutdatedPackages( |
439 outdatedPackages = self.__pip.getOutdatedPackages( |
450 venvName, |
440 venvName, |
451 localPackages=self.localCheckBox.isChecked(), |
441 localPackages=self.localCheckBox.isChecked(), |
453 usersite=self.userCheckBox.isChecked(), |
443 usersite=self.userCheckBox.isChecked(), |
454 ) |
444 ) |
455 for package, _version, latest in outdatedPackages: |
445 for package, _version, latest in outdatedPackages: |
456 items = self.packagesList.findItems( |
446 items = self.packagesList.findItems( |
457 package, |
447 package, |
458 Qt.MatchFlag.MatchExactly | |
448 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive, |
459 Qt.MatchFlag.MatchCaseSensitive |
|
460 ) |
449 ) |
461 if items: |
450 if items: |
462 itm = items[0] |
451 itm = items[0] |
463 itm.setText( |
452 itm.setText( |
464 PipPackagesWidget.AvailableVersionColumn, |
453 PipPackagesWidget.AvailableVersionColumn, latest |
465 latest) |
454 ) |
466 |
455 |
467 self.packagesList.sortItems( |
456 self.packagesList.sortItems( |
468 PipPackagesWidget.PackageColumn, |
457 PipPackagesWidget.PackageColumn, Qt.SortOrder.AscendingOrder |
469 Qt.SortOrder.AscendingOrder) |
458 ) |
470 for col in range(self.packagesList.columnCount()): |
459 for col in range(self.packagesList.columnCount()): |
471 self.packagesList.resizeColumnToContents(col) |
460 self.packagesList.resizeColumnToContents(col) |
472 self.packagesList.setUpdatesEnabled(True) |
461 self.packagesList.setUpdatesEnabled(True) |
473 |
462 |
474 # 3. update with vulnerability information |
463 # 3. update with vulnerability information |
475 if self.vulnerabilityCheckBox.isChecked(): |
464 if self.vulnerabilityCheckBox.isChecked(): |
476 self.__updateVulnerabilityData() |
465 self.__updateVulnerabilityData() |
477 self.statusLabel.hide() |
466 self.statusLabel.hide() |
478 |
467 |
479 self.__updateActionButtons() |
468 self.__updateActionButtons() |
480 self.__updateSearchActionButtons() |
469 self.__updateSearchActionButtons() |
481 self.__updateSearchButton() |
470 self.__updateSearchButton() |
482 self.__updateSearchMoreButton(False) |
471 self.__updateSearchMoreButton(False) |
483 |
472 |
484 @pyqtSlot(str) |
473 @pyqtSlot(str) |
485 def on_environmentsComboBox_currentTextChanged(self, name): |
474 def on_environmentsComboBox_currentTextChanged(self, name): |
486 """ |
475 """ |
487 Private slot handling the selection of a Python environment. |
476 Private slot handling the selection of a Python environment. |
488 |
477 |
489 @param name name of the selected Python environment |
478 @param name name of the selected Python environment |
490 @type str |
479 @type str |
491 """ |
480 """ |
492 if name != self.__selectedEnvironment: |
481 if name != self.__selectedEnvironment: |
493 if self.viewToggleButton.isChecked(): |
482 if self.viewToggleButton.isChecked(): |
494 self.__refreshDependencyTree() |
483 self.__refreshDependencyTree() |
495 else: |
484 else: |
496 self.__refreshPackagesList() |
485 self.__refreshPackagesList() |
497 self.__selectedEnvironment = name |
486 self.__selectedEnvironment = name |
498 |
487 |
499 @pyqtSlot() |
488 @pyqtSlot() |
500 def on_localCheckBox_clicked(self): |
489 def on_localCheckBox_clicked(self): |
501 """ |
490 """ |
502 Private slot handling the switching of the local mode. |
491 Private slot handling the switching of the local mode. |
503 """ |
492 """ |
504 self.__refreshPackagesList() |
493 self.__refreshPackagesList() |
505 |
494 |
506 @pyqtSlot() |
495 @pyqtSlot() |
507 def on_notRequiredCheckBox_clicked(self): |
496 def on_notRequiredCheckBox_clicked(self): |
508 """ |
497 """ |
509 Private slot handling the switching of the 'not required' mode. |
498 Private slot handling the switching of the 'not required' mode. |
510 """ |
499 """ |
511 self.__refreshPackagesList() |
500 self.__refreshPackagesList() |
512 |
501 |
513 @pyqtSlot() |
502 @pyqtSlot() |
514 def on_userCheckBox_clicked(self): |
503 def on_userCheckBox_clicked(self): |
515 """ |
504 """ |
516 Private slot handling the switching of the 'user-site' mode. |
505 Private slot handling the switching of the 'user-site' mode. |
517 """ |
506 """ |
518 self.__refreshPackagesList() |
507 self.__refreshPackagesList() |
519 |
508 |
520 def __showPackageInformation(self, packageName, infoWidget): |
509 def __showPackageInformation(self, packageName, infoWidget): |
521 """ |
510 """ |
522 Private method to show information for a package. |
511 Private method to show information for a package. |
523 |
512 |
524 @param packageName name of the package |
513 @param packageName name of the package |
525 @type str |
514 @type str |
526 @param infoWidget reference to the widget to contain the information |
515 @param infoWidget reference to the widget to contain the information |
527 @type QTreeWidget |
516 @type QTreeWidget |
528 """ |
517 """ |
529 environment = self.environmentsComboBox.currentText() |
518 environment = self.environmentsComboBox.currentText() |
530 interpreter = self.__pip.getVirtualenvInterpreter(environment) |
519 interpreter = self.__pip.getVirtualenvInterpreter(environment) |
531 if not interpreter: |
520 if not interpreter: |
532 return |
521 return |
533 |
522 |
534 args = ["-m", "pip", "show"] |
523 args = ["-m", "pip", "show"] |
535 if self.verboseCheckBox.isChecked(): |
524 if self.verboseCheckBox.isChecked(): |
536 args.append("--verbose") |
525 args.append("--verbose") |
537 if self.installedFilesCheckBox.isChecked(): |
526 if self.installedFilesCheckBox.isChecked(): |
538 args.append("--files") |
527 args.append("--files") |
539 args.append(packageName) |
528 args.append(packageName) |
540 |
529 |
541 with EricOverrideCursor(): |
530 with EricOverrideCursor(): |
542 success, output = self.__pip.runProcess(args, interpreter) |
531 success, output = self.__pip.runProcess(args, interpreter) |
543 |
532 |
544 if success and output: |
533 if success and output: |
545 mode = self.ShowProcessGeneralMode |
534 mode = self.ShowProcessGeneralMode |
546 for line in output.splitlines(): |
535 for line in output.splitlines(): |
547 line = line.rstrip() |
536 line = line.rstrip() |
548 if line != "---": |
537 if line != "---": |
549 if mode != self.ShowProcessGeneralMode: |
538 if mode != self.ShowProcessGeneralMode: |
550 if line[0] == " ": |
539 if line[0] == " ": |
551 QTreeWidgetItem( |
540 QTreeWidgetItem(infoWidget, [" ", line.strip()]) |
552 infoWidget, |
|
553 [" ", line.strip()]) |
|
554 else: |
541 else: |
555 mode = self.ShowProcessGeneralMode |
542 mode = self.ShowProcessGeneralMode |
556 if mode == self.ShowProcessGeneralMode: |
543 if mode == self.ShowProcessGeneralMode: |
557 try: |
544 try: |
558 label, info = line.split(": ", 1) |
545 label, info = line.split(": ", 1) |
560 label = line[:-1] |
547 label = line[:-1] |
561 info = "" |
548 info = "" |
562 label = label.lower() |
549 label = label.lower() |
563 if label in self.__infoLabels: |
550 if label in self.__infoLabels: |
564 QTreeWidgetItem( |
551 QTreeWidgetItem( |
565 infoWidget, |
552 infoWidget, [self.__infoLabels[label], info] |
566 [self.__infoLabels[label], info]) |
553 ) |
567 if label == "files": |
554 if label == "files": |
568 mode = self.ShowProcessFilesListMode |
555 mode = self.ShowProcessFilesListMode |
569 elif label == "classifiers": |
556 elif label == "classifiers": |
570 mode = self.ShowProcessClassifiersMode |
557 mode = self.ShowProcessClassifiersMode |
571 elif label == "entry-points": |
558 elif label == "entry-points": |
572 mode = self.ShowProcessEntryPointsMode |
559 mode = self.ShowProcessEntryPointsMode |
573 infoWidget.scrollToTop() |
560 infoWidget.scrollToTop() |
574 |
561 |
575 header = infoWidget.header() |
562 header = infoWidget.header() |
576 header.setStretchLastSection(False) |
563 header.setStretchLastSection(False) |
577 header.resizeSections(QHeaderView.ResizeMode.ResizeToContents) |
564 header.resizeSections(QHeaderView.ResizeMode.ResizeToContents) |
578 if ( |
565 if header.sectionSize(0) + header.sectionSize(1) < header.width(): |
579 header.sectionSize(0) + header.sectionSize(1) < |
|
580 header.width() |
|
581 ): |
|
582 header.setStretchLastSection(True) |
566 header.setStretchLastSection(True) |
583 |
567 |
584 @pyqtSlot() |
568 @pyqtSlot() |
585 def on_packagesList_itemSelectionChanged(self): |
569 def on_packagesList_itemSelectionChanged(self): |
586 """ |
570 """ |
587 Private slot reacting on a change of selected items. |
571 Private slot reacting on a change of selected items. |
588 """ |
572 """ |
589 if len(self.packagesList.selectedItems()) == 0: |
573 if len(self.packagesList.selectedItems()) == 0: |
590 self.infoWidget.clear() |
574 self.infoWidget.clear() |
591 |
575 |
592 @pyqtSlot(QTreeWidgetItem, int) |
576 @pyqtSlot(QTreeWidgetItem, int) |
593 def on_packagesList_itemPressed(self, item, column): |
577 def on_packagesList_itemPressed(self, item, column): |
594 """ |
578 """ |
595 Private slot reacting on a package item being pressed. |
579 Private slot reacting on a package item being pressed. |
596 |
580 |
597 @param item reference to the pressed item |
581 @param item reference to the pressed item |
598 @type QTreeWidgetItem |
582 @type QTreeWidgetItem |
599 @param column pressed column |
583 @param column pressed column |
600 @type int |
584 @type int |
601 """ |
585 """ |
602 self.infoWidget.clear() |
586 self.infoWidget.clear() |
603 |
587 |
604 if item is not None: |
588 if item is not None: |
605 if ( |
589 if column == PipPackagesWidget.VulnerabilityColumn and bool( |
606 column == PipPackagesWidget.VulnerabilityColumn and |
590 item.text(PipPackagesWidget.VulnerabilityColumn) |
607 bool(item.text(PipPackagesWidget.VulnerabilityColumn)) |
|
608 ): |
591 ): |
609 self.__showVulnerabilityInformation( |
592 self.__showVulnerabilityInformation( |
610 item.text(PipPackagesWidget.PackageColumn), |
593 item.text(PipPackagesWidget.PackageColumn), |
611 item.text(PipPackagesWidget.InstalledVersionColumn), |
594 item.text(PipPackagesWidget.InstalledVersionColumn), |
612 item.data(PipPackagesWidget.VulnerabilityColumn, |
595 item.data( |
613 PipPackagesWidget.VulnerabilityRole) |
596 PipPackagesWidget.VulnerabilityColumn, |
|
597 PipPackagesWidget.VulnerabilityRole, |
|
598 ), |
614 ) |
599 ) |
615 else: |
600 else: |
616 self.__showPackageInformation( |
601 self.__showPackageInformation( |
617 item.text(PipPackagesWidget.PackageColumn), |
602 item.text(PipPackagesWidget.PackageColumn), self.infoWidget |
618 self.infoWidget |
|
619 ) |
603 ) |
620 |
604 |
621 self.__updateActionButtons() |
605 self.__updateActionButtons() |
622 |
606 |
623 @pyqtSlot(QTreeWidgetItem, int) |
607 @pyqtSlot(QTreeWidgetItem, int) |
624 def on_packagesList_itemActivated(self, item, column): |
608 def on_packagesList_itemActivated(self, item, column): |
625 """ |
609 """ |
626 Private slot reacting on a package item being activated. |
610 Private slot reacting on a package item being activated. |
627 |
611 |
628 @param item reference to the activated item |
612 @param item reference to the activated item |
629 @type QTreeWidgetItem |
613 @type QTreeWidgetItem |
630 @param column activated column |
614 @param column activated column |
631 @type int |
615 @type int |
632 """ |
616 """ |
633 packageName = item.text(PipPackagesWidget.PackageColumn) |
617 packageName = item.text(PipPackagesWidget.PackageColumn) |
634 upgradable = bool(item.text(PipPackagesWidget.AvailableVersionColumn)) |
618 upgradable = bool(item.text(PipPackagesWidget.AvailableVersionColumn)) |
635 if column == PipPackagesWidget.InstalledVersionColumn: |
619 if column == PipPackagesWidget.InstalledVersionColumn: |
636 # show details for installed version |
620 # show details for installed version |
637 packageVersion = item.text( |
621 packageVersion = item.text(PipPackagesWidget.InstalledVersionColumn) |
638 PipPackagesWidget.InstalledVersionColumn) |
|
639 else: |
622 else: |
640 # show details for available version or installed one |
623 # show details for available version or installed one |
641 if item.text(PipPackagesWidget.AvailableVersionColumn): |
624 if item.text(PipPackagesWidget.AvailableVersionColumn): |
642 packageVersion = item.text( |
625 packageVersion = item.text(PipPackagesWidget.AvailableVersionColumn) |
643 PipPackagesWidget.AvailableVersionColumn) |
|
644 else: |
626 else: |
645 packageVersion = item.text( |
627 packageVersion = item.text(PipPackagesWidget.InstalledVersionColumn) |
646 PipPackagesWidget.InstalledVersionColumn) |
628 |
647 |
629 self.__showPackageDetails(packageName, packageVersion, upgradable=upgradable) |
648 self.__showPackageDetails(packageName, packageVersion, |
630 |
649 upgradable=upgradable) |
|
650 |
|
651 @pyqtSlot(bool) |
631 @pyqtSlot(bool) |
652 def on_verboseCheckBox_clicked(self, checked): |
632 def on_verboseCheckBox_clicked(self, checked): |
653 """ |
633 """ |
654 Private slot to handle a change of the verbose package information |
634 Private slot to handle a change of the verbose package information |
655 checkbox. |
635 checkbox. |
656 |
636 |
657 @param checked state of the checkbox |
637 @param checked state of the checkbox |
658 @type bool |
638 @type bool |
659 """ |
639 """ |
660 self.on_packagesList_itemPressed(self.packagesList.currentItem(), |
640 self.on_packagesList_itemPressed( |
661 self.packagesList.currentColumn()) |
641 self.packagesList.currentItem(), self.packagesList.currentColumn() |
662 |
642 ) |
|
643 |
663 @pyqtSlot(bool) |
644 @pyqtSlot(bool) |
664 def on_installedFilesCheckBox_clicked(self, checked): |
645 def on_installedFilesCheckBox_clicked(self, checked): |
665 """ |
646 """ |
666 Private slot to handle a change of the installed files information |
647 Private slot to handle a change of the installed files information |
667 checkbox. |
648 checkbox. |
668 |
649 |
669 @param checked state of the checkbox |
650 @param checked state of the checkbox |
670 @type bool |
651 @type bool |
671 """ |
652 """ |
672 self.on_packagesList_itemPressed(self.packagesList.currentItem(), |
653 self.on_packagesList_itemPressed( |
673 self.packagesList.currentColumn()) |
654 self.packagesList.currentItem(), self.packagesList.currentColumn() |
674 |
655 ) |
|
656 |
675 @pyqtSlot() |
657 @pyqtSlot() |
676 def on_refreshButton_clicked(self): |
658 def on_refreshButton_clicked(self): |
677 """ |
659 """ |
678 Private slot to refresh the display. |
660 Private slot to refresh the display. |
679 """ |
661 """ |
680 currentEnvironment = self.environmentsComboBox.currentText() |
662 currentEnvironment = self.environmentsComboBox.currentText() |
681 self.environmentsComboBox.clear() |
663 self.environmentsComboBox.clear() |
682 self.packagesList.clear() |
664 self.packagesList.clear() |
683 |
665 |
684 with EricOverrideCursor(): |
666 with EricOverrideCursor(): |
685 self.__populateEnvironments() |
667 self.__populateEnvironments() |
686 |
668 |
687 index = self.environmentsComboBox.findText( |
669 index = self.environmentsComboBox.findText( |
688 currentEnvironment, |
670 currentEnvironment, |
689 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive |
671 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive, |
690 ) |
672 ) |
691 if index != -1: |
673 if index != -1: |
692 self.environmentsComboBox.setCurrentIndex(index) |
674 self.environmentsComboBox.setCurrentIndex(index) |
693 |
675 |
694 self.__updateActionButtons() |
676 self.__updateActionButtons() |
695 |
677 |
696 @pyqtSlot() |
678 @pyqtSlot() |
697 def on_upgradeButton_clicked(self): |
679 def on_upgradeButton_clicked(self): |
698 """ |
680 """ |
699 Private slot to upgrade selected packages of the selected environment. |
681 Private slot to upgrade selected packages of the selected environment. |
700 """ |
682 """ |
701 packages = [itm.text(PipPackagesWidget.PackageColumn) |
683 packages = [ |
702 for itm in self.__selectedUpdateableItems()] |
684 itm.text(PipPackagesWidget.PackageColumn) |
|
685 for itm in self.__selectedUpdateableItems() |
|
686 ] |
703 if packages: |
687 if packages: |
704 self.executeUpgradePackages(packages) |
688 self.executeUpgradePackages(packages) |
705 |
689 |
706 @pyqtSlot() |
690 @pyqtSlot() |
707 def on_upgradeAllButton_clicked(self): |
691 def on_upgradeAllButton_clicked(self): |
708 """ |
692 """ |
709 Private slot to upgrade all packages of the selected environment. |
693 Private slot to upgrade all packages of the selected environment. |
710 """ |
694 """ |
711 packages = [itm.text(PipPackagesWidget.PackageColumn) |
695 packages = [ |
712 for itm in self.__allUpdateableItems()] |
696 itm.text(PipPackagesWidget.PackageColumn) |
|
697 for itm in self.__allUpdateableItems() |
|
698 ] |
713 if packages: |
699 if packages: |
714 self.executeUpgradePackages(packages) |
700 self.executeUpgradePackages(packages) |
715 |
701 |
716 @pyqtSlot() |
702 @pyqtSlot() |
717 def on_uninstallButton_clicked(self): |
703 def on_uninstallButton_clicked(self): |
718 """ |
704 """ |
719 Private slot to remove selected packages of the selected environment. |
705 Private slot to remove selected packages of the selected environment. |
720 """ |
706 """ |
721 packages = [itm.text(PipPackagesWidget.PackageColumn) |
707 packages = [ |
722 for itm in self.packagesList.selectedItems()] |
708 itm.text(PipPackagesWidget.PackageColumn) |
|
709 for itm in self.packagesList.selectedItems() |
|
710 ] |
723 self.executeUninstallPackages(packages) |
711 self.executeUninstallPackages(packages) |
724 |
712 |
725 def executeUninstallPackages(self, packages): |
713 def executeUninstallPackages(self, packages): |
726 """ |
714 """ |
727 Public method to uninstall the given list of packages. |
715 Public method to uninstall the given list of packages. |
728 |
716 |
729 @param packages list of package names to be uninstalled |
717 @param packages list of package names to be uninstalled |
730 @type list of str |
718 @type list of str |
731 """ |
719 """ |
732 if packages: |
720 if packages: |
733 ok = self.__pip.uninstallPackages( |
721 ok = self.__pip.uninstallPackages( |
734 packages, |
722 packages, venvName=self.environmentsComboBox.currentText() |
735 venvName=self.environmentsComboBox.currentText()) |
723 ) |
736 if ok: |
724 if ok: |
737 self.on_refreshButton_clicked() |
725 self.on_refreshButton_clicked() |
738 |
726 |
739 def executeUpgradePackages(self, packages): |
727 def executeUpgradePackages(self, packages): |
740 """ |
728 """ |
741 Public method to execute the pip upgrade command. |
729 Public method to execute the pip upgrade command. |
742 |
730 |
743 @param packages list of package names to be upgraded |
731 @param packages list of package names to be upgraded |
744 @type list of str |
732 @type list of str |
745 """ |
733 """ |
746 ok = self.__pip.upgradePackages( |
734 ok = self.__pip.upgradePackages( |
747 packages, venvName=self.environmentsComboBox.currentText(), |
735 packages, |
748 userSite=self.userCheckBox.isChecked()) |
736 venvName=self.environmentsComboBox.currentText(), |
|
737 userSite=self.userCheckBox.isChecked(), |
|
738 ) |
749 if ok: |
739 if ok: |
750 self.on_refreshButton_clicked() |
740 self.on_refreshButton_clicked() |
751 |
741 |
752 @pyqtSlot() |
742 @pyqtSlot() |
753 def on_showPackageDetailsButton_clicked(self): |
743 def on_showPackageDetailsButton_clicked(self): |
754 """ |
744 """ |
755 Private slot to show information for the selected package. |
745 Private slot to show information for the selected package. |
756 """ |
746 """ |
757 item = self.packagesList.selectedItems()[0] |
747 item = self.packagesList.selectedItems()[0] |
758 if item: |
748 if item: |
759 packageName = item.text(PipPackagesWidget.PackageColumn) |
749 packageName = item.text(PipPackagesWidget.PackageColumn) |
760 upgradable = bool(item.text( |
750 upgradable = bool(item.text(PipPackagesWidget.AvailableVersionColumn)) |
761 PipPackagesWidget.AvailableVersionColumn)) |
|
762 # show details for available version or installed one |
751 # show details for available version or installed one |
763 if item.text(PipPackagesWidget.AvailableVersionColumn): |
752 if item.text(PipPackagesWidget.AvailableVersionColumn): |
764 packageVersion = item.text( |
753 packageVersion = item.text(PipPackagesWidget.AvailableVersionColumn) |
765 PipPackagesWidget.AvailableVersionColumn) |
|
766 else: |
754 else: |
767 packageVersion = item.text( |
755 packageVersion = item.text(PipPackagesWidget.InstalledVersionColumn) |
768 PipPackagesWidget.InstalledVersionColumn) |
756 |
769 |
757 self.__showPackageDetails( |
770 self.__showPackageDetails(packageName, packageVersion, |
758 packageName, packageVersion, upgradable=upgradable |
771 upgradable=upgradable) |
759 ) |
772 |
760 |
773 ####################################################################### |
761 ####################################################################### |
774 ## Search widget related methods below |
762 ## Search widget related methods below |
775 ####################################################################### |
763 ####################################################################### |
776 |
764 |
777 def __updateSearchActionButtons(self): |
765 def __updateSearchActionButtons(self): |
778 """ |
766 """ |
779 Private method to update the action button states of the search widget. |
767 Private method to update the action button states of the search widget. |
780 """ |
768 """ |
781 installEnable = ( |
769 installEnable = ( |
782 len(self.searchResultList.selectedItems()) > 0 and |
770 len(self.searchResultList.selectedItems()) > 0 |
783 self.environmentsComboBox.currentIndex() > 0 and |
771 and self.environmentsComboBox.currentIndex() > 0 |
784 self.__isPipAvailable() |
772 and self.__isPipAvailable() |
785 ) |
773 ) |
786 self.installButton.setEnabled(installEnable) |
774 self.installButton.setEnabled(installEnable) |
787 self.installUserSiteButton.setEnabled(installEnable) |
775 self.installUserSiteButton.setEnabled(installEnable) |
788 |
776 |
789 self.showDetailsButton.setEnabled( |
777 self.showDetailsButton.setEnabled( |
790 len(self.searchResultList.selectedItems()) == 1 and |
778 len(self.searchResultList.selectedItems()) == 1 and self.__isPipAvailable() |
791 self.__isPipAvailable() |
779 ) |
792 ) |
780 |
793 |
|
794 def __updateSearchButton(self): |
781 def __updateSearchButton(self): |
795 """ |
782 """ |
796 Private method to update the state of the search button. |
783 Private method to update the state of the search button. |
797 """ |
784 """ |
798 self.searchButton.setEnabled( |
785 self.searchButton.setEnabled( |
799 bool(self.searchEditName.text()) and |
786 bool(self.searchEditName.text()) and self.__isPipAvailable() |
800 self.__isPipAvailable() |
787 ) |
801 ) |
788 |
802 |
|
803 def __updateSearchMoreButton(self, enable): |
789 def __updateSearchMoreButton(self, enable): |
804 """ |
790 """ |
805 Private method to update the state of the search more button. |
791 Private method to update the state of the search more button. |
806 |
792 |
807 @param enable flag indicating the desired enable state |
793 @param enable flag indicating the desired enable state |
808 @type bool |
794 @type bool |
809 """ |
795 """ |
810 self.searchMoreButton.setEnabled( |
796 self.searchMoreButton.setEnabled( |
811 enable and |
797 enable and bool(self.searchEditName.text()) and self.__isPipAvailable() |
812 bool(self.searchEditName.text()) and |
798 ) |
813 self.__isPipAvailable() |
799 |
814 ) |
|
815 |
|
816 @pyqtSlot(bool) |
800 @pyqtSlot(bool) |
817 def on_searchToggleButton_toggled(self, checked): |
801 def on_searchToggleButton_toggled(self, checked): |
818 """ |
802 """ |
819 Private slot to togle the search widget. |
803 Private slot to togle the search widget. |
820 |
804 |
821 @param checked state of the search widget button |
805 @param checked state of the search widget button |
822 @type bool |
806 @type bool |
823 """ |
807 """ |
824 self.searchWidget.setVisible(checked) |
808 self.searchWidget.setVisible(checked) |
825 |
809 |
826 if checked: |
810 if checked: |
827 self.searchEditName.setFocus(Qt.FocusReason.OtherFocusReason) |
811 self.searchEditName.setFocus(Qt.FocusReason.OtherFocusReason) |
828 self.searchEditName.selectAll() |
812 self.searchEditName.selectAll() |
829 |
813 |
830 self.__updateSearchActionButtons() |
814 self.__updateSearchActionButtons() |
831 self.__updateSearchButton() |
815 self.__updateSearchButton() |
832 self.__updateSearchMoreButton(False) |
816 self.__updateSearchMoreButton(False) |
833 |
817 |
834 @pyqtSlot(str) |
818 @pyqtSlot(str) |
835 def on_searchEditName_textChanged(self, txt): |
819 def on_searchEditName_textChanged(self, txt): |
836 """ |
820 """ |
837 Private slot handling a change of the search term. |
821 Private slot handling a change of the search term. |
838 |
822 |
839 @param txt search term |
823 @param txt search term |
840 @type str |
824 @type str |
841 """ |
825 """ |
842 self.__updateSearchButton() |
826 self.__updateSearchButton() |
843 |
827 |
844 @pyqtSlot() |
828 @pyqtSlot() |
845 def on_searchEditName_returnPressed(self): |
829 def on_searchEditName_returnPressed(self): |
846 """ |
830 """ |
847 Private slot initiating a search via a press of the Return key. |
831 Private slot initiating a search via a press of the Return key. |
848 """ |
832 """ |
849 if ( |
833 if bool(self.searchEditName.text()) and self.__isPipAvailable(): |
850 bool(self.searchEditName.text()) and |
|
851 self.__isPipAvailable() |
|
852 ): |
|
853 self.__searchFirst() |
834 self.__searchFirst() |
854 |
835 |
855 @pyqtSlot() |
836 @pyqtSlot() |
856 def on_searchButton_clicked(self): |
837 def on_searchButton_clicked(self): |
857 """ |
838 """ |
858 Private slot handling a press of the search button. |
839 Private slot handling a press of the search button. |
859 """ |
840 """ |
860 self.__searchFirst() |
841 self.__searchFirst() |
861 |
842 |
862 @pyqtSlot() |
843 @pyqtSlot() |
863 def on_searchMoreButton_clicked(self): |
844 def on_searchMoreButton_clicked(self): |
864 """ |
845 """ |
865 Private slot handling a press of the search more button. |
846 Private slot handling a press of the search more button. |
866 """ |
847 """ |
867 self.__search(self.__lastSearchPage + 1) |
848 self.__search(self.__lastSearchPage + 1) |
868 |
849 |
869 @pyqtSlot() |
850 @pyqtSlot() |
870 def on_searchResultList_itemSelectionChanged(self): |
851 def on_searchResultList_itemSelectionChanged(self): |
871 """ |
852 """ |
872 Private slot handling changes of the search result selection. |
853 Private slot handling changes of the search result selection. |
873 """ |
854 """ |
874 self.__updateSearchActionButtons() |
855 self.__updateSearchActionButtons() |
875 |
856 |
876 def __searchFirst(self): |
857 def __searchFirst(self): |
877 """ |
858 """ |
878 Private method to perform the search for packages. |
859 Private method to perform the search for packages. |
879 """ |
860 """ |
880 self.searchResultList.clear() |
861 self.searchResultList.clear() |
881 self.searchInfoLabel.clear() |
862 self.searchInfoLabel.clear() |
882 |
863 |
883 self.__updateSearchMoreButton(False) |
864 self.__updateSearchMoreButton(False) |
884 |
865 |
885 self.__search() |
866 self.__search() |
886 |
867 |
887 def __search(self, page=1): |
868 def __search(self, page=1): |
888 """ |
869 """ |
889 Private method to perform the search by calling the PyPI search URL. |
870 Private method to perform the search by calling the PyPI search URL. |
890 |
871 |
891 @param page search page to retrieve (defaults to 1) |
872 @param page search page to retrieve (defaults to 1) |
892 @type int (optional) |
873 @type int (optional) |
893 """ |
874 """ |
894 self.__lastSearchPage = page |
875 self.__lastSearchPage = page |
895 |
876 |
896 self.searchButton.setEnabled(False) |
877 self.searchButton.setEnabled(False) |
897 |
878 |
898 searchTerm = self.searchEditName.text().strip() |
879 searchTerm = self.searchEditName.text().strip() |
899 searchTerm = bytes(QUrl.toPercentEncoding(searchTerm)).decode() |
880 searchTerm = bytes(QUrl.toPercentEncoding(searchTerm)).decode() |
900 urlQuery = QUrlQuery() |
881 urlQuery = QUrlQuery() |
901 urlQuery.addQueryItem("q", searchTerm) |
882 urlQuery.addQueryItem("q", searchTerm) |
902 urlQuery.addQueryItem("page", str(page)) |
883 urlQuery.addQueryItem("page", str(page)) |
903 url = QUrl(self.__pip.getIndexUrlSearch()) |
884 url = QUrl(self.__pip.getIndexUrlSearch()) |
904 url.setQuery(urlQuery) |
885 url.setQuery(urlQuery) |
905 |
886 |
906 request = QNetworkRequest(QUrl(url)) |
887 request = QNetworkRequest(QUrl(url)) |
907 request.setAttribute( |
888 request.setAttribute( |
908 QNetworkRequest.Attribute.CacheLoadControlAttribute, |
889 QNetworkRequest.Attribute.CacheLoadControlAttribute, |
909 QNetworkRequest.CacheLoadControl.AlwaysNetwork) |
890 QNetworkRequest.CacheLoadControl.AlwaysNetwork, |
|
891 ) |
910 reply = self.__pip.getNetworkAccessManager().get(request) |
892 reply = self.__pip.getNetworkAccessManager().get(request) |
911 reply.finished.connect( |
893 reply.finished.connect(lambda: self.__searchResponse(reply)) |
912 lambda: self.__searchResponse(reply)) |
|
913 self.__replies.append(reply) |
894 self.__replies.append(reply) |
914 |
895 |
915 def __searchResponse(self, reply): |
896 def __searchResponse(self, reply): |
916 """ |
897 """ |
917 Private method to extract the search result data from the response. |
898 Private method to extract the search result data from the response. |
918 |
899 |
919 @param reply reference to the reply object containing the data |
900 @param reply reference to the reply object containing the data |
920 @type QNetworkReply |
901 @type QNetworkReply |
921 """ |
902 """ |
922 if reply in self.__replies: |
903 if reply in self.__replies: |
923 self.__replies.remove(reply) |
904 self.__replies.remove(reply) |
924 |
905 |
925 urlQuery = QUrlQuery(reply.url()) |
906 urlQuery = QUrlQuery(reply.url()) |
926 searchTerm = urlQuery.queryItemValue("q") |
907 searchTerm = urlQuery.queryItemValue("q") |
927 |
908 |
928 if reply.error() != QNetworkReply.NetworkError.NoError: |
909 if reply.error() != QNetworkReply.NetworkError.NoError: |
929 EricMessageBox.warning( |
910 EricMessageBox.warning( |
930 None, |
911 None, |
931 self.tr("Search PyPI"), |
912 self.tr("Search PyPI"), |
932 self.tr( |
913 self.tr( |
933 "<p>Received an error while searching for <b>{0}</b>.</p>" |
914 "<p>Received an error while searching for <b>{0}</b>.</p>" |
934 "<p>Error: {1}</p>" |
915 "<p>Error: {1}</p>" |
935 ).format(searchTerm, reply.errorString()) |
916 ).format(searchTerm, reply.errorString()), |
936 ) |
917 ) |
937 reply.deleteLater() |
918 reply.deleteLater() |
938 return |
919 return |
939 |
920 |
940 data = bytes(reply.readAll()).decode() |
921 data = bytes(reply.readAll()).decode() |
941 reply.deleteLater() |
922 reply.deleteLater() |
942 |
923 |
943 results = PypiSearchResultsParser(data).getResults() |
924 results = PypiSearchResultsParser(data).getResults() |
944 if results: |
925 if results: |
945 # PyPI returns max. 20 entries per page |
926 # PyPI returns max. 20 entries per page |
946 if len(results) < 20: |
927 if len(results) < 20: |
947 msg = self.tr("%n package(s) found.", "", |
928 msg = self.tr( |
948 (self.__lastSearchPage - 1) * 20 + len(results)) |
929 "%n package(s) found.", |
|
930 "", |
|
931 (self.__lastSearchPage - 1) * 20 + len(results), |
|
932 ) |
949 self.__updateSearchMoreButton(False) |
933 self.__updateSearchMoreButton(False) |
950 else: |
934 else: |
951 msg = self.tr("Showing first {0} packages found.").format( |
935 msg = self.tr("Showing first {0} packages found.").format( |
952 self.__lastSearchPage * 20) |
936 self.__lastSearchPage * 20 |
|
937 ) |
953 self.__updateSearchMoreButton(True) |
938 self.__updateSearchMoreButton(True) |
954 self.searchInfoLabel.setText(msg) |
939 self.searchInfoLabel.setText(msg) |
955 lastItem = self.searchResultList.topLevelItem( |
940 lastItem = self.searchResultList.topLevelItem( |
956 self.searchResultList.topLevelItemCount() - 1) |
941 self.searchResultList.topLevelItemCount() - 1 |
|
942 ) |
957 else: |
943 else: |
958 self.__updateSearchMoreButton(False) |
944 self.__updateSearchMoreButton(False) |
959 if self.__lastSearchPage == 1: |
945 if self.__lastSearchPage == 1: |
960 EricMessageBox.warning( |
946 EricMessageBox.warning( |
961 self, |
947 self, |
962 self.tr("Search PyPI"), |
948 self.tr("Search PyPI"), |
963 self.tr("""<p>There were no results for <b>{0}</b>.</p>""") |
949 self.tr("""<p>There were no results for <b>{0}</b>.</p>""").format( |
964 .format(searchTerm) |
950 searchTerm |
|
951 ), |
965 ) |
952 ) |
966 self.searchInfoLabel.setText( |
953 self.searchInfoLabel.setText( |
967 self.tr("""<p>There were no results for <b>{0}</b>.</p>""") |
954 self.tr("""<p>There were no results for <b>{0}</b>.</p>""").format( |
968 .format(searchTerm) |
955 searchTerm |
|
956 ) |
969 ) |
957 ) |
970 else: |
958 else: |
971 EricMessageBox.warning( |
959 EricMessageBox.warning( |
972 self, |
960 self, |
973 self.tr("Search PyPI"), |
961 self.tr("Search PyPI"), |
974 self.tr("""<p>There were no more results for""" |
962 self.tr( |
975 """ <b>{0}</b>.</p>""").format(searchTerm) |
963 """<p>There were no more results for""" """ <b>{0}</b>.</p>""" |
|
964 ).format(searchTerm), |
976 ) |
965 ) |
977 lastItem = None |
966 lastItem = None |
978 |
967 |
979 wrapper = textwrap.TextWrapper(width=80) |
968 wrapper = textwrap.TextWrapper(width=80) |
980 for result in results: |
969 for result in results: |
981 try: |
970 try: |
982 description = "\n".join([ |
971 description = "\n".join( |
983 wrapper.fill(line) for line in |
972 [ |
984 result['description'].strip().splitlines() |
973 wrapper.fill(line) |
985 ]) |
974 for line in result["description"].strip().splitlines() |
|
975 ] |
|
976 ) |
986 except KeyError: |
977 except KeyError: |
987 description = "" |
978 description = "" |
988 date = ( |
979 date = result["released"] if "released" in result else result["created"] |
989 result["released"] |
|
990 if "released" in result else |
|
991 result["created"] |
|
992 ) |
|
993 itm = QTreeWidgetItem( |
980 itm = QTreeWidgetItem( |
994 self.searchResultList, [ |
981 self.searchResultList, |
995 result['name'].strip(), |
982 [ |
996 result['version'], |
983 result["name"].strip(), |
|
984 result["version"], |
997 date.strip(), |
985 date.strip(), |
998 description, |
986 description, |
999 ]) |
987 ], |
1000 itm.setData(0, self.SearchVersionRole, result['version']) |
988 ) |
1001 |
989 itm.setData(0, self.SearchVersionRole, result["version"]) |
|
990 |
1002 if lastItem: |
991 if lastItem: |
1003 self.searchResultList.scrollToItem( |
992 self.searchResultList.scrollToItem( |
1004 lastItem, |
993 lastItem, QAbstractItemView.ScrollHint.PositionAtTop |
1005 QAbstractItemView.ScrollHint.PositionAtTop) |
994 ) |
1006 |
995 |
1007 header = self.searchResultList.header() |
996 header = self.searchResultList.header() |
1008 header.setStretchLastSection(False) |
997 header.setStretchLastSection(False) |
1009 header.resizeSections(QHeaderView.ResizeMode.ResizeToContents) |
998 header.resizeSections(QHeaderView.ResizeMode.ResizeToContents) |
1010 headerSize = 0 |
999 headerSize = 0 |
1011 for col in range(header.count()): |
1000 for col in range(header.count()): |
1012 headerSize += header.sectionSize(col) |
1001 headerSize += header.sectionSize(col) |
1013 if headerSize < header.width(): |
1002 if headerSize < header.width(): |
1014 header.setStretchLastSection(True) |
1003 header.setStretchLastSection(True) |
1015 |
1004 |
1016 self.__finishSearch() |
1005 self.__finishSearch() |
1017 |
1006 |
1018 def __finishSearch(self): |
1007 def __finishSearch(self): |
1019 """ |
1008 """ |
1020 Private slot performing the search finishing actions. |
1009 Private slot performing the search finishing actions. |
1021 """ |
1010 """ |
1022 self.__updateSearchActionButtons() |
1011 self.__updateSearchActionButtons() |
1023 self.__updateSearchButton() |
1012 self.__updateSearchButton() |
1024 |
1013 |
1025 self.searchEditName.setFocus(Qt.FocusReason.OtherFocusReason) |
1014 self.searchEditName.setFocus(Qt.FocusReason.OtherFocusReason) |
1026 |
1015 |
1027 @pyqtSlot() |
1016 @pyqtSlot() |
1028 def on_installButton_clicked(self): |
1017 def on_installButton_clicked(self): |
1029 """ |
1018 """ |
1030 Private slot to handle pressing the Install button.. |
1019 Private slot to handle pressing the Install button.. |
1031 """ |
1020 """ |
1032 packages = [ |
1021 packages = [ |
1033 itm.text(0).strip() |
1022 itm.text(0).strip() for itm in self.searchResultList.selectedItems() |
1034 for itm in self.searchResultList.selectedItems() |
|
1035 ] |
1023 ] |
1036 self.executeInstallPackages(packages) |
1024 self.executeInstallPackages(packages) |
1037 |
1025 |
1038 @pyqtSlot() |
1026 @pyqtSlot() |
1039 def on_installUserSiteButton_clicked(self): |
1027 def on_installUserSiteButton_clicked(self): |
1040 """ |
1028 """ |
1041 Private slot to handle pressing the Install to User-Site button.. |
1029 Private slot to handle pressing the Install to User-Site button.. |
1042 """ |
1030 """ |
1043 packages = [ |
1031 packages = [ |
1044 itm.text(0).strip() |
1032 itm.text(0).strip() for itm in self.searchResultList.selectedItems() |
1045 for itm in self.searchResultList.selectedItems() |
|
1046 ] |
1033 ] |
1047 self.executeInstallPackages(packages, userSite=True) |
1034 self.executeInstallPackages(packages, userSite=True) |
1048 |
1035 |
1049 def executeInstallPackages(self, packages, userSite=False): |
1036 def executeInstallPackages(self, packages, userSite=False): |
1050 """ |
1037 """ |
1051 Public method to install the given list of packages. |
1038 Public method to install the given list of packages. |
1052 |
1039 |
1053 @param packages list of package names to be installed |
1040 @param packages list of package names to be installed |
1054 @type list of str |
1041 @type list of str |
1055 @param userSite flag indicating to install to the user directory |
1042 @param userSite flag indicating to install to the user directory |
1056 @type bool |
1043 @type bool |
1057 """ |
1044 """ |
1058 venvName = self.environmentsComboBox.currentText() |
1045 venvName = self.environmentsComboBox.currentText() |
1059 if venvName and packages: |
1046 if venvName and packages: |
1060 self.__pip.installPackages(packages, venvName=venvName, |
1047 self.__pip.installPackages(packages, venvName=venvName, userSite=userSite) |
1061 userSite=userSite) |
|
1062 self.on_refreshButton_clicked() |
1048 self.on_refreshButton_clicked() |
1063 |
1049 |
1064 @pyqtSlot() |
1050 @pyqtSlot() |
1065 def on_showDetailsButton_clicked(self): |
1051 def on_showDetailsButton_clicked(self): |
1066 """ |
1052 """ |
1067 Private slot to handle pressing the Show Details button. |
1053 Private slot to handle pressing the Show Details button. |
1068 """ |
1054 """ |
1069 self.__showSearchedDetails() |
1055 self.__showSearchedDetails() |
1070 |
1056 |
1071 @pyqtSlot(QTreeWidgetItem, int) |
1057 @pyqtSlot(QTreeWidgetItem, int) |
1072 def on_searchResultList_itemActivated(self, item, column): |
1058 def on_searchResultList_itemActivated(self, item, column): |
1073 """ |
1059 """ |
1074 Private slot reacting on an search result item activation. |
1060 Private slot reacting on an search result item activation. |
1075 |
1061 |
1076 @param item reference to the activated item |
1062 @param item reference to the activated item |
1077 @type QTreeWidgetItem |
1063 @type QTreeWidgetItem |
1078 @param column activated column |
1064 @param column activated column |
1079 @type int |
1065 @type int |
1080 """ |
1066 """ |
1081 self.__showSearchedDetails(item) |
1067 self.__showSearchedDetails(item) |
1082 |
1068 |
1083 def __showSearchedDetails(self, item=None): |
1069 def __showSearchedDetails(self, item=None): |
1084 """ |
1070 """ |
1085 Private slot to show details about the selected search result package. |
1071 Private slot to show details about the selected search result package. |
1086 |
1072 |
1087 @param item reference to the search result item to show details for |
1073 @param item reference to the search result item to show details for |
1088 @type QTreeWidgetItem |
1074 @type QTreeWidgetItem |
1089 """ |
1075 """ |
1090 self.showDetailsButton.setEnabled(False) |
1076 self.showDetailsButton.setEnabled(False) |
1091 |
1077 |
1092 if not item: |
1078 if not item: |
1093 item = self.searchResultList.selectedItems()[0] |
1079 item = self.searchResultList.selectedItems()[0] |
1094 |
1080 |
1095 packageVersion = item.data(0, self.SearchVersionRole) |
1081 packageVersion = item.data(0, self.SearchVersionRole) |
1096 packageName = item.text(0) |
1082 packageName = item.text(0) |
1097 |
1083 |
1098 self.__showPackageDetails(packageName, packageVersion, |
1084 self.__showPackageDetails(packageName, packageVersion, installable=True) |
1099 installable=True) |
1085 |
1100 |
1086 def __showPackageDetails( |
1101 def __showPackageDetails(self, packageName, packageVersion, |
1087 self, packageName, packageVersion, upgradable=False, installable=False |
1102 upgradable=False, installable=False): |
1088 ): |
1103 """ |
1089 """ |
1104 Private method to populate the package details dialog. |
1090 Private method to populate the package details dialog. |
1105 |
1091 |
1106 @param packageName name of the package to show details for |
1092 @param packageName name of the package to show details for |
1107 @type str |
1093 @type str |
1108 @param packageVersion version of the package |
1094 @param packageVersion version of the package |
1109 @type str |
1095 @type str |
1110 @param upgradable flag indicating that the package may be upgraded |
1096 @param upgradable flag indicating that the package may be upgraded |
1113 @param installable flag indicating that the package may be installed |
1099 @param installable flag indicating that the package may be installed |
1114 (defaults to False) |
1100 (defaults to False) |
1115 @type bool (optional) |
1101 @type bool (optional) |
1116 """ |
1102 """ |
1117 with EricOverrideCursor(): |
1103 with EricOverrideCursor(): |
1118 packageData = self.__pip.getPackageDetails( |
1104 packageData = self.__pip.getPackageDetails(packageName, packageVersion) |
1119 packageName, packageVersion) |
1105 |
1120 |
|
1121 if packageData: |
1106 if packageData: |
1122 from .PipPackageDetailsDialog import PipPackageDetailsDialog |
1107 from .PipPackageDetailsDialog import PipPackageDetailsDialog |
1123 |
1108 |
1124 self.showDetailsButton.setEnabled(True) |
1109 self.showDetailsButton.setEnabled(True) |
1125 |
1110 |
1126 if installable: |
1111 if installable: |
1127 buttonsMode = PipPackageDetailsDialog.ButtonInstall |
1112 buttonsMode = PipPackageDetailsDialog.ButtonInstall |
1128 elif upgradable: |
1113 elif upgradable: |
1129 buttonsMode = ( |
1114 buttonsMode = ( |
1130 PipPackageDetailsDialog.ButtonRemove | |
1115 PipPackageDetailsDialog.ButtonRemove |
1131 PipPackageDetailsDialog.ButtonUpgrade |
1116 | PipPackageDetailsDialog.ButtonUpgrade |
1132 ) |
1117 ) |
1133 else: |
1118 else: |
1134 buttonsMode = PipPackageDetailsDialog.ButtonRemove |
1119 buttonsMode = PipPackageDetailsDialog.ButtonRemove |
1135 |
1120 |
1136 if self.__packageDetailsDialog is not None: |
1121 if self.__packageDetailsDialog is not None: |
1137 self.__packageDetailsDialog.close() |
1122 self.__packageDetailsDialog.close() |
1138 |
1123 |
1139 self.__packageDetailsDialog = ( |
1124 self.__packageDetailsDialog = PipPackageDetailsDialog( |
1140 PipPackageDetailsDialog(packageData, buttonsMode=buttonsMode, |
1125 packageData, buttonsMode=buttonsMode, parent=self |
1141 parent=self) |
|
1142 ) |
1126 ) |
1143 self.__packageDetailsDialog.show() |
1127 self.__packageDetailsDialog.show() |
1144 else: |
1128 else: |
1145 EricMessageBox.warning( |
1129 EricMessageBox.warning( |
1146 self, |
1130 self, |
1147 self.tr("Search PyPI"), |
1131 self.tr("Search PyPI"), |
1148 self.tr("""<p>No package details info for <b>{0}</b>""" |
1132 self.tr( |
1149 """ available.</p>""").format(packageName)) |
1133 """<p>No package details info for <b>{0}</b>""" |
1150 |
1134 """ available.</p>""" |
|
1135 ).format(packageName), |
|
1136 ) |
|
1137 |
1151 ####################################################################### |
1138 ####################################################################### |
1152 ## Menu related methods below |
1139 ## Menu related methods below |
1153 ####################################################################### |
1140 ####################################################################### |
1154 |
1141 |
1155 def __initPipMenu(self): |
1142 def __initPipMenu(self): |
1156 """ |
1143 """ |
1157 Private method to create the super menu and attach it to the super |
1144 Private method to create the super menu and attach it to the super |
1158 menu button. |
1145 menu button. |
1159 """ |
1146 """ |
1160 self.__pipMenu = QMenu() |
1147 self.__pipMenu = QMenu() |
1161 self.__installPipAct = self.__pipMenu.addAction( |
1148 self.__installPipAct = self.__pipMenu.addAction( |
1162 self.tr("Install Pip"), |
1149 self.tr("Install Pip"), self.__installPip |
1163 self.__installPip) |
1150 ) |
1164 self.__installPipUserAct = self.__pipMenu.addAction( |
1151 self.__installPipUserAct = self.__pipMenu.addAction( |
1165 self.tr("Install Pip to User-Site"), |
1152 self.tr("Install Pip to User-Site"), self.__installPipUser |
1166 self.__installPipUser) |
1153 ) |
1167 self.__repairPipAct = self.__pipMenu.addAction( |
1154 self.__repairPipAct = self.__pipMenu.addAction( |
1168 self.tr("Repair Pip"), |
1155 self.tr("Repair Pip"), self.__repairPip |
1169 self.__repairPip) |
1156 ) |
1170 self.__pipMenu.addSeparator() |
1157 self.__pipMenu.addSeparator() |
1171 self.__installPackagesAct = self.__pipMenu.addAction( |
1158 self.__installPackagesAct = self.__pipMenu.addAction( |
1172 self.tr("Install Packages"), |
1159 self.tr("Install Packages"), self.__installPackages |
1173 self.__installPackages) |
1160 ) |
1174 self.__installLocalPackageAct = self.__pipMenu.addAction( |
1161 self.__installLocalPackageAct = self.__pipMenu.addAction( |
1175 self.tr("Install Local Package"), |
1162 self.tr("Install Local Package"), self.__installLocalPackage |
1176 self.__installLocalPackage) |
1163 ) |
1177 self.__pipMenu.addSeparator() |
1164 self.__pipMenu.addSeparator() |
1178 self.__installRequirementsAct = self.__pipMenu.addAction( |
1165 self.__installRequirementsAct = self.__pipMenu.addAction( |
1179 self.tr("Install Requirements"), |
1166 self.tr("Install Requirements"), self.__installRequirements |
1180 self.__installRequirements) |
1167 ) |
1181 self.__reinstallPackagesAct = self.__pipMenu.addAction( |
1168 self.__reinstallPackagesAct = self.__pipMenu.addAction( |
1182 self.tr("Re-Install Selected Packages"), |
1169 self.tr("Re-Install Selected Packages"), self.__reinstallPackages |
1183 self.__reinstallPackages) |
1170 ) |
1184 self.__uninstallRequirementsAct = self.__pipMenu.addAction( |
1171 self.__uninstallRequirementsAct = self.__pipMenu.addAction( |
1185 self.tr("Uninstall Requirements"), |
1172 self.tr("Uninstall Requirements"), self.__uninstallRequirements |
1186 self.__uninstallRequirements) |
1173 ) |
1187 self.__generateRequirementsAct = self.__pipMenu.addAction( |
1174 self.__generateRequirementsAct = self.__pipMenu.addAction( |
1188 self.tr("Generate Requirements..."), |
1175 self.tr("Generate Requirements..."), self.__generateRequirements |
1189 self.__generateRequirements) |
1176 ) |
1190 self.__pipMenu.addSeparator() |
1177 self.__pipMenu.addSeparator() |
1191 self.__showLicensesDialogAct = self.__pipMenu.addAction( |
1178 self.__showLicensesDialogAct = self.__pipMenu.addAction( |
1192 self.tr("Show Licenses..."), |
1179 self.tr("Show Licenses..."), self.__showLicensesDialog |
1193 self.__showLicensesDialog) |
1180 ) |
1194 self.__pipMenu.addSeparator() |
1181 self.__pipMenu.addSeparator() |
1195 self.__checkVulnerabilityAct = self.__pipMenu.addAction( |
1182 self.__checkVulnerabilityAct = self.__pipMenu.addAction( |
1196 self.tr("Check Vulnerabilities"), |
1183 self.tr("Check Vulnerabilities"), self.__updateVulnerabilityData |
1197 self.__updateVulnerabilityData) |
1184 ) |
1198 # updateVulnerabilityDbAct |
1185 # updateVulnerabilityDbAct |
1199 self.__pipMenu.addAction( |
1186 self.__pipMenu.addAction( |
1200 self.tr("Update Vulnerability Database"), |
1187 self.tr("Update Vulnerability Database"), self.__updateVulnerabilityDbCache |
1201 self.__updateVulnerabilityDbCache) |
1188 ) |
1202 self.__pipMenu.addSeparator() |
1189 self.__pipMenu.addSeparator() |
1203 self.__cyclonedxAct = self.__pipMenu.addAction( |
1190 self.__cyclonedxAct = self.__pipMenu.addAction( |
1204 self.tr("Create SBOM file"), |
1191 self.tr("Create SBOM file"), self.__createSBOMFile |
1205 self.__createSBOMFile) |
1192 ) |
1206 self.__pipMenu.addSeparator() |
1193 self.__pipMenu.addSeparator() |
1207 self.__cacheInfoAct = self.__pipMenu.addAction( |
1194 self.__cacheInfoAct = self.__pipMenu.addAction( |
1208 self.tr("Show Cache Info..."), |
1195 self.tr("Show Cache Info..."), self.__showCacheInfo |
1209 self.__showCacheInfo) |
1196 ) |
1210 self.__cacheShowListAct = self.__pipMenu.addAction( |
1197 self.__cacheShowListAct = self.__pipMenu.addAction( |
1211 self.tr("Show Cached Files..."), |
1198 self.tr("Show Cached Files..."), self.__showCacheList |
1212 self.__showCacheList) |
1199 ) |
1213 self.__cacheRemoveAct = self.__pipMenu.addAction( |
1200 self.__cacheRemoveAct = self.__pipMenu.addAction( |
1214 self.tr("Remove Cached Files..."), |
1201 self.tr("Remove Cached Files..."), self.__removeCachedFiles |
1215 self.__removeCachedFiles) |
1202 ) |
1216 self.__cachePurgeAct = self.__pipMenu.addAction( |
1203 self.__cachePurgeAct = self.__pipMenu.addAction( |
1217 self.tr("Purge Cache..."), |
1204 self.tr("Purge Cache..."), self.__purgeCache |
1218 self.__purgeCache) |
1205 ) |
1219 self.__pipMenu.addSeparator() |
1206 self.__pipMenu.addSeparator() |
1220 # editUserConfigAct |
1207 # editUserConfigAct |
1221 self.__pipMenu.addAction( |
1208 self.__pipMenu.addAction( |
1222 self.tr("Edit User Configuration..."), |
1209 self.tr("Edit User Configuration..."), self.__editUserConfiguration |
1223 self.__editUserConfiguration) |
1210 ) |
1224 self.__editVirtualenvConfigAct = self.__pipMenu.addAction( |
1211 self.__editVirtualenvConfigAct = self.__pipMenu.addAction( |
1225 self.tr("Edit Environment Configuration..."), |
1212 self.tr("Edit Environment Configuration..."), |
1226 self.__editVirtualenvConfiguration) |
1213 self.__editVirtualenvConfiguration, |
|
1214 ) |
1227 self.__pipMenu.addSeparator() |
1215 self.__pipMenu.addSeparator() |
1228 # pipConfigAct |
1216 # pipConfigAct |
1229 self.__pipMenu.addAction( |
1217 self.__pipMenu.addAction(self.tr("Configure..."), self.__pipConfigure) |
1230 self.tr("Configure..."), |
|
1231 self.__pipConfigure) |
|
1232 |
1218 |
1233 self.__pipMenu.aboutToShow.connect(self.__aboutToShowPipMenu) |
1219 self.__pipMenu.aboutToShow.connect(self.__aboutToShowPipMenu) |
1234 |
1220 |
1235 self.pipMenuButton.setMenu(self.__pipMenu) |
1221 self.pipMenuButton.setMenu(self.__pipMenu) |
1236 |
1222 |
1237 def __aboutToShowPipMenu(self): |
1223 def __aboutToShowPipMenu(self): |
1238 """ |
1224 """ |
1239 Private slot to set the action enabled status. |
1225 Private slot to set the action enabled status. |
1240 """ |
1226 """ |
1241 enable = bool(self.environmentsComboBox.currentText()) |
1227 enable = bool(self.environmentsComboBox.currentText()) |
1242 enablePip = self.__isPipAvailable() |
1228 enablePip = self.__isPipAvailable() |
1243 enablePipCache = self.__availablePipVersion() >= (20, 1, 0) |
1229 enablePipCache = self.__availablePipVersion() >= (20, 1, 0) |
1244 |
1230 |
1245 self.__installPipAct.setEnabled(not enablePip) |
1231 self.__installPipAct.setEnabled(not enablePip) |
1246 self.__installPipUserAct.setEnabled(not enablePip) |
1232 self.__installPipUserAct.setEnabled(not enablePip) |
1247 self.__repairPipAct.setEnabled(enablePip) |
1233 self.__repairPipAct.setEnabled(enablePip) |
1248 |
1234 |
1249 self.__installPackagesAct.setEnabled(enablePip) |
1235 self.__installPackagesAct.setEnabled(enablePip) |
1250 self.__installLocalPackageAct.setEnabled(enablePip) |
1236 self.__installLocalPackageAct.setEnabled(enablePip) |
1251 self.__reinstallPackagesAct.setEnabled(enablePip) |
1237 self.__reinstallPackagesAct.setEnabled(enablePip) |
1252 |
1238 |
1253 self.__installRequirementsAct.setEnabled(enablePip) |
1239 self.__installRequirementsAct.setEnabled(enablePip) |
1254 self.__uninstallRequirementsAct.setEnabled(enablePip) |
1240 self.__uninstallRequirementsAct.setEnabled(enablePip) |
1255 self.__generateRequirementsAct.setEnabled(enablePip) |
1241 self.__generateRequirementsAct.setEnabled(enablePip) |
1256 |
1242 |
1257 self.__cacheInfoAct.setEnabled(enablePipCache) |
1243 self.__cacheInfoAct.setEnabled(enablePipCache) |
1258 self.__cacheShowListAct.setEnabled(enablePipCache) |
1244 self.__cacheShowListAct.setEnabled(enablePipCache) |
1259 self.__cacheRemoveAct.setEnabled(enablePipCache) |
1245 self.__cacheRemoveAct.setEnabled(enablePipCache) |
1260 self.__cachePurgeAct.setEnabled(enablePipCache) |
1246 self.__cachePurgeAct.setEnabled(enablePipCache) |
1261 |
1247 |
1262 self.__editVirtualenvConfigAct.setEnabled(enable) |
1248 self.__editVirtualenvConfigAct.setEnabled(enable) |
1263 |
1249 |
1264 self.__checkVulnerabilityAct.setEnabled( |
1250 self.__checkVulnerabilityAct.setEnabled( |
1265 enable & self.vulnerabilityCheckBox.isEnabled()) |
1251 enable & self.vulnerabilityCheckBox.isEnabled() |
1266 |
1252 ) |
|
1253 |
1267 self.__cyclonedxAct.setEnabled(enable) |
1254 self.__cyclonedxAct.setEnabled(enable) |
1268 |
1255 |
1269 self.__showLicensesDialogAct.setEnabled(enable) |
1256 self.__showLicensesDialogAct.setEnabled(enable) |
1270 |
1257 |
1271 @pyqtSlot() |
1258 @pyqtSlot() |
1272 def __installPip(self): |
1259 def __installPip(self): |
1273 """ |
1260 """ |
1274 Private slot to install pip into the selected environment. |
1261 Private slot to install pip into the selected environment. |
1275 """ |
1262 """ |
1276 venvName = self.environmentsComboBox.currentText() |
1263 venvName = self.environmentsComboBox.currentText() |
1277 if venvName: |
1264 if venvName: |
1278 self.__pip.installPip(venvName) |
1265 self.__pip.installPip(venvName) |
1279 self.on_refreshButton_clicked() |
1266 self.on_refreshButton_clicked() |
1280 |
1267 |
1281 @pyqtSlot() |
1268 @pyqtSlot() |
1282 def __installPipUser(self): |
1269 def __installPipUser(self): |
1283 """ |
1270 """ |
1284 Private slot to install pip into the user site for the selected |
1271 Private slot to install pip into the user site for the selected |
1285 environment. |
1272 environment. |
1286 """ |
1273 """ |
1287 venvName = self.environmentsComboBox.currentText() |
1274 venvName = self.environmentsComboBox.currentText() |
1288 if venvName: |
1275 if venvName: |
1289 self.__pip.installPip(venvName, userSite=True) |
1276 self.__pip.installPip(venvName, userSite=True) |
1290 self.on_refreshButton_clicked() |
1277 self.on_refreshButton_clicked() |
1291 |
1278 |
1292 @pyqtSlot() |
1279 @pyqtSlot() |
1293 def __repairPip(self): |
1280 def __repairPip(self): |
1294 """ |
1281 """ |
1295 Private slot to repair the pip installation of the selected |
1282 Private slot to repair the pip installation of the selected |
1296 environment. |
1283 environment. |
1297 """ |
1284 """ |
1298 venvName = self.environmentsComboBox.currentText() |
1285 venvName = self.environmentsComboBox.currentText() |
1299 if venvName: |
1286 if venvName: |
1300 self.__pip.repairPip(venvName) |
1287 self.__pip.repairPip(venvName) |
1301 self.on_refreshButton_clicked() |
1288 self.on_refreshButton_clicked() |
1302 |
1289 |
1303 @pyqtSlot() |
1290 @pyqtSlot() |
1304 def __installPackages(self): |
1291 def __installPackages(self): |
1305 """ |
1292 """ |
1306 Private slot to install packages to be given by the user. |
1293 Private slot to install packages to be given by the user. |
1307 """ |
1294 """ |
1308 venvName = self.environmentsComboBox.currentText() |
1295 venvName = self.environmentsComboBox.currentText() |
1309 if venvName: |
1296 if venvName: |
1310 from .PipPackagesInputDialog import PipPackagesInputDialog |
1297 from .PipPackagesInputDialog import PipPackagesInputDialog |
|
1298 |
1311 dlg = PipPackagesInputDialog(self, self.tr("Install Packages")) |
1299 dlg = PipPackagesInputDialog(self, self.tr("Install Packages")) |
1312 if dlg.exec() == QDialog.DialogCode.Accepted: |
1300 if dlg.exec() == QDialog.DialogCode.Accepted: |
1313 packages, user = dlg.getData() |
1301 packages, user = dlg.getData() |
1314 self.executeInstallPackages(packages, userSite=user) |
1302 self.executeInstallPackages(packages, userSite=user) |
1315 |
1303 |
1316 @pyqtSlot() |
1304 @pyqtSlot() |
1317 def __installLocalPackage(self): |
1305 def __installLocalPackage(self): |
1318 """ |
1306 """ |
1319 Private slot to install a package available on local storage. |
1307 Private slot to install a package available on local storage. |
1320 """ |
1308 """ |
1321 venvName = self.environmentsComboBox.currentText() |
1309 venvName = self.environmentsComboBox.currentText() |
1322 if venvName: |
1310 if venvName: |
1323 from .PipFileSelectionDialog import PipFileSelectionDialog |
1311 from .PipFileSelectionDialog import PipFileSelectionDialog |
|
1312 |
1324 dlg = PipFileSelectionDialog(self, "package") |
1313 dlg = PipFileSelectionDialog(self, "package") |
1325 if dlg.exec() == QDialog.DialogCode.Accepted: |
1314 if dlg.exec() == QDialog.DialogCode.Accepted: |
1326 package, user = dlg.getData() |
1315 package, user = dlg.getData() |
1327 if package and os.path.exists(package): |
1316 if package and os.path.exists(package): |
1328 self.executeInstallPackages([package], userSite=user) |
1317 self.executeInstallPackages([package], userSite=user) |
1329 |
1318 |
1330 @pyqtSlot() |
1319 @pyqtSlot() |
1331 def __reinstallPackages(self): |
1320 def __reinstallPackages(self): |
1332 """ |
1321 """ |
1333 Private slot to force a re-installation of the selected packages. |
1322 Private slot to force a re-installation of the selected packages. |
1334 """ |
1323 """ |
1335 packages = [itm.text(PipPackagesWidget.PackageColumn) |
1324 packages = [ |
1336 for itm in self.packagesList.selectedItems()] |
1325 itm.text(PipPackagesWidget.PackageColumn) |
|
1326 for itm in self.packagesList.selectedItems() |
|
1327 ] |
1337 venvName = self.environmentsComboBox.currentText() |
1328 venvName = self.environmentsComboBox.currentText() |
1338 if venvName and packages: |
1329 if venvName and packages: |
1339 self.__pip.installPackages(packages, venvName=venvName, |
1330 self.__pip.installPackages(packages, venvName=venvName, forceReinstall=True) |
1340 forceReinstall=True) |
|
1341 self.on_refreshButton_clicked() |
1331 self.on_refreshButton_clicked() |
1342 |
1332 |
1343 @pyqtSlot() |
1333 @pyqtSlot() |
1344 def __installRequirements(self): |
1334 def __installRequirements(self): |
1345 """ |
1335 """ |
1346 Private slot to install packages as given in a requirements file. |
1336 Private slot to install packages as given in a requirements file. |
1347 """ |
1337 """ |
1348 venvName = self.environmentsComboBox.currentText() |
1338 venvName = self.environmentsComboBox.currentText() |
1349 if venvName: |
1339 if venvName: |
1350 self.__pip.installRequirements(venvName) |
1340 self.__pip.installRequirements(venvName) |
1351 self.on_refreshButton_clicked() |
1341 self.on_refreshButton_clicked() |
1352 |
1342 |
1353 @pyqtSlot() |
1343 @pyqtSlot() |
1354 def __uninstallRequirements(self): |
1344 def __uninstallRequirements(self): |
1355 """ |
1345 """ |
1356 Private slot to uninstall packages as given in a requirements file. |
1346 Private slot to uninstall packages as given in a requirements file. |
1357 """ |
1347 """ |
1358 venvName = self.environmentsComboBox.currentText() |
1348 venvName = self.environmentsComboBox.currentText() |
1359 if venvName: |
1349 if venvName: |
1360 self.__pip.uninstallRequirements(venvName) |
1350 self.__pip.uninstallRequirements(venvName) |
1361 self.on_refreshButton_clicked() |
1351 self.on_refreshButton_clicked() |
1362 |
1352 |
1363 @pyqtSlot() |
1353 @pyqtSlot() |
1364 def __generateRequirements(self): |
1354 def __generateRequirements(self): |
1365 """ |
1355 """ |
1366 Private slot to generate the contents for a requirements file. |
1356 Private slot to generate the contents for a requirements file. |
1367 """ |
1357 """ |
1368 venvName = self.environmentsComboBox.currentText() |
1358 venvName = self.environmentsComboBox.currentText() |
1369 if venvName: |
1359 if venvName: |
1370 from .PipFreezeDialog import PipFreezeDialog |
1360 from .PipFreezeDialog import PipFreezeDialog |
|
1361 |
1371 self.__freezeDialog = PipFreezeDialog(self.__pip, self) |
1362 self.__freezeDialog = PipFreezeDialog(self.__pip, self) |
1372 self.__freezeDialog.show() |
1363 self.__freezeDialog.show() |
1373 self.__freezeDialog.start(venvName) |
1364 self.__freezeDialog.start(venvName) |
1374 |
1365 |
1375 @pyqtSlot() |
1366 @pyqtSlot() |
1376 def __editUserConfiguration(self): |
1367 def __editUserConfiguration(self): |
1377 """ |
1368 """ |
1378 Private slot to edit the user configuration. |
1369 Private slot to edit the user configuration. |
1379 """ |
1370 """ |
1380 self.__editConfiguration() |
1371 self.__editConfiguration() |
1381 |
1372 |
1382 @pyqtSlot() |
1373 @pyqtSlot() |
1383 def __editVirtualenvConfiguration(self): |
1374 def __editVirtualenvConfiguration(self): |
1384 """ |
1375 """ |
1385 Private slot to edit the configuration of the selected environment. |
1376 Private slot to edit the configuration of the selected environment. |
1386 """ |
1377 """ |
1387 venvName = self.environmentsComboBox.currentText() |
1378 venvName = self.environmentsComboBox.currentText() |
1388 if venvName: |
1379 if venvName: |
1389 self.__editConfiguration(venvName=venvName) |
1380 self.__editConfiguration(venvName=venvName) |
1390 |
1381 |
1391 def __editConfiguration(self, venvName=""): |
1382 def __editConfiguration(self, venvName=""): |
1392 """ |
1383 """ |
1393 Private method to edit a configuration. |
1384 Private method to edit a configuration. |
1394 |
1385 |
1395 @param venvName name of the environment to act upon |
1386 @param venvName name of the environment to act upon |
1396 @type str |
1387 @type str |
1397 """ |
1388 """ |
1398 from QScintilla.MiniEditor import MiniEditor |
1389 from QScintilla.MiniEditor import MiniEditor |
|
1390 |
1399 if venvName: |
1391 if venvName: |
1400 cfgFile = self.__pip.getVirtualenvConfig(venvName) |
1392 cfgFile = self.__pip.getVirtualenvConfig(venvName) |
1401 if not cfgFile: |
1393 if not cfgFile: |
1402 return |
1394 return |
1403 else: |
1395 else: |
1405 cfgDir = os.path.dirname(cfgFile) |
1397 cfgDir = os.path.dirname(cfgFile) |
1406 if not cfgDir: |
1398 if not cfgDir: |
1407 EricMessageBox.critical( |
1399 EricMessageBox.critical( |
1408 None, |
1400 None, |
1409 self.tr("Edit Configuration"), |
1401 self.tr("Edit Configuration"), |
1410 self.tr("""No valid configuration path determined.""" |
1402 self.tr("""No valid configuration path determined.""" """ Aborting"""), |
1411 """ Aborting""")) |
1403 ) |
1412 return |
1404 return |
1413 |
1405 |
1414 try: |
1406 try: |
1415 if not os.path.isdir(cfgDir): |
1407 if not os.path.isdir(cfgDir): |
1416 os.makedirs(cfgDir) |
1408 os.makedirs(cfgDir) |
1417 except OSError: |
1409 except OSError: |
1418 EricMessageBox.critical( |
1410 EricMessageBox.critical( |
1419 None, |
1411 None, |
1420 self.tr("Edit Configuration"), |
1412 self.tr("Edit Configuration"), |
1421 self.tr("""No valid configuration path determined.""" |
1413 self.tr("""No valid configuration path determined.""" """ Aborting"""), |
1422 """ Aborting""")) |
1414 ) |
1423 return |
1415 return |
1424 |
1416 |
1425 if not os.path.exists(cfgFile): |
1417 if not os.path.exists(cfgFile): |
1426 with contextlib.suppress(OSError), open(cfgFile, "w") as f: |
1418 with contextlib.suppress(OSError), open(cfgFile, "w") as f: |
1427 f.write("[global]\n") |
1419 f.write("[global]\n") |
1428 |
1420 |
1429 # check, if the destination is writeable |
1421 # check, if the destination is writeable |
1430 if not os.access(cfgFile, os.W_OK): |
1422 if not os.access(cfgFile, os.W_OK): |
1431 EricMessageBox.critical( |
1423 EricMessageBox.critical( |
1432 None, |
1424 None, |
1433 self.tr("Edit Configuration"), |
1425 self.tr("Edit Configuration"), |
1434 self.tr("""No valid configuration path determined.""" |
1426 self.tr("""No valid configuration path determined.""" """ Aborting"""), |
1435 """ Aborting""")) |
1427 ) |
1436 return |
1428 return |
1437 |
1429 |
1438 self.__editor = MiniEditor(cfgFile, "Properties") |
1430 self.__editor = MiniEditor(cfgFile, "Properties") |
1439 self.__editor.show() |
1431 self.__editor.show() |
1440 |
1432 |
1441 def __pipConfigure(self): |
1433 def __pipConfigure(self): |
1442 """ |
1434 """ |
1443 Private slot to open the configuration page. |
1435 Private slot to open the configuration page. |
1444 """ |
1436 """ |
1445 ericApp().getObject("UserInterface").showPreferences("pipPage") |
1437 ericApp().getObject("UserInterface").showPreferences("pipPage") |
1446 |
1438 |
1447 @pyqtSlot() |
1439 @pyqtSlot() |
1448 def __showCacheInfo(self): |
1440 def __showCacheInfo(self): |
1449 """ |
1441 """ |
1450 Private slot to show information about the cache. |
1442 Private slot to show information about the cache. |
1451 """ |
1443 """ |
1452 venvName = self.environmentsComboBox.currentText() |
1444 venvName = self.environmentsComboBox.currentText() |
1453 if venvName: |
1445 if venvName: |
1454 self.__pip.showCacheInfo(venvName) |
1446 self.__pip.showCacheInfo(venvName) |
1455 |
1447 |
1456 @pyqtSlot() |
1448 @pyqtSlot() |
1457 def __showCacheList(self): |
1449 def __showCacheList(self): |
1458 """ |
1450 """ |
1459 Private slot to show a list of cached files. |
1451 Private slot to show a list of cached files. |
1460 """ |
1452 """ |
1461 venvName = self.environmentsComboBox.currentText() |
1453 venvName = self.environmentsComboBox.currentText() |
1462 if venvName: |
1454 if venvName: |
1463 self.__pip.cacheList(venvName) |
1455 self.__pip.cacheList(venvName) |
1464 |
1456 |
1465 @pyqtSlot() |
1457 @pyqtSlot() |
1466 def __removeCachedFiles(self): |
1458 def __removeCachedFiles(self): |
1467 """ |
1459 """ |
1468 Private slot to remove files from the pip cache. |
1460 Private slot to remove files from the pip cache. |
1469 """ |
1461 """ |
1470 venvName = self.environmentsComboBox.currentText() |
1462 venvName = self.environmentsComboBox.currentText() |
1471 if venvName: |
1463 if venvName: |
1472 self.__pip.cacheRemove(venvName) |
1464 self.__pip.cacheRemove(venvName) |
1473 |
1465 |
1474 @pyqtSlot() |
1466 @pyqtSlot() |
1475 def __purgeCache(self): |
1467 def __purgeCache(self): |
1476 """ |
1468 """ |
1477 Private slot to empty the pip cache. |
1469 Private slot to empty the pip cache. |
1478 """ |
1470 """ |
1479 venvName = self.environmentsComboBox.currentText() |
1471 venvName = self.environmentsComboBox.currentText() |
1480 if venvName: |
1472 if venvName: |
1481 self.__pip.cachePurge(venvName) |
1473 self.__pip.cachePurge(venvName) |
1482 |
1474 |
1483 ################################################################## |
1475 ################################################################## |
1484 ## Interface to the vulnerability checks below |
1476 ## Interface to the vulnerability checks below |
1485 ################################################################## |
1477 ################################################################## |
1486 |
1478 |
1487 @pyqtSlot(bool) |
1479 @pyqtSlot(bool) |
1488 def on_vulnerabilityCheckBox_clicked(self, checked): |
1480 def on_vulnerabilityCheckBox_clicked(self, checked): |
1489 """ |
1481 """ |
1490 Private slot handling a change of the automatic vulnerability checks. |
1482 Private slot handling a change of the automatic vulnerability checks. |
1491 |
1483 |
1492 @param checked flag indicating the state of the check box |
1484 @param checked flag indicating the state of the check box |
1493 @type bool |
1485 @type bool |
1494 """ |
1486 """ |
1495 if checked: |
1487 if checked: |
1496 self.__updateVulnerabilityData(clearFirst=True) |
1488 self.__updateVulnerabilityData(clearFirst=True) |
1497 |
1489 |
1498 self.packagesList.header().setSectionHidden( |
1490 self.packagesList.header().setSectionHidden( |
1499 PipPackagesWidget.VulnerabilityColumn, not checked) |
1491 PipPackagesWidget.VulnerabilityColumn, not checked |
1500 |
1492 ) |
|
1493 |
1501 @pyqtSlot() |
1494 @pyqtSlot() |
1502 def __clearVulnerabilityInfo(self): |
1495 def __clearVulnerabilityInfo(self): |
1503 """ |
1496 """ |
1504 Private slot to clear the vulnerability info. |
1497 Private slot to clear the vulnerability info. |
1505 """ |
1498 """ |
1506 for row in range(self.packagesList.topLevelItemCount()): |
1499 for row in range(self.packagesList.topLevelItemCount()): |
1507 itm = self.packagesList.topLevelItem(row) |
1500 itm = self.packagesList.topLevelItem(row) |
1508 itm.setText(PipPackagesWidget.VulnerabilityColumn, "") |
1501 itm.setText(PipPackagesWidget.VulnerabilityColumn, "") |
1509 itm.setToolTip(PipPackagesWidget.VulnerabilityColumn, "") |
1502 itm.setToolTip(PipPackagesWidget.VulnerabilityColumn, "") |
1510 itm.setIcon(PipPackagesWidget.VulnerabilityColumn, QIcon()) |
1503 itm.setIcon(PipPackagesWidget.VulnerabilityColumn, QIcon()) |
1511 itm.setData(PipPackagesWidget.VulnerabilityColumn, |
1504 itm.setData( |
1512 PipPackagesWidget.VulnerabilityRole, |
1505 PipPackagesWidget.VulnerabilityColumn, |
1513 None) |
1506 PipPackagesWidget.VulnerabilityRole, |
1514 |
1507 None, |
|
1508 ) |
|
1509 |
1515 @pyqtSlot() |
1510 @pyqtSlot() |
1516 def __updateVulnerabilityData(self, clearFirst=True): |
1511 def __updateVulnerabilityData(self, clearFirst=True): |
1517 """ |
1512 """ |
1518 Private slot to update the shown vulnerability info. |
1513 Private slot to update the shown vulnerability info. |
1519 |
1514 |
1520 @param clearFirst flag indicating to clear the vulnerability info first |
1515 @param clearFirst flag indicating to clear the vulnerability info first |
1521 (defaults to True) |
1516 (defaults to True) |
1522 @type bool (optional) |
1517 @type bool (optional) |
1523 """ |
1518 """ |
1524 if clearFirst: |
1519 if clearFirst: |
1525 self.__clearVulnerabilityInfo() |
1520 self.__clearVulnerabilityInfo() |
1526 |
1521 |
1527 packages = [] |
1522 packages = [] |
1528 for row in range(self.packagesList.topLevelItemCount()): |
1523 for row in range(self.packagesList.topLevelItemCount()): |
1529 itm = self.packagesList.topLevelItem(row) |
1524 itm = self.packagesList.topLevelItem(row) |
1530 packages.append(Package( |
1525 packages.append( |
1531 name=itm.text(PipPackagesWidget.PackageColumn), |
1526 Package( |
1532 version=itm.text(PipPackagesWidget.InstalledVersionColumn) |
1527 name=itm.text(PipPackagesWidget.PackageColumn), |
1533 )) |
1528 version=itm.text(PipPackagesWidget.InstalledVersionColumn), |
1534 |
1529 ) |
1535 error, vulnerabilities = ( |
1530 ) |
1536 self.__pip.getVulnerabilityChecker().check(packages) |
1531 |
1537 ) |
1532 error, vulnerabilities = self.__pip.getVulnerabilityChecker().check(packages) |
1538 if error == VulnerabilityCheckError.OK: |
1533 if error == VulnerabilityCheckError.OK: |
1539 for package in vulnerabilities: |
1534 for package in vulnerabilities: |
1540 items = self.packagesList.findItems( |
1535 items = self.packagesList.findItems( |
1541 package, |
1536 package, Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive |
1542 Qt.MatchFlag.MatchExactly | |
|
1543 Qt.MatchFlag.MatchCaseSensitive |
|
1544 ) |
1537 ) |
1545 if items: |
1538 if items: |
1546 itm = items[0] |
1539 itm = items[0] |
1547 itm.setData( |
1540 itm.setData( |
1548 PipPackagesWidget.VulnerabilityColumn, |
1541 PipPackagesWidget.VulnerabilityColumn, |
1549 PipPackagesWidget.VulnerabilityRole, |
1542 PipPackagesWidget.VulnerabilityRole, |
1550 vulnerabilities[package] |
1543 vulnerabilities[package], |
1551 ) |
1544 ) |
1552 affected = {v.spec for v in vulnerabilities[package]} |
1545 affected = {v.spec for v in vulnerabilities[package]} |
1553 itm.setText( |
1546 itm.setText( |
1554 PipPackagesWidget.VulnerabilityColumn, |
1547 PipPackagesWidget.VulnerabilityColumn, ", ".join(affected) |
1555 ', '.join(affected) |
|
1556 ) |
1548 ) |
1557 itm.setIcon( |
1549 itm.setIcon( |
1558 PipPackagesWidget.VulnerabilityColumn, |
1550 PipPackagesWidget.VulnerabilityColumn, |
1559 UI.PixmapCache.getIcon("securityLow") |
1551 UI.PixmapCache.getIcon("securityLow"), |
1560 ) |
1552 ) |
1561 |
1553 |
1562 elif error in (VulnerabilityCheckError.FullDbUnavailable, |
1554 elif error in ( |
1563 VulnerabilityCheckError.SummaryDbUnavailable): |
1555 VulnerabilityCheckError.FullDbUnavailable, |
|
1556 VulnerabilityCheckError.SummaryDbUnavailable, |
|
1557 ): |
1564 self.vulnerabilityCheckBox.setChecked(False) |
1558 self.vulnerabilityCheckBox.setChecked(False) |
1565 self.vulnerabilityCheckBox.setEnabled(False) |
1559 self.vulnerabilityCheckBox.setEnabled(False) |
1566 self.packagesList.setColumnHidden( |
1560 self.packagesList.setColumnHidden( |
1567 PipPackagesWidget.VulnerabilityColumn, True) |
1561 PipPackagesWidget.VulnerabilityColumn, True |
1568 |
1562 ) |
|
1563 |
1569 @pyqtSlot() |
1564 @pyqtSlot() |
1570 def __updateVulnerabilityDbCache(self): |
1565 def __updateVulnerabilityDbCache(self): |
1571 """ |
1566 """ |
1572 Private slot to initiate an update of the local cache of the |
1567 Private slot to initiate an update of the local cache of the |
1573 vulnerability database. |
1568 vulnerability database. |
1574 """ |
1569 """ |
1575 with EricOverrideCursor(): |
1570 with EricOverrideCursor(): |
1576 self.__pip.getVulnerabilityChecker().updateVulnerabilityDb() |
1571 self.__pip.getVulnerabilityChecker().updateVulnerabilityDb() |
1577 |
1572 |
1578 def __showVulnerabilityInformation(self, packageName, packageVersion, |
1573 def __showVulnerabilityInformation( |
1579 vulnerabilities): |
1574 self, packageName, packageVersion, vulnerabilities |
|
1575 ): |
1580 """ |
1576 """ |
1581 Private method to show the detected vulnerability data. |
1577 Private method to show the detected vulnerability data. |
1582 |
1578 |
1583 @param packageName name of the package |
1579 @param packageName name of the package |
1584 @type str |
1580 @type str |
1585 @param packageVersion installed version number |
1581 @param packageVersion installed version number |
1586 @type str |
1582 @type str |
1587 @param vulnerabilities list of vulnerabilities |
1583 @param vulnerabilities list of vulnerabilities |
1588 @type list of Vulnerability |
1584 @type list of Vulnerability |
1589 """ |
1585 """ |
1590 header = ( |
1586 header = self.tr("{0} {1}", "package name, package version").format( |
1591 self.tr("{0} {1}", "package name, package version") |
1587 packageName, packageVersion |
1592 .format(packageName, packageVersion) |
|
1593 ) |
1588 ) |
1594 topItem = QTreeWidgetItem(self.infoWidget, [header]) |
1589 topItem = QTreeWidgetItem(self.infoWidget, [header]) |
1595 topItem.setFirstColumnSpanned(True) |
1590 topItem.setFirstColumnSpanned(True) |
1596 topItem.setExpanded(True) |
1591 topItem.setExpanded(True) |
1597 font = topItem.font(0) |
1592 font = topItem.font(0) |
1598 font.setBold(True) |
1593 font.setBold(True) |
1599 topItem.setFont(0, font) |
1594 topItem.setFont(0, font) |
1600 |
1595 |
1601 for vulnerability in vulnerabilities: |
1596 for vulnerability in vulnerabilities: |
1602 title = ( |
1597 title = ( |
1603 vulnerability.cve |
1598 vulnerability.cve |
1604 if vulnerability.cve else |
1599 if vulnerability.cve |
1605 vulnerability.vulnerabilityId |
1600 else vulnerability.vulnerabilityId |
1606 ) |
1601 ) |
1607 titleItem = QTreeWidgetItem(topItem, [title]) |
1602 titleItem = QTreeWidgetItem(topItem, [title]) |
1608 titleItem.setFirstColumnSpanned(True) |
1603 titleItem.setFirstColumnSpanned(True) |
1609 titleItem.setExpanded(True) |
1604 titleItem.setExpanded(True) |
1610 |
1605 |
1611 QTreeWidgetItem( |
1606 QTreeWidgetItem( |
1612 titleItem, |
1607 titleItem, [self.tr("Affected Version:"), vulnerability.spec] |
1613 [self.tr("Affected Version:"), vulnerability.spec]) |
1608 ) |
1614 itm = QTreeWidgetItem( |
1609 itm = QTreeWidgetItem( |
1615 titleItem, |
1610 titleItem, [self.tr("Advisory:"), vulnerability.advisory] |
1616 [self.tr("Advisory:"), vulnerability.advisory]) |
1611 ) |
1617 itm.setToolTip(1, "<p>{0}</p>".format( |
1612 itm.setToolTip( |
1618 vulnerability.advisory.replace("\r\n", "<br/>") |
1613 1, "<p>{0}</p>".format(vulnerability.advisory.replace("\r\n", "<br/>")) |
1619 )) |
1614 ) |
1620 |
1615 |
1621 self.infoWidget.scrollToTop() |
1616 self.infoWidget.scrollToTop() |
1622 self.infoWidget.resizeColumnToContents(0) |
1617 self.infoWidget.resizeColumnToContents(0) |
1623 |
1618 |
1624 header = self.infoWidget.header() |
1619 header = self.infoWidget.header() |
1625 header.setStretchLastSection(True) |
1620 header.setStretchLastSection(True) |
1626 |
1621 |
1627 ####################################################################### |
1622 ####################################################################### |
1628 ## Dependency tree related methods below |
1623 ## Dependency tree related methods below |
1629 ####################################################################### |
1624 ####################################################################### |
1630 |
1625 |
1631 @pyqtSlot(bool) |
1626 @pyqtSlot(bool) |
1632 def on_viewToggleButton_toggled(self, checked): |
1627 def on_viewToggleButton_toggled(self, checked): |
1633 """ |
1628 """ |
1634 Private slot handling the view selection. |
1629 Private slot handling the view selection. |
1635 |
1630 |
1636 @param checked state of the toggle button |
1631 @param checked state of the toggle button |
1637 @type bool |
1632 @type bool |
1638 """ |
1633 """ |
1639 if checked: |
1634 if checked: |
1640 self.viewsStackWidget.setCurrentWidget( |
1635 self.viewsStackWidget.setCurrentWidget(self.dependenciesPage) |
1641 self.dependenciesPage) |
|
1642 self.__refreshDependencyTree() |
1636 self.__refreshDependencyTree() |
1643 else: |
1637 else: |
1644 self.viewsStackWidget.setCurrentWidget( |
1638 self.viewsStackWidget.setCurrentWidget(self.packagesPage) |
1645 self.packagesPage) |
|
1646 self.__refreshPackagesList() |
1639 self.__refreshPackagesList() |
1647 |
1640 |
1648 @pyqtSlot(bool) |
1641 @pyqtSlot(bool) |
1649 def on_requiresButton_toggled(self, checked): |
1642 def on_requiresButton_toggled(self, checked): |
1650 """ |
1643 """ |
1651 Private slot handling the selection of the view type. |
1644 Private slot handling the selection of the view type. |
1652 |
1645 |
1653 @param checked state of the radio button (unused) |
1646 @param checked state of the radio button (unused) |
1654 @type bool |
1647 @type bool |
1655 """ |
1648 """ |
1656 self.__refreshDependencyTree() |
1649 self.__refreshDependencyTree() |
1657 |
1650 |
1658 @pyqtSlot() |
1651 @pyqtSlot() |
1659 def on_localDepCheckBox_clicked(self): |
1652 def on_localDepCheckBox_clicked(self): |
1660 """ |
1653 """ |
1661 Private slot handling the switching of the local mode. |
1654 Private slot handling the switching of the local mode. |
1662 """ |
1655 """ |
1663 self.__refreshDependencyTree() |
1656 self.__refreshDependencyTree() |
1664 |
1657 |
1665 @pyqtSlot() |
1658 @pyqtSlot() |
1666 def on_userDepCheckBox_clicked(self): |
1659 def on_userDepCheckBox_clicked(self): |
1667 """ |
1660 """ |
1668 Private slot handling the switching of the 'user-site' mode. |
1661 Private slot handling the switching of the 'user-site' mode. |
1669 """ |
1662 """ |
1670 self.__refreshDependencyTree() |
1663 self.__refreshDependencyTree() |
1671 |
1664 |
1672 def __refreshDependencyTree(self): |
1665 def __refreshDependencyTree(self): |
1673 """ |
1666 """ |
1674 Private method to refresh the dependency tree. |
1667 Private method to refresh the dependency tree. |
1675 """ |
1668 """ |
1676 self.dependenciesList.clear() |
1669 self.dependenciesList.clear() |
1683 venvName, |
1676 venvName, |
1684 localPackages=self.localDepCheckBox.isChecked(), |
1677 localPackages=self.localDepCheckBox.isChecked(), |
1685 usersite=self.userDepCheckBox.isChecked(), |
1678 usersite=self.userDepCheckBox.isChecked(), |
1686 reverse=self.requiredByButton.isChecked(), |
1679 reverse=self.requiredByButton.isChecked(), |
1687 ) |
1680 ) |
1688 |
1681 |
1689 self.dependenciesList.setUpdatesEnabled(False) |
1682 self.dependenciesList.setUpdatesEnabled(False) |
1690 for dependency in dependencies: |
1683 for dependency in dependencies: |
1691 self.__addDependency(dependency, self.dependenciesList) |
1684 self.__addDependency(dependency, self.dependenciesList) |
1692 |
1685 |
1693 self.dependenciesList.sortItems( |
1686 self.dependenciesList.sortItems( |
1694 PipPackagesWidget.DepPackageColumn, |
1687 PipPackagesWidget.DepPackageColumn, Qt.SortOrder.AscendingOrder |
1695 Qt.SortOrder.AscendingOrder) |
1688 ) |
1696 for col in range(self.dependenciesList.columnCount()): |
1689 for col in range(self.dependenciesList.columnCount()): |
1697 self.dependenciesList.resizeColumnToContents(col) |
1690 self.dependenciesList.resizeColumnToContents(col) |
1698 self.dependenciesList.setUpdatesEnabled(True) |
1691 self.dependenciesList.setUpdatesEnabled(True) |
1699 |
1692 |
1700 self.__updateDepActionButtons() |
1693 self.__updateDepActionButtons() |
1701 |
1694 |
1702 def __addDependency(self, dependency, parent): |
1695 def __addDependency(self, dependency, parent): |
1703 """ |
1696 """ |
1704 Private method to add a dependency branch to a given parent. |
1697 Private method to add a dependency branch to a given parent. |
1705 |
1698 |
1706 @param dependency dependency to be added |
1699 @param dependency dependency to be added |
1707 @type dict |
1700 @type dict |
1708 @param parent reference to the parent item |
1701 @param parent reference to the parent item |
1709 @type QTreeWidget or QTreeWidgetItem |
1702 @type QTreeWidget or QTreeWidgetItem |
1710 """ |
1703 """ |
1711 itm = QTreeWidgetItem(parent, [ |
1704 itm = QTreeWidgetItem( |
1712 dependency["package_name"], |
1705 parent, |
1713 dependency["installed_version"], |
1706 [ |
1714 dependency["required_version"], |
1707 dependency["package_name"], |
1715 ]) |
1708 dependency["installed_version"], |
|
1709 dependency["required_version"], |
|
1710 ], |
|
1711 ) |
1716 itm.setExpanded(True) |
1712 itm.setExpanded(True) |
1717 |
1713 |
1718 if dependency["installed_version"] == "?": |
1714 if dependency["installed_version"] == "?": |
1719 itm.setText(PipPackagesWidget.DepInstalledVersionColumn, |
1715 itm.setText(PipPackagesWidget.DepInstalledVersionColumn, self.tr("unknown")) |
1720 self.tr("unknown")) |
1716 |
1721 |
|
1722 if dependency["required_version"].lower() not in ("any", "?"): |
1717 if dependency["required_version"].lower() not in ("any", "?"): |
1723 spec = ( |
1718 spec = ( |
1724 "=={0}".format(dependency["required_version"]) |
1719 "=={0}".format(dependency["required_version"]) |
1725 if dependency["required_version"][0] in "0123456789" else |
1720 if dependency["required_version"][0] in "0123456789" |
1726 dependency["required_version"] |
1721 else dependency["required_version"] |
1727 ) |
1722 ) |
1728 specifierSet = SpecifierSet(specifiers=spec) |
1723 specifierSet = SpecifierSet(specifiers=spec) |
1729 if not specifierSet.contains(dependency["installed_version"]): |
1724 if not specifierSet.contains(dependency["installed_version"]): |
1730 itm.setIcon(PipPackagesWidget.DepRequiredVersionColumn, |
1725 itm.setIcon( |
1731 UI.PixmapCache.getIcon("warning")) |
1726 PipPackagesWidget.DepRequiredVersionColumn, |
1732 |
1727 UI.PixmapCache.getIcon("warning"), |
|
1728 ) |
|
1729 |
1733 elif dependency["required_version"].lower() == "any": |
1730 elif dependency["required_version"].lower() == "any": |
1734 itm.setText(PipPackagesWidget.DepRequiredVersionColumn, |
1731 itm.setText(PipPackagesWidget.DepRequiredVersionColumn, self.tr("any")) |
1735 self.tr("any")) |
1732 |
1736 |
|
1737 elif dependency["required_version"] == "?": |
1733 elif dependency["required_version"] == "?": |
1738 itm.setText(PipPackagesWidget.DepRequiredVersionColumn, |
1734 itm.setText(PipPackagesWidget.DepRequiredVersionColumn, self.tr("unknown")) |
1739 self.tr("unknown")) |
1735 |
1740 |
|
1741 # recursively add sub-dependencies |
1736 # recursively add sub-dependencies |
1742 for dep in dependency["dependencies"]: |
1737 for dep in dependency["dependencies"]: |
1743 self.__addDependency(dep, itm) |
1738 self.__addDependency(dep, itm) |
1744 |
1739 |
1745 @pyqtSlot(QTreeWidgetItem, int) |
1740 @pyqtSlot(QTreeWidgetItem, int) |
1746 def on_dependenciesList_itemActivated(self, item, column): |
1741 def on_dependenciesList_itemActivated(self, item, column): |
1747 """ |
1742 """ |
1748 Private slot reacting on a package item of the dependency tree being |
1743 Private slot reacting on a package item of the dependency tree being |
1749 activated. |
1744 activated. |
1750 |
1745 |
1751 @param item reference to the activated item |
1746 @param item reference to the activated item |
1752 @type QTreeWidgetItem |
1747 @type QTreeWidgetItem |
1753 @param column activated column |
1748 @param column activated column |
1754 @type int |
1749 @type int |
1755 """ |
1750 """ |
1756 packageName = item.text(PipPackagesWidget.DepPackageColumn) |
1751 packageName = item.text(PipPackagesWidget.DepPackageColumn) |
1757 packageVersion = item.text( |
1752 packageVersion = item.text(PipPackagesWidget.DepInstalledVersionColumn) |
1758 PipPackagesWidget.DepInstalledVersionColumn) |
1753 |
1759 |
|
1760 self.__showPackageDetails(packageName, packageVersion) |
1754 self.__showPackageDetails(packageName, packageVersion) |
1761 |
1755 |
1762 @pyqtSlot() |
1756 @pyqtSlot() |
1763 def on_dependenciesList_itemSelectionChanged(self): |
1757 def on_dependenciesList_itemSelectionChanged(self): |
1764 """ |
1758 """ |
1765 Private slot reacting on a change of selected items of the dependency |
1759 Private slot reacting on a change of selected items of the dependency |
1766 tree. |
1760 tree. |
1767 """ |
1761 """ |
1768 if len(self.dependenciesList.selectedItems()) == 0: |
1762 if len(self.dependenciesList.selectedItems()) == 0: |
1769 self.dependencyInfoWidget.clear() |
1763 self.dependencyInfoWidget.clear() |
1770 |
1764 |
1771 @pyqtSlot(QTreeWidgetItem, int) |
1765 @pyqtSlot(QTreeWidgetItem, int) |
1772 def on_dependenciesList_itemPressed(self, item, column): |
1766 def on_dependenciesList_itemPressed(self, item, column): |
1773 """ |
1767 """ |
1774 Private slot reacting on a package item of the dependency tree being |
1768 Private slot reacting on a package item of the dependency tree being |
1775 pressed. |
1769 pressed. |
1776 |
1770 |
1777 @param item reference to the pressed item |
1771 @param item reference to the pressed item |
1778 @type QTreeWidgetItem |
1772 @type QTreeWidgetItem |
1779 @param column pressed column |
1773 @param column pressed column |
1780 @type int |
1774 @type int |
1781 """ |
1775 """ |
1782 self.dependencyInfoWidget.clear() |
1776 self.dependencyInfoWidget.clear() |
1783 |
1777 |
1784 if item is not None: |
1778 if item is not None: |
1785 self.__showPackageInformation( |
1779 self.__showPackageInformation( |
1786 item.text(PipPackagesWidget.DepPackageColumn), |
1780 item.text(PipPackagesWidget.DepPackageColumn), self.dependencyInfoWidget |
1787 self.dependencyInfoWidget |
1781 ) |
1788 ) |
1782 |
1789 |
|
1790 self.__updateDepActionButtons() |
1783 self.__updateDepActionButtons() |
1791 |
1784 |
1792 @pyqtSlot() |
1785 @pyqtSlot() |
1793 def on_refreshDependenciesButton_clicked(self): |
1786 def on_refreshDependenciesButton_clicked(self): |
1794 """ |
1787 """ |
1795 Private slot to refresh the dependency tree. |
1788 Private slot to refresh the dependency tree. |
1796 """ |
1789 """ |
1797 currentEnvironment = self.environmentsComboBox.currentText() |
1790 currentEnvironment = self.environmentsComboBox.currentText() |
1798 self.environmentsComboBox.clear() |
1791 self.environmentsComboBox.clear() |
1799 self.dependenciesList.clear() |
1792 self.dependenciesList.clear() |
1800 |
1793 |
1801 with EricOverrideCursor(): |
1794 with EricOverrideCursor(): |
1802 self.__populateEnvironments() |
1795 self.__populateEnvironments() |
1803 |
1796 |
1804 index = self.environmentsComboBox.findText( |
1797 index = self.environmentsComboBox.findText( |
1805 currentEnvironment, |
1798 currentEnvironment, |
1806 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive |
1799 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive, |
1807 ) |
1800 ) |
1808 if index != -1: |
1801 if index != -1: |
1809 self.environmentsComboBox.setCurrentIndex(index) |
1802 self.environmentsComboBox.setCurrentIndex(index) |
1810 |
1803 |
1811 self.__updateDepActionButtons() |
1804 self.__updateDepActionButtons() |
1812 |
1805 |
1813 @pyqtSlot() |
1806 @pyqtSlot() |
1814 def on_showDepPackageDetailsButton_clicked(self): |
1807 def on_showDepPackageDetailsButton_clicked(self): |
1815 """ |
1808 """ |
1816 Private slot to show information for the selected package of the |
1809 Private slot to show information for the selected package of the |
1817 dependency tree. |
1810 dependency tree. |
1818 """ |
1811 """ |
1819 item = self.dependenciesList.selectedItems()[0] |
1812 item = self.dependenciesList.selectedItems()[0] |
1820 if item: |
1813 if item: |
1821 packageName = item.text(PipPackagesWidget.DepPackageColumn) |
1814 packageName = item.text(PipPackagesWidget.DepPackageColumn) |
1822 packageVersion = item.text( |
1815 packageVersion = item.text(PipPackagesWidget.DepInstalledVersionColumn) |
1823 PipPackagesWidget.DepInstalledVersionColumn) |
1816 |
1824 |
|
1825 self.__showPackageDetails(packageName, packageVersion) |
1817 self.__showPackageDetails(packageName, packageVersion) |
1826 |
1818 |
1827 def __updateDepActionButtons(self): |
1819 def __updateDepActionButtons(self): |
1828 """ |
1820 """ |
1829 Private method to set the state of the dependency page action buttons. |
1821 Private method to set the state of the dependency page action buttons. |
1830 """ |
1822 """ |
1831 self.showDepPackageDetailsButton.setEnabled( |
1823 self.showDepPackageDetailsButton.setEnabled( |
1832 len(self.dependenciesList.selectedItems()) == 1 and |
1824 len(self.dependenciesList.selectedItems()) == 1 and self.__isPipAvailable() |
1833 self.__isPipAvailable() |
1825 ) |
1834 ) |
1826 |
1835 |
|
1836 ################################################################## |
1827 ################################################################## |
1837 ## Interface to show the licenses dialog below |
1828 ## Interface to show the licenses dialog below |
1838 ################################################################## |
1829 ################################################################## |
1839 |
1830 |
1840 @pyqtSlot() |
1831 @pyqtSlot() |
1841 def __showLicensesDialog(self): |
1832 def __showLicensesDialog(self): |
1842 """ |
1833 """ |
1843 Private slot to show a dialog with the licenses of the selected |
1834 Private slot to show a dialog with the licenses of the selected |
1844 environment. |
1835 environment. |
1845 """ |
1836 """ |
1846 from .PipLicensesDialog import PipLicensesDialog |
1837 from .PipLicensesDialog import PipLicensesDialog |
1847 |
1838 |
1848 environment = self.environmentsComboBox.currentText() |
1839 environment = self.environmentsComboBox.currentText() |
1849 localPackages = ( |
1840 localPackages = ( |
1850 self.localDepCheckBox.isChecked() |
1841 self.localDepCheckBox.isChecked() |
1851 if self.viewToggleButton.isChecked() else |
1842 if self.viewToggleButton.isChecked() |
1852 self.localCheckBox.isChecked() |
1843 else self.localCheckBox.isChecked() |
1853 ) |
1844 ) |
1854 usersite = ( |
1845 usersite = ( |
1855 self.userDepCheckBox.isChecked() |
1846 self.userDepCheckBox.isChecked() |
1856 if self.viewToggleButton.isChecked() else |
1847 if self.viewToggleButton.isChecked() |
1857 self.userCheckBox.isChecked() |
1848 else self.userCheckBox.isChecked() |
1858 ) |
1849 ) |
1859 dlg = PipLicensesDialog( |
1850 dlg = PipLicensesDialog( |
1860 self.__pip, |
1851 self.__pip, |
1861 environment, |
1852 environment, |
1862 localPackages=localPackages, |
1853 localPackages=localPackages, |
1863 usersite=usersite, |
1854 usersite=usersite, |
1864 parent=self |
1855 parent=self, |
1865 ) |
1856 ) |
1866 dlg.exec() |
1857 dlg.exec() |
1867 |
1858 |
1868 ################################################################## |
1859 ################################################################## |
1869 ## Interface to create a SBOM file using CycloneDX |
1860 ## Interface to create a SBOM file using CycloneDX |
1870 ################################################################## |
1861 ################################################################## |
1871 |
1862 |
1872 @pyqtSlot() |
1863 @pyqtSlot() |
1873 def __createSBOMFile(self): |
1864 def __createSBOMFile(self): |
1874 """ |
1865 """ |
1875 Private slot to create a "Software Bill Of Material" file. |
1866 Private slot to create a "Software Bill Of Material" file. |
1876 """ |
1867 """ |
1877 import CycloneDXInterface |
1868 import CycloneDXInterface |
1878 |
1869 |
1879 venvName = self.environmentsComboBox.currentText() |
1870 venvName = self.environmentsComboBox.currentText() |
1880 if venvName == self.__pip.getProjectEnvironmentString(): |
1871 if venvName == self.__pip.getProjectEnvironmentString(): |
1881 venvName = "<project>" |
1872 venvName = "<project>" |
1882 CycloneDXInterface.createCycloneDXFile(venvName) |
1873 CycloneDXInterface.createCycloneDXFile(venvName) |