From 0eefa5760c43c3ae1d750330e7642b5777c94475 Mon Sep 17 00:00:00 2001 From: Henrik Levkowetz Date: Tue, 25 Feb 2014 20:22:20 +0000 Subject: [PATCH] Added a management command to run pyflakes, with the added feature of being able to mark individual lines with # pyflakes:ignore, which is needed in some cases. - Legacy-Id: 7367 --- ietf/utils/management/commands/flakes.py | 105 +++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 ietf/utils/management/commands/flakes.py diff --git a/ietf/utils/management/commands/flakes.py b/ietf/utils/management/commands/flakes.py new file mode 100644 index 000000000..81599f940 --- /dev/null +++ b/ietf/utils/management/commands/flakes.py @@ -0,0 +1,105 @@ +import ast +import os +from pyflakes import checker, messages +import sys + +from django.conf import settings +from django.core.management.base import BaseCommand + +# BlackHole, PySyntaxError and checking based on +# https://github.com/patrys/gedit-pyflakes-plugin.git +class BlackHole(object): + write = flush = lambda *args, **kwargs: None + + def __enter__(self): + self.stderr, sys.stderr = sys.stderr, self + + def __exit__(self, *args, **kwargs): + sys.stderr = self.stderr + + +class PySyntaxError(messages.Message): + message = 'syntax error in line %d: %s' + + def __init__(self, filename, lineno, col, message): + super(PySyntaxError, self).__init__(filename, lineno) + self.message_args = (col, message) + + +def check(codeString, filename): + """ + Check the Python source given by C{codeString} for flakes. + + @param codeString: The Python source to check. + @type codeString: C{str} + + @param filename: The name of the file the source came from, used to report + errors. + @type filename: C{str} + + @return: The number of warnings emitted. + @rtype: C{int} + """ + + try: + with BlackHole(): + tree = ast.parse(codeString, filename) + except SyntaxError, e: + return [PySyntaxError(filename, e.lineno, e.offset, e.text)] + else: + # Okay, it's syntactically valid. Now parse it into an ast and check + # it. + w = checker.Checker(tree, filename) + + lines = codeString.split('\n') + # honour pyflakes:ignore comments + messages = [message for message in w.messages + if lines[message.lineno-1].find('pyflakes:ignore') < 0] + messages.sort(lambda a, b: cmp(a.lineno, b.lineno)) + + return messages + + +def checkPath(filename): + """ + Check the given path, printing out any warnings detected. + + @return: the number of warnings printed + """ + try: + return check(file(filename, 'U').read() + '\n', filename) + except IOError, msg: + return ["%s: %s" % (filename, msg.args[1])] + except TypeError: + pass + +def checkPaths(filenames): + warnings = [] + for arg in filenames: + if os.path.isdir(arg): + for dirpath, dirnames, filenames in os.walk(arg): + for filename in filenames: + if filename.endswith('.py'): + warnings.extend(checkPath(os.path.join(dirpath, + filename))) + else: + warnings.extend(checkPath(arg)) + return warnings +#### pyflakes.scripts.pyflakes ends. + + +class Command(BaseCommand): + help = "Run pyflakes syntax checks." + args = '[filename [filename [...]]]' + + def handle(self, *filenames, **options): + if not filenames: + filenames = getattr(settings, 'PYFLAKES_DEFAULT_ARGS', ['.']) + warnings = checkPaths(filenames) + for warning in warnings: + print warning + + if warnings: + print 'Total warnings: %d' % len(warnings) + raise SystemExit(1) + \ No newline at end of file