Run checks expecting an AST

This commit is contained in:
Ian Cordasco 2016-03-15 14:10:20 -05:00
parent 576d1f6c85
commit 0b063a1024
4 changed files with 48 additions and 2 deletions

View file

@ -326,6 +326,37 @@ class FileChecker(object):
self.processor.keyword_arguments_for(plugin.parameters, arguments)
return plugin.execute(**arguments)
def run_ast_checks(self):
"""Run all checks expecting an abstract syntax tree."""
try:
ast = self.processor.build_ast()
except (ValueError, SyntaxError, TypeError):
(exc_type, exception) = sys.exc_info()[:2]
if len(exception.args) > 1:
offset = exception.args[1]
if len(offset) > 2:
offset = offset[1:3]
else:
offset = (1, 0)
self.report('E999', offset[0], offset[1], '%s: %s' %
(exc_type.__name__, exception.args[0]))
return
for plugin in self.checks.ast_plugins:
checker = self.run_check(plugin, tree=ast)
# NOTE(sigmavirus24): If we want to allow for AST plugins that are
# not classes exclusively, we can do the following:
# retrieve_results = getattr(checker, 'run', lambda: checker)
# Otherwise, we just call run on the checker
for (line_number, offset, text, check) in checker.run():
self.report(
error_code=None,
line_number=line_number,
column=offset,
text=text,
)
def run_logical_checks(self):
"""Run all checks expecting a logical line."""
comments, logical_line, mapping = self.processor.build_logical_line()
@ -404,6 +435,8 @@ class FileChecker(object):
self.report(exc.error_code, exc.line_number, exc.column_number,
exc.error_message)
self.run_ast_checks()
if results_queue is not None:
results_queue.put((self.filename, self.results))

View file

@ -227,6 +227,9 @@ class Application(object):
self.option_manager, argv
)
self.check_plugins.provide_options(self.option_manager, self.options,
self.args)
def make_formatter(self):
# type: () -> NoneType
"""Initialize a formatter based on the parsed options."""

View file

@ -10,6 +10,7 @@ from flake8 import defaults
from flake8 import exceptions
from flake8 import utils
PyCF_ONLY_AST = 1024
NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
# Work around Python < 2.6 behaviour, which does not generate NL after
# a comment which is on a line by itself.
@ -172,6 +173,10 @@ class FileProcessor(object):
(previous_row, previous_column) = end
return comments, logical, mapping
def build_ast(self):
"""Build an abstract syntax tree from the list of lines."""
return compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
def build_logical_line(self):
"""Build a logical line from the current tokens list."""
comments, logical, mapping_list = self.build_logical_line_tokens()
@ -223,6 +228,10 @@ class FileProcessor(object):
except tokenize.TokenError as exc:
raise exceptions.InvalidSyntax(exc.message, exception=exc)
def line_for(self, line_number):
"""Retrieve the physical line at the specified line number."""
return self.lines[line_number - 1]
def next_line(self):
"""Get the next line from the list."""
if self.line_number >= self.total_lines:

View file

@ -187,12 +187,13 @@ class StyleGuide(object):
error, codes_str)
return False
def handle_error(self, code, filename, line_number, column_number, text):
def handle_error(self, code, filename, line_number, column_number, text,
physical_line=None):
# type: (str, str, int, int, str) -> NoneType
"""Handle an error reported by a check."""
error = Error(code, filename, line_number, column_number, text)
if (self.should_report_error(error.code) is Decision.Selected and
self.is_inline_ignored(error) is False):
self.is_inline_ignored(error, physical_line) is False):
self.formatter.handle(error)
self.listener.notify(error.code, error)