Skip to content

Instantly share code, notes, and snippets.

@mpasternacki
Created May 25, 2010 12:41

Revisions

  1. mpasternacki created this gist May 25, 2010.
    107 changes: 107 additions & 0 deletions flakes.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    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)