PipInterface/PipPackagesWidget.py

branch
pypi
changeset 6792
9dd854f05c83
parent 6785
058d63c537a4
child 6793
cca6a35f3ad2
equal deleted inserted replaced
6785:058d63c537a4 6792:9dd854f05c83
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 11
12 from PyQt5.QtCore import pyqtSlot, Qt 12 from PyQt5.QtCore import pyqtSlot, Qt
13 from PyQt5.QtGui import QCursor 13 from PyQt5.QtGui import QCursor
14 from PyQt5.QtWidgets import QWidget, QToolButton, QApplication 14 from PyQt5.QtWidgets import QWidget, QToolButton, QApplication, QHeaderView, \
15 QTreeWidgetItem
16
17 from E5Gui.E5Application import e5App
15 18
16 from .Ui_PipPackagesWidget import Ui_PipPackagesWidget 19 from .Ui_PipPackagesWidget import Ui_PipPackagesWidget
17 20
18 import UI.PixmapCache 21 import UI.PixmapCache
19 22
20 from .Pip import Pip 23 from .Pip import Pip
21 24
22 25
23 class PipPackagesWidget(QWidget, Ui_PipPackagesWidget): 26 class PipPackagesWidget(QWidget, Ui_PipPackagesWidget):
24 """ 27 """
25 Class documentation goes here. 28 Class implementing the pip packages management widget.
26 """ 29 """
30 ShowProcessGeneralMode = 0
31 ShowProcessClassifiersMode = 1
32 ShowProcessEntryPointsMode = 2
33 ShowProcessFilesListMode = 3
34
27 def __init__(self, parent=None): 35 def __init__(self, parent=None):
28 """ 36 """
29 Constructor 37 Constructor
30 38
31 @param parent reference to the parent widget 39 @param parent reference to the parent widget
46 54
47 self.searchToggleButton.setIcon(UI.PixmapCache.getIcon("find")) 55 self.searchToggleButton.setIcon(UI.PixmapCache.getIcon("find"))
48 56
49 self.__pip = Pip(self) 57 self.__pip = Pip(self)
50 58
59 self.packagesList.header().setSortIndicator(0, Qt.AscendingOrder)
60
61 self.__infoLabels = {
62 "name": self.tr("Name:"),
63 "version": self.tr("Version:"),
64 "location": self.tr("Location:"),
65 "requires": self.tr("Requires:"),
66 "summary": self.tr("Summary:"),
67 "home-page": self.tr("Homepage:"),
68 "author": self.tr("Author:"),
69 "author-email": self.tr("Author Email:"),
70 "license": self.tr("License:"),
71 "metadata-version": self.tr("Metadata Version:"),
72 "installer": self.tr("Installer:"),
73 "classifiers": self.tr("Classifiers:"),
74 "entry-points": self.tr("Entry Points:"),
75 "files": self.tr("Files:"),
76 }
77 self.infoWidget.setHeaderLabels(["Key", "Value"])
78
79 venvManager = e5App().getObject("VirtualEnvManager")
80 venvManager.virtualEnvironmentAdded.connect(
81 self.on_refreshButton_clicked)
82 venvManager.virtualEnvironmentRemoved.connect(
83 self.on_refreshButton_clicked)
84
85 project = e5App().getObject("Project")
86 project.projectOpened.connect(
87 self.on_refreshButton_clicked)
88 project.projectClosed.connect(
89 self.on_refreshButton_clicked)
90
51 self.__initPipMenu() 91 self.__initPipMenu()
52 self.__populateEnvironments() 92 self.__populateEnvironments()
53 self.__updateActionButtons() 93 self.__updateActionButtons()
54 94
55 self.statusLabel.hide() 95 self.statusLabel.hide()
56 self.searchWidget.hide() 96 self.searchWidget.hide()
57
58 def __initPipMenu(self):
59 """
60 Private method to create the super menu and attach it to the super
61 menu button.
62 """
63 self.__pip.initActions()
64
65 self.__pipMenu = self.__pip.initMenu()
66
67 self.pipMenuButton.setMenu(self.__pipMenu)
68 97
69 def __populateEnvironments(self): 98 def __populateEnvironments(self):
70 """ 99 """
71 Private method to get a list of environments and populate the selector. 100 Private method to get a list of environments and populate the selector.
72 """ 101 """
74 projectVenv = self.__pip.getProjectEnvironmentString() 103 projectVenv = self.__pip.getProjectEnvironmentString()
75 if projectVenv: 104 if projectVenv:
76 self.environmentsComboBox.addItem(projectVenv) 105 self.environmentsComboBox.addItem(projectVenv)
77 self.environmentsComboBox.addItems(self.__pip.getVirtualenvNames()) 106 self.environmentsComboBox.addItems(self.__pip.getVirtualenvNames())
78 107
108 #######################################################################
109 ## Slots handling widget signals below
110 #######################################################################
111
112 def __selectedUpdateableItems(self):
113 """
114 Private method to get a list of selected items that can be updated.
115
116 @return list of selected items that can be updated
117 @rtype list of QTreeWidgetItem
118 """
119 return [
120 itm for itm in self.packagesList.selectedItems()
121 if bool(itm.text(2))
122 ]
123
124 def __allUpdateableItems(self):
125 """
126 Private method to get a list of all items that can be updated.
127
128 @return list of all items that can be updated
129 @rtype list of QTreeWidgetItem
130 """
131 updateableItems = []
132 for index in range(self.packagesList.topLevelItemCount()):
133 itm = self.packagesList.topLevelItem(index)
134 if itm.text(2):
135 updateableItems.append(itm)
136
137 return updateableItems
138
79 def __updateActionButtons(self): 139 def __updateActionButtons(self):
80 """ 140 """
81 Private method to set the state of the action buttons. 141 Private method to set the state of the action buttons.
82 """ 142 """
83 # TODO: not yet implemented 143 self.upgradeButton.setEnabled(
84 pass 144 bool(self.__selectedUpdateableItems()))
85 145 self.uninstallButton.setEnabled(
86 ####################################################################### 146 bool(self.packagesList.selectedItems()))
87 ## Slots handling widget signals below 147 self.upgradeAllButton.setEnabled(
88 ####################################################################### 148 bool(self.__allUpdateableItems()))
89 149
90 @pyqtSlot(int) 150 def __refreshPackagesList(self):
91 def on_environmentsComboBox_currentIndexChanged(self, index): 151 """
92 """ 152 Private method to referesh the packages list.
93 Private slot handling the selection of a conda environment.
94
95 @param index index of the selected conda environment
96 @type int
97 """ 153 """
98 self.packagesList.clear() 154 self.packagesList.clear()
99 venvName = self.environmentsComboBox.currentText() 155 venvName = self.environmentsComboBox.currentText()
100 if venvName: 156 if venvName:
101 interpreter = self.__pip.getVirtualenvInterpreter(venvName) 157 interpreter = self.__pip.getVirtualenvInterpreter(venvName)
105 self.statusLabel.setText( 161 self.statusLabel.setText(
106 self.tr("Getting installed packages...")) 162 self.tr("Getting installed packages..."))
107 QApplication.processEvents() 163 QApplication.processEvents()
108 164
109 # 1. populate with installed packages 165 # 1. populate with installed packages
110 pass # TODO: add code to list installed 166 self.packagesList.setUpdatesEnabled(False)
167 installedPackages = self.__pip.getInstalledPackages(
168 venvName,
169 localPackages=self.localCheckBox.isChecked(),
170 notRequired=self.notRequiredCheckBox.isChecked(),
171 usersite=self.userCheckBox.isChecked(),
172 )
173 for package, version in installedPackages:
174 QTreeWidgetItem(self.packagesList, [package, version])
175 self.packagesList.setUpdatesEnabled(True)
176 self.statusLabel.setText(
177 self.tr("Getting outdated packages..."))
178 QApplication.processEvents()
111 179
112 # 2. update with update information 180 # 2. update with update information
113 pass # TODO: add code to list outdated 181 self.packagesList.setUpdatesEnabled(False)
182 outdatedPackages = self.__pip.getOutdatedPackages(
183 venvName,
184 localPackages=self.localCheckBox.isChecked(),
185 notRequired=self.notRequiredCheckBox.isChecked(),
186 usersite=self.userCheckBox.isChecked(),
187 )
188 for package, _version, latest in outdatedPackages:
189 items = self.packagesList.findItems(
190 package, Qt.MatchExactly | Qt.MatchCaseSensitive)
191 if items:
192 itm = items[0]
193 itm.setText(2, latest)
114 194
115 self.packagesList.sortItems(0, Qt.AscendingOrder) 195 self.packagesList.sortItems(0, Qt.AscendingOrder)
116 for col in range(self.packagesList.columnCount()): 196 for col in range(self.packagesList.columnCount()):
117 self.packagesList.resizeColumnToContents(col) 197 self.packagesList.resizeColumnToContents(col)
118 self.packagesList.setUpdatesEnabled(True) 198 self.packagesList.setUpdatesEnabled(True)
120 self.statusLabel.hide() 200 self.statusLabel.hide()
121 201
122 self.__updateActionButtons() 202 self.__updateActionButtons()
123 self.__updateSearchActionButtons() 203 self.__updateSearchActionButtons()
124 204
205 @pyqtSlot(int)
206 def on_environmentsComboBox_currentIndexChanged(self, index):
207 """
208 Private slot handling the selection of a conda environment.
209
210 @param index index of the selected conda environment
211 @type int
212 """
213 self.__refreshPackagesList()
214
215 @pyqtSlot(bool)
216 def on_localCheckBox_clicked(self, checked):
217 """
218 Private slot handling the switching of the local mode.
219
220 @param checked state of the local check box
221 @type bool
222 """
223 self.__refreshPackagesList()
224
225 @pyqtSlot(bool)
226 def on_notRequiredCheckBox_clicked(self, checked):
227 """
228 Private slot handling the switching of the 'not required' mode.
229
230 @param checked state of the 'not required' check box
231 @type bool
232 """
233 self.__refreshPackagesList()
234
235 @pyqtSlot(bool)
236 def on_userCheckBox_clicked(self, checked):
237 """
238 Private slot handling the switching of the 'user-site' mode.
239
240 @param checked state of the 'user-site' check box
241 @type bool
242 """
243 self.__refreshPackagesList()
244
245 @pyqtSlot()
246 def on_packagesList_itemSelectionChanged(self):
247 """
248 Private slot handling the selection of a package.
249 """
250 self.infoWidget.clear()
251
252 if len(self.packagesList.selectedItems()) == 1:
253 itm = self.packagesList.selectedItems()[0]
254
255 environment = self.environmentsComboBox.currentText()
256 interpreter = self.__pip.getVirtualenvInterpreter(environment)
257 if not interpreter:
258 return
259
260 QApplication.setOverrideCursor(Qt.WaitCursor)
261
262 args = ["-m", "pip", "show"]
263 if self.verboseCheckBox.isChecked():
264 args.append("--verbose")
265 if self.installedFilesCheckBox.isChecked():
266 args.append("--files")
267 args.append(itm.text(0))
268 success, output = self.__pip.runProcess(args, interpreter)
269
270 if success and output:
271 mode = self.ShowProcessGeneralMode
272 for line in output.splitlines():
273 line = line.rstrip()
274 if line != "---":
275 if mode != self.ShowProcessGeneralMode:
276 if line[0] == " ":
277 QTreeWidgetItem(
278 self.infoWidget,
279 [" ", line.strip()])
280 else:
281 mode = self.ShowProcessGeneralMode
282 if mode == self.ShowProcessGeneralMode:
283 try:
284 label, info = line.split(": ", 1)
285 except ValueError:
286 label = line[:-1]
287 info = ""
288 label = label.lower()
289 if label in self.__infoLabels:
290 QTreeWidgetItem(
291 self.infoWidget,
292 [self.__infoLabels[label], info])
293 if label == "files":
294 mode = self.ShowProcessFilesListMode
295 elif label == "classifiers":
296 mode = self.ShowProcessClassifiersMode
297 elif label == "entry-points":
298 mode = self.ShowProcessEntryPointsMode
299 self.infoWidget.scrollToTop()
300
301 header = self.infoWidget.header()
302 header.setStretchLastSection(False)
303 header.resizeSections(QHeaderView.ResizeToContents)
304 if header.sectionSize(0) + header.sectionSize(1) < header.width():
305 header.setStretchLastSection(True)
306
307 QApplication.restoreOverrideCursor()
308
309 self.__updateActionButtons()
310
311 @pyqtSlot(bool)
312 def on_verboseCheckBox_clicked(self, checked):
313 """
314 Private slot to handle a change of the verbose package information
315 checkbox.
316
317 @param checked state of the checkbox
318 @type bool
319 """
320 self.on_packagesList_itemSelectionChanged()
321
322 @pyqtSlot(bool)
323 def on_installedFilesCheckBox_clicked(self, checked):
324 """
325 Private slot to handle a change of the installed files information
326 checkbox.
327
328 @param checked state of the checkbox
329 @type bool
330 """
331 self.on_packagesList_itemSelectionChanged()
332
333 @pyqtSlot()
334 def on_refreshButton_clicked(self):
335 """
336 Private slot to refresh the display.
337 """
338 currentEnvironment = self.environmentsComboBox.currentText()
339 self.environmentsComboBox.clear()
340 self.packagesList.clear()
341
342 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
343 QApplication.processEvents()
344
345 self.__populateEnvironments()
346
347 index = self.environmentsComboBox.findText(
348 currentEnvironment, Qt.MatchExactly | Qt.MatchCaseSensitive)
349 if index != -1:
350 self.environmentsComboBox.setCurrentIndex(index)
351
352 QApplication.restoreOverrideCursor()
353 self.__updateActionButtons()
354
355 @pyqtSlot()
356 def on_upgradeButton_clicked(self):
357 """
358 Private slot to upgrade selected packages of the selected environment.
359 """
360 packages = [itm.text(0) for itm in self.__selectedUpdateableItems()]
361 if packages:
362 ok = self.__executeUpgradePackages(packages)
363 if ok:
364 self.on_refreshButton_clicked()
365
366 @pyqtSlot()
367 def on_upgradeAllButton_clicked(self):
368 """
369 Private slot to upgrade all packages of the selected environment.
370 """
371 packages = [itm.text(0) for itm in self.__allUpdateableItems()]
372 if packages:
373 ok = self.__executeUpgradePackages(packages)
374 if ok:
375 self.on_refreshButton_clicked()
376
377 @pyqtSlot()
378 def on_uninstallButton_clicked(self):
379 """
380 Private slot to remove selected packages of the selected environment.
381 """
382 packages = [itm.text(0) for itm in self.packagesList.selectedItems()]
383 if packages:
384 ok = self.__pip.uninstallPackages(
385 packages,
386 venvName=self.environmentsComboBox.currentText())
387 if ok:
388 self.on_refreshButton_clicked()
389
390 def __executeUpgradePackages(self, packages):
391 """
392 Private method to execute the pip upgrade command.
393
394 @param packages list of package names to be upgraded
395 @type list of str
396 @return flag indicating success
397 @rtype bool
398 """
399 ok = self.__pip.upgradePackages(
400 packages, venvName=self.environmentsComboBox.currentText(),
401 userSite=self.userCheckBox.isChecked())
402 return ok
403
125 ####################################################################### 404 #######################################################################
126 ## Search widget related methods below 405 ## Search widget related methods below
127 ####################################################################### 406 #######################################################################
128 407
129 def __updateSearchActionButtons(self): 408 def __updateSearchActionButtons(self):
154 self.__updateSearchActionButtons() 433 self.__updateSearchActionButtons()
155 434
156 ####################################################################### 435 #######################################################################
157 ## Menu related methods below 436 ## Menu related methods below
158 ####################################################################### 437 #######################################################################
159 438
439 def __initPipMenu(self):
440 """
441 Private method to create the super menu and attach it to the super
442 menu button.
443 """
444 self.__pip.initActions()
445
446 self.__pipMenu = self.__pip.initMenu()
447
448 self.pipMenuButton.setMenu(self.__pipMenu)

eric ide

mercurial