Sun, 06 Nov 2022 11:22:39 +0100
Corrected a code style issue.
9453 | 1 | # -*- coding: utf-8 -*- |
2 | ||
3 | # Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> | |
4 | # | |
5 | ||
6 | """ | |
7 | Module implementing a dialog showing the isort code formatting progress and the results. | |
8 | """ | |
9 | ||
9475
5c09d70e9290
Replaced a custom function by use of standard functions from contextlib.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9473
diff
changeset
|
10 | import contextlib |
9453 | 11 | import copy |
12 | import io | |
13 | import multiprocessing | |
9475
5c09d70e9290
Replaced a custom function by use of standard functions from contextlib.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9473
diff
changeset
|
14 | import os |
9453 | 15 | import pathlib |
16 | ||
17 | from dataclasses import dataclass | |
18 | ||
9468
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
19 | from isort import settings |
9453 | 20 | from isort.api import check_file, sort_file |
9473
3f23dbf37dbe
Resorted the import statements using isort.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9472
diff
changeset
|
21 | from PyQt6.QtCore import QCoreApplication, Qt, pyqtSlot |
9453 | 22 | from PyQt6.QtWidgets import ( |
23 | QAbstractButton, | |
24 | QDialog, | |
25 | QDialogButtonBox, | |
26 | QHeaderView, | |
27 | QTreeWidgetItem, | |
28 | ) | |
29 | ||
30 | from eric7 import Preferences | |
31 | from eric7.EricWidgets import EricMessageBox | |
32 | ||
33 | from .FormattingDiffWidget import FormattingDiffWidget | |
34 | from .IsortFormattingAction import IsortFormattingAction | |
35 | from .Ui_IsortFormattingDialog import Ui_IsortFormattingDialog | |
36 | ||
37 | ||
38 | class IsortFormattingDialog(QDialog, Ui_IsortFormattingDialog): | |
39 | """ | |
40 | Class implementing a dialog showing the isort code formatting progress and the | |
41 | results. | |
42 | """ | |
43 | ||
9460
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
44 | DataRole = Qt.ItemDataRole.UserRole |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
45 | DataTypeRole = Qt.ItemDataRole.UserRole + 1 |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
46 | FileNameRole = Qt.ItemDataRole.UserRole + 2 |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
47 | StatusRole = Qt.ItemDataRole.UserRole + 3 |
9453 | 48 | |
9460
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
49 | FileNameColumn = 1 |
9453 | 50 | StatusColumn = 0 |
51 | ||
52 | def __init__( | |
53 | self, | |
54 | configuration, | |
55 | filesList, | |
56 | project=None, | |
57 | action=IsortFormattingAction.Sort, | |
58 | parent=None, | |
59 | ): | |
60 | """ | |
61 | Constructor | |
62 | ||
63 | @param configuration dictionary containing the configuration parameters | |
64 | @type dict | |
65 | @param filesList list of absolute file paths to be processed | |
66 | @type list of str | |
67 | @param project reference to the project object (defaults to None) | |
68 | @type Project (optional) | |
69 | @param action action to be performed (defaults to IsortFormattingAction.Sort) | |
70 | @type IsortFormattingAction (optional) | |
71 | @param parent reference to the parent widget (defaults to None) | |
72 | @type QWidget (optional) | |
73 | """ | |
74 | super().__init__(parent) | |
75 | self.setupUi(self) | |
76 | ||
77 | self.resultsList.header().setSortIndicator(1, Qt.SortOrder.AscendingOrder) | |
78 | ||
9465
8a020c34dce2
Fine tuned the isort support so the configuration will default to project specific config files overwritten by data entered via the dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9460
diff
changeset
|
79 | self.__project = project |
8a020c34dce2
Fine tuned the isort support so the configuration will default to project specific config files overwritten by data entered via the dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9460
diff
changeset
|
80 | |
9453 | 81 | self.__config = copy.deepcopy(configuration) |
82 | self.__config["quiet"] = True # we don't want extra output | |
83 | self.__config["overwrite_in_place"] = True # we want to overwrite the files | |
84 | if "config_source" in self.__config: | |
85 | del self.__config["config_source"] | |
9465
8a020c34dce2
Fine tuned the isort support so the configuration will default to project specific config files overwritten by data entered via the dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9460
diff
changeset
|
86 | |
8a020c34dce2
Fine tuned the isort support so the configuration will default to project specific config files overwritten by data entered via the dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9460
diff
changeset
|
87 | # Create an isort Config object and pre-load it with parameters contained in |
8a020c34dce2
Fine tuned the isort support so the configuration will default to project specific config files overwritten by data entered via the dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9460
diff
changeset
|
88 | # project specific configuration files (like pyproject.toml). The configuration |
8a020c34dce2
Fine tuned the isort support so the configuration will default to project specific config files overwritten by data entered via the dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9460
diff
changeset
|
89 | # given as a dictionary (i.e. data entered in the configuration dialog) |
8a020c34dce2
Fine tuned the isort support so the configuration will default to project specific config files overwritten by data entered via the dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9460
diff
changeset
|
90 | # overwrites these. If the project is not passed, the isort config is based on |
8a020c34dce2
Fine tuned the isort support so the configuration will default to project specific config files overwritten by data entered via the dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9460
diff
changeset
|
91 | # the isort defaults. |
9468
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
92 | if project: |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
93 | # clear the caches in order to force a re-read of config files |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
94 | settings._get_config_data.cache_clear() |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
95 | settings._find_config.cache_clear() |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
96 | try: |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
97 | self.__isortConfig = ( |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
98 | settings.Config(settings_path=project.getProjectPath(), **self.__config) |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
99 | if project |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
100 | else settings.Config(**self.__config) |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
101 | ) |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
102 | except KeyError: |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
103 | # invalid configuration entry found in some config file; use just the dialog |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
104 | # parameters |
a4d8091cd8f7
Changed the isort formatting dialog to ensure the cached isort config data is cleared.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9465
diff
changeset
|
105 | self.__isortConfig = settings.Config(**self.__config) |
9465
8a020c34dce2
Fine tuned the isort support so the configuration will default to project specific config files overwritten by data entered via the dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9460
diff
changeset
|
106 | |
9453 | 107 | self.__config["__action__"] = action # needed by the workers |
108 | ||
109 | self.__filesList = filesList[:] | |
110 | ||
111 | self.__diffDialog = None | |
112 | ||
113 | self.__allFilter = self.tr("<all>") | |
114 | ||
115 | self.__sortImportsButton = self.buttonBox.addButton( | |
116 | self.tr("Sort Imports"), QDialogButtonBox.ButtonRole.ActionRole | |
117 | ) | |
118 | self.__sortImportsButton.setVisible(False) | |
119 | ||
120 | self.show() | |
121 | QCoreApplication.processEvents() | |
122 | ||
123 | self.__performAction() | |
124 | ||
125 | def __performAction(self): | |
126 | """ | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
127 | Private method to execute the requested sorting action. |
9453 | 128 | """ |
9472
5798ee4a8807
Corrected a little glitch in the isort formatting dialog.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9468
diff
changeset
|
129 | self.progressBar.setMaximum(len(self.__filesList)) |
9453 | 130 | self.progressBar.setValue(0) |
131 | self.progressBar.setVisible(True) | |
132 | ||
133 | self.statisticsGroup.setVisible(False) | |
134 | self.__statistics = IsortStatistics() | |
135 | ||
136 | self.__cancelled = False | |
137 | ||
138 | self.statusFilterComboBox.clear() | |
139 | self.resultsList.clear() | |
140 | ||
141 | self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True) | |
142 | self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False) | |
143 | self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True) | |
144 | ||
145 | files = self.__filterFiles(self.__filesList) | |
146 | if len(files) > 1: | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
147 | self.__sortManyFiles(files) |
9453 | 148 | elif len(files) == 1: |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
149 | self.__sortOneFile(files[0]) |
9453 | 150 | |
151 | def __filterFiles(self, filesList): | |
152 | """ | |
153 | Private method to filter the given list of files according the | |
154 | configuration parameters. | |
155 | ||
156 | @param filesList list of files | |
157 | @type list of str | |
158 | @return list of filtered files | |
159 | @rtype list of str | |
160 | """ | |
161 | files = [] | |
162 | for file in filesList: | |
163 | if not self.__isortConfig.is_supported_filetype( | |
164 | file | |
165 | ) or self.__isortConfig.is_skipped(pathlib.Path(file)): | |
166 | self.__handleIsortResult(file, "skipped") | |
167 | else: | |
168 | files.append(file) | |
169 | ||
170 | return files | |
171 | ||
172 | def __resort(self): | |
173 | """ | |
174 | Private method to resort the result list. | |
175 | """ | |
176 | self.resultsList.sortItems( | |
177 | self.resultsList.sortColumn(), | |
178 | self.resultsList.header().sortIndicatorOrder(), | |
179 | ) | |
180 | ||
181 | def __resizeColumns(self): | |
182 | """ | |
183 | Private method to resize the columns of the result list. | |
184 | """ | |
185 | self.resultsList.header().resizeSections( | |
186 | QHeaderView.ResizeMode.ResizeToContents | |
187 | ) | |
188 | self.resultsList.header().setStretchLastSection(True) | |
189 | ||
190 | def __populateStatusFilterCombo(self): | |
191 | """ | |
192 | Private method to populate the status filter combo box with allowed selections. | |
193 | """ | |
194 | allowedSelections = set() | |
195 | for row in range(self.resultsList.topLevelItemCount()): | |
196 | allowedSelections.add( | |
197 | self.resultsList.topLevelItem(row).text( | |
198 | IsortFormattingDialog.StatusColumn | |
199 | ) | |
200 | ) | |
201 | ||
202 | self.statusFilterComboBox.addItem(self.__allFilter) | |
203 | self.statusFilterComboBox.addItems(sorted(allowedSelections)) | |
204 | ||
205 | def __finish(self): | |
206 | """ | |
207 | Private method to perform some actions after the run was performed or canceled. | |
208 | """ | |
209 | self.__resort() | |
210 | self.__resizeColumns() | |
211 | ||
212 | self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) | |
213 | self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) | |
214 | self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) | |
215 | ||
216 | self.progressBar.setVisible(False) | |
217 | ||
218 | self.__sortImportsButton.setVisible( | |
219 | self.__config["__action__"] is not IsortFormattingAction.Sort | |
220 | and self.__statistics.changeCount > 0 | |
221 | ) | |
222 | ||
223 | self.__updateStatistics() | |
224 | self.__populateStatusFilterCombo() | |
225 | ||
226 | def __updateStatistics(self): | |
227 | """ | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
228 | Private method to update the statistics about the recent sorting run and |
9453 | 229 | make them visible. |
230 | """ | |
231 | self.reformattedLabel.setText( | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
232 | self.tr("Resorted:") |
9453 | 233 | if self.__config["__action__"] is IsortFormattingAction.Sort |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
234 | else self.tr("Would Resort:") |
9453 | 235 | ) |
236 | ||
237 | total = self.progressBar.maximum() | |
238 | ||
239 | self.totalCountLabel.setText("{0:n}".format(total)) | |
240 | self.skippedCountLabel.setText("{0:n}".format(self.__statistics.skippedCount)) | |
241 | self.failuresCountLabel.setText("{0:n}".format(self.__statistics.failureCount)) | |
242 | self.processedCountLabel.setText( | |
243 | "{0:n}".format(self.__statistics.processedCount) | |
244 | ) | |
245 | self.reformattedCountLabel.setText( | |
246 | "{0:n}".format(self.__statistics.changeCount) | |
247 | ) | |
248 | self.unchangedCountLabel.setText("{0:n}".format(self.__statistics.sameCount)) | |
249 | ||
250 | self.statisticsGroup.setVisible(True) | |
251 | ||
252 | @pyqtSlot(QAbstractButton) | |
253 | def on_buttonBox_clicked(self, button): | |
254 | """ | |
255 | Private slot to handle button presses of the dialog buttons. | |
256 | ||
257 | @param button reference to the pressed button | |
258 | @type QAbstractButton | |
259 | """ | |
260 | if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel): | |
261 | self.__cancelled = True | |
262 | elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close): | |
263 | self.accept() | |
264 | elif button is self.__sortImportsButton: | |
265 | self.__sortImportsButtonClicked() | |
266 | ||
267 | @pyqtSlot() | |
268 | def __sortImportsButtonClicked(self): | |
269 | """ | |
270 | Private slot handling the selection of the 'Sort Imports' button. | |
271 | """ | |
9460
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
272 | files = [] |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
273 | for row in range(self.resultsList.topLevelItemCount()): |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
274 | itm = self.resultsList.topLevelItem(row) |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
275 | if itm.data(0, IsortFormattingDialog.StatusRole) == "changed": |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
276 | files.append(itm.data(0, IsortFormattingDialog.FileNameRole)) |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
277 | if files: |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
278 | self.__filesList = files |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
279 | |
9453 | 280 | self.__config["__action__"] = IsortFormattingAction.Sort |
281 | self.__performAction() | |
282 | ||
283 | @pyqtSlot(QTreeWidgetItem, int) | |
284 | def on_resultsList_itemDoubleClicked(self, item, column): | |
285 | """ | |
286 | Private slot handling a double click of a result item. | |
287 | ||
288 | @param item reference to the double clicked item | |
289 | @type QTreeWidgetItem | |
290 | @param column column number that was double clicked | |
291 | @type int | |
292 | """ | |
293 | dataType = item.data(0, IsortFormattingDialog.DataTypeRole) | |
294 | if dataType == "error": | |
295 | EricMessageBox.critical( | |
296 | self, | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
297 | self.tr("Imports Sorting Failure"), |
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
298 | self.tr( |
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
299 | "<p>Imports sorting failed due to this error.</p><p>{0}</p>" |
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
300 | ).format(item.data(0, IsortFormattingDialog.DataRole)), |
9453 | 301 | ) |
302 | elif dataType == "diff": | |
303 | if self.__diffDialog is None: | |
304 | self.__diffDialog = FormattingDiffWidget() | |
305 | self.__diffDialog.showDiff(item.data(0, IsortFormattingDialog.DataRole)) | |
306 | ||
307 | @pyqtSlot(str) | |
308 | def on_statusFilterComboBox_currentTextChanged(self, status): | |
309 | """ | |
310 | Private slot handling the selection of a status for items to be shown. | |
311 | ||
312 | @param status selected status | |
313 | @type str | |
314 | """ | |
315 | for row in range(self.resultsList.topLevelItemCount()): | |
316 | itm = self.resultsList.topLevelItem(row) | |
317 | itm.setHidden( | |
318 | status != self.__allFilter | |
319 | and itm.text(IsortFormattingDialog.StatusColumn) != status | |
320 | ) | |
321 | ||
322 | def closeEvent(self, evt): | |
323 | """ | |
324 | Protected slot implementing a close event handler. | |
325 | ||
326 | @param evt reference to the close event | |
327 | @type QCloseEvent | |
328 | """ | |
329 | if self.__diffDialog is not None: | |
330 | self.__diffDialog.close() | |
331 | evt.accept() | |
332 | ||
333 | def __handleIsortResult(self, filename, status, data=""): | |
334 | """ | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
335 | Private method to handle an isort sorting result. |
9453 | 336 | |
337 | @param filename name of the processed file | |
338 | @type str | |
339 | @param status status of the performed action (one of 'changed', 'failed', | |
340 | 'skipped' or 'unchanged') | |
341 | @type str | |
342 | @param data action data (error message or unified diff) (defaults to "") | |
343 | @type str (optional) | |
344 | """ | |
345 | isError = False | |
346 | ||
347 | if status == "changed": | |
348 | statusMsg = ( | |
349 | self.tr("would resort") | |
350 | if self.__config["__action__"] | |
351 | in (IsortFormattingAction.Check, IsortFormattingAction.Diff) | |
352 | else self.tr("resorted") | |
353 | ) | |
354 | self.__statistics.changeCount += 1 | |
355 | ||
356 | elif status == "unchanged": | |
357 | statusMsg = self.tr("unchanged") | |
358 | self.__statistics.sameCount += 1 | |
359 | ||
360 | elif status == "skipped": | |
361 | statusMsg = self.tr("skipped") | |
362 | self.__statistics.skippedCount += 1 | |
363 | ||
364 | elif status == "failed": | |
365 | statusMsg = self.tr("failed") | |
366 | self.__statistics.failureCount += 1 | |
367 | isError = True | |
368 | ||
369 | elif status == "unsupported": | |
370 | statusMsg = self.tr("error") | |
371 | data = self.tr("Unsupported 'isort' action ({0}) given.").format( | |
372 | self.__config["__action__"] | |
373 | ) | |
374 | self.__statistics.failureCount += 1 | |
375 | isError = True | |
376 | ||
377 | else: | |
378 | statusMsg = self.tr("invalid status ({0})").format(status) | |
379 | self.__statistics.failureCount += 1 | |
380 | isError = True | |
381 | ||
382 | if status != "skipped": | |
383 | self.__statistics.processedCount += 1 | |
384 | ||
9460
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
385 | itm = QTreeWidgetItem( |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
386 | self.resultsList, |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
387 | [ |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
388 | statusMsg, |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
389 | self.__project.getRelativePath(filename) |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
390 | if self.__project |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
391 | else filename, |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
392 | ], |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
393 | ) |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
394 | itm.setData(0, IsortFormattingDialog.StatusRole, status) |
0d1b5d0fd815
Modified the Black and Isort dialogs such, that only files that need a change are processed after a diff or check run by pressing the relevant button.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9455
diff
changeset
|
395 | itm.setData(0, IsortFormattingDialog.FileNameRole, filename) |
9453 | 396 | if data: |
397 | itm.setData( | |
398 | 0, IsortFormattingDialog.DataTypeRole, "error" if isError else "diff" | |
399 | ) | |
400 | itm.setData(0, IsortFormattingDialog.DataRole, data) | |
401 | ||
402 | self.progressBar.setValue(self.progressBar.value() + 1) | |
403 | ||
404 | QCoreApplication.processEvents() | |
405 | ||
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
406 | def __sortManyFiles(self, files): |
9453 | 407 | """ |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
408 | Private method to sort imports of the list of files according the configuration |
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
409 | using multiple processes in parallel. |
9453 | 410 | |
411 | @param files list of files to be processed | |
412 | @type list of str | |
413 | """ | |
414 | maxProcesses = Preferences.getUI("BackgroundServiceProcesses") | |
415 | if maxProcesses == 0: | |
416 | # determine based on CPU count | |
417 | try: | |
418 | NumberOfProcesses = multiprocessing.cpu_count() | |
419 | if NumberOfProcesses >= 1: | |
420 | NumberOfProcesses -= 1 | |
421 | except NotImplementedError: | |
422 | NumberOfProcesses = 1 | |
423 | else: | |
424 | NumberOfProcesses = maxProcesses | |
425 | ||
426 | # Create queues | |
427 | taskQueue = multiprocessing.Queue() | |
428 | doneQueue = multiprocessing.Queue() | |
429 | ||
430 | # Submit tasks (initially two times the number of processes) | |
431 | tasks = len(files) | |
432 | initialTasks = min(2 * NumberOfProcesses, tasks) | |
433 | for _ in range(initialTasks): | |
434 | file = files.pop(0) | |
435 | taskQueue.put((file, self.__config["__action__"])) | |
436 | ||
437 | # Start worker processes | |
438 | workers = [ | |
439 | multiprocessing.Process( | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
440 | target=self.sortingWorkerTask, |
9453 | 441 | args=(taskQueue, doneQueue, self.__isortConfig), |
442 | ) | |
443 | for _ in range(NumberOfProcesses) | |
444 | ] | |
445 | for worker in workers: | |
446 | worker.start() | |
447 | ||
448 | # Get the results from the worker tasks | |
449 | for _ in range(tasks): | |
450 | result = doneQueue.get() | |
451 | self.__handleIsortResult(result.filename, result.status, data=result.data) | |
452 | ||
453 | if self.__cancelled: | |
454 | break | |
455 | ||
456 | if files: | |
457 | file = files.pop(0) | |
458 | taskQueue.put((file, self.__config["__action__"])) | |
459 | ||
460 | # Tell child processes to stop | |
461 | for _ in range(NumberOfProcesses): | |
462 | taskQueue.put("STOP") | |
463 | ||
464 | for worker in workers: | |
465 | worker.join() | |
466 | worker.close() | |
467 | ||
468 | taskQueue.close() | |
469 | doneQueue.close() | |
470 | ||
471 | self.__finish() | |
472 | ||
473 | @staticmethod | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
474 | def sortingWorkerTask(inputQueue, outputQueue, isortConfig): |
9453 | 475 | """ |
476 | Static method acting as the parallel worker for the formatting task. | |
477 | ||
478 | @param inputQueue input queue | |
479 | @type multiprocessing.Queue | |
480 | @param outputQueue output queue | |
481 | @type multiprocessing.Queue | |
482 | @param isortConfig config object for isort | |
483 | @type isort.Config | |
484 | """ | |
485 | for file, action in iter(inputQueue.get, "STOP"): | |
486 | if action == IsortFormattingAction.Diff: | |
487 | result = IsortFormattingDialog.__isortCheckFile( | |
488 | file, | |
489 | isortConfig, | |
490 | withDiff=True, | |
491 | ) | |
492 | ||
493 | elif action == IsortFormattingAction.Sort: | |
494 | result = IsortFormattingDialog.__isortSortFile( | |
495 | file, | |
496 | isortConfig, | |
497 | ) | |
498 | ||
499 | else: | |
500 | result = IsortResult( | |
501 | status="unsupported", | |
502 | filename=file, | |
503 | ) | |
504 | ||
505 | outputQueue.put(result) | |
506 | ||
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
507 | def __sortOneFile(self, file): |
9453 | 508 | """ |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
509 | Private method to sort the imports of the list of files according the |
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
510 | configuration. |
9453 | 511 | |
512 | @param file name of the file to be processed | |
513 | @type str | |
514 | """ | |
515 | if self.__config["__action__"] == IsortFormattingAction.Diff: | |
516 | result = IsortFormattingDialog.__isortCheckFile( | |
517 | file, | |
518 | self.__isortConfig, | |
519 | withDiff=True, | |
520 | ) | |
521 | ||
522 | elif self.__config["__action__"] == IsortFormattingAction.Sort: | |
523 | result = IsortFormattingDialog.__isortSortFile( | |
524 | file, | |
525 | self.__isortConfig, | |
526 | ) | |
527 | ||
528 | else: | |
529 | result = IsortResult( | |
530 | status="unsupported", | |
531 | filename=file, | |
532 | ) | |
533 | ||
534 | self.__handleIsortResult(result.filename, result.status, data=result.data) | |
535 | ||
536 | self.__finish() | |
537 | ||
538 | @staticmethod | |
539 | def __isortCheckFile(filename, isortConfig, withDiff=True): | |
540 | """ | |
541 | Static method to check, if a file's import statements need to be changed. | |
542 | ||
543 | @param filename name of the file to be processed | |
544 | @type str | |
545 | @param isortConfig config object for isort | |
546 | @type isort.Config | |
547 | @param withDiff flag indicating to return a unified diff, if the file needs to | |
548 | be changed (defaults to True) | |
549 | @type bool (optional) | |
550 | @return result object | |
551 | @rtype IsortResult | |
552 | """ | |
553 | diffIO = io.StringIO() if withDiff else False | |
9481
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
554 | with open(os.devnull, "w") as devnull, contextlib.redirect_stderr(devnull): |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
555 | ok = check_file( |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
556 | filename, |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
557 | show_diff=diffIO, |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
558 | config=isortConfig, |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
559 | ) |
9453 | 560 | if withDiff: |
561 | data = "" if ok else diffIO.getvalue() | |
562 | diffIO.close() | |
563 | else: | |
564 | data = "" | |
565 | ||
566 | status = "unchanged" if ok else "changed" | |
567 | ||
568 | return IsortResult(status=status, filename=filename, data=data) | |
569 | ||
570 | @staticmethod | |
571 | def __isortSortFile(filename, isortConfig): | |
572 | """ | |
573 | Static method to sort the import statements of a file. | |
574 | ||
575 | @param filename name of the file to be processed | |
576 | @type str | |
577 | @param isortConfig config object for isort | |
578 | @type isort.Config | |
579 | @return result object | |
580 | @rtype IsortResult | |
581 | """ | |
9481
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
582 | with open(os.devnull, "w") as devnull, contextlib.redirect_stderr(devnull): |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
583 | ok = sort_file( |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
584 | filename, |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
585 | config=isortConfig, |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
586 | ask_to_apply=False, |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
587 | write_to_stdout=False, |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
588 | show_diff=False, |
0b936ff1bbb9
Corrected a code style issue.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9475
diff
changeset
|
589 | ) |
9453 | 590 | |
591 | status = "changed" if ok else "unchanged" | |
592 | ||
593 | return IsortResult(status=status, filename=filename) | |
594 | ||
595 | ||
596 | @dataclass | |
597 | class IsortStatistics: | |
598 | """ | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
599 | Class containing the isort statistic data. |
9453 | 600 | """ |
601 | ||
602 | skippedCount: int = 0 | |
603 | changeCount: int = 0 | |
604 | sameCount: int = 0 | |
605 | failureCount: int = 0 | |
606 | processedCount: int = 0 | |
607 | ||
608 | ||
609 | @dataclass | |
610 | class IsortResult: | |
611 | """ | |
9455
5f138ee215a5
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9453
diff
changeset
|
612 | Class containing the isort result data. |
9453 | 613 | """ |
614 | ||
615 | status: str = "" | |
616 | filename: str = "" | |
617 | data: str = "" |