src/eric7/CondaInterface/CondaPackagesWidget.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9278
36448ca469c2
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
9 9
10 import os 10 import os
11 11
12 from PyQt6.QtCore import pyqtSlot, Qt 12 from PyQt6.QtCore import pyqtSlot, Qt
13 from PyQt6.QtWidgets import ( 13 from PyQt6.QtWidgets import (
14 QWidget, QToolButton, QMenu, QTreeWidgetItem, QApplication, QLineEdit, 14 QWidget,
15 QDialog 15 QToolButton,
16 QMenu,
17 QTreeWidgetItem,
18 QApplication,
19 QLineEdit,
20 QDialog,
16 ) 21 )
17 22
18 from EricWidgets import EricFileDialog, EricMessageBox, EricTextInputDialog 23 from EricWidgets import EricFileDialog, EricMessageBox, EricTextInputDialog
19 from EricWidgets.EricApplication import ericApp 24 from EricWidgets.EricApplication import ericApp
20 from EricGui.EricOverrideCursor import EricOverrideCursor 25 from EricGui.EricOverrideCursor import EricOverrideCursor
28 33
29 class CondaPackagesWidget(QWidget, Ui_CondaPackagesWidget): 34 class CondaPackagesWidget(QWidget, Ui_CondaPackagesWidget):
30 """ 35 """
31 Class implementing the conda packages management widget. 36 Class implementing the conda packages management widget.
32 """ 37 """
38
33 # Role definition of packages list 39 # Role definition of packages list
34 PackageVersionRole = Qt.ItemDataRole.UserRole + 1 40 PackageVersionRole = Qt.ItemDataRole.UserRole + 1
35 PackageBuildRole = Qt.ItemDataRole.UserRole + 2 41 PackageBuildRole = Qt.ItemDataRole.UserRole + 2
36 42
37 # Role definitions of search results list 43 # Role definitions of search results list
38 PackageDetailedDataRole = Qt.ItemDataRole.UserRole + 1 44 PackageDetailedDataRole = Qt.ItemDataRole.UserRole + 1
39 45
40 def __init__(self, conda, parent=None): 46 def __init__(self, conda, parent=None):
41 """ 47 """
42 Constructor 48 Constructor
43 49
44 @param conda reference to the conda interface 50 @param conda reference to the conda interface
45 @type Conda 51 @type Conda
46 @param parent reference to the parent widget 52 @param parent reference to the parent widget
47 @type QWidget 53 @type QWidget
48 """ 54 """
49 super().__init__(parent) 55 super().__init__(parent)
50 self.setupUi(self) 56 self.setupUi(self)
51 57
52 self.layout().setContentsMargins(0, 3, 0, 0) 58 self.layout().setContentsMargins(0, 3, 0, 0)
53 59
54 self.__conda = conda 60 self.__conda = conda
55 61
56 if not CondaInterface.isCondaAvailable(): 62 if not CondaInterface.isCondaAvailable():
57 self.baseWidget.hide() 63 self.baseWidget.hide()
58 self.searchWidget.hide() 64 self.searchWidget.hide()
59 65
60 else: 66 else:
61 self.notAvailableWidget.hide() 67 self.notAvailableWidget.hide()
62 68
63 self.__initCondaInterface() 69 self.__initCondaInterface()
64 70
65 def __initCondaInterface(self): 71 def __initCondaInterface(self):
66 """ 72 """
67 Private method to initialize the conda interface elements. 73 Private method to initialize the conda interface elements.
68 """ 74 """
69 self.statusLabel.hide() 75 self.statusLabel.hide()
70 76
71 self.condaMenuButton.setObjectName( 77 self.condaMenuButton.setObjectName("conda_supermenu_button")
72 "conda_supermenu_button")
73 self.condaMenuButton.setIcon(UI.PixmapCache.getIcon("superMenu")) 78 self.condaMenuButton.setIcon(UI.PixmapCache.getIcon("superMenu"))
74 self.condaMenuButton.setToolTip(self.tr("Conda Menu")) 79 self.condaMenuButton.setToolTip(self.tr("Conda Menu"))
75 self.condaMenuButton.setPopupMode( 80 self.condaMenuButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
76 QToolButton.ToolButtonPopupMode.InstantPopup) 81 self.condaMenuButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
77 self.condaMenuButton.setToolButtonStyle(
78 Qt.ToolButtonStyle.ToolButtonIconOnly)
79 self.condaMenuButton.setFocusPolicy(Qt.FocusPolicy.NoFocus) 82 self.condaMenuButton.setFocusPolicy(Qt.FocusPolicy.NoFocus)
80 self.condaMenuButton.setAutoRaise(True) 83 self.condaMenuButton.setAutoRaise(True)
81 self.condaMenuButton.setShowMenuInside(True) 84 self.condaMenuButton.setShowMenuInside(True)
82 85
83 self.refreshButton.setIcon(UI.PixmapCache.getIcon("reload")) 86 self.refreshButton.setIcon(UI.PixmapCache.getIcon("reload"))
84 self.upgradeButton.setIcon(UI.PixmapCache.getIcon("1uparrow")) 87 self.upgradeButton.setIcon(UI.PixmapCache.getIcon("1uparrow"))
85 self.upgradeAllButton.setIcon(UI.PixmapCache.getIcon("2uparrow")) 88 self.upgradeAllButton.setIcon(UI.PixmapCache.getIcon("2uparrow"))
86 self.uninstallButton.setIcon(UI.PixmapCache.getIcon("minus")) 89 self.uninstallButton.setIcon(UI.PixmapCache.getIcon("minus"))
87 self.searchToggleButton.setIcon(UI.PixmapCache.getIcon("find")) 90 self.searchToggleButton.setIcon(UI.PixmapCache.getIcon("find"))
88 self.searchButton.setIcon(UI.PixmapCache.getIcon("findNext")) 91 self.searchButton.setIcon(UI.PixmapCache.getIcon("findNext"))
89 self.installButton.setIcon(UI.PixmapCache.getIcon("plus")) 92 self.installButton.setIcon(UI.PixmapCache.getIcon("plus"))
90 self.showDetailsButton.setIcon(UI.PixmapCache.getIcon("info")) 93 self.showDetailsButton.setIcon(UI.PixmapCache.getIcon("info"))
91 94
92 if CondaInterface.condaVersion() >= (4, 4, 0): 95 if CondaInterface.condaVersion() >= (4, 4, 0):
93 self.searchOptionsWidget.hide() 96 self.searchOptionsWidget.hide()
94 else: 97 else:
95 self.platformComboBox.addItems(sorted([ 98 self.platformComboBox.addItems(
96 "", "win-32", "win-64", "osx-64", "linux-32", "linux-64", 99 sorted(
97 ])) 100 [
98 101 "",
102 "win-32",
103 "win-64",
104 "osx-64",
105 "linux-32",
106 "linux-64",
107 ]
108 )
109 )
110
99 self.__initCondaMenu() 111 self.__initCondaMenu()
100 self.__populateEnvironments() 112 self.__populateEnvironments()
101 self.__updateActionButtons() 113 self.__updateActionButtons()
102 114
103 self.searchWidget.hide() 115 self.searchWidget.hide()
104 116
105 self.__conda.condaEnvironmentCreated.connect( 117 self.__conda.condaEnvironmentCreated.connect(self.on_refreshButton_clicked)
106 self.on_refreshButton_clicked) 118 self.__conda.condaEnvironmentRemoved.connect(self.on_refreshButton_clicked)
107 self.__conda.condaEnvironmentRemoved.connect( 119
108 self.on_refreshButton_clicked)
109
110 def __populateEnvironments(self): 120 def __populateEnvironments(self):
111 """ 121 """
112 Private method to get a list of environments and populate the selector. 122 Private method to get a list of environments and populate the selector.
113 """ 123 """
114 environments = [("", "")] + sorted( 124 environments = [("", "")] + sorted(self.__conda.getCondaEnvironmentsList())
115 self.__conda.getCondaEnvironmentsList())
116 for environment in environments: 125 for environment in environments:
117 self.environmentsComboBox.addItem(environment[0], environment[1]) 126 self.environmentsComboBox.addItem(environment[0], environment[1])
118 127
119 def __initCondaMenu(self): 128 def __initCondaMenu(self):
120 """ 129 """
121 Private method to create the super menu and attach it to the super 130 Private method to create the super menu and attach it to the super
122 menu button. 131 menu button.
123 """ 132 """
124 self.__condaMenu = QMenu(self) 133 self.__condaMenu = QMenu(self)
125 self.__envActs = [] 134 self.__envActs = []
126 135
127 self.__cleanMenu = QMenu(self.tr("Clean"), self) 136 self.__cleanMenu = QMenu(self.tr("Clean"), self)
128 self.__cleanMenu.addAction( 137 self.__cleanMenu.addAction(
129 self.tr("All"), lambda: self.__conda.cleanConda("all")) 138 self.tr("All"), lambda: self.__conda.cleanConda("all")
139 )
130 self.__cleanMenu.addAction( 140 self.__cleanMenu.addAction(
131 self.tr("Cache"), lambda: self.__conda.cleanConda("index-cache")) 141 self.tr("Cache"), lambda: self.__conda.cleanConda("index-cache")
142 )
132 self.__cleanMenu.addAction( 143 self.__cleanMenu.addAction(
133 self.tr("Lock Files"), 144 self.tr("Lock Files"), lambda: self.__conda.cleanConda("lock")
134 lambda: self.__conda.cleanConda("lock")) 145 )
135 self.__cleanMenu.addAction( 146 self.__cleanMenu.addAction(
136 self.tr("Packages"), lambda: self.__conda.cleanConda("packages")) 147 self.tr("Packages"), lambda: self.__conda.cleanConda("packages")
148 )
137 self.__cleanMenu.addAction( 149 self.__cleanMenu.addAction(
138 self.tr("Tarballs"), lambda: self.__conda.cleanConda("tarballs")) 150 self.tr("Tarballs"), lambda: self.__conda.cleanConda("tarballs")
139 151 )
140 self.__condaMenu.addAction( 152
141 self.tr("About Conda..."), self.__aboutConda) 153 self.__condaMenu.addAction(self.tr("About Conda..."), self.__aboutConda)
154 self.__condaMenu.addSeparator()
155 self.__condaMenu.addAction(self.tr("Update Conda"), self.__conda.updateConda)
156 self.__condaMenu.addSeparator()
157 self.__envActs.append(
158 self.__condaMenu.addAction(
159 self.tr("Install Packages"), self.__installPackages
160 )
161 )
162 self.__envActs.append(
163 self.__condaMenu.addAction(
164 self.tr("Install Requirements"), self.__installRequirements
165 )
166 )
167 self.__condaMenu.addSeparator()
168 self.__envActs.append(
169 self.__condaMenu.addAction(
170 self.tr("Generate Requirements"), self.__generateRequirements
171 )
172 )
142 self.__condaMenu.addSeparator() 173 self.__condaMenu.addSeparator()
143 self.__condaMenu.addAction( 174 self.__condaMenu.addAction(
144 self.tr("Update Conda"), self.__conda.updateConda) 175 self.tr("Create Environment from Requirements"), self.__createEnvironment
145 self.__condaMenu.addSeparator() 176 )
146 self.__envActs.append(self.__condaMenu.addAction( 177 self.__envActs.append(
147 self.tr("Install Packages"), self.__installPackages)) 178 self.__condaMenu.addAction(
148 self.__envActs.append(self.__condaMenu.addAction( 179 self.tr("Clone Environment"), self.__cloneEnvironment
149 self.tr("Install Requirements"), self.__installRequirements)) 180 )
150 self.__condaMenu.addSeparator() 181 )
151 self.__envActs.append(self.__condaMenu.addAction(
152 self.tr("Generate Requirements"), self.__generateRequirements))
153 self.__condaMenu.addSeparator()
154 self.__condaMenu.addAction(
155 self.tr("Create Environment from Requirements"),
156 self.__createEnvironment)
157 self.__envActs.append(self.__condaMenu.addAction(
158 self.tr("Clone Environment"), self.__cloneEnvironment))
159 self.__deleteEnvAct = self.__condaMenu.addAction( 182 self.__deleteEnvAct = self.__condaMenu.addAction(
160 self.tr("Delete Environment"), self.__deleteEnvironment) 183 self.tr("Delete Environment"), self.__deleteEnvironment
184 )
161 self.__condaMenu.addSeparator() 185 self.__condaMenu.addSeparator()
162 self.__condaMenu.addMenu(self.__cleanMenu) 186 self.__condaMenu.addMenu(self.__cleanMenu)
163 self.__condaMenu.addSeparator() 187 self.__condaMenu.addSeparator()
164 self.__condaMenu.addAction( 188 self.__condaMenu.addAction(
165 self.tr("Edit User Configuration..."), 189 self.tr("Edit User Configuration..."), self.__editUserConfiguration
166 self.__editUserConfiguration) 190 )
167 self.__condaMenu.addSeparator() 191 self.__condaMenu.addSeparator()
168 self.__condaMenu.addAction( 192 self.__condaMenu.addAction(self.tr("Configure..."), self.__condaConfigure)
169 self.tr("Configure..."), self.__condaConfigure) 193
170
171 self.condaMenuButton.setMenu(self.__condaMenu) 194 self.condaMenuButton.setMenu(self.__condaMenu)
172 195
173 self.__condaMenu.aboutToShow.connect(self.__aboutToShowCondaMenu) 196 self.__condaMenu.aboutToShow.connect(self.__aboutToShowCondaMenu)
174 197
175 def __selectedUpdateableItems(self): 198 def __selectedUpdateableItems(self):
176 """ 199 """
177 Private method to get a list of selected items that can be updated. 200 Private method to get a list of selected items that can be updated.
178 201
179 @return list of selected items that can be updated 202 @return list of selected items that can be updated
180 @rtype list of QTreeWidgetItem 203 @rtype list of QTreeWidgetItem
181 """ 204 """
182 return [ 205 return [itm for itm in self.packagesList.selectedItems() if bool(itm.text(2))]
183 itm for itm in self.packagesList.selectedItems() 206
184 if bool(itm.text(2))
185 ]
186
187 def __allUpdateableItems(self): 207 def __allUpdateableItems(self):
188 """ 208 """
189 Private method to get a list of all items that can be updated. 209 Private method to get a list of all items that can be updated.
190 210
191 @return list of all items that can be updated 211 @return list of all items that can be updated
192 @rtype list of QTreeWidgetItem 212 @rtype list of QTreeWidgetItem
193 """ 213 """
194 updateableItems = [] 214 updateableItems = []
195 for index in range(self.packagesList.topLevelItemCount()): 215 for index in range(self.packagesList.topLevelItemCount()):
196 itm = self.packagesList.topLevelItem(index) 216 itm = self.packagesList.topLevelItem(index)
197 if itm.text(2): 217 if itm.text(2):
198 updateableItems.append(itm) 218 updateableItems.append(itm)
199 219
200 return updateableItems 220 return updateableItems
201 221
202 def __updateActionButtons(self): 222 def __updateActionButtons(self):
203 """ 223 """
204 Private method to set the state of the action buttons. 224 Private method to set the state of the action buttons.
205 """ 225 """
206 self.upgradeButton.setEnabled( 226 self.upgradeButton.setEnabled(bool(self.__selectedUpdateableItems()))
207 bool(self.__selectedUpdateableItems())) 227 self.uninstallButton.setEnabled(bool(self.packagesList.selectedItems()))
208 self.uninstallButton.setEnabled( 228 self.upgradeAllButton.setEnabled(bool(self.__allUpdateableItems()))
209 bool(self.packagesList.selectedItems())) 229
210 self.upgradeAllButton.setEnabled(
211 bool(self.__allUpdateableItems()))
212
213 @pyqtSlot(int) 230 @pyqtSlot(int)
214 def on_environmentsComboBox_currentIndexChanged(self, index): 231 def on_environmentsComboBox_currentIndexChanged(self, index):
215 """ 232 """
216 Private slot handling the selection of a conda environment. 233 Private slot handling the selection of a conda environment.
217 234
218 @param index index of the selected conda environment 235 @param index index of the selected conda environment
219 @type int 236 @type int
220 """ 237 """
221 self.packagesList.clear() 238 self.packagesList.clear()
222 prefix = self.environmentsComboBox.itemData(index) 239 prefix = self.environmentsComboBox.itemData(index)
223 if prefix: 240 if prefix:
224 self.statusLabel.show() 241 self.statusLabel.show()
225 self.statusLabel.setText(self.tr("Getting installed packages...")) 242 self.statusLabel.setText(self.tr("Getting installed packages..."))
226 243
227 with EricOverrideCursor(): 244 with EricOverrideCursor():
228 # 1. populate with installed packages 245 # 1. populate with installed packages
229 self.packagesList.setUpdatesEnabled(False) 246 self.packagesList.setUpdatesEnabled(False)
230 installedPackages = self.__conda.getInstalledPackages( 247 installedPackages = self.__conda.getInstalledPackages(prefix=prefix)
231 prefix=prefix)
232 for package, version, build in installedPackages: 248 for package, version, build in installedPackages:
233 itm = QTreeWidgetItem(self.packagesList, 249 itm = QTreeWidgetItem(self.packagesList, [package, version])
234 [package, version])
235 itm.setData(1, self.PackageVersionRole, version) 250 itm.setData(1, self.PackageVersionRole, version)
236 itm.setData(1, self.PackageBuildRole, build) 251 itm.setData(1, self.PackageBuildRole, build)
237 self.packagesList.setUpdatesEnabled(True) 252 self.packagesList.setUpdatesEnabled(True)
238 self.statusLabel.setText( 253 self.statusLabel.setText(self.tr("Getting outdated packages..."))
239 self.tr("Getting outdated packages..."))
240 QApplication.processEvents() 254 QApplication.processEvents()
241 255
242 # 2. update with update information 256 # 2. update with update information
243 self.packagesList.setUpdatesEnabled(False) 257 self.packagesList.setUpdatesEnabled(False)
244 updateablePackages = self.__conda.getUpdateablePackages( 258 updateablePackages = self.__conda.getUpdateablePackages(prefix=prefix)
245 prefix=prefix)
246 for package, version, build in updateablePackages: 259 for package, version, build in updateablePackages:
247 items = self.packagesList.findItems( 260 items = self.packagesList.findItems(
248 package, 261 package,
249 Qt.MatchFlag.MatchExactly | 262 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive,
250 Qt.MatchFlag.MatchCaseSensitive) 263 )
251 if items: 264 if items:
252 itm = items[0] 265 itm = items[0]
253 itm.setText(2, version) 266 itm.setText(2, version)
254 itm.setData(2, self.PackageVersionRole, version) 267 itm.setData(2, self.PackageVersionRole, version)
255 itm.setData(2, self.PackageBuildRole, build) 268 itm.setData(2, self.PackageBuildRole, build)
256 if itm.data(1, self.PackageVersionRole) == version: 269 if itm.data(1, self.PackageVersionRole) == version:
257 # build must be different, show in version display 270 # build must be different, show in version display
258 itm.setText(1, self.tr("{0} (Build: {1})").format( 271 itm.setText(
259 itm.data(1, self.PackageVersionRole), 272 1,
260 itm.data(1, self.PackageBuildRole), 273 self.tr("{0} (Build: {1})").format(
261 )) 274 itm.data(1, self.PackageVersionRole),
262 itm.setText(2, self.tr("{0} (Build: {1})").format( 275 itm.data(1, self.PackageBuildRole),
263 itm.data(2, self.PackageVersionRole), 276 ),
264 itm.data(2, self.PackageBuildRole), 277 )
265 )) 278 itm.setText(
266 279 2,
280 self.tr("{0} (Build: {1})").format(
281 itm.data(2, self.PackageVersionRole),
282 itm.data(2, self.PackageBuildRole),
283 ),
284 )
285
267 self.packagesList.sortItems(0, Qt.SortOrder.AscendingOrder) 286 self.packagesList.sortItems(0, Qt.SortOrder.AscendingOrder)
268 for col in range(self.packagesList.columnCount()): 287 for col in range(self.packagesList.columnCount()):
269 self.packagesList.resizeColumnToContents(col) 288 self.packagesList.resizeColumnToContents(col)
270 self.packagesList.setUpdatesEnabled(True) 289 self.packagesList.setUpdatesEnabled(True)
271 self.statusLabel.hide() 290 self.statusLabel.hide()
272 291
273 self.__updateActionButtons() 292 self.__updateActionButtons()
274 self.__updateSearchActionButtons() 293 self.__updateSearchActionButtons()
275 294
276 @pyqtSlot() 295 @pyqtSlot()
277 def on_packagesList_itemSelectionChanged(self): 296 def on_packagesList_itemSelectionChanged(self):
278 """ 297 """
279 Private slot to handle the selection of some items.. 298 Private slot to handle the selection of some items..
280 """ 299 """
281 self.__updateActionButtons() 300 self.__updateActionButtons()
282 301
283 @pyqtSlot() 302 @pyqtSlot()
284 def on_refreshButton_clicked(self): 303 def on_refreshButton_clicked(self):
285 """ 304 """
286 Private slot to refresh the display. 305 Private slot to refresh the display.
287 """ 306 """
288 currentEnvironment = self.environmentsComboBox.currentText() 307 currentEnvironment = self.environmentsComboBox.currentText()
289 self.environmentsComboBox.clear() 308 self.environmentsComboBox.clear()
290 self.packagesList.clear() 309 self.packagesList.clear()
291 310
292 with EricOverrideCursor(): 311 with EricOverrideCursor():
293 self.__populateEnvironments() 312 self.__populateEnvironments()
294 313
295 index = self.environmentsComboBox.findText( 314 index = self.environmentsComboBox.findText(
296 currentEnvironment, 315 currentEnvironment,
297 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive) 316 Qt.MatchFlag.MatchExactly | Qt.MatchFlag.MatchCaseSensitive,
317 )
298 if index != -1: 318 if index != -1:
299 self.environmentsComboBox.setCurrentIndex(index) 319 self.environmentsComboBox.setCurrentIndex(index)
300 320
301 self.__updateActionButtons() 321 self.__updateActionButtons()
302 322
303 @pyqtSlot() 323 @pyqtSlot()
304 def on_upgradeButton_clicked(self): 324 def on_upgradeButton_clicked(self):
305 """ 325 """
306 Private slot to upgrade selected packages of the selected environment. 326 Private slot to upgrade selected packages of the selected environment.
307 """ 327 """
308 packages = [itm.text(0) for itm in self.__selectedUpdateableItems()] 328 packages = [itm.text(0) for itm in self.__selectedUpdateableItems()]
309 if packages: 329 if packages:
310 prefix = self.environmentsComboBox.itemData( 330 prefix = self.environmentsComboBox.itemData(
311 self.environmentsComboBox.currentIndex()) 331 self.environmentsComboBox.currentIndex()
332 )
312 ok = self.__conda.updatePackages(packages, prefix=prefix) 333 ok = self.__conda.updatePackages(packages, prefix=prefix)
313 if ok: 334 if ok:
314 self.on_refreshButton_clicked() 335 self.on_refreshButton_clicked()
315 336
316 @pyqtSlot() 337 @pyqtSlot()
317 def on_upgradeAllButton_clicked(self): 338 def on_upgradeAllButton_clicked(self):
318 """ 339 """
319 Private slot to upgrade all packages of the selected environment. 340 Private slot to upgrade all packages of the selected environment.
320 """ 341 """
321 prefix = self.environmentsComboBox.itemData( 342 prefix = self.environmentsComboBox.itemData(
322 self.environmentsComboBox.currentIndex()) 343 self.environmentsComboBox.currentIndex()
344 )
323 ok = self.__conda.updateAllPackages(prefix=prefix) 345 ok = self.__conda.updateAllPackages(prefix=prefix)
324 if ok: 346 if ok:
325 self.on_refreshButton_clicked() 347 self.on_refreshButton_clicked()
326 348
327 @pyqtSlot() 349 @pyqtSlot()
328 def on_uninstallButton_clicked(self): 350 def on_uninstallButton_clicked(self):
329 """ 351 """
330 Private slot to remove selected packages of the selected environment. 352 Private slot to remove selected packages of the selected environment.
331 """ 353 """
332 packages = [itm.text(0) for itm in self.packagesList.selectedItems()] 354 packages = [itm.text(0) for itm in self.packagesList.selectedItems()]
333 if packages: 355 if packages:
334 prefix = self.environmentsComboBox.itemData( 356 prefix = self.environmentsComboBox.itemData(
335 self.environmentsComboBox.currentIndex()) 357 self.environmentsComboBox.currentIndex()
358 )
336 ok = self.__conda.uninstallPackages(packages, prefix=prefix) 359 ok = self.__conda.uninstallPackages(packages, prefix=prefix)
337 if ok: 360 if ok:
338 self.on_refreshButton_clicked() 361 self.on_refreshButton_clicked()
339 362
340 ####################################################################### 363 #######################################################################
341 ## Search widget related methods below 364 ## Search widget related methods below
342 ####################################################################### 365 #######################################################################
343 366
344 def __updateSearchActionButtons(self): 367 def __updateSearchActionButtons(self):
345 """ 368 """
346 Private method to update the action button states of the search widget. 369 Private method to update the action button states of the search widget.
347 """ 370 """
348 enable = len(self.searchResultList.selectedItems()) == 1 371 enable = len(self.searchResultList.selectedItems()) == 1
349 self.installButton.setEnabled( 372 self.installButton.setEnabled(
350 enable and self.environmentsComboBox.currentIndex() > 0) 373 enable and self.environmentsComboBox.currentIndex() > 0
374 )
351 self.showDetailsButton.setEnabled( 375 self.showDetailsButton.setEnabled(
352 enable and bool(self.searchResultList.selectedItems()[0].parent())) 376 enable and bool(self.searchResultList.selectedItems()[0].parent())
353 377 )
378
354 def __doSearch(self): 379 def __doSearch(self):
355 """ 380 """
356 Private method to search for packages. 381 Private method to search for packages.
357 """ 382 """
358 self.searchResultList.clear() 383 self.searchResultList.clear()
359 pattern = self.searchEdit.text() 384 pattern = self.searchEdit.text()
360 if pattern: 385 if pattern:
361 with EricOverrideCursor(): 386 with EricOverrideCursor():
362 prefix = ( 387 prefix = (
363 "" 388 ""
364 if CondaInterface.condaVersion() >= (4, 4, 0) else 389 if CondaInterface.condaVersion() >= (4, 4, 0)
365 self.environmentsComboBox.itemData( 390 else self.environmentsComboBox.itemData(
366 self.environmentsComboBox.currentIndex()) 391 self.environmentsComboBox.currentIndex()
392 )
367 ) 393 )
368 ok, result = self.__conda.searchPackages( 394 ok, result = self.__conda.searchPackages(
369 pattern, 395 pattern,
370 fullNameOnly=self.fullNameButton.isChecked(), 396 fullNameOnly=self.fullNameButton.isChecked(),
371 packageSpec=self.packageSpecButton.isChecked(), 397 packageSpec=self.packageSpecButton.isChecked(),
372 platform=self.platformComboBox.currentText(), 398 platform=self.platformComboBox.currentText(),
373 prefix=prefix, 399 prefix=prefix,
374 ) 400 )
375 401
376 if ok and result: 402 if ok and result:
377 self.searchResultList.setUpdatesEnabled(False) 403 self.searchResultList.setUpdatesEnabled(False)
378 for package in result: 404 for package in result:
379 itm = QTreeWidgetItem(self.searchResultList, 405 itm = QTreeWidgetItem(self.searchResultList, [package])
380 [package])
381 itm.setExpanded(False) 406 itm.setExpanded(False)
382 for detail in result[package]: 407 for detail in result[package]:
383 version = detail["version"] 408 version = detail["version"]
384 build = detail["build"] 409 build = detail["build"]
385 if "subdir" in detail: 410 if "subdir" in detail:
386 platform = detail["subdir"] 411 platform = detail["subdir"]
387 elif "platform" in detail: 412 elif "platform" in detail:
388 platform = detail["platform"] 413 platform = detail["platform"]
389 else: 414 else:
390 platform = "" 415 platform = ""
391 citm = QTreeWidgetItem( 416 citm = QTreeWidgetItem(itm, ["", version, build, platform])
392 itm, ["", version, build, platform]) 417 citm.setData(0, self.PackageDetailedDataRole, detail)
393 citm.setData(0, self.PackageDetailedDataRole, 418
394 detail) 419 self.searchResultList.sortItems(0, Qt.SortOrder.AscendingOrder)
395
396 self.searchResultList.sortItems(
397 0, Qt.SortOrder.AscendingOrder)
398 self.searchResultList.resizeColumnToContents(0) 420 self.searchResultList.resizeColumnToContents(0)
399 self.searchResultList.setUpdatesEnabled(True) 421 self.searchResultList.setUpdatesEnabled(True)
400 if not ok: 422 if not ok:
401 try: 423 try:
402 message = result["message"] 424 message = result["message"]
403 except KeyError: 425 except KeyError:
404 message = result["error"] 426 message = result["error"]
405 EricMessageBox.warning( 427 EricMessageBox.warning(
406 self, 428 self, self.tr("Conda Search Package Error"), message
407 self.tr("Conda Search Package Error"), 429 )
408 message) 430
409
410 def __showDetails(self, item): 431 def __showDetails(self, item):
411 """ 432 """
412 Private method to show a dialog with details about a package item. 433 Private method to show a dialog with details about a package item.
413 434
414 @param item reference to the package item 435 @param item reference to the package item
415 @type QTreeWidgetItem 436 @type QTreeWidgetItem
416 """ 437 """
417 details = item.data(0, self.PackageDetailedDataRole) 438 details = item.data(0, self.PackageDetailedDataRole)
418 if details: 439 if details:
419 from .CondaPackageDetailsWidget import CondaPackageDetailsDialog 440 from .CondaPackageDetailsWidget import CondaPackageDetailsDialog
441
420 dlg = CondaPackageDetailsDialog(details, self) 442 dlg = CondaPackageDetailsDialog(details, self)
421 dlg.exec() 443 dlg.exec()
422 444
423 @pyqtSlot(str) 445 @pyqtSlot(str)
424 def on_searchEdit_textChanged(self, txt): 446 def on_searchEdit_textChanged(self, txt):
425 """ 447 """
426 Private slot handling changes of the entered search specification. 448 Private slot handling changes of the entered search specification.
427 449
428 @param txt current search entry 450 @param txt current search entry
429 @type str 451 @type str
430 """ 452 """
431 self.searchButton.setEnabled(bool(txt)) 453 self.searchButton.setEnabled(bool(txt))
432 454
433 @pyqtSlot() 455 @pyqtSlot()
434 def on_searchEdit_returnPressed(self): 456 def on_searchEdit_returnPressed(self):
435 """ 457 """
436 Private slot handling the user pressing the Return button in the 458 Private slot handling the user pressing the Return button in the
437 search edit. 459 search edit.
438 """ 460 """
439 self.__doSearch() 461 self.__doSearch()
440 462
441 @pyqtSlot() 463 @pyqtSlot()
442 def on_searchButton_clicked(self): 464 def on_searchButton_clicked(self):
443 """ 465 """
444 Private slot handling the press of the search button. 466 Private slot handling the press of the search button.
445 """ 467 """
446 self.__doSearch() 468 self.__doSearch()
447 469
448 @pyqtSlot() 470 @pyqtSlot()
449 def on_installButton_clicked(self): 471 def on_installButton_clicked(self):
450 """ 472 """
451 Private slot to install a selected package. 473 Private slot to install a selected package.
452 """ 474 """
460 package = "{0}={1}={2}".format( 482 package = "{0}={1}={2}".format(
461 item.parent().text(0), 483 item.parent().text(0),
462 item.text(1), 484 item.text(1),
463 item.text(2), 485 item.text(2),
464 ) 486 )
465 487
466 prefix = self.environmentsComboBox.itemData( 488 prefix = self.environmentsComboBox.itemData(
467 self.environmentsComboBox.currentIndex()) 489 self.environmentsComboBox.currentIndex()
490 )
468 ok = self.__conda.installPackages([package], prefix=prefix) 491 ok = self.__conda.installPackages([package], prefix=prefix)
469 if ok: 492 if ok:
470 self.on_refreshButton_clicked() 493 self.on_refreshButton_clicked()
471 494
472 @pyqtSlot() 495 @pyqtSlot()
473 def on_showDetailsButton_clicked(self): 496 def on_showDetailsButton_clicked(self):
474 """ 497 """
475 Private slot handling the 'Show Details' button. 498 Private slot handling the 'Show Details' button.
476 """ 499 """
477 item = self.searchResultList.selectedItems()[0] 500 item = self.searchResultList.selectedItems()[0]
478 self.__showDetails(item) 501 self.__showDetails(item)
479 502
480 @pyqtSlot() 503 @pyqtSlot()
481 def on_searchResultList_itemSelectionChanged(self): 504 def on_searchResultList_itemSelectionChanged(self):
482 """ 505 """
483 Private slot handling a change of selected search results. 506 Private slot handling a change of selected search results.
484 """ 507 """
485 self.__updateSearchActionButtons() 508 self.__updateSearchActionButtons()
486 509
487 @pyqtSlot(QTreeWidgetItem) 510 @pyqtSlot(QTreeWidgetItem)
488 def on_searchResultList_itemExpanded(self, item): 511 def on_searchResultList_itemExpanded(self, item):
489 """ 512 """
490 Private slot handling the expansion of an item. 513 Private slot handling the expansion of an item.
491 514
492 @param item reference to the expanded item 515 @param item reference to the expanded item
493 @type QTreeWidgetItem 516 @type QTreeWidgetItem
494 """ 517 """
495 for col in range(1, self.searchResultList.columnCount()): 518 for col in range(1, self.searchResultList.columnCount()):
496 self.searchResultList.resizeColumnToContents(col) 519 self.searchResultList.resizeColumnToContents(col)
497 520
498 @pyqtSlot(QTreeWidgetItem, int) 521 @pyqtSlot(QTreeWidgetItem, int)
499 def on_searchResultList_itemDoubleClicked(self, item, column): 522 def on_searchResultList_itemDoubleClicked(self, item, column):
500 """ 523 """
501 Private slot handling a double click of an item. 524 Private slot handling a double click of an item.
502 525
503 @param item reference to the item that was double clicked 526 @param item reference to the item that was double clicked
504 @type QTreeWidgetItem 527 @type QTreeWidgetItem
505 @param column column of the double click 528 @param column column of the double click
506 @type int 529 @type int
507 """ 530 """
508 if item.parent() is not None: 531 if item.parent() is not None:
509 self.__showDetails(item) 532 self.__showDetails(item)
510 533
511 @pyqtSlot(bool) 534 @pyqtSlot(bool)
512 def on_searchToggleButton_toggled(self, checked): 535 def on_searchToggleButton_toggled(self, checked):
513 """ 536 """
514 Private slot to togle the search widget. 537 Private slot to togle the search widget.
515 538
516 @param checked state of the search widget button 539 @param checked state of the search widget button
517 @type bool 540 @type bool
518 """ 541 """
519 self.searchWidget.setVisible(checked) 542 self.searchWidget.setVisible(checked)
520 543
521 if checked: 544 if checked:
522 self.searchEdit.setFocus(Qt.FocusReason.OtherFocusReason) 545 self.searchEdit.setFocus(Qt.FocusReason.OtherFocusReason)
523 self.searchEdit.selectAll() 546 self.searchEdit.selectAll()
524 547
525 self.__updateSearchActionButtons() 548 self.__updateSearchActionButtons()
526 549
527 ####################################################################### 550 #######################################################################
528 ## Menu related methods below 551 ## Menu related methods below
529 ####################################################################### 552 #######################################################################
530 553
531 @pyqtSlot() 554 @pyqtSlot()
532 def __aboutToShowCondaMenu(self): 555 def __aboutToShowCondaMenu(self):
533 """ 556 """
534 Private slot to handle the conda menu about to be shown. 557 Private slot to handle the conda menu about to be shown.
535 """ 558 """
536 selectedEnvironment = self.environmentsComboBox.currentText() 559 selectedEnvironment = self.environmentsComboBox.currentText()
537 enable = selectedEnvironment not in [""] 560 enable = selectedEnvironment not in [""]
538 for act in self.__envActs: 561 for act in self.__envActs:
539 act.setEnabled(enable) 562 act.setEnabled(enable)
540 563
541 self.__deleteEnvAct.setEnabled( 564 self.__deleteEnvAct.setEnabled(
542 selectedEnvironment not in ["", self.__conda.RootName]) 565 selectedEnvironment not in ["", self.__conda.RootName]
543 566 )
567
544 @pyqtSlot() 568 @pyqtSlot()
545 def __aboutConda(self): 569 def __aboutConda(self):
546 """ 570 """
547 Private slot to show some information about the conda installation. 571 Private slot to show some information about the conda installation.
548 """ 572 """
549 infoDict = self.__conda.getCondaInformation() 573 infoDict = self.__conda.getCondaInformation()
550 574
551 from .CondaInfoDialog import CondaInfoDialog 575 from .CondaInfoDialog import CondaInfoDialog
576
552 dlg = CondaInfoDialog(infoDict, self) 577 dlg = CondaInfoDialog(infoDict, self)
553 dlg.exec() 578 dlg.exec()
554 579
555 @pyqtSlot() 580 @pyqtSlot()
556 def __installPackages(self): 581 def __installPackages(self):
557 """ 582 """
558 Private slot to install packages. 583 Private slot to install packages.
559 """ 584 """
560 prefix = self.environmentsComboBox.itemData( 585 prefix = self.environmentsComboBox.itemData(
561 self.environmentsComboBox.currentIndex()) 586 self.environmentsComboBox.currentIndex()
587 )
562 if prefix: 588 if prefix:
563 ok, packageSpecs = EricTextInputDialog.getText( 589 ok, packageSpecs = EricTextInputDialog.getText(
564 self, 590 self,
565 self.tr("Install Packages"), 591 self.tr("Install Packages"),
566 self.tr("Package Specifications (separated by whitespace):"), 592 self.tr("Package Specifications (separated by whitespace):"),
567 QLineEdit.EchoMode.Normal, 593 QLineEdit.EchoMode.Normal,
568 minimumWidth=600) 594 minimumWidth=600,
595 )
569 if ok and packageSpecs.strip(): 596 if ok and packageSpecs.strip():
570 packages = [p.strip() for p in packageSpecs.split()] 597 packages = [p.strip() for p in packageSpecs.split()]
571 ok = self.__conda.installPackages(packages, prefix=prefix) 598 ok = self.__conda.installPackages(packages, prefix=prefix)
572 if ok: 599 if ok:
573 self.on_refreshButton_clicked() 600 self.on_refreshButton_clicked()
574 601
575 @pyqtSlot() 602 @pyqtSlot()
576 def __installRequirements(self): 603 def __installRequirements(self):
577 """ 604 """
578 Private slot to install packages from requirements files. 605 Private slot to install packages from requirements files.
579 """ 606 """
580 prefix = self.environmentsComboBox.itemData( 607 prefix = self.environmentsComboBox.itemData(
581 self.environmentsComboBox.currentIndex()) 608 self.environmentsComboBox.currentIndex()
609 )
582 if prefix: 610 if prefix:
583 requirements = EricFileDialog.getOpenFileNames( 611 requirements = EricFileDialog.getOpenFileNames(
584 self, 612 self,
585 self.tr("Install Packages"), 613 self.tr("Install Packages"),
586 "", 614 "",
587 self.tr("Text Files (*.txt);;All Files (*)")) 615 self.tr("Text Files (*.txt);;All Files (*)"),
616 )
588 if requirements: 617 if requirements:
589 args = [] 618 args = []
590 for requirement in requirements: 619 for requirement in requirements:
591 args.extend(["--file", requirement]) 620 args.extend(["--file", requirement])
592 ok = self.__conda.installPackages(args, prefix=prefix) 621 ok = self.__conda.installPackages(args, prefix=prefix)
593 if ok: 622 if ok:
594 self.on_refreshButton_clicked() 623 self.on_refreshButton_clicked()
595 624
596 @pyqtSlot() 625 @pyqtSlot()
597 def __generateRequirements(self): 626 def __generateRequirements(self):
598 """ 627 """
599 Private slot to generate a requirements file. 628 Private slot to generate a requirements file.
600 """ 629 """
601 prefix = self.environmentsComboBox.itemData( 630 prefix = self.environmentsComboBox.itemData(
602 self.environmentsComboBox.currentIndex()) 631 self.environmentsComboBox.currentIndex()
632 )
603 if prefix: 633 if prefix:
604 env = self.environmentsComboBox.currentText() 634 env = self.environmentsComboBox.currentText()
605 635
606 from .CondaExportDialog import CondaExportDialog 636 from .CondaExportDialog import CondaExportDialog
607 637
608 self.__requirementsDialog = CondaExportDialog( 638 self.__requirementsDialog = CondaExportDialog(self.__conda, env, prefix)
609 self.__conda, env, prefix)
610 self.__requirementsDialog.show() 639 self.__requirementsDialog.show()
611 QApplication.processEvents() 640 QApplication.processEvents()
612 self.__requirementsDialog.start() 641 self.__requirementsDialog.start()
613 642
614 @pyqtSlot() 643 @pyqtSlot()
615 def __cloneEnvironment(self): 644 def __cloneEnvironment(self):
616 """ 645 """
617 Private slot to clone a conda environment. 646 Private slot to clone a conda environment.
618 """ 647 """
619 from .CondaNewEnvironmentDataDialog import ( 648 from .CondaNewEnvironmentDataDialog import CondaNewEnvironmentDataDialog
620 CondaNewEnvironmentDataDialog) 649
621
622 prefix = self.environmentsComboBox.itemData( 650 prefix = self.environmentsComboBox.itemData(
623 self.environmentsComboBox.currentIndex()) 651 self.environmentsComboBox.currentIndex()
652 )
624 if prefix: 653 if prefix:
625 dlg = CondaNewEnvironmentDataDialog(self.tr("Clone Environment"), 654 dlg = CondaNewEnvironmentDataDialog(
626 False, self) 655 self.tr("Clone Environment"), False, self
656 )
627 if dlg.exec() == QDialog.DialogCode.Accepted: 657 if dlg.exec() == QDialog.DialogCode.Accepted:
628 virtEnvName, envName, _ = dlg.getData() 658 virtEnvName, envName, _ = dlg.getData()
629 args = [ 659 args = [
630 "--name", 660 "--name",
631 envName.strip(), 661 envName.strip(),
632 "--clone", 662 "--clone",
633 prefix, 663 prefix,
634 ] 664 ]
635 ok, prefix, interpreter = self.__conda.createCondaEnvironment( 665 ok, prefix, interpreter = self.__conda.createCondaEnvironment(args)
636 args)
637 if ok: 666 if ok:
638 ericApp().getObject("VirtualEnvManager").addVirtualEnv( 667 ericApp().getObject("VirtualEnvManager").addVirtualEnv(
639 virtEnvName, prefix, interpreter, isConda=True) 668 virtEnvName, prefix, interpreter, isConda=True
640 669 )
670
641 @pyqtSlot() 671 @pyqtSlot()
642 def __createEnvironment(self): 672 def __createEnvironment(self):
643 """ 673 """
644 Private slot to create a conda environment from a requirements file. 674 Private slot to create a conda environment from a requirements file.
645 """ 675 """
646 from .CondaNewEnvironmentDataDialog import ( 676 from .CondaNewEnvironmentDataDialog import CondaNewEnvironmentDataDialog
647 CondaNewEnvironmentDataDialog) 677
648 678 dlg = CondaNewEnvironmentDataDialog(self.tr("Create Environment"), True, self)
649 dlg = CondaNewEnvironmentDataDialog(self.tr("Create Environment"),
650 True, self)
651 if dlg.exec() == QDialog.DialogCode.Accepted: 679 if dlg.exec() == QDialog.DialogCode.Accepted:
652 virtEnvName, envName, requirements = dlg.getData() 680 virtEnvName, envName, requirements = dlg.getData()
653 args = [ 681 args = [
654 "--name", 682 "--name",
655 envName.strip(), 683 envName.strip(),
657 requirements, 685 requirements,
658 ] 686 ]
659 ok, prefix, interpreter = self.__conda.createCondaEnvironment(args) 687 ok, prefix, interpreter = self.__conda.createCondaEnvironment(args)
660 if ok: 688 if ok:
661 ericApp().getObject("VirtualEnvManager").addVirtualEnv( 689 ericApp().getObject("VirtualEnvManager").addVirtualEnv(
662 virtEnvName, prefix, interpreter, isConda=True) 690 virtEnvName, prefix, interpreter, isConda=True
663 691 )
692
664 @pyqtSlot() 693 @pyqtSlot()
665 def __deleteEnvironment(self): 694 def __deleteEnvironment(self):
666 """ 695 """
667 Private slot to delete a conda environment. 696 Private slot to delete a conda environment.
668 """ 697 """
669 envName = self.environmentsComboBox.currentText() 698 envName = self.environmentsComboBox.currentText()
670 ok = EricMessageBox.yesNo( 699 ok = EricMessageBox.yesNo(
671 self, 700 self,
672 self.tr("Delete Environment"), 701 self.tr("Delete Environment"),
673 self.tr("""<p>Shall the environment <b>{0}</b> really be""" 702 self.tr(
674 """ deleted?</p>""").format(envName) 703 """<p>Shall the environment <b>{0}</b> really be""" """ deleted?</p>"""
704 ).format(envName),
675 ) 705 )
676 if ok: 706 if ok:
677 self.__conda.removeCondaEnvironment(name=envName) 707 self.__conda.removeCondaEnvironment(name=envName)
678 708
679 @pyqtSlot() 709 @pyqtSlot()
680 def __editUserConfiguration(self): 710 def __editUserConfiguration(self):
681 """ 711 """
682 Private slot to edit the user configuration. 712 Private slot to edit the user configuration.
683 """ 713 """
684 from QScintilla.MiniEditor import MiniEditor 714 from QScintilla.MiniEditor import MiniEditor
685 715
686 cfgFile = CondaInterface.userConfiguration() 716 cfgFile = CondaInterface.userConfiguration()
687 if not cfgFile: 717 if not cfgFile:
688 return 718 return
689 719
690 if not os.path.exists(cfgFile): 720 if not os.path.exists(cfgFile):
691 self.__conda.writeDefaultConfiguration() 721 self.__conda.writeDefaultConfiguration()
692 722
693 # check, if the destination is writeable 723 # check, if the destination is writeable
694 if not os.access(cfgFile, os.W_OK): 724 if not os.access(cfgFile, os.W_OK):
695 EricMessageBox.critical( 725 EricMessageBox.critical(
696 None, 726 None,
697 self.tr("Edit Configuration"), 727 self.tr("Edit Configuration"),
698 self.tr("""The configuration file "{0}" does not exist""" 728 self.tr(
699 """ or is not writable.""").format(cfgFile)) 729 """The configuration file "{0}" does not exist"""
730 """ or is not writable."""
731 ).format(cfgFile),
732 )
700 return 733 return
701 734
702 self.__editor = MiniEditor(cfgFile, "YAML") 735 self.__editor = MiniEditor(cfgFile, "YAML")
703 self.__editor.show() 736 self.__editor.show()
704 737
705 @pyqtSlot() 738 @pyqtSlot()
706 def __condaConfigure(self): 739 def __condaConfigure(self):
707 """ 740 """
708 Private slot to open the configuration page. 741 Private slot to open the configuration page.
709 """ 742 """
710 ericApp().getObject("UserInterface").showPreferences("condaPage") 743 ericApp().getObject("UserInterface").showPreferences("condaPage")
711 744
712 @pyqtSlot() 745 @pyqtSlot()
713 def on_recheckButton_clicked(self): 746 def on_recheckButton_clicked(self):
714 """ 747 """
715 Private slot to re-check the availability of conda and adjust the 748 Private slot to re-check the availability of conda and adjust the
716 interface if it became available. 749 interface if it became available.
717 """ 750 """
718 if CondaInterface.isCondaAvailable(): 751 if CondaInterface.isCondaAvailable():
719 self.__initCondaInterface() 752 self.__initCondaInterface()
720 753
721 self.notAvailableWidget.hide() 754 self.notAvailableWidget.hide()
722 self.baseWidget.show() 755 self.baseWidget.show()

eric ide

mercurial