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