forked from twisted/twistedchecker
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
147 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
#!/usr/bin/env python | ||
""" | ||
API for the command-line I{pyflakes} tool. | ||
This is a copy of pyflakes/api.py file which excludes some files | ||
for twistedchecker. | ||
""" | ||
from __future__ import with_statement | ||
|
||
import sys | ||
import os | ||
import re | ||
import _ast | ||
from optparse import OptionParser | ||
|
||
from pyflakes import checker, __version__ | ||
from pyflakes import reporter as modReporter | ||
|
||
__all__ = ['check', 'checkPath', 'checkRecursive', 'iterSourceCode', 'main'] | ||
|
||
|
||
RE_EXCLUDE = '.*functionaltests.*' | ||
|
||
|
||
def check(codeString, filename, reporter=None): | ||
""" | ||
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} | ||
@param reporter: A L{Reporter} instance, where errors and warnings will be | ||
reported. | ||
@return: The number of warnings emitted. | ||
@rtype: C{int} | ||
""" | ||
if reporter is None: | ||
reporter = modReporter._makeDefaultReporter() | ||
# First, compile into an AST and handle syntax errors. | ||
try: | ||
tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST) | ||
except SyntaxError: | ||
value = sys.exc_info()[1] | ||
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. | ||
reporter.unexpectedError(filename, 'problem decoding source') | ||
else: | ||
reporter.syntaxError(filename, msg, lineno, offset, text) | ||
return 1 | ||
except Exception: | ||
reporter.unexpectedError(filename, 'problem decoding source') | ||
return 1 | ||
# Okay, it's syntactically valid. Now check it. | ||
w = checker.Checker(tree, filename) | ||
w.messages.sort(key=lambda m: m.lineno) | ||
for warning in w.messages: | ||
reporter.flake(warning) | ||
return len(w.messages) | ||
|
||
|
||
def checkPath(filename, reporter=None): | ||
""" | ||
Check the given path, printing out any warnings detected. | ||
@param reporter: A L{Reporter} instance, where errors and warnings will be | ||
reported. | ||
@return: the number of warnings printed | ||
""" | ||
if reporter is None: | ||
reporter = modReporter._makeDefaultReporter() | ||
try: | ||
with open(filename, 'rb') as f: | ||
codestr = f.read() | ||
if sys.version_info < (2, 7): | ||
codestr += '\n' # Work around for Python <= 2.6 | ||
except UnicodeError: | ||
reporter.unexpectedError(filename, 'problem decoding source') | ||
return 1 | ||
except IOError: | ||
msg = sys.exc_info()[1] | ||
reporter.unexpectedError(filename, msg.args[1]) | ||
return 1 | ||
return check(codestr, filename, reporter) | ||
|
||
|
||
def iterSourceCode(paths): | ||
""" | ||
Iterate over all Python source files in C{paths}. | ||
@param paths: A list of paths. Directories will be recursed into and | ||
any .py files found will be yielded. Any non-directories will be | ||
yielded as-is. | ||
""" | ||
for path in paths: | ||
if os.path.isdir(path): | ||
for dirpath, dirnames, filenames in os.walk(path): | ||
for filename in filenames: | ||
if filename.endswith('.py'): | ||
yield os.path.join(dirpath, filename) | ||
else: | ||
yield path | ||
|
||
|
||
def checkRecursive(paths, reporter): | ||
""" | ||
Recursively check all source files in C{paths}. | ||
@param paths: A list of paths to Python source files and directories | ||
containing Python source files. | ||
@param reporter: A L{Reporter} where all of the warnings and errors | ||
will be reported to. | ||
@return: The number of warnings found. | ||
""" | ||
warnings = 0 | ||
for sourcePath in iterSourceCode(paths): | ||
if re.search(RE_EXCLUDE, sourcePath): | ||
continue | ||
warnings += checkPath(sourcePath, reporter) | ||
return warnings | ||
|
||
|
||
def main(prog=None): | ||
parser = OptionParser(prog=prog, version=__version__) | ||
(__, args) = parser.parse_args() | ||
reporter = modReporter._makeDefaultReporter() | ||
if args: | ||
warnings = checkRecursive(args, reporter) | ||
else: | ||
warnings = check(sys.stdin.read(), '<stdin>', reporter) | ||
raise SystemExit(warnings > 0) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |