diff -r cba5c14bcd5e -r ef2b5af23ce7 eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py --- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py Mon Jun 15 18:23:27 2020 +0200 +++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py Mon Jun 15 19:01:02 2020 +0200 @@ -12,6 +12,7 @@ except ImportError: import queue +import ast import sys import multiprocessing @@ -272,6 +273,48 @@ outputQueue.put((filename, result)) +def __checkSyntax(filename, source): + """ + Private module function to perform a syntax check. + + @param filename source filename + @type str + @param source string containing the code to check + @type str + @return tuple containing the error dictionary with syntax error details + and a statistics dictionary or a tuple containing two None + @rtype tuple of (dict, dict) or tuple of (None, None) + """ + src = "".join(source) + # Check type for py2: if not str it's unicode + if sys.version_info[0] == 2: + try: + src = src.encode('utf-8') + except UnicodeError: + pass + + try: + ast.parse(src, filename, 'exec') + return None, None + except (SyntaxError, TypeError): + exc_type, exc = sys.exc_info()[:2] + if len(exc.args) > 1: + offset = exc.args[1] + if len(offset) > 2: + offset = offset[1:3] + else: + offset = (1, 0) + return ({ + "file": filename, + "line": offset[0], + "offset": offset[1], + "code": "E901", + "args": [exc_type.__name__, exc.args[0]], + }, { + "E901": 1, + }) + + def __checkCodeStyle(filename, source, args): """ Private module function to perform the code style check and/or fix @@ -340,68 +383,73 @@ else: ignore = [] - # TODO: perform syntax check and report invalid syntax once for all - - # check coding style - pycodestyle.BLANK_LINES_CONFIG = { - # Top level class and function. - 'top_level': blankLines[0], - # Methods and nested class and function. - 'method': blankLines[1], - } - styleGuide = pycodestyle.StyleGuide( - reporter=CodeStyleCheckerReport, - repeat=repeatMessages, - select=select, - ignore=ignore, - max_line_length=maxLineLength, - max_doc_length=maxDocLineLength, - hang_closing=hangClosing, - ) - report = styleGuide.check_files([filename]) - stats.update(report.counters) - errors = report.errors - - # check documentation style - docStyleChecker = DocStyleChecker( - source, filename, select, ignore, [], repeatMessages, - maxLineLength=maxDocLineLength, docType=docType) - docStyleChecker.run() - stats.update(docStyleChecker.counters) - errors += docStyleChecker.errors + syntaxError, syntaxStats = __checkSyntax(filename, source) + if syntaxError: + errors = [syntaxError] + stats.update(syntaxStats) - # miscellaneous additional checks - miscellaneousChecker = MiscellaneousChecker( - source, filename, select, ignore, [], repeatMessages, - miscellaneousArgs) - miscellaneousChecker.run() - stats.update(miscellaneousChecker.counters) - errors += miscellaneousChecker.errors - - # check code complexity - complexityChecker = ComplexityChecker( - source, filename, select, ignore, codeComplexityArgs) - complexityChecker.run() - stats.update(complexityChecker.counters) - errors += complexityChecker.errors - - # check function annotations - if sys.version_info >= (3, 5, 0): - # annotations are supported from Python 3.5 on - from AnnotationsChecker import AnnotationsChecker - annotationsChecker = AnnotationsChecker( + # perform the checks only, if syntax is ok + else: + # check coding style + pycodestyle.BLANK_LINES_CONFIG = { + # Top level class and function. + 'top_level': blankLines[0], + # Methods and nested class and function. + 'method': blankLines[1], + } + styleGuide = pycodestyle.StyleGuide( + reporter=CodeStyleCheckerReport, + repeat=repeatMessages, + select=select, + ignore=ignore, + max_line_length=maxLineLength, + max_doc_length=maxDocLineLength, + hang_closing=hangClosing, + ) + report = styleGuide.check_files([filename]) + stats.update(report.counters) + errors = report.errors + + # check documentation style + docStyleChecker = DocStyleChecker( source, filename, select, ignore, [], repeatMessages, - annotationArgs) - annotationsChecker.run() - stats.update(annotationsChecker.counters) - errors += annotationsChecker.errors - - securityChecker = SecurityChecker( - source, filename, select, ignore, [], repeatMessages, - securityArgs) - securityChecker.run() - stats.update(securityChecker.counters) - errors += securityChecker.errors + maxLineLength=maxDocLineLength, docType=docType) + docStyleChecker.run() + stats.update(docStyleChecker.counters) + errors += docStyleChecker.errors + + # miscellaneous additional checks + miscellaneousChecker = MiscellaneousChecker( + source, filename, select, ignore, [], repeatMessages, + miscellaneousArgs) + miscellaneousChecker.run() + stats.update(miscellaneousChecker.counters) + errors += miscellaneousChecker.errors + + # check code complexity + complexityChecker = ComplexityChecker( + source, filename, select, ignore, codeComplexityArgs) + complexityChecker.run() + stats.update(complexityChecker.counters) + errors += complexityChecker.errors + + # check function annotations + if sys.version_info >= (3, 5, 0): + # annotations are supported from Python 3.5 on + from AnnotationsChecker import AnnotationsChecker + annotationsChecker = AnnotationsChecker( + source, filename, select, ignore, [], repeatMessages, + annotationArgs) + annotationsChecker.run() + stats.update(annotationsChecker.counters) + errors += annotationsChecker.errors + + securityChecker = SecurityChecker( + source, filename, select, ignore, [], repeatMessages, + securityArgs) + securityChecker.run() + stats.update(securityChecker.counters) + errors += securityChecker.errors errorsDict = {} for error in errors: