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