More unit tests
[codimension.git] / thirdparty / pyflakes / api.py
blobb132566bd9ab364f30e3ea4b680f7065bbad64f2
1 """
2 API for the command-line I{pyflakes} tool.
3 """
4 from __future__ import with_statement
6 import sys
7 import os
8 import _ast
9 from optparse import OptionParser
11 from pyflakes import checker, __version__
12 from pyflakes import reporter as modReporter
14 __all__ = ['check', 'checkPath', 'checkRecursive', 'iterSourceCode', 'main']
17 def check(codeString, filename, reporter=None):
18 """
19 Check the Python source given by C{codeString} for flakes.
21 @param codeString: The Python source to check.
22 @type codeString: C{str}
24 @param filename: The name of the file the source came from, used to report
25 errors.
26 @type filename: C{str}
28 @param reporter: A L{Reporter} instance, where errors and warnings will be
29 reported.
31 @return: The number of warnings emitted.
32 @rtype: C{int}
33 """
34 if reporter is None:
35 reporter = modReporter._makeDefaultReporter()
36 # First, compile into an AST and handle syntax errors.
37 try:
38 tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST)
39 except SyntaxError:
40 value = sys.exc_info()[1]
41 msg = value.args[0]
43 (lineno, offset, text) = value.lineno, value.offset, value.text
45 # If there's an encoding problem with the file, the text is None.
46 if text is None:
47 # Avoid using msg, since for the only known case, it contains a
48 # bogus message that claims the encoding the file declared was
49 # unknown.
50 reporter.unexpectedError(filename, 'problem decoding source')
51 else:
52 reporter.syntaxError(filename, msg, lineno, offset, text)
53 return 1
54 except Exception:
55 reporter.unexpectedError(filename, 'problem decoding source')
56 return 1
57 # Okay, it's syntactically valid. Now check it.
58 w = checker.Checker(tree, filename)
59 w.messages.sort(key=lambda m: m.lineno)
60 for warning in w.messages:
61 reporter.flake(warning)
62 return len(w.messages)
65 def checkPath(filename, reporter=None):
66 """
67 Check the given path, printing out any warnings detected.
69 @param reporter: A L{Reporter} instance, where errors and warnings will be
70 reported.
72 @return: the number of warnings printed
73 """
74 if reporter is None:
75 reporter = modReporter._makeDefaultReporter()
76 try:
77 with open(filename, 'U') as f:
78 codestr = f.read() + '\n'
79 except UnicodeError:
80 reporter.unexpectedError(filename, 'problem decoding source')
81 return 1
82 except IOError:
83 msg = sys.exc_info()[1]
84 reporter.unexpectedError(filename, msg.args[1])
85 return 1
86 return check(codestr, filename, reporter)
89 def iterSourceCode(paths):
90 """
91 Iterate over all Python source files in C{paths}.
93 @param paths: A list of paths. Directories will be recursed into and
94 any .py files found will be yielded. Any non-directories will be
95 yielded as-is.
96 """
97 for path in paths:
98 if os.path.isdir(path):
99 for dirpath, dirnames, filenames in os.walk(path):
100 for filename in filenames:
101 if filename.endswith('.py'):
102 yield os.path.join(dirpath, filename)
103 else:
104 yield path
107 def checkRecursive(paths, reporter):
109 Recursively check all source files in C{paths}.
111 @param paths: A list of paths to Python source files and directories
112 containing Python source files.
113 @param reporter: A L{Reporter} where all of the warnings and errors
114 will be reported to.
115 @return: The number of warnings found.
117 warnings = 0
118 for sourcePath in iterSourceCode(paths):
119 warnings += checkPath(sourcePath, reporter)
120 return warnings
123 def main(prog=None):
124 parser = OptionParser(prog=prog, version=__version__)
125 __, args = parser.parse_args()
126 reporter = modReporter._makeDefaultReporter()
127 if args:
128 warnings = checkRecursive(args, reporter)
129 else:
130 warnings = check(sys.stdin.read(), '<stdin>', reporter)
131 raise SystemExit(warnings > 0)