src/eric7/CodeFormatting/BlackConfigurationDialog.py

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

eric ide

mercurial