src/eric7/Plugins/CheckerPlugins/SyntaxChecker/SyntaxCheckerDialog.py

branch
eric7
changeset 10304
ff7d3d6b952d
parent 10302
8cb0dabf852f
child 10341
3fdffd9cc21d
equal deleted inserted replaced
10303:ee1aadab1215 10304:ff7d3d6b952d
71 self.__timenow = time.monotonic() 71 self.__timenow = time.monotonic()
72 72
73 self.__fileList = [] 73 self.__fileList = []
74 self.__project = None 74 self.__project = None
75 self.__arguments = () 75 self.__arguments = ()
76 self.__statistics = self.__defaultStatistics()
76 self.filterFrame.setVisible(False) 77 self.filterFrame.setVisible(False)
77 78
78 self.checkProgress.setVisible(False) 79 self.checkProgress.setVisible(False)
79 80
80 try: 81 try:
92 """ 93 """
93 self.resultList.sortItems( 94 self.resultList.sortItems(
94 self.resultList.sortColumn(), self.resultList.header().sortIndicatorOrder() 95 self.resultList.sortColumn(), self.resultList.header().sortIndicatorOrder()
95 ) 96 )
96 97
98 def __defaultStatistics(self):
99 """
100 Private method to return the default statistics entry.
101
102 @return dictionary with default statistics entry
103 @rtype dict
104 """
105 return {
106 "files_checked": 0,
107 "files_issues": 0,
108 "errors": 0,
109 "py_warnings": 0,
110 "warnings": 0,
111 }
112
113 def __updateStatistics(self, fileStatistics):
114 """
115 Private method to update the statistics.
116
117 @param fileStatistics dictionary containing the file statistics
118 @type dict
119 """
120 self.__statistics["files_checked"] += 1
121 if any(fileStatistics.values()):
122 self.__statistics["files_issues"] += 1
123 self.__statistics["errors"] += fileStatistics["errors"]
124 self.__statistics["py_warnings"] += fileStatistics["py_warnings"]
125 self.__statistics["warnings"] += fileStatistics["warnings"]
126
127 def __resetStatistics(self, skipped):
128 """
129 Private method to reset the statistics data.
130
131 @param skipped number of files not being checked
132 @type int
133 """
134 self.__statistics["files_checked"] = 0
135 self.__statistics["files_skipped"] = skipped
136 self.__statistics["files_issues"] = 0
137 self.__statistics["errors"] = 0
138 self.__statistics["py_warnings"] = 0
139 self.__statistics["warnings"] = 0
140
141 def __createFileStatistics(self, problems):
142 """
143 Private method to return the file statistics entry.
144
145 @param problems dictionary with the keys 'error', 'py_warnings' and
146 'warnings' which hold a list of issues each
147 @type dict
148 @return dictionary with the file statistics
149 @rtype dict
150 """
151 return {
152 "errors": 1 if problems.get("error") else 0,
153 "py_warnings": len(problems.get("py_warnings", [])),
154 "warnings": len(problems.get("warnings", [])),
155 }
156
97 def __createErrorItem(self, filename, message): 157 def __createErrorItem(self, filename, message):
98 """ 158 """
99 Private slot to create a new error item in the result list. 159 Private slot to create a new error item in the result list.
100 160
101 @param filename name of the file 161 @param filename name of the file
112 if not self.resultList.findItems(msg, Qt.MatchFlag.MatchExactly): 172 if not self.resultList.findItems(msg, Qt.MatchFlag.MatchExactly):
113 itm = QTreeWidgetItem(self.__errorItem, [msg]) 173 itm = QTreeWidgetItem(self.__errorItem, [msg])
114 itm.setForeground(0, Qt.GlobalColor.red) 174 itm.setForeground(0, Qt.GlobalColor.red)
115 itm.setFirstColumnSpanned(True) 175 itm.setFirstColumnSpanned(True)
116 176
177 def __createHeaderItem(self, filename, fileStatistics=None):
178 """
179 Private method to create a header item in the result list.
180
181 @param filename file name of file
182 @type str
183 @param fileStatistics dictionary containing statistical data of the check
184 result (defaults to None)
185 @type dict (optional)
186 """
187 itemText = self.__project.getRelativePath(filename)
188
189 if fileStatistics:
190 statisticsTextList = []
191 if fileStatistics["errors"]:
192 statisticsTextList.append(
193 self.tr("Errors: {0}").format(fileStatistics["errors"])
194 )
195 if fileStatistics["py_warnings"]:
196 statisticsTextList.append(
197 self.tr("Python Warnings: {0}").format(
198 fileStatistics["py_warnings"]
199 )
200 )
201 if fileStatistics["warnings"]:
202 statisticsTextList.append(
203 self.tr("Warnings: {0}").format(fileStatistics["warnings"])
204 )
205 if statisticsTextList:
206 itemText += "{0}\n{1}".format(itemText, ", ".join(statisticsTextList))
207
208 self.__lastFileItem = QTreeWidgetItem(self.resultList, [itemText])
209 self.__lastFileItem.setFirstColumnSpanned(True)
210 self.__lastFileItem.setExpanded(True)
211 self.__lastFileItem.setData(0, self.filenameRole, filename)
212
117 def __createResultItem( 213 def __createResultItem(
118 self, filename, line, index, error, sourcecode, isWarning=False 214 self, filename, line, index, error, sourcecode, isWarning=False
119 ): 215 ):
120 """ 216 """
121 Private method to create an entry in the result list. 217 Private method to create an entry in the result list.
136 if ( 232 if (
137 self.__lastFileItem is None 233 self.__lastFileItem is None
138 or self.__lastFileItem.data(0, self.filenameRole) != filename 234 or self.__lastFileItem.data(0, self.filenameRole) != filename
139 ): 235 ):
140 # It's a new file 236 # It's a new file
141 self.__lastFileItem = QTreeWidgetItem( 237 self.__createHeaderItem(filename)
142 self.resultList, [self.__project.getRelativePath(filename)]
143 )
144 self.__lastFileItem.setFirstColumnSpanned(True)
145 self.__lastFileItem.setExpanded(True)
146 self.__lastFileItem.setData(0, self.filenameRole, filename)
147 238
148 itm = QTreeWidgetItem(self.__lastFileItem) 239 itm = QTreeWidgetItem(self.__lastFileItem)
149 if isWarning: 240 if isWarning:
150 itm.setIcon(0, EricPixmapCache.getIcon("warning")) 241 itm.setIcon(0, EricPixmapCache.getIcon("warning"))
151 else: 242 else:
234 self.excludeFilesEdit.setText(self.__data["ExcludeFiles"]) 325 self.excludeFilesEdit.setText(self.__data["ExcludeFiles"])
235 self.builtinsEdit.setText(self.__data["AdditionalBuiltins"]) 326 self.builtinsEdit.setText(self.__data["AdditionalBuiltins"])
236 327
237 self.on_startButton_clicked() # press the start button 328 self.on_startButton_clicked() # press the start button
238 329
239 def start(self, fn, codestring=""): 330 def start(self, fn, codestring="", skipped=0):
240 """ 331 """
241 Public slot to start the syntax check. 332 Public slot to start the syntax check.
242 333
243 @param fn file or list of files or directory to be checked 334 @param fn file or list of files or directory to be checked
244 @type str or list of str 335 @type str or list of str
245 @param codestring string containing the code to be checked. If this is given, 336 @param codestring string containing the code to be checked. If this is given,
246 fn must be a single file name. 337 fn must be a single file name.
247 @type str 338 @type str
339 @param skipped number of files not being checked
340 @type int
248 """ 341 """
249 self.__batch = False 342 self.__batch = False
250 343
251 if self.syntaxCheckService is not None: 344 if self.syntaxCheckService is not None:
252 if self.__project is None: 345 if self.__project is None:
277 else: 370 else:
278 self.files = [fn] 371 self.files = [fn]
279 372
280 self.__errorItem = None 373 self.__errorItem = None
281 self.__clearErrors(self.files) 374 self.__clearErrors(self.files)
375 self.__resetStatistics(skipped)
282 376
283 if codestring or len(self.files) > 0: 377 if codestring or len(self.files) > 0:
284 self.checkProgress.setMaximum(max(1, len(self.files))) 378 self.checkProgress.setMaximum(max(1, len(self.files)))
285 self.checkProgress.setVisible(len(self.files) > 1) 379 self.checkProgress.setVisible(len(self.files) > 1)
286 QApplication.processEvents() 380 QApplication.processEvents()
410 """ 504 """
411 Private slot to display the reported messages. 505 Private slot to display the reported messages.
412 506
413 @param fn filename of the checked file 507 @param fn filename of the checked file
414 @type str 508 @type str
415 @param problems dictionary with the keys 'error' and 'warnings' which 509 @param problems dictionary with the keys 'error', 'py_warnings' and
416 hold a list containing details about the error/ warnings 510 'warnings' which hold a list containing details about the error or
417 (file name, line number, column, codestring (only at syntax 511 warnings (file name, line number, column, codestring (only at syntax
418 errors), the message) 512 errors), message)
419 @type dict 513 @type dict
420 """ 514 """
421 if self.__finished: 515 if self.__finished:
422 return 516 return
423 517
424 # Check if it's the requested file, otherwise ignore signal if not 518 # Check if it's the requested file, otherwise ignore signal if not
425 # in batch mode 519 # in batch mode
426 if not self.__batch and fn != self.filename: 520 if not self.__batch and fn != self.filename:
427 return 521 return
428 522
429 error = problems.get("error") 523 fileStatistics = self.__createFileStatistics(problems)
430 if error: 524 self.__updateStatistics(fileStatistics)
431 self.noResults = False 525 if any(fileStatistics.values()):
432 _fn, lineno, col, code, msg = error 526 self.__createHeaderItem(fn, fileStatistics)
433 self.__createResultItem(_fn, lineno, col, msg, code, False) 527
434 528 error = problems.get("error")
435 warnings = problems.get("py_warnings", []) + problems.get("warnings", []) 529 if error:
436 if warnings:
437 if self.__batch:
438 try:
439 source = Utilities.readEncodedFile(fn)[0]
440 source = Utilities.normalizeCode(source)
441 source = source.splitlines()
442 except (OSError, UnicodeError):
443 source = ""
444 else:
445 source = self.source.splitlines()
446 for filename, lineno, col, _code, msg in warnings:
447 self.noResults = False 530 self.noResults = False
448 if source: 531 filename, lineno, col, code, msg = error
532 self.__createResultItem(filename, lineno, col, msg, code, False)
533
534 warnings = problems.get("py_warnings", []) + problems.get("warnings", [])
535 if warnings:
536 if self.__batch:
449 try: 537 try:
450 src_line = source[lineno - 1].strip() 538 source = Utilities.readEncodedFile(fn)[0]
451 except IndexError: 539 source = Utilities.normalizeCode(source)
540 source = source.splitlines()
541 except (OSError, UnicodeError):
542 source = ""
543 else:
544 source = self.source.splitlines()
545 for filename, lineno, col, _code, msg in warnings:
546 self.noResults = False
547 if source:
548 try:
549 src_line = source[lineno - 1].strip()
550 except IndexError:
551 src_line = ""
552 else:
452 src_line = "" 553 src_line = ""
453 else: 554 self.__createResultItem(filename, lineno, col, msg, src_line, True)
454 src_line = ""
455 self.__createResultItem(filename, lineno, col, msg, src_line, True)
456 555
457 self.progress += 1 556 self.progress += 1
458 self.checkProgress.setValue(self.progress) 557 self.checkProgress.setValue(self.progress)
459 if time.monotonic() - self.__timenow > 0.01: 558 if time.monotonic() - self.__timenow > 0.01:
460 QApplication.processEvents() 559 QApplication.processEvents()
461 self.__timenow = time.monotonic() 560 self.__timenow = time.monotonic()
462 self.__resort() 561 self.__resort()
463 562
464 if not self.__batch: 563 if not self.__batch:
465 self.check() 564 self.check()
565
566 def __updateStatisticsArea(self):
567 """
568 Private method to update the statistics area of the dialog.
569 """
570 self.totalLabel.setText(
571 str(self.__statistics["files_skipped"] + self.__statistics["files_checked"])
572 )
573 self.skippedLabel.setText(str(self.__statistics["files_skipped"]))
574 self.checkedLabel.setText(str(self.__statistics["files_checked"]))
575 self.issuesLabel.setText(str(self.__statistics["files_issues"]))
576 self.errorsLabel.setText(str(self.__statistics["errors"]))
577 self.warningsLabel.setText(str(self.__statistics["warnings"]))
578 self.pyWarningsLabel.setText(str(self.__statistics["py_warnings"]))
466 579
467 def __finish(self): 580 def __finish(self):
468 """ 581 """
469 Private slot called when the syntax check finished or the user 582 Private slot called when the syntax check finished or the user
470 pressed the button. 583 pressed the button.
491 self.showButton.setEnabled(True) 604 self.showButton.setEnabled(True)
492 self.resultList.header().resizeSections( 605 self.resultList.header().resizeSections(
493 QHeaderView.ResizeMode.ResizeToContents 606 QHeaderView.ResizeMode.ResizeToContents
494 ) 607 )
495 self.resultList.header().setStretchLastSection(True) 608 self.resultList.header().setStretchLastSection(True)
609 self.__updateStatisticsArea()
496 610
497 self.checkProgress.setVisible(False) 611 self.checkProgress.setVisible(False)
498 612
499 def __cancel(self): 613 def __cancel(self):
500 """ 614 """
533 def on_startButton_clicked(self): 647 def on_startButton_clicked(self):
534 """ 648 """
535 Private slot to start a syntax check run. 649 Private slot to start a syntax check run.
536 """ 650 """
537 fileList = self.__fileList[:] 651 fileList = self.__fileList[:]
652 totalLen = len(fileList)
538 653
539 filterString = self.excludeFilesEdit.text() 654 filterString = self.excludeFilesEdit.text()
540 self.__data["ExcludeFiles"] = filterString 655 self.__data["ExcludeFiles"] = filterString
541 self.__data["AdditionalBuiltins"] = self.builtinsEdit.text().strip() 656 self.__data["AdditionalBuiltins"] = self.builtinsEdit.text().strip()
542 if self.__data != self.__project.getData("CHECKERSPARMS", "SyntaxChecker"): 657 if self.__data != self.__project.getData("CHECKERSPARMS", "SyntaxChecker"):
548 663
549 self.resultList.clear() 664 self.resultList.clear()
550 self.noResults = True 665 self.noResults = True
551 self.cancelled = False 666 self.cancelled = False
552 self.setArguments((self.__data["AdditionalBuiltins"].split(),)) 667 self.setArguments((self.__data["AdditionalBuiltins"].split(),))
553 self.start(fileList) 668 self.start(fileList, skipped=totalLen - len(fileList))
554 669
555 @pyqtSlot(QTreeWidgetItem, int) 670 @pyqtSlot(QTreeWidgetItem, int)
556 def on_resultList_itemActivated(self, itm, col): 671 def on_resultList_itemActivated(self, itm, col):
557 """ 672 """
558 Private slot to handle the activation of an item. 673 Private slot to handle the activation of an item.

eric ide

mercurial