CondaInterface/CondaExecDialog.py

branch
conda
changeset 6677
6299d69a218a
child 6678
5f1de9e59227
equal deleted inserted replaced
6676:536ad4fa35aa 6677:6299d69a218a
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show the output of a conda execution.
8 """
9
10 from __future__ import unicode_literals
11 try:
12 str = unicode
13 except NameError:
14 pass
15
16 import json
17
18 from PyQt5.QtCore import pyqtSlot, QProcess, QTimer
19 from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QAbstractButton
20
21 from E5Gui import E5MessageBox
22
23 from .Ui_CondaExecDialog import Ui_CondaExecDialog
24
25 import Preferences
26
27
28 class CondaExecDialog(QDialog, Ui_CondaExecDialog):
29 """
30 Class documentation goes here.
31 """
32 def __init__(self, configuration, venvManager, parent=None):
33 """
34 Constructor
35
36 @param parent reference to the parent widget
37 @type QWidget
38 """
39 super(CondaExecDialog, self).__init__(parent)
40 self.setupUi(self)
41
42 self.__venvName = configuration["logicalName"]
43 self.__venvManager = venvManager
44
45 self.__process = None
46 self.__condaExe = Preferences.getConda("CondaExecutable")
47 if not self.__condaExe:
48 self.__condaExe = "conda"
49
50 @pyqtSlot(QAbstractButton)
51 def on_buttonBox_clicked(self, button):
52 """
53 Private slot called by a button of the button box clicked.
54
55 @param button button that was clicked
56 @type QAbstractButton
57 """
58 if button == self.buttonBox.button(QDialogButtonBox.Close):
59 self.accept()
60 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
61 self.__finish()
62
63 def start(self, arguments):
64 """
65 Public slot to start the conda command.
66
67 @param arguments commandline arguments for conda program
68 @type list of str
69 """
70 self.errorGroup.hide()
71 self.progressLabel.hide()
72 self.progressBar.hide()
73
74 self.contents.clear()
75 self.errors.clear()
76 self.progressLabel.clear()
77 self.progressBar.setValue(0)
78
79 self.__bufferedStdout = None
80 self.__json = "--json" in arguments
81 self.__firstProgress = True
82
83 self.__process = QProcess()
84 self.__process.readyReadStandardOutput.connect(self.__readStdout)
85 self.__process.readyReadStandardError.connect(self.__readStderr)
86 self.__process.finished.connect(self.__finish)
87
88 self.__process.start(self.__condaExe, arguments)
89 procStarted = self.__process.waitForStarted(5000)
90 if not procStarted:
91 E5MessageBox.critical(
92 self,
93 self.tr("Conda Execution"),
94 self.tr("""The conda executable could not be started. Is it"""
95 """ configured correctly?"""))
96 self.__finish(1, 0)
97 else:
98 self.__logOutput(self.tr("Operation started.\n"))
99
100 def __finish(self, exitCode, exitStatus, giveUp=False):
101 """
102 Private slot called when the process finished.
103
104 It is called when the process finished or
105 the user pressed the button.
106
107 @param exitCode exit code of the process (integer)
108 @param exitStatus exit status of the process (QProcess.ExitStatus)
109 @keyparam giveUp flag indicating to not start another attempt (boolean)
110 """
111 if self.__process is not None and \
112 self.__process.state() != QProcess.NotRunning:
113 self.__process.terminate()
114 QTimer.singleShot(2000, self.__process.kill)
115 self.__process.waitForFinished(3000)
116
117 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
118 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
119 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
120
121 self.__logOutput(self.tr("Operation finished.\n"))
122 if self.__json:
123 if self.__bufferedStdout:
124 try:
125 jsonDict = json.loads(self.__bufferedStdout)
126 except Exception as error:
127 self.__logError(str(error))
128 return
129
130 if "success" in jsonDict and jsonDict["success"]:
131 if "prefix" in jsonDict:
132 prefix = jsonDict["prefix"]
133 elif "dst_prefix" in jsonDict:
134 prefix = jsonDict["dst_prefix"]
135 else:
136 prefix = ""
137 self.__venvManager.addVirtualEnv(self.__venvName,
138 prefix,
139 isConda=True)
140
141 def __progressLabelString(self, text):
142 """
143 Private method to process a string and format it for the progress
144 label.
145
146 @param text text to be processed
147 @type str
148 @return formatted progress label string
149 @rtype str
150 """
151 parts = text.split("|")
152 return self.tr("{0} (Size: {1})".format(parts[0].strip(),
153 parts[1].strip()))
154
155 def __readStdout(self):
156 """
157 Private slot to handle the readyReadStandardOutput signal.
158
159 It reads the output of the process, formats it and inserts it into
160 the contents pane.
161 """
162 all_stdout = str(self.__process.readAllStandardOutput(),
163 Preferences.getSystem("IOEncoding"),
164 'replace')
165 all_stdout = all_stdout.replace("\x00", "")
166 if self.__json:
167 for stdout in all_stdout.splitlines():
168 try:
169 jsonDict = json.loads(stdout.replace("\x00", "").strip())
170 if "progress" in jsonDict:
171 self.progressLabel.setText(
172 self.__progressLabelString(jsonDict["fetch"]))
173 self.progressBar.setValue(
174 int(jsonDict["progress"] * 100))
175 if self.__firstProgress:
176 self.progressLabel.show()
177 self.progressBar.show()
178 self.__firstProgress = False
179 else:
180 if self.__bufferedStdout is None:
181 self.__bufferedStdout = stdout
182 else:
183 self.__bufferedStdout += stdout
184 except (TypeError, ValueError):
185 if self.__bufferedStdout is None:
186 self.__bufferedStdout = stdout
187 else:
188 self.__bufferedStdout += stdout
189 else:
190 self.__logOutput(all_stdout)
191
192 def __readStderr(self):
193 """
194 Private slot to handle the readyReadStandardError signal.
195
196 It reads the error output of the process and inserts it into the
197 error pane.
198 """
199 self.__process.setReadChannel(QProcess.StandardError)
200
201 while self.__process.canReadLine():
202 stderr = str(self.__process.readLine(),
203 Preferences.getSystem("IOEncoding"),
204 'replace')
205 self.__logError(stderr)
206
207 def __logOutput(self, stdout):
208 """
209 Private method to log some output.
210
211 @param stdout output string to log
212 @type str
213 """
214 self.contents.insertPlainText(stdout)
215 self.contents.ensureCursorVisible()
216
217 def __logError(self, stderr):
218 """
219 Private method to log an error.
220
221 @param stderr error string to log
222 @type str
223 """
224 self.errorGroup.show()
225 self.errors.insertPlainText(stderr)
226 self.errors.ensureCursorVisible()

eric ide

mercurial