74 |
76 |
75 self.resultsList.header().setSortIndicator(1, Qt.SortOrder.AscendingOrder) |
77 self.resultsList.header().setSortIndicator(1, Qt.SortOrder.AscendingOrder) |
76 |
78 |
77 self.statisticsGroup.setVisible(False) |
79 self.statisticsGroup.setVisible(False) |
78 |
80 |
|
81 self.__statistics = BlackStatistics() |
|
82 |
79 self.__report = BlackReport(self) |
83 self.__report = BlackReport(self) |
80 self.__report.check = action is BlackFormattingAction.Check |
84 self.__report.check = action is BlackFormattingAction.Check |
81 self.__report.diff = action is BlackFormattingAction.Diff |
85 self.__report.diff = action is BlackFormattingAction.Diff |
|
86 self.__report.result.connect(self.__handleBlackFormattingResult) |
82 |
87 |
83 self.__config = copy.deepcopy(configuration) |
88 self.__config = copy.deepcopy(configuration) |
84 self.__project = project |
89 self.__project = project |
85 self.__action = action |
90 self.__action = action |
86 |
91 |
189 if self.__action is BlackFormattingAction.Format |
194 if self.__action is BlackFormattingAction.Format |
190 else self.tr("would reformat") |
195 else self.tr("would reformat") |
191 ) |
196 ) |
192 |
197 |
193 total = self.progressBar.maximum() |
198 total = self.progressBar.maximum() |
194 processed = total - self.__report.ignored_count |
199 processed = total - self.__statistics.ignoreCount |
195 |
200 |
196 self.totalCountLabel.setText("{0:n}".format(total)) |
201 self.totalCountLabel.setText("{0:n}".format(total)) |
197 self.excludedCountLabel.setText("{0:n}".format(self.__report.ignored_count)) |
202 self.excludedCountLabel.setText("{0:n}".format(self.__statistics.ignoreCount)) |
198 self.failuresCountLabel.setText("{0:n}".format(self.__report.failure_count)) |
203 self.failuresCountLabel.setText("{0:n}".format(self.__statistics.failureCount)) |
199 self.processedCountLabel.setText("{0:n}".format(processed)) |
204 self.processedCountLabel.setText("{0:n}".format(processed)) |
200 self.reformattedCountLabel.setText("{0:n}".format(self.__report.change_count)) |
205 self.reformattedCountLabel.setText( |
201 self.unchangedCountLabel.setText("{0:n}".format(self.__report.same_count)) |
206 "{0:n}".format(self.__statistics.changeCount) |
|
207 ) |
|
208 self.unchangedCountLabel.setText("{0:n}".format(self.__statistics.sameCount)) |
202 |
209 |
203 self.statisticsGroup.setVisible(True) |
210 self.statisticsGroup.setVisible(True) |
204 |
211 |
205 @pyqtSlot(QAbstractButton) |
212 @pyqtSlot(QAbstractButton) |
206 def on_buttonBox_clicked(self, button): |
213 def on_buttonBox_clicked(self, button): |
237 elif dataType == "diff": |
244 elif dataType == "diff": |
238 if self.__diffDialog is None: |
245 if self.__diffDialog is None: |
239 self.__diffDialog = BlackDiffWidget() |
246 self.__diffDialog = BlackDiffWidget() |
240 self.__diffDialog.showDiff(item.data(0, BlackFormattingDialog.DataRole)) |
247 self.__diffDialog.showDiff(item.data(0, BlackFormattingDialog.DataRole)) |
241 |
248 |
242 def addResultEntry(self, status, fileName, isError=False, data=None): |
|
243 """ |
|
244 Public method to add an entry to the result list. |
|
245 |
|
246 @param status status of the operation |
|
247 @type str |
|
248 @param fileName name of the processed file |
|
249 @type str |
|
250 @param isError flag indicating that data contains an error message (defaults to |
|
251 False) |
|
252 @type bool (optional) |
|
253 @param data associated data (diff or error message) (defaults to None) |
|
254 @type str (optional) |
|
255 """ |
|
256 if self.__project: |
|
257 fileName = self.__project.getRelativePath(fileName) |
|
258 |
|
259 itm = QTreeWidgetItem(self.resultsList, [status, fileName]) |
|
260 if data: |
|
261 itm.setData( |
|
262 0, BlackFormattingDialog.DataTypeRole, "error" if isError else "diff" |
|
263 ) |
|
264 itm.setData(0, BlackFormattingDialog.DataRole, data) |
|
265 |
|
266 self.progressBar.setValue(self.progressBar.value() + 1) |
|
267 |
|
268 QCoreApplication.processEvents() |
|
269 |
|
270 def __formatFiles(self): |
249 def __formatFiles(self): |
271 """ |
250 """ |
272 Private method to format the list of files according the configuration. |
251 Private method to format the list of files according the configuration. |
273 """ |
252 """ |
274 writeBack = black.WriteBack.from_configuration( |
253 writeBack = black.WriteBack.from_configuration( |
368 itm.setHidden( |
347 itm.setHidden( |
369 status != self.__allFilter |
348 status != self.__allFilter |
370 and itm.text(BlackFormattingDialog.StatusColumn) != status |
349 and itm.text(BlackFormattingDialog.StatusColumn) != status |
371 ) |
350 ) |
372 |
351 |
373 |
352 @pyqtSlot(str, str, str) |
374 class BlackReport(black.Report): |
353 def __handleBlackFormattingResult(self, status, filename, data): |
|
354 """ |
|
355 Private slot to handle the result of a black reformatting action. |
|
356 |
|
357 @param status status of the performed action (one of 'changed', 'unchanged', |
|
358 'unmodified', 'failed' or 'ignored') |
|
359 @type str |
|
360 @param filename name of the processed file |
|
361 @type str |
|
362 @param data action data (error message or unified diff) |
|
363 @type str |
|
364 """ |
|
365 isError = False |
|
366 |
|
367 if status == "changed": |
|
368 statusMsg = ( |
|
369 self.tr("would reformat") |
|
370 if self.__action |
|
371 in (BlackFormattingAction.Check, BlackFormattingAction.Diff) |
|
372 else self.tr("reformatted") |
|
373 ) |
|
374 self.__statistics.changeCount += 1 |
|
375 |
|
376 elif status == "unchanged": |
|
377 statusMsg = self.tr("unchanged") |
|
378 self.__statistics.sameCount += 1 |
|
379 |
|
380 elif status == "unmodified": |
|
381 statusMsg = self.tr("unmodified") |
|
382 self.__statistics.sameCount += 1 |
|
383 |
|
384 elif status == "ignored": |
|
385 statusMsg = self.tr("ignored") |
|
386 self.__statistics.ignoreCount += 1 |
|
387 |
|
388 elif status == "failed": |
|
389 statusMsg = self.tr("failed") |
|
390 self.__statistics.failureCount += 1 |
|
391 isError = True |
|
392 |
|
393 else: |
|
394 statusMsg = self.tr("invalid status ({0})").format(status) |
|
395 self.__statistics.failureCount += 1 |
|
396 isError = True |
|
397 |
|
398 if self.__project: |
|
399 filename = self.__project.getRelativePath(filename) |
|
400 |
|
401 itm = QTreeWidgetItem(self.resultsList, [statusMsg, filename]) |
|
402 if data: |
|
403 itm.setData( |
|
404 0, BlackFormattingDialog.DataTypeRole, "error" if isError else "diff" |
|
405 ) |
|
406 itm.setData(0, BlackFormattingDialog.DataRole, data) |
|
407 |
|
408 self.progressBar.setValue(self.progressBar.value() + 1) |
|
409 |
|
410 QCoreApplication.processEvents() |
|
411 |
|
412 |
|
413 @dataclass |
|
414 class BlackStatistics: |
|
415 """ |
|
416 Class containing the reformatting statistic data. |
|
417 """ |
|
418 |
|
419 ignoreCount: int = 0 |
|
420 changeCount: int = 0 |
|
421 sameCount: int = 0 |
|
422 failureCount: int = 0 |
|
423 |
|
424 |
|
425 class BlackReport(QObject, black.Report): |
375 """ |
426 """ |
376 Class extending the black Report to work with our dialog. |
427 Class extending the black Report to work with our dialog. |
377 """ |
428 |
|
429 @signal result(status, file name, data) emitted to signal the reformatting result |
|
430 as three strings giving the status (one of 'changed', 'unchanged', 'unmodified', |
|
431 'failed' or 'ignored'), the file name and data related to the result |
|
432 """ |
|
433 |
|
434 result = pyqtSignal(str, str, str) |
378 |
435 |
379 def __init__(self, dialog): |
436 def __init__(self, dialog): |
380 """ |
437 """ |
381 Constructor |
438 Constructor |
382 |
439 |
383 @param dialog reference to the result dialog |
440 @param dialog reference to the result dialog |
384 @type QDialog |
441 @type QDialog |
385 """ |
442 """ |
386 super().__init__() |
443 QObject.__init__(self, dialog) |
|
444 black.Report.__init__(self) |
387 |
445 |
388 self.ignored_count = 0 |
446 self.ignored_count = 0 |
389 |
447 |
390 self.__dialog = dialog |
448 self.__dialog = dialog |
391 |
449 |
399 @type black.Changed |
457 @type black.Changed |
400 @param diff unified diff of potential changes (defaults to "") |
458 @param diff unified diff of potential changes (defaults to "") |
401 @type str |
459 @type str |
402 """ |
460 """ |
403 if changed is black.Changed.YES: |
461 if changed is black.Changed.YES: |
404 status = ( |
462 status = "changed" |
405 QCoreApplication.translate("BlackFormattingDialog", "would reformat") |
|
406 if self.check or self.diff |
|
407 else QCoreApplication.translate("BlackFormattingDialog", "reformatted") |
|
408 ) |
|
409 self.change_count += 1 |
|
410 |
463 |
411 elif changed is black.Changed.NO: |
464 elif changed is black.Changed.NO: |
412 status = QCoreApplication.translate("BlackFormattingDialog", "unchanged") |
465 status = "unchanged" |
413 self.same_count += 1 |
|
414 |
466 |
415 elif changed is black.Changed.CACHED: |
467 elif changed is black.Changed.CACHED: |
416 status = QCoreApplication.translate("BlackFormattingDialog", "unmodified") |
468 status = "unmodified" |
417 self.same_count += 1 |
469 |
418 |
470 self.result.emit(status, str(src), diff) |
419 if self.diff: |
|
420 self.__dialog.addResultEntry(status, str(src), data=diff) |
|
421 else: |
|
422 self.__dialog.addResultEntry(status, str(src)) |
|
423 |
471 |
424 def failed(self, src, message): |
472 def failed(self, src, message): |
425 """ |
473 """ |
426 Public method to handle a reformat failure. |
474 Public method to handle a reformat failure. |
427 |
475 |
428 @param src name of the processed file |
476 @param src name of the processed file |
429 @type pathlib.Path |
477 @type pathlib.Path |
430 @param message error message |
478 @param message error message |
431 @type str |
479 @type str |
432 """ |
480 """ |
433 status = QCoreApplication.translate("BlackFormattingDialog", "failed") |
481 self.result.emit("failed", str(src), message) |
434 self.failure_count += 1 |
|
435 |
|
436 self.__dialog.addResultEntry(status, str(src), isError=True, data=message) |
|
437 |
482 |
438 def path_ignored(self, src, message=""): |
483 def path_ignored(self, src, message=""): |
439 """ |
484 """ |
440 Public method handling an ignored path. |
485 Public method handling an ignored path. |
441 |
486 |
442 @param src name of the processed file |
487 @param src name of the processed file |
443 @type pathlib.Path or str |
488 @type pathlib.Path or str |
444 @param message ignore message (default to "") |
489 @param message ignore message (default to "") |
445 @type str (optional) |
490 @type str (optional) |
446 """ |
491 """ |
447 status = QCoreApplication.translate("BlackFormattingDialog", "ignored") |
492 self.result.emit("ignored", str(src), "") |
448 self.ignored_count += 1 |
|
449 |
|
450 self.__dialog.addResultEntry(status, str(src)) |
|