src/eric7/CondaInterface/CondaExecDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
22 22
23 class CondaExecDialog(QDialog, Ui_CondaExecDialog): 23 class CondaExecDialog(QDialog, Ui_CondaExecDialog):
24 """ 24 """
25 Class implementing a dialog to show the output of a conda execution. 25 Class implementing a dialog to show the output of a conda execution.
26 """ 26 """
27
27 def __init__(self, command, parent=None): 28 def __init__(self, command, parent=None):
28 """ 29 """
29 Constructor 30 Constructor
30 31
31 @param command conda command executed 32 @param command conda command executed
32 @type str 33 @type str
33 @param parent reference to the parent widget 34 @param parent reference to the parent widget
34 @type QWidget 35 @type QWidget
35 """ 36 """
36 super().__init__(parent) 37 super().__init__(parent)
37 self.setupUi(self) 38 self.setupUi(self)
38 39
39 self.buttonBox.button( 40 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
40 QDialogButtonBox.StandardButton.Close).setEnabled(False) 41 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
41 self.buttonBox.button( 42
42 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
43
44 self.__condaCommand = command 43 self.__condaCommand = command
45 44
46 self.__process = None 45 self.__process = None
47 self.__condaExe = Preferences.getConda("CondaExecutable") 46 self.__condaExe = Preferences.getConda("CondaExecutable")
48 if not self.__condaExe: 47 if not self.__condaExe:
49 self.__condaExe = "conda" 48 self.__condaExe = "conda"
50 49
51 @pyqtSlot(QAbstractButton) 50 @pyqtSlot(QAbstractButton)
52 def on_buttonBox_clicked(self, button): 51 def on_buttonBox_clicked(self, button):
53 """ 52 """
54 Private slot called by a button of the button box clicked. 53 Private slot called by a button of the button box clicked.
55 54
56 @param button button that was clicked 55 @param button button that was clicked
57 @type QAbstractButton 56 @type QAbstractButton
58 """ 57 """
59 if button == self.buttonBox.button( 58 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
60 QDialogButtonBox.StandardButton.Close
61 ):
62 self.accept() 59 self.accept()
63 elif button == self.buttonBox.button( 60 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
64 QDialogButtonBox.StandardButton.Cancel
65 ):
66 self.__finish(1, 0) 61 self.__finish(1, 0)
67 62
68 def start(self, arguments): 63 def start(self, arguments):
69 """ 64 """
70 Public slot to start the conda command. 65 Public slot to start the conda command.
71 66
72 @param arguments commandline arguments for conda program 67 @param arguments commandline arguments for conda program
73 @type list of str 68 @type list of str
74 """ 69 """
75 self.errorGroup.hide() 70 self.errorGroup.hide()
76 self.progressLabel.hide() 71 self.progressLabel.hide()
77 self.progressBar.hide() 72 self.progressBar.hide()
78 73
79 self.contents.clear() 74 self.contents.clear()
80 self.errors.clear() 75 self.errors.clear()
81 self.progressLabel.clear() 76 self.progressLabel.clear()
82 self.progressBar.setValue(0) 77 self.progressBar.setValue(0)
83 78
84 self.__bufferedStdout = None 79 self.__bufferedStdout = None
85 self.__json = "--json" in arguments 80 self.__json = "--json" in arguments
86 self.__firstProgress = True 81 self.__firstProgress = True
87 self.__lastFetchFile = "" 82 self.__lastFetchFile = ""
88 83
89 self.__statusOk = False 84 self.__statusOk = False
90 self.__result = None 85 self.__result = None
91 86
92 self.__logOutput(self.__condaExe + " " + " ".join(arguments) + "\n\n") 87 self.__logOutput(self.__condaExe + " " + " ".join(arguments) + "\n\n")
93 88
94 self.__process = QProcess() 89 self.__process = QProcess()
95 self.__process.readyReadStandardOutput.connect(self.__readStdout) 90 self.__process.readyReadStandardOutput.connect(self.__readStdout)
96 self.__process.readyReadStandardError.connect(self.__readStderr) 91 self.__process.readyReadStandardError.connect(self.__readStderr)
97 self.__process.finished.connect(self.__finish) 92 self.__process.finished.connect(self.__finish)
98 93
99 self.__process.start(self.__condaExe, arguments) 94 self.__process.start(self.__condaExe, arguments)
100 procStarted = self.__process.waitForStarted(5000) 95 procStarted = self.__process.waitForStarted(5000)
101 if not procStarted: 96 if not procStarted:
102 EricMessageBox.critical( 97 EricMessageBox.critical(
103 self, 98 self,
104 self.tr("Conda Execution"), 99 self.tr("Conda Execution"),
105 self.tr("""The conda executable could not be started. Is it""" 100 self.tr(
106 """ configured correctly?""")) 101 """The conda executable could not be started. Is it"""
102 """ configured correctly?"""
103 ),
104 )
107 self.__finish(1, 0) 105 self.__finish(1, 0)
108 else: 106 else:
109 self.__logOutput(self.tr("Operation started.\n")) 107 self.__logOutput(self.tr("Operation started.\n"))
110 108
111 def __finish(self, exitCode, exitStatus, giveUp=False): 109 def __finish(self, exitCode, exitStatus, giveUp=False):
112 """ 110 """
113 Private slot called when the process finished. 111 Private slot called when the process finished.
114 112
115 It is called when the process finished or 113 It is called when the process finished or
116 the user pressed the button. 114 the user pressed the button.
117 115
118 @param exitCode exit code of the process 116 @param exitCode exit code of the process
119 @type int 117 @type int
120 @param exitStatus exit status of the process 118 @param exitStatus exit status of the process
121 @type QProcess.ExitStatus 119 @type QProcess.ExitStatus
122 @param giveUp flag indicating to not start another attempt 120 @param giveUp flag indicating to not start another attempt
123 @type bool 121 @type bool
124 """ 122 """
125 if (self.__process is not None and 123 if (
126 self.__process.state() != QProcess.ProcessState.NotRunning): 124 self.__process is not None
125 and self.__process.state() != QProcess.ProcessState.NotRunning
126 ):
127 self.__process.terminate() 127 self.__process.terminate()
128 QTimer.singleShot(2000, self.__process.kill) 128 QTimer.singleShot(2000, self.__process.kill)
129 self.__process.waitForFinished(3000) 129 self.__process.waitForFinished(3000)
130 130
131 self.buttonBox.button( 131 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
132 QDialogButtonBox.StandardButton.Close).setEnabled(True) 132 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
133 self.buttonBox.button( 133 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
134 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) 134
135 self.buttonBox.button(
136 QDialogButtonBox.StandardButton.Close).setDefault(True)
137
138 self.progressLabel.hide() 135 self.progressLabel.hide()
139 self.progressBar.hide() 136 self.progressBar.hide()
140 137
141 self.__statusOk = exitCode == 0 138 self.__statusOk = exitCode == 0
142 139
143 self.__logOutput(self.tr("Operation finished.\n")) 140 self.__logOutput(self.tr("Operation finished.\n"))
144 if not self.__json and self.__bufferedStdout: 141 if not self.__json and self.__bufferedStdout:
145 self.__logOutput(self.__bufferedStdout) 142 self.__logOutput(self.__bufferedStdout)
146 143
147 if self.__json and self.__bufferedStdout: 144 if self.__json and self.__bufferedStdout:
148 index = self.__bufferedStdout.find("{") 145 index = self.__bufferedStdout.find("{")
149 rindex = self.__bufferedStdout.rfind("}") 146 rindex = self.__bufferedStdout.rfind("}")
150 self.__bufferedStdout = self.__bufferedStdout[index:rindex + 1] 147 self.__bufferedStdout = self.__bufferedStdout[index : rindex + 1]
151 try: 148 try:
152 self.__result = json.loads(self.__bufferedStdout) 149 self.__result = json.loads(self.__bufferedStdout)
153 except Exception as error: 150 except Exception as error:
154 self.__result = {} 151 self.__result = {}
155 self.__logError(str(error)) 152 self.__logError(str(error))
156 return 153 return
157 154
158 if "error" in self.__result: 155 if "error" in self.__result:
159 self.__logError(self.__result["error"]) 156 self.__logError(self.__result["error"])
160 self.__statusOk = False 157 self.__statusOk = False
161 elif ("success" in self.__result and 158 elif "success" in self.__result and not self.__result["success"]:
162 not self.__result["success"]):
163 self.__logError( 159 self.__logError(
164 self.tr("Conda command '{0}' did not return success.") 160 self.tr("Conda command '{0}' did not return success.").format(
165 .format(self.__condaCommand)) 161 self.__condaCommand
162 )
163 )
166 if "message" in self.__result: 164 if "message" in self.__result:
167 self.__logError("\n") 165 self.__logError("\n")
168 self.__logError( 166 self.__logError(
169 self.tr("\nConda Message: {0}").format( 167 self.tr("\nConda Message: {0}").format(self.__result["message"])
170 self.__result["message"])) 168 )
171 self.__statusOk = False 169 self.__statusOk = False
172 elif "message" in self.__result: 170 elif "message" in self.__result:
173 self.__logOutput( 171 self.__logOutput(
174 self.tr("\nConda Message: {0}").format( 172 self.tr("\nConda Message: {0}").format(self.__result["message"])
175 self.__result["message"])) 173 )
176 174
177 def getResult(self): 175 def getResult(self):
178 """ 176 """
179 Public method to the result of the command execution. 177 Public method to the result of the command execution.
180 178
181 @return tuple containing a flag indicating success and the result data. 179 @return tuple containing a flag indicating success and the result data.
182 @rtype tuple of (bool, dict) 180 @rtype tuple of (bool, dict)
183 """ 181 """
184 return self.__statusOk, self.__result 182 return self.__statusOk, self.__result
185 183
186 def __setProgressValues(self, jsonDict, progressType): 184 def __setProgressValues(self, jsonDict, progressType):
187 """ 185 """
188 Private method to set the value of the progress bar. 186 Private method to set the value of the progress bar.
189 187
190 @param jsonDict dictionary containing the progress info 188 @param jsonDict dictionary containing the progress info
191 @type dict 189 @type dict
192 @param progressType action type to check for 190 @param progressType action type to check for
193 @type str 191 @type str
194 @return flag indicating success 192 @return flag indicating success
196 """ 194 """
197 if progressType in jsonDict and "progress" in jsonDict: 195 if progressType in jsonDict and "progress" in jsonDict:
198 if jsonDict["maxval"] == 1: 196 if jsonDict["maxval"] == 1:
199 self.progressBar.setMaximum(100) 197 self.progressBar.setMaximum(100)
200 # percent values 198 # percent values
201 self.progressBar.setValue( 199 self.progressBar.setValue(int(jsonDict["progress"] * 100))
202 int(jsonDict["progress"] * 100))
203 parts = jsonDict["fetch"].split("|") 200 parts = jsonDict["fetch"].split("|")
204 filename = parts[0].strip() 201 filename = parts[0].strip()
205 filesize = parts[1].strip() 202 filesize = parts[1].strip()
206 else: 203 else:
207 self.progressBar.setMaximum(jsonDict["maxval"]) 204 self.progressBar.setMaximum(jsonDict["maxval"])
208 self.progressBar.setValue(jsonDict["progress"]) 205 self.progressBar.setValue(jsonDict["progress"])
209 filename = jsonDict["fetch"].strip() 206 filename = jsonDict["fetch"].strip()
210 filesize = Globals.dataString(int(jsonDict["maxval"])) 207 filesize = Globals.dataString(int(jsonDict["maxval"]))
211 208
212 self.progressLabel.setText( 209 self.progressLabel.setText(
213 self.tr("{0} (Size: {1})").format(filename, filesize)) 210 self.tr("{0} (Size: {1})").format(filename, filesize)
214 211 )
212
215 if progressType == "fetch": 213 if progressType == "fetch":
216 if filename != self.__lastFetchFile: 214 if filename != self.__lastFetchFile:
217 self.__logOutput( 215 self.__logOutput(self.tr("Fetching {0} ...").format(filename))
218 self.tr("Fetching {0} ...").format(filename))
219 self.__lastFetchFile = filename 216 self.__lastFetchFile = filename
220 elif jsonDict["finished"]: 217 elif jsonDict["finished"]:
221 self.__logOutput(self.tr(" Done.\n")) 218 self.__logOutput(self.tr(" Done.\n"))
222 219
223 if self.__firstProgress: 220 if self.__firstProgress:
224 self.progressLabel.show() 221 self.progressLabel.show()
225 self.progressBar.show() 222 self.progressBar.show()
226 self.__firstProgress = False 223 self.__firstProgress = False
227 224
228 return True 225 return True
229 226
230 return False 227 return False
231 228
232 def __readStdout(self): 229 def __readStdout(self):
233 """ 230 """
234 Private slot to handle the readyReadStandardOutput signal. 231 Private slot to handle the readyReadStandardOutput signal.
235 232
236 It reads the output of the process, formats it and inserts it into 233 It reads the output of the process, formats it and inserts it into
237 the contents pane. 234 the contents pane.
238 """ 235 """
239 all_stdout = str(self.__process.readAllStandardOutput(), 236 all_stdout = str(
240 Preferences.getSystem("IOEncoding"), 237 self.__process.readAllStandardOutput(),
241 'replace') 238 Preferences.getSystem("IOEncoding"),
239 "replace",
240 )
242 all_stdout = all_stdout.replace("\x00", "") 241 all_stdout = all_stdout.replace("\x00", "")
243 if self.__json: 242 if self.__json:
244 for stdout in all_stdout.splitlines(): 243 for stdout in all_stdout.splitlines():
245 try: 244 try:
246 jsonDict = json.loads(stdout.replace("\x00", "").strip()) 245 jsonDict = json.loads(stdout.replace("\x00", "").strip())
257 self.__bufferedStdout = stdout 256 self.__bufferedStdout = stdout
258 else: 257 else:
259 self.__bufferedStdout += stdout 258 self.__bufferedStdout += stdout
260 else: 259 else:
261 self.__logOutput(all_stdout) 260 self.__logOutput(all_stdout)
262 261
263 def __readStderr(self): 262 def __readStderr(self):
264 """ 263 """
265 Private slot to handle the readyReadStandardError signal. 264 Private slot to handle the readyReadStandardError signal.
266 265
267 It reads the error output of the process and inserts it into the 266 It reads the error output of the process and inserts it into the
268 error pane. 267 error pane.
269 """ 268 """
270 self.__process.setReadChannel(QProcess.ProcessChannel.StandardError) 269 self.__process.setReadChannel(QProcess.ProcessChannel.StandardError)
271 270
272 while self.__process.canReadLine(): 271 while self.__process.canReadLine():
273 stderr = str(self.__process.readLine(), 272 stderr = str(
274 Preferences.getSystem("IOEncoding"), 273 self.__process.readLine(),
275 'replace') 274 Preferences.getSystem("IOEncoding"),
275 "replace",
276 )
276 self.__logError(stderr) 277 self.__logError(stderr)
277 278
278 def __logOutput(self, stdout): 279 def __logOutput(self, stdout):
279 """ 280 """
280 Private method to log some output. 281 Private method to log some output.
281 282
282 @param stdout output string to log 283 @param stdout output string to log
283 @type str 284 @type str
284 """ 285 """
285 self.contents.insertPlainText(stdout) 286 self.contents.insertPlainText(stdout)
286 self.contents.ensureCursorVisible() 287 self.contents.ensureCursorVisible()
287 288
288 def __logError(self, stderr): 289 def __logError(self, stderr):
289 """ 290 """
290 Private method to log an error. 291 Private method to log an error.
291 292
292 @param stderr error string to log 293 @param stderr error string to log
293 @type str 294 @type str
294 """ 295 """
295 self.errorGroup.show() 296 self.errorGroup.show()
296 self.errors.insertPlainText(stderr) 297 self.errors.insertPlainText(stderr)

eric ide

mercurial