PyLintInterface/PyLintConfigDialog.py

branch
eric7
changeset 98
ab4aabca55ec
parent 95
50eba81e4a9f
child 101
98784d037491
equal deleted inserted replaced
97:2226347d86e4 98:ab4aabca55ec
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2005 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to configure the PyLint process.
8 """
9
10 import os
11 import copy
12
13 from PyQt6.QtCore import pyqtSlot, QProcess
14 from PyQt6.QtWidgets import QDialog
15
16 from EricWidgets.EricApplication import ericApp
17 from EricWidgets import EricMessageBox
18 from EricWidgets.EricPathPicker import EricPathPickerModes
19
20 from .Ui_PyLintConfigDialog import Ui_PyLintConfigDialog
21
22 import Preferences
23
24
25 class PyLintConfigDialog(QDialog, Ui_PyLintConfigDialog):
26 """
27 Class implementing a dialog to configure the PyLint process.
28 """
29 def __init__(self, ppath, exe, parms, version):
30 """
31 Constructor
32
33 @param ppath project path; used to set the default path for the
34 rcfile picker
35 @type str
36 @param exe name of the pylint executable
37 @type str
38 @param parms parameters to set in the dialog
39 @type dict
40 @param version pylint version (unused)
41 @type str
42 """
43 super().__init__(None)
44 self.setupUi(self)
45
46 self.__version = version
47 self.__pylintProc = None
48 self.__lint = exe
49
50 self.__initializeDefaults()
51
52 # get a copy of the defaults to store the user settings
53 self.parameters = copy.deepcopy(self.defaults)
54
55 # combine it with the values of parms
56 if parms is not None:
57 self.parameters.update(parms)
58
59 self.configfilePicker.setWindowTitle(
60 self.tr("Select configuration file"))
61 self.configfilePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
62 self.configfilePicker.setFilters(self.tr(
63 "Configuration Files (*.cfg *.cnf *.rc);;"
64 "All Files (*)"
65 ))
66 self.configfilePicker.setDefaultDirectory(ppath)
67
68 self.reportfilePicker.setWindowTitle(
69 self.tr("Select report file"))
70 self.reportfilePicker.setMode(EricPathPickerModes.SAVE_FILE_MODE)
71 self.reportfilePicker.setFilters(self.tr(
72 "HTML Files (*.html);;"
73 "Report Files (*.rpt);;"
74 "Text Files (*.txt);;"
75 "All Files (*)"
76 ))
77
78
79 # initialize general tab
80 self.configfilePicker.setText(self.parameters['configFile'])
81 self.txtOutputButton.setChecked(self.parameters['txtReport'])
82 self.htmlOutputButton.setChecked(self.parameters['htmlReport'])
83 self.dialogOutputButton.setChecked(self.parameters['dialogReport'])
84 self.reportfilePicker.setText(self.parameters['reportFile'])
85
86 # initialize checkers tab
87 self.basicCheckBox.setChecked(self.parameters['enableBasic'])
88 self.classesCheckBox.setChecked(self.parameters['enableClasses'])
89 self.designCheckBox.setChecked(self.parameters['enableDesign'])
90 self.exceptionsCheckBox.setChecked(self.parameters['enableExceptions'])
91 self.formatCheckBox.setChecked(self.parameters['enableFormat'])
92 self.importsCheckBox.setChecked(self.parameters['enableImports'])
93 self.metricsCheckBox.setChecked(self.parameters['enableMetrics'])
94 self.miscellaneousCheckBox.setChecked(
95 self.parameters['enableMiscellaneous'])
96 self.newstyleCheckBox.setChecked(self.parameters['enableNewstyle'])
97 self.similaritiesCheckBox.setChecked(
98 self.parameters['enableSimilarities'])
99 self.typecheckCheckBox.setChecked(self.parameters['enableTypecheck'])
100 self.variablesCheckBox.setChecked(self.parameters['enableVariables'])
101 self.loggingCheckBox.setChecked(self.parameters['enableLogging'])
102 self.stringFormatCheckBox.setChecked(
103 self.parameters['enableStringFormat'])
104
105 # initialize messages tab
106 self.enabledMessagesEdit.setText(self.parameters['enabledMessages'])
107 self.disabledMessagesEdit.setText(self.parameters['disabledMessages'])
108
109 def __initializeDefaults(self):
110 """
111 Private method to set the default values.
112
113 These are needed later on to generate the commandline
114 parameters.
115 """
116 self.defaults = {
117 # general options
118 'configFile': '',
119 'reportFile': '',
120 'txtReport': False,
121 'htmlReport': True,
122 'dialogReport': False,
123
124 # enabled checkers
125 'enableBasic': True,
126 'enableClasses': True,
127 'enableDesign': True,
128 'enableExceptions': True,
129 'enableFormat': False,
130 'enableImports': False,
131 'enableLogging': True,
132 'enableMetrics': True,
133 'enableMiscellaneous': True,
134 'enableNewstyle': True,
135 'enableSimilarities': True,
136 'enableStringFormat': True,
137 'enableTypecheck': True,
138 'enableVariables': True,
139
140 # messages
141 'enabledMessages': '',
142 'disabledMessages': '',
143 }
144
145 def generateParameters(self):
146 """
147 Public method that generates the commandline parameters.
148
149 It generates a list of strings to be used
150 to set the QProcess arguments for the pylint call and
151 a list containing the non default parameters. The second
152 list can be passed back upon object generation to overwrite
153 the default settings.
154
155 <b>Note</b>: The arguments list contains the name of the pylint
156 executable as the first parameter.
157
158 @return a tuple of the commandline parameters and non default
159 parameters
160 @rtype tuple of (list of str, dict)
161 """
162 parms = {}
163 args = []
164
165 # 1. the program name
166 args.append(self.__lint)
167
168 # 2. the commandline options
169 # 2.1 general options
170 if self.parameters['configFile'] != self.defaults['configFile']:
171 parms['configFile'] = self.parameters['configFile']
172 args.append('--rcfile={0}'.format(self.parameters['configFile']))
173 parms['txtReport'] = self.parameters['txtReport']
174 parms['htmlReport'] = self.parameters['htmlReport']
175 parms['dialogReport'] = self.parameters['dialogReport']
176 if self.parameters['htmlReport']:
177 args.append('--output-format=html')
178 elif self.parameters['dialogReport']:
179 args.append('--output-format=parseable')
180 args.append('--reports=n')
181 else:
182 args.append('--output-format=text')
183 if self.parameters['reportFile'] != self.defaults['reportFile']:
184 parms['reportFile'] = self.parameters['reportFile']
185
186 # 2.2 checkers options
187 parms['enableBasic'] = self.parameters['enableBasic']
188 parms['enableClasses'] = self.parameters['enableClasses']
189 parms['enableDesign'] = self.parameters['enableDesign']
190 parms['enableExceptions'] = self.parameters['enableExceptions']
191 parms['enableFormat'] = self.parameters['enableFormat']
192 parms['enableImports'] = self.parameters['enableImports']
193 parms['enableMetrics'] = self.parameters['enableMetrics']
194 parms['enableMiscellaneous'] = self.parameters['enableMiscellaneous']
195 parms['enableNewstyle'] = self.parameters['enableNewstyle']
196 parms['enableSimilarities'] = self.parameters['enableSimilarities']
197 parms['enableTypecheck'] = self.parameters['enableTypecheck']
198 parms['enableVariables'] = self.parameters['enableVariables']
199 parms['enableLogging'] = self.parameters['enableLogging']
200 parms['enableStringFormat'] = self.parameters['enableStringFormat']
201
202 checkers = []
203 if self.parameters['enableBasic']:
204 checkers.append('basic')
205 if self.parameters['enableClasses']:
206 checkers.append('classes')
207 if self.parameters['enableDesign']:
208 checkers.append('design')
209 if self.parameters['enableExceptions']:
210 checkers.append('exceptions')
211 if self.parameters['enableFormat']:
212 checkers.append('format')
213 if self.parameters['enableImports']:
214 checkers.append('imports')
215 if self.parameters['enableMetrics']:
216 checkers.append('metrics')
217 if self.parameters['enableMiscellaneous']:
218 checkers.append('miscellaneous')
219 if self.parameters['enableNewstyle']:
220 checkers.append('newstyle')
221 if self.parameters['enableSimilarities']:
222 checkers.append('similarities')
223 if self.parameters['enableTypecheck']:
224 checkers.append('typecheck')
225 if self.parameters['enableVariables']:
226 checkers.append('variables')
227 if self.parameters['enableLogging']:
228 checkers.append('logging')
229 if self.parameters['enableStringFormat']:
230 checkers.append('string')
231
232 args.append('--disable=all')
233 if checkers:
234 args.append('--enable={0}'.format(','.join(checkers)))
235
236 # 2.3 messages options
237 parms['enabledMessages'] = self.parameters['enabledMessages']
238 parms['disabledMessages'] = self.parameters['disabledMessages']
239 if parms['enabledMessages']:
240 args.append('--enable={0}'.format(parms['enabledMessages']))
241 if parms['disabledMessages']:
242 args.append('--disable={0}'.format(parms['disabledMessages']))
243
244 return (args, parms)
245
246 def accept(self):
247 """
248 Public slot called by the Ok button.
249
250 It saves the values in the parameters dictionary.
251 """
252 # get data of general tab
253 self.parameters['configFile'] = self.configfilePicker.text()
254 self.parameters['txtReport'] = self.txtOutputButton.isChecked()
255 self.parameters['htmlReport'] = self.htmlOutputButton.isChecked()
256 self.parameters['dialogReport'] = self.dialogOutputButton.isChecked()
257 self.parameters['reportFile'] = self.reportfilePicker.text()
258
259 # get data of checkers tab
260 self.parameters['enableBasic'] = self.basicCheckBox.isChecked()
261 self.parameters['enableClasses'] = self.classesCheckBox.isChecked()
262 self.parameters['enableDesign'] = self.designCheckBox.isChecked()
263 self.parameters['enableExceptions'] = (
264 self.exceptionsCheckBox.isChecked())
265 self.parameters['enableFormat'] = self.formatCheckBox.isChecked()
266 self.parameters['enableImports'] = self.importsCheckBox.isChecked()
267 self.parameters['enableMetrics'] = self.metricsCheckBox.isChecked()
268 self.parameters['enableMiscellaneous'] = (
269 self.miscellaneousCheckBox.isChecked())
270 self.parameters['enableNewstyle'] = self.newstyleCheckBox.isChecked()
271 self.parameters['enableSimilarities'] = (
272 self.similaritiesCheckBox.isChecked())
273 self.parameters['enableTypecheck'] = self.typecheckCheckBox.isChecked()
274 self.parameters['enableVariables'] = self.variablesCheckBox.isChecked()
275 self.parameters['enableLogging'] = self.loggingCheckBox.isChecked()
276 self.parameters['enableStringFormat'] = (
277 self.stringFormatCheckBox.isChecked())
278
279 # get data of messages tab
280 self.parameters['enabledMessages'] = ','.join(
281 [m.strip() for m in self.enabledMessagesEdit.text().split(',')])
282 self.parameters['disabledMessages'] = ','.join(
283 [m.strip() for m in self.disabledMessagesEdit.text().split(',')])
284
285 # call the accept slot of the base class
286 super().accept()
287
288 ###########################################################################
289 ## Methods below are needed to generate a configuration file template
290 ###########################################################################
291
292 @pyqtSlot()
293 def on_configButton_clicked(self):
294 """
295 Private slot to handle the generation of a sample configuration.
296 """
297 self.buf = ""
298 self.__pylintProc = QProcess()
299 args = []
300
301 self.__ioEncoding = Preferences.getSystem("IOEncoding")
302
303 args.append('--generate-rcfile')
304
305 self.__pylintProc.readyReadStandardOutput.connect(self.__readStdout)
306 self.__pylintProc.readyReadStandardError.connect(self.__readStderr)
307 self.__pylintProc.finished.connect(self.__createConfigDone)
308
309 self.__pylintProc.start(self.__lint, args)
310 procStarted = self.__pylintProc.waitForStarted()
311 if procStarted:
312 ericApp().getObject("ViewManager").enableEditorsCheckFocusIn(False)
313 else:
314 EricMessageBox.critical(
315 self,
316 self.tr('Process Generation Error'),
317 self.tr(
318 'Could not start {0}.<br>'
319 'Ensure that it is in the search path.'
320 ).format(self.__lint))
321
322 def __createConfigDone(self, exitCode, exitStatus):
323 """
324 Private slot to handle the the finished signal of the pylint process.
325
326 @param exitCode exit code of the process
327 @type int
328 @param exitStatus exit status of the process
329 @type QProcess.ExitStatus
330 """
331 vm = ericApp().getObject("ViewManager")
332 vm.enableEditorsCheckFocusIn(True)
333 if exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0:
334 vm.newEditor()
335 aw = vm.activeWindow()
336 aw.insertAt(self.buf, 0, 0)
337 aw.setLanguage('dummy.rc')
338 self.reject()
339
340 def __readStdout(self):
341 """
342 Private slot to handle the readyReadStandardOutput signal of the
343 pylint process.
344 """
345 if self.__pylintProc is None:
346 return
347
348 self.__pylintProc.setReadChannel(
349 QProcess.ProcessChannel.StandardOutput)
350
351 while self.__pylintProc and self.__pylintProc.canReadLine():
352 line = str(self.__pylintProc.readLine(), self.__ioEncoding,
353 "replace").rstrip()
354 self.buf += line + os.linesep
355
356 def __readStderr(self):
357 """
358 Private slot to handle the readyReadStandardError signal of the
359 pylint process.
360 """
361 if self.__pylintProc is None:
362 return
363
364 self.__pylintProc.setReadChannel(
365 QProcess.ProcessChannel.StandardError)
366 while self.__pylintProc and self.__pylintProc.canReadLine():
367 s = 'pylint: ' + str(
368 self.__pylintProc.readLine(), self.__ioEncoding, "replace")
369 ericApp().getObject("UserInterface").appendStderr.emit(s)

eric ide

mercurial