eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py

changeset 6942
2602857055c5
parent 6786
701b511ba8f5
child 7040
f89952e5fc11
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2011 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show the results of the code style check.
8 """
9
10 from __future__ import unicode_literals
11
12 import os
13 import fnmatch
14
15 from PyQt5.QtCore import pyqtSlot, Qt, QTimer
16 from PyQt5.QtGui import QIcon
17 from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QAbstractButton, \
18 QDialogButtonBox, QApplication, QHeaderView, QListWidgetItem
19
20 from E5Gui.E5Application import e5App
21
22 from .Ui_CodeStyleCheckerDialog import Ui_CodeStyleCheckerDialog
23
24 import UI.PixmapCache
25 import Preferences
26 import Utilities
27
28 from . import pycodestyle
29
30 try:
31 basestring # __IGNORE_WARNING__
32 except Exception:
33 basestring = str # define for Python3
34
35
36 class CodeStyleCheckerDialog(QDialog, Ui_CodeStyleCheckerDialog):
37 """
38 Class implementing a dialog to show the results of the code style check.
39 """
40 filenameRole = Qt.UserRole + 1
41 lineRole = Qt.UserRole + 2
42 positionRole = Qt.UserRole + 3
43 messageRole = Qt.UserRole + 4
44 fixableRole = Qt.UserRole + 5
45 codeRole = Qt.UserRole + 6
46 ignoredRole = Qt.UserRole + 7
47
48 availableFutures = [
49 'division', 'absolute_import', 'with_statement',
50 'print_function', 'unicode_literals', 'generator_stop']
51
52 noResults = 0
53 noFiles = 1
54 hasResults = 2
55
56 def __init__(self, styleCheckService, parent=None):
57 """
58 Constructor
59
60 @param styleCheckService reference to the service
61 (CodeStyleCheckService)
62 @param parent reference to the parent widget (QWidget)
63 """
64 super(CodeStyleCheckerDialog, self).__init__(parent)
65 self.setupUi(self)
66 self.setWindowFlags(Qt.Window)
67
68 self.optionsTabWidget.setCurrentIndex(0)
69
70 self.excludeMessagesSelectButton.setIcon(
71 UI.PixmapCache.getIcon("select.png"))
72 self.includeMessagesSelectButton.setIcon(
73 UI.PixmapCache.getIcon("select.png"))
74 self.fixIssuesSelectButton.setIcon(
75 UI.PixmapCache.getIcon("select.png"))
76 self.noFixIssuesSelectButton.setIcon(
77 UI.PixmapCache.getIcon("select.png"))
78
79 self.docTypeComboBox.addItem(self.tr("PEP-257"), "pep257")
80 self.docTypeComboBox.addItem(self.tr("Eric"), "eric")
81
82 for future in CodeStyleCheckerDialog.availableFutures:
83 itm = QListWidgetItem(future, self.futuresList)
84 itm.setFlags(itm.flags() | Qt.ItemIsUserCheckable)
85 itm.setCheckState(Qt.Unchecked)
86
87 self.statisticsButton = self.buttonBox.addButton(
88 self.tr("Statistics..."), QDialogButtonBox.ActionRole)
89 self.statisticsButton.setToolTip(
90 self.tr("Press to show some statistics for the last run"))
91 self.statisticsButton.setEnabled(False)
92 self.showButton = self.buttonBox.addButton(
93 self.tr("Show"), QDialogButtonBox.ActionRole)
94 self.showButton.setToolTip(
95 self.tr("Press to show all files containing an issue"))
96 self.showButton.setEnabled(False)
97 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
98 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
99
100 self.resultList.headerItem().setText(self.resultList.columnCount(), "")
101 self.resultList.header().setSortIndicator(0, Qt.AscendingOrder)
102
103 self.addBuiltinButton.setIcon(UI.PixmapCache.getIcon("plus.png"))
104 self.deleteBuiltinButton.setIcon(UI.PixmapCache.getIcon("minus.png"))
105
106 self.checkProgress.setVisible(False)
107 self.checkProgressLabel.setVisible(False)
108 self.checkProgressLabel.setMaximumWidth(600)
109
110 self.styleCheckService = styleCheckService
111 self.styleCheckService.styleChecked.connect(self.__processResult)
112 self.styleCheckService.batchFinished.connect(self.__batchFinished)
113 self.styleCheckService.error.connect(self.__processError)
114 self.filename = None
115
116 self.results = CodeStyleCheckerDialog.noResults
117 self.cancelled = False
118 self.__lastFileItem = None
119 self.__batch = False
120 self.__finished = True
121 self.__errorItem = None
122
123 self.__fileOrFileList = ""
124 self.__project = None
125 self.__forProject = False
126 self.__data = {}
127 self.__statistics = {}
128 self.__onlyFixes = {}
129 self.__noFixCodesList = []
130
131 self.on_loadDefaultButton_clicked()
132
133 def __resort(self):
134 """
135 Private method to resort the tree.
136 """
137 self.resultList.sortItems(self.resultList.sortColumn(),
138 self.resultList.header().sortIndicatorOrder()
139 )
140
141 def __createErrorItem(self, filename, message):
142 """
143 Private slot to create a new error item in the result list.
144
145 @param filename name of the file
146 @type str
147 @param message error message
148 @type str
149 """
150 if self.__errorItem is None:
151 self.__errorItem = QTreeWidgetItem(self.resultList, [
152 self.tr("Errors")])
153 self.__errorItem.setExpanded(True)
154 self.__errorItem.setForeground(0, Qt.red)
155
156 msg = "{0} ({1})".format(self.__project.getRelativePath(filename),
157 message)
158 if not self.resultList.findItems(msg, Qt.MatchExactly):
159 itm = QTreeWidgetItem(self.__errorItem, [msg])
160 itm.setForeground(0, Qt.red)
161 itm.setFirstColumnSpanned(True)
162
163 def __createResultItem(self, filename, line, pos, message, fixed,
164 autofixing, ignored):
165 """
166 Private method to create an entry in the result list.
167
168 @param filename file name of the file (string)
169 @param line line number of issue (integer or string)
170 @param pos character position of issue (integer or string)
171 @param message message text (string)
172 @param fixed flag indicating a fixed issue (boolean)
173 @param autofixing flag indicating, that we are fixing issues
174 automatically (boolean)
175 @param ignored flag indicating an ignored issue (boolean)
176 @return reference to the created item (QTreeWidgetItem)
177 """
178 from .CodeStyleFixer import FixableCodeStyleIssues
179
180 if self.__lastFileItem is None:
181 # It's a new file
182 self.__lastFileItem = QTreeWidgetItem(self.resultList, [
183 self.__project.getRelativePath(filename)])
184 self.__lastFileItem.setFirstColumnSpanned(True)
185 self.__lastFileItem.setExpanded(True)
186 self.__lastFileItem.setData(0, self.filenameRole, filename)
187
188 fixable = False
189 code, message = message.split(None, 1)
190 itm = QTreeWidgetItem(
191 self.__lastFileItem,
192 ["{0:6}".format(line), code, message])
193 if code.startswith(("W", "-", "C", "M")):
194 itm.setIcon(1, UI.PixmapCache.getIcon("warning.png"))
195 elif code.startswith("N"):
196 itm.setIcon(1, UI.PixmapCache.getIcon("namingError.png"))
197 elif code.startswith("D"):
198 itm.setIcon(1, UI.PixmapCache.getIcon("docstringError.png"))
199 else:
200 itm.setIcon(1, UI.PixmapCache.getIcon("syntaxError.png"))
201 if fixed:
202 itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed.png"))
203 elif code in FixableCodeStyleIssues and not autofixing and \
204 code not in self.__noFixCodesList:
205 itm.setIcon(0, UI.PixmapCache.getIcon("issueFixable.png"))
206 fixable = True
207
208 itm.setTextAlignment(0, Qt.AlignRight)
209 itm.setTextAlignment(1, Qt.AlignHCenter)
210
211 itm.setTextAlignment(0, Qt.AlignVCenter)
212 itm.setTextAlignment(1, Qt.AlignVCenter)
213 itm.setTextAlignment(2, Qt.AlignVCenter)
214
215 itm.setData(0, self.filenameRole, filename)
216 itm.setData(0, self.lineRole, int(line))
217 itm.setData(0, self.positionRole, int(pos))
218 itm.setData(0, self.messageRole, message)
219 itm.setData(0, self.fixableRole, fixable)
220 itm.setData(0, self.codeRole, code)
221 itm.setData(0, self.ignoredRole, ignored)
222
223 if ignored:
224 font = itm.font(0)
225 font.setItalic(True)
226 for col in range(itm.columnCount()):
227 itm.setFont(col, font)
228
229 return itm
230
231 def __modifyFixedResultItem(self, itm, text, fixed):
232 """
233 Private method to modify a result list entry to show its
234 positive fixed state.
235
236 @param itm reference to the item to modify (QTreeWidgetItem)
237 @param text text to be appended (string)
238 @param fixed flag indicating a fixed issue (boolean)
239 """
240 if fixed:
241 code, message = text.split(None, 1)
242 itm.setText(2, message)
243 itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed.png"))
244
245 itm.setData(0, self.messageRole, message)
246 else:
247 itm.setIcon(0, QIcon())
248 itm.setData(0, self.fixableRole, False)
249
250 def __updateStatistics(self, statistics, fixer, ignoredErrors):
251 """
252 Private method to update the collected statistics.
253
254 @param statistics dictionary of statistical data with
255 message code as key and message count as value
256 @param fixer reference to the code style fixer (CodeStyleFixer)
257 @param ignoredErrors number of ignored errors (integer)
258 """
259 self.__statistics["_FilesCount"] += 1
260 stats = [k for k in statistics.keys() if k[0].isupper()]
261 if stats:
262 self.__statistics["_FilesIssues"] += 1
263 for key in statistics:
264 if key in self.__statistics:
265 self.__statistics[key] += statistics[key]
266 else:
267 self.__statistics[key] = statistics[key]
268 self.__statistics["_IssuesFixed"] += fixer
269 self.__statistics["_IgnoredErrors"] += ignoredErrors
270
271 def __updateFixerStatistics(self, fixer):
272 """
273 Private method to update the collected fixer related statistics.
274
275 @param fixer reference to the code style fixer (CodeStyleFixer)
276 """
277 self.__statistics["_IssuesFixed"] += fixer
278
279 def __resetStatistics(self):
280 """
281 Private slot to reset the statistics data.
282 """
283 self.__statistics = {}
284 self.__statistics["_FilesCount"] = 0
285 self.__statistics["_FilesIssues"] = 0
286 self.__statistics["_IssuesFixed"] = 0
287 self.__statistics["_IgnoredErrors"] = 0
288
289 def prepare(self, fileList, project):
290 """
291 Public method to prepare the dialog with a list of filenames.
292
293 @param fileList list of filenames (list of strings)
294 @param project reference to the project object (Project)
295 """
296 self.__fileOrFileList = fileList[:]
297 self.__project = project
298 self.__forProject = True
299
300 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
301 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
302 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
303
304 self.__data = self.__project.getData("CHECKERSPARMS", "Pep8Checker")
305 if self.__data is None or \
306 len(self.__data) < 6:
307 # initialize the data structure
308 self.__data = {
309 "ExcludeFiles": "",
310 "ExcludeMessages": pycodestyle.DEFAULT_IGNORE,
311 "IncludeMessages": "",
312 "RepeatMessages": False,
313 "FixCodes": "",
314 "FixIssues": False,
315 }
316 if "MaxLineLength" not in self.__data:
317 self.__data["MaxLineLength"] = pycodestyle.MAX_LINE_LENGTH
318 if "MaxDocLineLength" not in self.__data:
319 # Use MAX_LINE_LENGTH to avoid messages on existing code
320 self.__data["MaxDocLineLength"] = pycodestyle.MAX_LINE_LENGTH
321 if "BlankLines" not in self.__data:
322 self.__data["BlankLines"] = (2, 1)
323 # top level, method
324 if "HangClosing" not in self.__data:
325 self.__data["HangClosing"] = False
326 if "NoFixCodes" not in self.__data:
327 self.__data["NoFixCodes"] = "E501"
328 if "DocstringType" not in self.__data:
329 self.__data["DocstringType"] = "pep257"
330 if "ShowIgnored" not in self.__data:
331 self.__data["ShowIgnored"] = False
332 if "MaxCodeComplexity" not in self.__data:
333 self.__data["MaxCodeComplexity"] = 10
334 if "LineComplexity" not in self.__data:
335 self.__data["LineComplexity"] = 15
336 if "LineComplexityScore" not in self.__data:
337 self.__data["LineComplexityScore"] = 10
338 if "ValidEncodings" not in self.__data:
339 self.__data["ValidEncodings"] = "latin-1, utf-8"
340 if "CopyrightMinFileSize" not in self.__data or \
341 "CopyrightAuthor" not in self.__data:
342 self.__data["CopyrightMinFileSize"] = 0
343 self.__data["CopyrightAuthor"] = ""
344 if "FutureChecker" not in self.__data:
345 self.__data["FutureChecker"] = ""
346 if "BuiltinsChecker" not in self.__data:
347 self.__data["BuiltinsChecker"] = {
348 "str": ["unicode", ],
349 "chr": ["unichr", ],
350 }
351
352 self.excludeFilesEdit.setText(self.__data["ExcludeFiles"])
353 self.excludeMessagesEdit.setText(self.__data["ExcludeMessages"])
354 self.includeMessagesEdit.setText(self.__data["IncludeMessages"])
355 self.repeatCheckBox.setChecked(self.__data["RepeatMessages"])
356 self.fixIssuesEdit.setText(self.__data["FixCodes"])
357 self.noFixIssuesEdit.setText(self.__data["NoFixCodes"])
358 self.fixIssuesCheckBox.setChecked(self.__data["FixIssues"])
359 self.ignoredCheckBox.setChecked(self.__data["ShowIgnored"])
360 self.lineLengthSpinBox.setValue(self.__data["MaxLineLength"])
361 self.docLineLengthSpinBox.setValue(self.__data["MaxDocLineLength"])
362 self.blankBeforeTopLevelSpinBox.setValue(self.__data["BlankLines"][0])
363 self.blankBeforeMethodSpinBox.setValue(self.__data["BlankLines"][1])
364 self.hangClosingCheckBox.setChecked(self.__data["HangClosing"])
365 self.docTypeComboBox.setCurrentIndex(
366 self.docTypeComboBox.findData(self.__data["DocstringType"]))
367 self.complexitySpinBox.setValue(self.__data["MaxCodeComplexity"])
368 self.lineComplexitySpinBox.setValue(self.__data["LineComplexity"])
369 self.lineComplexityScoreSpinBox.setValue(
370 self.__data["LineComplexityScore"])
371 self.encodingsEdit.setText(self.__data["ValidEncodings"])
372 self.copyrightFileSizeSpinBox.setValue(
373 self.__data["CopyrightMinFileSize"])
374 self.copyrightAuthorEdit.setText(self.__data["CopyrightAuthor"])
375 self.__initFuturesList(self.__data["FutureChecker"])
376 self.__initBuiltinsIgnoreList(self.__data["BuiltinsChecker"])
377
378 def start(self, fn, save=False, repeat=None):
379 """
380 Public slot to start the code style check.
381
382 @param fn file or list of files or directory to be checked
383 (string or list of strings)
384 @keyparam save flag indicating to save the given
385 file/file list/directory (boolean)
386 @keyparam repeat state of the repeat check box if it is not None
387 (None or boolean)
388 """
389 if self.__project is None:
390 self.__project = e5App().getObject("Project")
391
392 self.cancelled = False
393 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
394 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True)
395 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
396 self.statisticsButton.setEnabled(False)
397 self.showButton.setEnabled(False)
398 self.fixButton.setEnabled(False)
399 self.startButton.setEnabled(False)
400 if repeat is not None:
401 self.repeatCheckBox.setChecked(repeat)
402 self.checkProgress.setVisible(True)
403 QApplication.processEvents()
404
405 if save:
406 self.__fileOrFileList = fn
407
408 if isinstance(fn, list):
409 self.files = fn[:]
410 elif os.path.isdir(fn):
411 self.files = []
412 extensions = set(Preferences.getPython("PythonExtensions") +
413 Preferences.getPython("Python3Extensions"))
414 for ext in extensions:
415 self.files.extend(Utilities.direntries(
416 fn, True, '*{0}'.format(ext), 0))
417 else:
418 self.files = [fn]
419
420 # filter the list depending on the filter string
421 if self.files:
422 filterString = self.excludeFilesEdit.text()
423 filterList = [f.strip() for f in filterString.split(",")
424 if f.strip()]
425 for fileFilter in filterList:
426 self.files = \
427 [f for f in self.files
428 if not fnmatch.fnmatch(f, fileFilter.strip())]
429
430 self.__errorItem = None
431 self.__resetStatistics()
432 self.__clearErrors(self.files)
433
434 if len(self.files) > 0:
435 self.checkProgress.setMaximum(len(self.files))
436 self.checkProgressLabel.setVisible(len(self.files) > 1)
437 self.checkProgress.setVisible(len(self.files) > 1)
438 QApplication.processEvents()
439
440 # extract the configuration values
441 excludeMessages = self.excludeMessagesEdit.text()
442 includeMessages = self.includeMessagesEdit.text()
443 repeatMessages = self.repeatCheckBox.isChecked()
444 fixCodes = self.fixIssuesEdit.text()
445 noFixCodes = self.noFixIssuesEdit.text()
446 self.__noFixCodesList = \
447 [c.strip() for c in noFixCodes.split(",") if c.strip()]
448 fixIssues = self.fixIssuesCheckBox.isChecked() and repeatMessages
449 self.showIgnored = self.ignoredCheckBox.isChecked() and \
450 repeatMessages
451 maxLineLength = self.lineLengthSpinBox.value()
452 maxDocLineLength = self.docLineLengthSpinBox.value()
453 blankLines = (
454 self.blankBeforeTopLevelSpinBox.value(),
455 self.blankBeforeMethodSpinBox.value()
456 )
457 hangClosing = self.hangClosingCheckBox.isChecked()
458 docType = self.docTypeComboBox.itemData(
459 self.docTypeComboBox.currentIndex())
460 codeComplexityArgs = {
461 "McCabeComplexity": self.complexitySpinBox.value(),
462 "LineComplexity": self.lineComplexitySpinBox.value(),
463 "LineComplexityScore": self.lineComplexityScoreSpinBox.value(),
464 }
465 miscellaneousArgs = {
466 "CodingChecker": self.encodingsEdit.text(),
467 "CopyrightChecker": {
468 "MinFilesize": self.copyrightFileSizeSpinBox.value(),
469 "Author": self.copyrightAuthorEdit.text(),
470 },
471 "FutureChecker": self.__getSelectedFutureImports(),
472 "BuiltinsChecker": self.__getBuiltinsIgnoreList(),
473 }
474
475 self.__options = [excludeMessages, includeMessages, repeatMessages,
476 fixCodes, noFixCodes, fixIssues, maxLineLength,
477 maxDocLineLength, blankLines, hangClosing,
478 docType, codeComplexityArgs, miscellaneousArgs]
479
480 # now go through all the files
481 self.progress = 0
482 self.files.sort()
483 if len(self.files) == 1:
484 self.__batch = False
485 self.check()
486 else:
487 self.__batch = True
488 self.checkBatch()
489 else:
490 self.results = CodeStyleCheckerDialog.noFiles
491 self.__finished = False
492 self.__finish()
493
494 def __modifyOptions(self, source):
495 """
496 Private method to modify the options based on eflag: entries.
497
498 This method looks for comment lines like '# eflag: noqa = M601'
499 at the end of the source in order to extend the list of excluded
500 messages for one file only.
501
502 @param source source text (list of str or str)
503 @return list of checker options
504 """
505 options = self.__options[:]
506 flags = Utilities.extractFlags(source)
507 if "noqa" in flags and isinstance(flags["noqa"], basestring):
508 excludeMessages = \
509 options[0].strip().rstrip(",")
510 if excludeMessages:
511 excludeMessages += ","
512 excludeMessages += flags["noqa"]
513 options[0] = excludeMessages
514 return options
515
516 def check(self, codestring=''):
517 """
518 Public method to start a style check for one file.
519
520 The results are reported to the __processResult slot.
521
522 @keyparam codestring optional sourcestring (str)
523 """
524 if not self.files:
525 self.checkProgressLabel.setPath("")
526 self.checkProgress.setMaximum(1)
527 self.checkProgress.setValue(1)
528 self.__finish()
529 return
530
531 self.filename = self.files.pop(0)
532 self.checkProgress.setValue(self.progress)
533 self.checkProgressLabel.setPath(self.filename)
534 QApplication.processEvents()
535
536 if self.cancelled:
537 self.__resort()
538 return
539
540 self.__lastFileItem = None
541
542 if codestring:
543 source = codestring.splitlines(True)
544 encoding = Utilities.get_coding(source)
545 else:
546 try:
547 source, encoding = Utilities.readEncodedFile(
548 self.filename)
549 source = source.splitlines(True)
550 except (UnicodeError, IOError) as msg:
551 self.results = CodeStyleCheckerDialog.hasResults
552 self.__createResultItem(
553 self.filename, 1, 1,
554 self.tr("Error: {0}").format(str(msg))
555 .rstrip(), False, False, False)
556 self.progress += 1
557 # Continue with next file
558 self.check()
559 return
560 if encoding.endswith(
561 ('-selected', '-default', '-guessed', '-ignore')):
562 encoding = encoding.rsplit('-', 1)[0]
563
564 options = self.__modifyOptions(source)
565
566 errors = []
567 self.__itms = []
568 for error, itm in self.__onlyFixes.pop(self.filename, []):
569 errors.append(error)
570 self.__itms.append(itm)
571
572 eol = self.__getEol(self.filename)
573 args = options + [
574 errors, eol, encoding, Preferences.getEditor("CreateBackupFile")
575 ]
576 self.__finished = False
577 self.styleCheckService.styleCheck(
578 None, self.filename, source, args)
579
580 def checkBatch(self):
581 """
582 Public method to start a style check batch job.
583
584 The results are reported to the __processResult slot.
585 """
586 self.__lastFileItem = None
587
588 self.checkProgressLabel.setPath(self.tr("Preparing files..."))
589 progress = 0
590
591 argumentsList = []
592 for filename in self.files:
593 progress += 1
594 self.checkProgress.setValue(progress)
595 QApplication.processEvents()
596
597 try:
598 source, encoding = Utilities.readEncodedFile(
599 filename)
600 source = source.splitlines(True)
601 except (UnicodeError, IOError) as msg:
602 self.results = CodeStyleCheckerDialog.hasResults
603 self.__createResultItem(
604 filename, 1, 1,
605 self.tr("Error: {0}").format(str(msg))
606 .rstrip(), False, False, False)
607 continue
608
609 if encoding.endswith(
610 ('-selected', '-default', '-guessed', '-ignore')):
611 encoding = encoding.rsplit('-', 1)[0]
612
613 options = self.__modifyOptions(source)
614
615 errors = []
616 self.__itms = []
617 for error, itm in self.__onlyFixes.pop(filename, []):
618 errors.append(error)
619 self.__itms.append(itm)
620
621 eol = self.__getEol(filename)
622 args = options + [
623 errors, eol, encoding,
624 Preferences.getEditor("CreateBackupFile")
625 ]
626 argumentsList.append((filename, source, args))
627
628 # reset the progress bar to the checked files
629 self.checkProgress.setValue(self.progress)
630 self.checkProgressLabel.setPath(self.tr("Transferring data..."))
631 QApplication.processEvents()
632
633 self.__finished = False
634 self.styleCheckService.styleBatchCheck(argumentsList)
635
636 def __batchFinished(self):
637 """
638 Private slot handling the completion of a batch job.
639 """
640 self.checkProgressLabel.setPath("")
641 self.checkProgress.setMaximum(1)
642 self.checkProgress.setValue(1)
643 self.__finish()
644
645 def __processError(self, fn, msg):
646 """
647 Private slot to process an error indication from the service.
648
649 @param fn filename of the file
650 @type str
651 @param msg error message
652 @type str
653 """
654 self.__createErrorItem(fn, msg)
655
656 if not self.__batch:
657 self.check()
658
659 def __processResult(self, fn, codeStyleCheckerStats, fixes, results):
660 """
661 Private slot called after perfoming a style check on one file.
662
663 @param fn filename of the just checked file (str)
664 @param codeStyleCheckerStats stats of style and name check (dict)
665 @param fixes number of applied fixes (int)
666 @param results tuple for each found violation of style (tuple of
667 lineno (int), position (int), text (str), ignored (bool),
668 fixed (bool), autofixing (bool))
669 """
670 if self.__finished:
671 return
672
673 # Check if it's the requested file, otherwise ignore signal if not
674 # in batch mode
675 if not self.__batch and fn != self.filename:
676 return
677
678 # disable updates of the list for speed
679 self.resultList.setUpdatesEnabled(False)
680 self.resultList.setSortingEnabled(False)
681
682 fixed = None
683 ignoredErrors = 0
684 if self.__itms:
685 for itm, (_lineno, _position, text, _ignored, fixed,
686 _autofixing) in zip(self.__itms, results):
687 self.__modifyFixedResultItem(itm, text, fixed)
688 self.__updateFixerStatistics(fixes)
689 else:
690 self.__lastFileItem = None
691
692 for lineno, position, text, ignored, fixed, autofixing in results:
693 if ignored:
694 ignoredErrors += 1
695 if self.showIgnored:
696 text = self.tr("{0} (ignored)").format(text)
697 else:
698 continue
699 self.results = CodeStyleCheckerDialog.hasResults
700 self.__createResultItem(
701 fn, lineno, position, text, fixed, autofixing, ignored)
702
703 self.__updateStatistics(
704 codeStyleCheckerStats, fixes, ignoredErrors)
705
706 if fixed:
707 vm = e5App().getObject("ViewManager")
708 editor = vm.getOpenEditor(fn)
709 if editor:
710 editor.refresh()
711
712 self.progress += 1
713
714 self.__resort()
715 # reenable updates of the list
716 self.resultList.setSortingEnabled(True)
717 self.resultList.setUpdatesEnabled(True)
718
719 self.checkProgress.setValue(self.progress)
720 self.checkProgressLabel.setPath(fn)
721 QApplication.processEvents()
722
723 if not self.__batch:
724 self.check()
725
726 def __finish(self):
727 """
728 Private slot called when the code style check finished or the user
729 pressed the cancel button.
730 """
731 if not self.__finished:
732 self.__finished = True
733
734 self.cancelled = True
735 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
736 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
737 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
738 self.statisticsButton.setEnabled(True)
739 self.showButton.setEnabled(True)
740 self.startButton.setEnabled(True)
741
742 if self.results != CodeStyleCheckerDialog.hasResults:
743 if self.results == CodeStyleCheckerDialog.noResults:
744 QTreeWidgetItem(
745 self.resultList, [self.tr('No issues found.')])
746 else:
747 QTreeWidgetItem(
748 self.resultList,
749 [self.tr('No files found (check your ignore list).')])
750 QApplication.processEvents()
751 self.showButton.setEnabled(False)
752 else:
753 self.showButton.setEnabled(True)
754 self.resultList.header().resizeSections(
755 QHeaderView.ResizeToContents)
756 self.resultList.header().setStretchLastSection(True)
757
758 self.checkProgress.setVisible(False)
759 self.checkProgressLabel.setVisible(False)
760
761 def __getEol(self, fn):
762 """
763 Private method to get the applicable eol string.
764
765 @param fn filename where to determine the line ending (str)
766 @return eol string (string)
767 """
768 if self.__project.isOpen() and self.__project.isProjectFile(fn):
769 eol = self.__project.getEolString()
770 else:
771 eol = Utilities.linesep()
772 return eol
773
774 @pyqtSlot()
775 def on_startButton_clicked(self):
776 """
777 Private slot to start a code style check run.
778 """
779 if self.__forProject:
780 data = {
781 "ExcludeFiles": self.excludeFilesEdit.text(),
782 "ExcludeMessages": self.excludeMessagesEdit.text(),
783 "IncludeMessages": self.includeMessagesEdit.text(),
784 "RepeatMessages": self.repeatCheckBox.isChecked(),
785 "FixCodes": self.fixIssuesEdit.text(),
786 "NoFixCodes": self.noFixIssuesEdit.text(),
787 "FixIssues": self.fixIssuesCheckBox.isChecked(),
788 "ShowIgnored": self.ignoredCheckBox.isChecked(),
789 "MaxLineLength": self.lineLengthSpinBox.value(),
790 "MaxDocLineLength": self.docLineLengthSpinBox.value(),
791 "BlankLines": (
792 self.blankBeforeTopLevelSpinBox.value(),
793 self.blankBeforeMethodSpinBox.value()
794 ),
795 "HangClosing": self.hangClosingCheckBox.isChecked(),
796 "DocstringType": self.docTypeComboBox.itemData(
797 self.docTypeComboBox.currentIndex()),
798 "MaxCodeComplexity": self.complexitySpinBox.value(),
799 "LineComplexity": self.lineComplexitySpinBox.value(),
800 "LineComplexityScore": self.lineComplexityScoreSpinBox.value(),
801 "ValidEncodings": self.encodingsEdit.text(),
802 "CopyrightMinFileSize": self.copyrightFileSizeSpinBox.value(),
803 "CopyrightAuthor": self.copyrightAuthorEdit.text(),
804 "FutureChecker": self.__getSelectedFutureImports(),
805 "BuiltinsChecker": self.__getBuiltinsIgnoreList(),
806 }
807 if data != self.__data:
808 self.__data = data
809 self.__project.setData("CHECKERSPARMS", "Pep8Checker",
810 self.__data)
811
812 self.resultList.clear()
813 self.results = CodeStyleCheckerDialog.noResults
814 self.cancelled = False
815 self.start(self.__fileOrFileList)
816
817 def __selectCodes(self, edit, showFixCodes):
818 """
819 Private method to select message codes via a selection dialog.
820
821 @param edit reference of the line edit to be populated (QLineEdit)
822 @param showFixCodes flag indicating to show a list of fixable
823 issues (boolean)
824 """
825 from .CodeStyleCodeSelectionDialog import CodeStyleCodeSelectionDialog
826 dlg = CodeStyleCodeSelectionDialog(edit.text(), showFixCodes, self)
827 if dlg.exec_() == QDialog.Accepted:
828 edit.setText(dlg.getSelectedCodes())
829
830 @pyqtSlot()
831 def on_excludeMessagesSelectButton_clicked(self):
832 """
833 Private slot to select the message codes to be excluded via a
834 selection dialog.
835 """
836 self.__selectCodes(self.excludeMessagesEdit, False)
837
838 @pyqtSlot()
839 def on_includeMessagesSelectButton_clicked(self):
840 """
841 Private slot to select the message codes to be included via a
842 selection dialog.
843 """
844 self.__selectCodes(self.includeMessagesEdit, False)
845
846 @pyqtSlot()
847 def on_fixIssuesSelectButton_clicked(self):
848 """
849 Private slot to select the issue codes to be fixed via a
850 selection dialog.
851 """
852 self.__selectCodes(self.fixIssuesEdit, True)
853
854 @pyqtSlot()
855 def on_noFixIssuesSelectButton_clicked(self):
856 """
857 Private slot to select the issue codes not to be fixed via a
858 selection dialog.
859 """
860 self.__selectCodes(self.noFixIssuesEdit, True)
861
862 @pyqtSlot(QTreeWidgetItem, int)
863 def on_resultList_itemActivated(self, item, column):
864 """
865 Private slot to handle the activation of an item.
866
867 @param item reference to the activated item (QTreeWidgetItem)
868 @param column column the item was activated in (integer)
869 """
870 if self.results != CodeStyleCheckerDialog.hasResults:
871 return
872
873 if item.parent():
874 fn = Utilities.normabspath(item.data(0, self.filenameRole))
875 lineno = item.data(0, self.lineRole)
876 position = item.data(0, self.positionRole)
877 message = item.data(0, self.messageRole)
878 code = item.data(0, self.codeRole)
879
880 vm = e5App().getObject("ViewManager")
881 vm.openSourceFile(fn, lineno=lineno, pos=position + 1)
882 editor = vm.getOpenEditor(fn)
883
884 if code in ["E901", "E902"]:
885 editor.toggleSyntaxError(lineno, 0, True, message, True)
886 else:
887 editor.toggleWarning(
888 lineno, 0, True, message, warningType=editor.WarningStyle)
889
890 editor.updateVerticalScrollBar()
891
892 @pyqtSlot()
893 def on_resultList_itemSelectionChanged(self):
894 """
895 Private slot to change the dialog state depending on the selection.
896 """
897 self.fixButton.setEnabled(len(self.__getSelectedFixableItems()) > 0)
898
899 @pyqtSlot()
900 def on_showButton_clicked(self):
901 """
902 Private slot to handle the "Show" button press.
903 """
904 vm = e5App().getObject("ViewManager")
905
906 selectedIndexes = []
907 for index in range(self.resultList.topLevelItemCount()):
908 if self.resultList.topLevelItem(index).isSelected():
909 selectedIndexes.append(index)
910 if len(selectedIndexes) == 0:
911 selectedIndexes = list(range(self.resultList.topLevelItemCount()))
912 for index in selectedIndexes:
913 itm = self.resultList.topLevelItem(index)
914 fn = Utilities.normabspath(itm.data(0, self.filenameRole))
915 vm.openSourceFile(fn, 1)
916 editor = vm.getOpenEditor(fn)
917 editor.clearStyleWarnings()
918 for cindex in range(itm.childCount()):
919 citm = itm.child(cindex)
920 lineno = citm.data(0, self.lineRole)
921 message = citm.data(0, self.messageRole)
922 editor.toggleWarning(
923 lineno, 0, True, message, warningType=editor.WarningStyle)
924
925 # go through the list again to clear warning markers for files,
926 # that are ok
927 openFiles = vm.getOpenFilenames()
928 errorFiles = []
929 for index in range(self.resultList.topLevelItemCount()):
930 itm = self.resultList.topLevelItem(index)
931 errorFiles.append(
932 Utilities.normabspath(itm.data(0, self.filenameRole)))
933 for file in openFiles:
934 if file not in errorFiles:
935 editor = vm.getOpenEditor(file)
936 editor.clearStyleWarnings()
937
938 editor = vm.activeWindow()
939 editor.updateVerticalScrollBar()
940
941 @pyqtSlot()
942 def on_statisticsButton_clicked(self):
943 """
944 Private slot to show the statistics dialog.
945 """
946 from .CodeStyleStatisticsDialog import CodeStyleStatisticsDialog
947 dlg = CodeStyleStatisticsDialog(self.__statistics, self)
948 dlg.exec_()
949
950 @pyqtSlot()
951 def on_loadDefaultButton_clicked(self):
952 """
953 Private slot to load the default configuration values.
954 """
955 self.excludeFilesEdit.setText(Preferences.Prefs.settings.value(
956 "PEP8/ExcludeFilePatterns", ""))
957 self.excludeMessagesEdit.setText(Preferences.Prefs.settings.value(
958 "PEP8/ExcludeMessages", pycodestyle.DEFAULT_IGNORE))
959 self.includeMessagesEdit.setText(Preferences.Prefs.settings.value(
960 "PEP8/IncludeMessages", ""))
961 self.repeatCheckBox.setChecked(Preferences.toBool(
962 Preferences.Prefs.settings.value("PEP8/RepeatMessages", False)))
963 self.fixIssuesEdit.setText(Preferences.Prefs.settings.value(
964 "PEP8/FixCodes", ""))
965 self.noFixIssuesEdit.setText(Preferences.Prefs.settings.value(
966 "PEP8/NoFixCodes", "E501"))
967 self.fixIssuesCheckBox.setChecked(Preferences.toBool(
968 Preferences.Prefs.settings.value("PEP8/FixIssues", False)))
969 self.ignoredCheckBox.setChecked(Preferences.toBool(
970 Preferences.Prefs.settings.value("PEP8/ShowIgnored", False)))
971 self.lineLengthSpinBox.setValue(int(Preferences.Prefs.settings.value(
972 "PEP8/MaxLineLength", pycodestyle.MAX_LINE_LENGTH)))
973 # Use MAX_LINE_LENGTH to avoid messages on existing code
974 self.docLineLengthSpinBox.setValue(int(
975 Preferences.Prefs.settings.value(
976 "PEP8/MaxDocLineLength", pycodestyle.MAX_LINE_LENGTH)))
977 self.blankBeforeTopLevelSpinBox.setValue(
978 int(Preferences.Prefs.settings.value(
979 "PEP8/BlankLinesBeforeTopLevel", 2)))
980 self.blankBeforeMethodSpinBox.setValue(
981 int(Preferences.Prefs.settings.value(
982 "PEP8/BlankLinesBeforeMethod", 1)))
983 self.hangClosingCheckBox.setChecked(Preferences.toBool(
984 Preferences.Prefs.settings.value("PEP8/HangClosing", False)))
985 self.docTypeComboBox.setCurrentIndex(self.docTypeComboBox.findData(
986 Preferences.Prefs.settings.value("PEP8/DocstringType", "pep257")))
987 self.complexitySpinBox.setValue(int(Preferences.Prefs.settings.value(
988 "PEP8/MaxCodeComplexity", 10)))
989 self.lineComplexitySpinBox.setValue(
990 int(Preferences.Prefs.settings.value(
991 "PEP8/LineComplexity", 15)))
992 self.lineComplexityScoreSpinBox.setValue(
993 int(Preferences.Prefs.settings.value(
994 "PEP8/LineComplexityScore", 10)))
995 self.encodingsEdit.setText(Preferences.Prefs.settings.value(
996 "PEP8/ValidEncodings", "latin-1, utf-8"))
997 self.copyrightFileSizeSpinBox.setValue(int(
998 Preferences.Prefs.settings.value("PEP8/CopyrightMinFileSize", 0)))
999 self.copyrightAuthorEdit.setText(
1000 Preferences.Prefs.settings.value("PEP8/CopyrightAuthor", ""))
1001 self.__initFuturesList(
1002 Preferences.Prefs.settings.value("PEP8/FutureChecker", ""))
1003 self.__initBuiltinsIgnoreList(Preferences.toDict(
1004 Preferences.Prefs.settings.value("PEP8/BuiltinsChecker", {
1005 "str": ["unicode", ],
1006 "chr": ["unichr", ],
1007 })))
1008
1009 @pyqtSlot()
1010 def on_storeDefaultButton_clicked(self):
1011 """
1012 Private slot to store the current configuration values as
1013 default values.
1014 """
1015 Preferences.Prefs.settings.setValue(
1016 "PEP8/ExcludeFilePatterns", self.excludeFilesEdit.text())
1017 Preferences.Prefs.settings.setValue(
1018 "PEP8/ExcludeMessages", self.excludeMessagesEdit.text())
1019 Preferences.Prefs.settings.setValue(
1020 "PEP8/IncludeMessages", self.includeMessagesEdit.text())
1021 Preferences.Prefs.settings.setValue(
1022 "PEP8/RepeatMessages", self.repeatCheckBox.isChecked())
1023 Preferences.Prefs.settings.setValue(
1024 "PEP8/FixCodes", self.fixIssuesEdit.text())
1025 Preferences.Prefs.settings.setValue(
1026 "PEP8/NoFixCodes", self.noFixIssuesEdit.text())
1027 Preferences.Prefs.settings.setValue(
1028 "PEP8/FixIssues", self.fixIssuesCheckBox.isChecked())
1029 Preferences.Prefs.settings.setValue(
1030 "PEP8/ShowIgnored", self.ignoredCheckBox.isChecked())
1031 Preferences.Prefs.settings.setValue(
1032 "PEP8/MaxLineLength", self.lineLengthSpinBox.value())
1033 Preferences.Prefs.settings.setValue(
1034 "PEP8/MaxDocLineLength", self.docLineLengthSpinBox.value())
1035 Preferences.Prefs.settings.setValue(
1036 "PEP8/BlankLinesBeforeTopLevel",
1037 self.blankBeforeTopLevelSpinBox.value())
1038 Preferences.Prefs.settings.setValue(
1039 "PEP8/BlankLinesBeforeMethod",
1040 self.blankBeforeMethodSpinBox.value())
1041 Preferences.Prefs.settings.setValue(
1042 "PEP8/HangClosing", self.hangClosingCheckBox.isChecked())
1043 Preferences.Prefs.settings.setValue(
1044 "PEP8/DocstringType", self.docTypeComboBox.itemData(
1045 self.docTypeComboBox.currentIndex()))
1046 Preferences.Prefs.settings.setValue(
1047 "PEP8/MaxCodeComplexity", self.complexitySpinBox.value())
1048 Preferences.Prefs.settings.setValue(
1049 "PEP8/LineComplexity", self.lineComplexitySpinBox.value())
1050 Preferences.Prefs.settings.setValue(
1051 "PEP8/LineComplexityScore",
1052 self.lineComplexityScoreSpinBox.value())
1053 Preferences.Prefs.settings.setValue(
1054 "PEP8/ValidEncodings", self.encodingsEdit.text())
1055 Preferences.Prefs.settings.setValue(
1056 "PEP8/CopyrightMinFileSize", self.copyrightFileSizeSpinBox.value())
1057 Preferences.Prefs.settings.setValue(
1058 "PEP8/CopyrightAuthor", self.copyrightAuthorEdit.text())
1059 Preferences.Prefs.settings.setValue(
1060 "PEP8/FutureChecker", self.__getSelectedFutureImports())
1061 Preferences.Prefs.settings.setValue(
1062 "PEP8/BuiltinsChecker", self.__getBuiltinsIgnoreList())
1063
1064 @pyqtSlot()
1065 def on_resetDefaultButton_clicked(self):
1066 """
1067 Private slot to reset the configuration values to their default values.
1068 """
1069 Preferences.Prefs.settings.setValue("PEP8/ExcludeFilePatterns", "")
1070 Preferences.Prefs.settings.setValue(
1071 "PEP8/ExcludeMessages", pycodestyle.DEFAULT_IGNORE)
1072 Preferences.Prefs.settings.setValue("PEP8/IncludeMessages", "")
1073 Preferences.Prefs.settings.setValue("PEP8/RepeatMessages", False)
1074 Preferences.Prefs.settings.setValue("PEP8/FixCodes", "")
1075 Preferences.Prefs.settings.setValue("PEP8/NoFixCodes", "E501")
1076 Preferences.Prefs.settings.setValue("PEP8/FixIssues", False)
1077 Preferences.Prefs.settings.setValue("PEP8/ShowIgnored", False)
1078 Preferences.Prefs.settings.setValue(
1079 "PEP8/MaxLineLength", pycodestyle.MAX_LINE_LENGTH)
1080 # Hard reset to pycodestyle preferences
1081 Preferences.Prefs.settings.setValue(
1082 "PEP8/MaxDocLineLength", pycodestyle.MAX_DOC_LENGTH)
1083 Preferences.Prefs.settings.setValue(
1084 "PEP8/BlankLinesBeforeTopLevel", 2)
1085 Preferences.Prefs.settings.setValue(
1086 "PEP8/BlankLinesBeforeMethod", 1)
1087 Preferences.Prefs.settings.setValue("PEP8/HangClosing", False)
1088 Preferences.Prefs.settings.setValue("PEP8/DocstringType", "pep257")
1089 Preferences.Prefs.settings.setValue("PEP8/MaxCodeComplexity", 10)
1090 Preferences.Prefs.settings.setValue("PEP8/LineComplexity", 15)
1091 Preferences.Prefs.settings.setValue("PEP8/LineComplexityScore", 10)
1092 Preferences.Prefs.settings.setValue(
1093 "PEP8/ValidEncodings", "latin-1, utf-8")
1094 Preferences.Prefs.settings.setValue("PEP8/CopyrightMinFileSize", 0)
1095 Preferences.Prefs.settings.setValue("PEP8/CopyrightAuthor", "")
1096 Preferences.Prefs.settings.setValue("PEP8/FutureChecker", "")
1097 Preferences.Prefs.settings.setValue("PEP8/BuiltinsChecker", {
1098 "str": ["unicode", ],
1099 "chr": ["unichr", ],
1100 })
1101 # Update UI with default values
1102 self.on_loadDefaultButton_clicked()
1103
1104 @pyqtSlot(QAbstractButton)
1105 def on_buttonBox_clicked(self, button):
1106 """
1107 Private slot called by a button of the button box clicked.
1108
1109 @param button button that was clicked (QAbstractButton)
1110 """
1111 if button == self.buttonBox.button(QDialogButtonBox.Close):
1112 self.close()
1113 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
1114 if self.__batch:
1115 self.styleCheckService.cancelStyleBatchCheck()
1116 QTimer.singleShot(1000, self.__finish)
1117 else:
1118 self.__finish()
1119 elif button == self.showButton:
1120 self.on_showButton_clicked()
1121 elif button == self.statisticsButton:
1122 self.on_statisticsButton_clicked()
1123
1124 def __clearErrors(self, files):
1125 """
1126 Private method to clear all warning markers of open editors to be
1127 checked.
1128
1129 @param files list of files to be checked (list of string)
1130 """
1131 vm = e5App().getObject("ViewManager")
1132 openFiles = vm.getOpenFilenames()
1133 for file in [f for f in openFiles if f in files]:
1134 editor = vm.getOpenEditor(file)
1135 editor.clearStyleWarnings()
1136
1137 @pyqtSlot()
1138 def on_fixButton_clicked(self):
1139 """
1140 Private slot to fix selected issues.
1141
1142 Build a dictionary of issues to fix. Update the initialized __options.
1143 Then call check with the dict as keyparam to fix selected issues.
1144 """
1145 fixableItems = self.__getSelectedFixableItems()
1146 # dictionary of lists of tuples containing the issue and the item
1147 fixesDict = {}
1148 for itm in fixableItems:
1149 filename = itm.data(0, self.filenameRole)
1150 if filename not in fixesDict:
1151 fixesDict[filename] = []
1152 fixesDict[filename].append((
1153 (filename, itm.data(0, self.lineRole),
1154 itm.data(0, self.positionRole),
1155 "{0} {1}".format(itm.data(0, self.codeRole),
1156 itm.data(0, self.messageRole))),
1157 itm
1158 ))
1159
1160 # update the configuration values (3: fixCodes, 4: noFixCodes,
1161 # 5: fixIssues, 6: maxLineLength)
1162 self.__options[3] = self.fixIssuesEdit.text()
1163 self.__options[4] = self.noFixIssuesEdit.text()
1164 self.__options[5] = True
1165 self.__options[6] = self.lineLengthSpinBox.value()
1166
1167 self.files = list(fixesDict.keys())
1168 # now go through all the files
1169 self.progress = 0
1170 self.files.sort()
1171 self.cancelled = False
1172 self.__onlyFixes = fixesDict
1173 self.check()
1174
1175 def __getSelectedFixableItems(self):
1176 """
1177 Private method to extract all selected items for fixable issues.
1178
1179 @return selected items for fixable issues (list of QTreeWidgetItem)
1180 """
1181 fixableItems = []
1182 for itm in self.resultList.selectedItems():
1183 if itm.childCount() > 0:
1184 for index in range(itm.childCount()):
1185 citm = itm.child(index)
1186 if self.__itemFixable(citm) and citm not in fixableItems:
1187 fixableItems.append(citm)
1188 elif self.__itemFixable(itm) and itm not in fixableItems:
1189 fixableItems.append(itm)
1190
1191 return fixableItems
1192
1193 def __itemFixable(self, itm):
1194 """
1195 Private method to check, if an item has a fixable issue.
1196
1197 @param itm item to be checked (QTreeWidgetItem)
1198 @return flag indicating a fixable issue (boolean)
1199 """
1200 return (itm.data(0, self.fixableRole) and
1201 not itm.data(0, self.ignoredRole))
1202
1203 def __initFuturesList(self, selectedFutures):
1204 """
1205 Private method to set the selected status of the future imports.
1206
1207 @param selectedFutures comma separated list of expected future imports
1208 @type str
1209 """
1210 if selectedFutures:
1211 expectedImports = [
1212 i.strip() for i in selectedFutures.split(",")
1213 if bool(i.strip())]
1214 else:
1215 expectedImports = []
1216 for row in range(self.futuresList.count()):
1217 itm = self.futuresList.item(row)
1218 if itm.text() in expectedImports:
1219 itm.setCheckState(Qt.Checked)
1220 else:
1221 itm.setCheckState(Qt.Unchecked)
1222
1223 def __getSelectedFutureImports(self):
1224 """
1225 Private method to get the expected future imports.
1226
1227 @return expected future imports as a comma separated string
1228 @rtype str
1229 """
1230 selectedFutures = []
1231 for row in range(self.futuresList.count()):
1232 itm = self.futuresList.item(row)
1233 if itm.checkState() == Qt.Checked:
1234 selectedFutures.append(itm.text())
1235 return ", ".join(selectedFutures)
1236
1237 def __initBuiltinsIgnoreList(self, builtinsIgnoreDict):
1238 """
1239 Private method to populate the list of shadowed builtins to be ignored.
1240
1241 @param builtinsIgnoreDict dictionary containing the builtins
1242 assignments to be ignored
1243 @type dict of list of str
1244 """
1245 self.builtinsAssignmentList.clear()
1246 for left, rightList in builtinsIgnoreDict.items():
1247 for right in rightList:
1248 QTreeWidgetItem(self.builtinsAssignmentList, [left, right])
1249
1250 self.on_builtinsAssignmentList_itemSelectionChanged()
1251
1252 def __getBuiltinsIgnoreList(self):
1253 """
1254 Private method to get a dictionary containing the builtins assignments
1255 to be ignored.
1256
1257 @return dictionary containing the builtins assignments to be ignored
1258 @rtype dict of list of str
1259 """
1260 builtinsIgnoreDict = {}
1261 for row in range(self.builtinsAssignmentList.topLevelItemCount()):
1262 itm = self.builtinsAssignmentList.topLevelItem(row)
1263 left, right = itm.text(0), itm.text(1)
1264 if left not in builtinsIgnoreDict:
1265 builtinsIgnoreDict[left] = []
1266 builtinsIgnoreDict[left].append(right)
1267
1268 return builtinsIgnoreDict
1269
1270 @pyqtSlot()
1271 def on_builtinsAssignmentList_itemSelectionChanged(self):
1272 """
1273 Private slot to react upon changes of the selected builtin assignments.
1274 """
1275 self.deleteBuiltinButton.setEnabled(
1276 len(self.builtinsAssignmentList.selectedItems()) > 0)
1277
1278 @pyqtSlot()
1279 def on_addBuiltinButton_clicked(self):
1280 """
1281 Private slot to add a built-in assignment to be ignored.
1282 """
1283 from .CodeStyleAddBuiltinIgnoreDialog import \
1284 CodeStyleAddBuiltinIgnoreDialog
1285 dlg = CodeStyleAddBuiltinIgnoreDialog(self)
1286 if dlg.exec_() == QDialog.Accepted:
1287 left, right = dlg.getData()
1288 QTreeWidgetItem(self.builtinsAssignmentList, [left, right])
1289
1290 @pyqtSlot()
1291 def on_deleteBuiltinButton_clicked(self):
1292 """
1293 Private slot to delete the selected items from the list.
1294 """
1295 for itm in self.builtinsAssignmentList.selectedItems():
1296 index = self.builtinsAssignmentList.indexOfTopLevelItem(itm)
1297 self.builtinsAssignmentList.takeTopLevelItem(index)
1298 del itm

eric ide

mercurial