Wed, 13 Jul 2022 15:07:40 +0200
Fixed a bug in the Black configuration dialog causing 'pyproject.toml' values being handled incorrectly.
9214 | 1 | # -*- coding: utf-8 -*- |
2 | ||
3 | # Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> | |
4 | # | |
5 | ||
6 | """ | |
7 | Module implementing a dialog to enter the parameters for a Black formatting run. | |
8 | """ | |
9 | ||
10 | import contextlib | |
11 | import copy | |
12 | import pathlib | |
13 | ||
14 | import black | |
15 | import tomlkit | |
16 | ||
17 | from PyQt6.QtCore import pyqtSlot, Qt | |
18 | from PyQt6.QtGui import QFontMetricsF, QGuiApplication | |
19 | from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QListWidgetItem | |
20 | ||
21 | from EricWidgets import EricMessageBox | |
22 | from EricWidgets.EricApplication import ericApp | |
23 | ||
24 | from .Ui_BlackConfigurationDialog import Ui_BlackConfigurationDialog | |
25 | ||
26 | from . import BlackUtilities | |
27 | ||
28 | ||
29 | class BlackConfigurationDialog(QDialog, Ui_BlackConfigurationDialog): | |
30 | """ | |
31 | Class implementing a dialog to enter the parameters for a Black formatting run. | |
32 | """ | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
33 | |
9214 | 34 | def __init__(self, withProject=True, parent=None): |
35 | """ | |
36 | Constructor | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
37 | |
9214 | 38 | @param withProject flag indicating to look for project configurations |
39 | (defaults to True) | |
40 | @type bool | |
41 | @param parent reference to the parent widget (defaults to None) | |
42 | @type QWidget (optional) | |
43 | """ | |
44 | super().__init__(parent) | |
45 | self.setupUi(self) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
46 | |
9214 | 47 | self.__project = ericApp().getObject("Project") if withProject else None |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
48 | |
9214 | 49 | indentTabWidth = ( |
50 | QFontMetricsF(self.excludeEdit.font()).horizontalAdvance(" ") * 2 | |
51 | ) | |
52 | self.excludeEdit.document().setIndentWidth(indentTabWidth) | |
53 | self.excludeEdit.setTabStopDistance(indentTabWidth) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
54 | |
9214 | 55 | self.__pyprojectData = {} |
56 | self.__projectData = {} | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
57 | |
9214 | 58 | self.__tomlButton = self.buttonBox.addButton( |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
59 | self.tr("Generate TOML"), QDialogButtonBox.ButtonRole.ActionRole |
9214 | 60 | ) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
61 | self.__tomlButton.setToolTip( |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
62 | self.tr("Place a code snippet for 'pyproject.toml' into the clipboard.") |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
63 | ) |
9214 | 64 | self.__tomlButton.clicked.connect(self.__createTomlSnippet) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
65 | |
9214 | 66 | # setup the source combobox |
67 | self.sourceComboBox.addItem("", "") | |
68 | if self.__project: | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
69 | pyprojectPath = ( |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
70 | pathlib.Path(self.__project.getProjectPath()) / "pyproject.toml" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
71 | ) |
9214 | 72 | if pyprojectPath.exists(): |
73 | with contextlib.suppress(tomlkit.exceptions.ParseError, OSError): | |
74 | with pyprojectPath.open("r", encoding="utf-8") as f: | |
75 | data = tomlkit.load(f) | |
76 | config = data.get("tool", {}).get("black", {}) | |
77 | if config: | |
78 | self.__pyprojectData = { | |
9222
e384c0e986be
Fixed a bug in the Black configuration dialog causing 'pyproject.toml' values being handled incorrectly.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9221
diff
changeset
|
79 | k.replace("--", ""): v for k, v in config.items() |
9214 | 80 | } |
81 | self.sourceComboBox.addItem("pyproject.toml", "pyproject") | |
82 | if self.__project.getData("OTHERTOOLSPARMS", "Black") is not None: | |
83 | self.__projectData = copy.deepcopy( | |
84 | self.__project.getData("OTHERTOOLSPARMS", "Black") | |
85 | ) | |
86 | self.sourceComboBox.addItem(self.tr("Project File"), "project") | |
87 | self.sourceComboBox.addItem(self.tr("Defaults"), "default") | |
88 | self.sourceComboBox.addItem(self.tr("Configuration Below"), "dialog") | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
89 | |
9214 | 90 | self.__populateTargetVersionsList() |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
91 | |
9214 | 92 | if self.__projectData: |
93 | source = self.__projectData.get("source", "") | |
94 | self.sourceComboBox.setCurrentIndex(self.sourceComboBox.findData(source)) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
95 | |
9214 | 96 | def __populateTargetVersionsList(self): |
97 | """ | |
98 | Private method to populate the target versions list widget with checkable | |
99 | Python version entries. | |
100 | """ | |
101 | targets = [ | |
102 | (int(t[2]), int(t[3:]), t) | |
103 | for t in dir(black.TargetVersion) | |
104 | if t.startswith("PY") | |
105 | ] | |
106 | for target in sorted(targets): | |
107 | itm = QListWidgetItem( | |
108 | "Python {0}.{1}".format(target[0], target[1]), self.targetVersionsList | |
109 | ) | |
110 | itm.setData(Qt.ItemDataRole.UserRole, target[2]) | |
111 | itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable) | |
112 | itm.setCheckState(Qt.CheckState.Unchecked) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
113 | |
9214 | 114 | def __loadConfiguration(self, configurationDict): |
115 | """ | |
116 | Private method to load the configuration section with data of the given | |
117 | dictionary. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
118 | |
9214 | 119 | @param configurationDict reference to the data to be loaded |
120 | @type dict | |
121 | """ | |
122 | confDict = copy.deepcopy(BlackUtilities.getDefaultConfiguration()) | |
123 | confDict.update(configurationDict) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
124 | |
9214 | 125 | self.lineLengthSpinBox.setValue(int(confDict["line-length"])) |
126 | self.skipStringNormalCheckBox.setChecked(confDict["skip-string-normalization"]) | |
127 | self.skipMagicCommaCheckBox.setChecked(confDict["skip-magic-trailing-comma"]) | |
128 | self.excludeEdit.setPlainText(confDict["extend-exclude"]) | |
129 | for row in range(self.targetVersionsList.count()): | |
130 | itm = self.targetVersionsList.item(row) | |
131 | itm.setCheckState( | |
132 | Qt.CheckState.Checked | |
133 | if itm.data(Qt.ItemDataRole.UserRole).lower() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
134 | in confDict["target-version"] |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
135 | else Qt.CheckState.Unchecked |
9214 | 136 | ) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
137 | |
9214 | 138 | @pyqtSlot(str) |
139 | def on_sourceComboBox_currentTextChanged(self, selection): | |
140 | """ | |
141 | Private slot to handle the selection of a configuration source. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
142 | |
9214 | 143 | @param selection text of the currently selected item |
144 | @type str | |
145 | """ | |
146 | self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled( | |
147 | bool(selection) | |
148 | ) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
149 | |
9214 | 150 | source = self.sourceComboBox.currentData() |
151 | if source == "pyproject": | |
152 | self.__loadConfiguration(self.__pyprojectData) | |
153 | elif source == "project": | |
154 | self.__loadConfiguration(self.__projectData) | |
155 | elif source == "default": | |
156 | self.__loadConfiguration(BlackUtilities.getDefaultConfiguration()) | |
157 | elif source == "dialog": | |
158 | # just leave the current entries | |
159 | pass | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
160 | |
9214 | 161 | @pyqtSlot() |
162 | def on_excludeEdit_textChanged(self): | |
163 | """ | |
164 | Private slot to enable the validate button depending on the exclude text. | |
165 | """ | |
166 | self.validateButton.setEnabled(bool(self.excludeEdit.toPlainText())) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
167 | |
9214 | 168 | @pyqtSlot() |
169 | def on_validateButton_clicked(self): | |
170 | """ | |
171 | Private slot to validate the entered exclusion regular expression. | |
172 | """ | |
173 | regexp = self.excludeEdit.toPlainText() | |
174 | valid, error = BlackUtilities.validateRegExp(regexp) | |
175 | if valid: | |
176 | EricMessageBox.information( | |
177 | self, | |
178 | self.tr("Validation"), | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
179 | self.tr("""The exclusion expression is valid."""), |
9214 | 180 | ) |
181 | else: | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
182 | EricMessageBox.critical(self, self.tr("Validation Error"), error) |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
183 | |
9214 | 184 | def __getTargetList(self): |
185 | """ | |
186 | Private method to get the list of checked target versions. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
187 | |
9214 | 188 | @return list of target versions |
189 | @rtype list of str | |
190 | """ | |
191 | targets = [] | |
192 | for row in range(self.targetVersionsList.count()): | |
193 | itm = self.targetVersionsList.item(row) | |
194 | if itm.checkState() == Qt.CheckState.Checked: | |
195 | targets.append(itm.data(Qt.ItemDataRole.UserRole).lower()) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
196 | |
9214 | 197 | return targets |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
198 | |
9214 | 199 | @pyqtSlot() |
200 | def __createTomlSnippet(self): | |
201 | """ | |
202 | Private slot to generate a TOML snippet of the current configuration. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
203 | |
9214 | 204 | Note: Only non-default values are included in this snippet. |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
205 | |
9214 | 206 | The code snippet is copied to the clipboard and may be placed inside the |
207 | 'pyproject.toml' file. | |
208 | """ | |
209 | doc = tomlkit.document() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
210 | |
9214 | 211 | black = tomlkit.table() |
212 | targetList = self.__getTargetList() | |
213 | if targetList: | |
214 | black["target-version"] = targetList | |
215 | black["line-length"] = self.lineLengthSpinBox.value() | |
216 | if self.skipStringNormalCheckBox.isChecked(): | |
217 | black["skip-string-normalization"] = True | |
218 | if self.skipMagicCommaCheckBox.isChecked(): | |
219 | black["skip-magic-trailing-comma"] = True | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
220 | |
9214 | 221 | excludeRegexp = self.excludeEdit.toPlainText() |
222 | if excludeRegexp and BlackUtilities.validateRegExp(excludeRegexp)[0]: | |
223 | black["extend-exclude"] = tomlkit.string( | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
224 | "\n{0}\n".format(excludeRegexp.strip()), literal=True, multiline=True |
9214 | 225 | ) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
226 | |
9214 | 227 | doc["tool"] = tomlkit.table(is_super_table=True) |
228 | doc["tool"]["black"] = black | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
229 | |
9214 | 230 | QGuiApplication.clipboard().setText(tomlkit.dumps(doc)) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
231 | |
9214 | 232 | EricMessageBox.information( |
233 | self, | |
9216
e89083501ce3
Updated translations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9214
diff
changeset
|
234 | self.tr("Create TOML snippet"), |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
235 | self.tr( |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
236 | """The 'pyproject.toml' snippet was copied to the clipboard""" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
237 | """ successfully.""" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
238 | ), |
9214 | 239 | ) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
240 | |
9214 | 241 | def getConfiguration(self): |
242 | """ | |
243 | Public method to get the current configuration parameters. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
244 | |
9214 | 245 | @return dictionary containing the configuration parameters |
246 | @rtype dict | |
247 | """ | |
248 | configuration = BlackUtilities.getDefaultConfiguration() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
249 | |
9214 | 250 | configuration["source"] = self.sourceComboBox.currentData() |
251 | configuration["target-version"] = self.__getTargetList() | |
252 | configuration["line-length"] = self.lineLengthSpinBox.value() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
253 | configuration[ |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
254 | "skip-string-normalization" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
255 | ] = self.skipStringNormalCheckBox.isChecked() |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
256 | configuration[ |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
257 | "skip-magic-trailing-comma" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
258 | ] = self.skipMagicCommaCheckBox.isChecked() |
9214 | 259 | configuration["extend-exclude"] = self.excludeEdit.toPlainText().strip() |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
260 | |
9214 | 261 | if self.__project: |
262 | self.__project.setData("OTHERTOOLSPARMS", "Black", configuration) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9216
diff
changeset
|
263 | |
9214 | 264 | return configuration |