from django.conf import settings from django.core.management.base import BaseCommand #### pyflakes.scripts.pyflakes, modified: ## - return array of warnings instead of printing them ## - honour pyflakes:ignore comments import compiler, sys import os import pyflakes.checker 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} """ # Since compiler.parse does not reliably report syntax errors, use the # built in compiler first to detect those. try: try: compile(codeString, filename, "exec") except MemoryError: # Python 2.4 will raise MemoryError if the source can't be # decoded. if sys.version_info[:2] == (2, 4): raise SyntaxError(None) raise except (SyntaxError, IndentationError), value: msg = value.args[0] (lineno, offset, text) = value.lineno, value.offset, value.text # If there's an encoding problem with the file, the text is None. if text is None: # Avoid using msg, since for the only known case, it contains a # bogus message that claims the encoding the file declared was # unknown. return ["%s: problem decoding source" % (filename, )] else: line = text.splitlines()[-1] if offset is not None: offset = offset - (len(text) - len(line)) return ['%s:%d: %s' % (filename, lineno, msg)] else: # Okay, it's syntactically valid. Now parse it into an ast and check # it. tree = compiler.parse(codeString) w = pyflakes.checker.Checker(tree, filename) lines = codeString.split('\n') 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])] 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)