~launchpad-pqm/launchpad/devel

10637.3.1 by Guilherme Salgado
Use the default python version instead of a hard-coded version
1
#!/usr/bin/python
8687.15.4 by Karl Fogel
Add the copyright header block to more files; tweak format in a few files.
2
#
3
# Copyright 2009 Canonical Ltd.  This software is licensed under the
4
# GNU Affero General Public License version 3 (see the file LICENSE).
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
5
6
"""Run pyflakes checks on a set of files."""
7
8
import compiler
9
import os
10
import sys
11
import traceback
12
2914.3.2 by Dafydd Harries
refactor check_file/check_files
13
import pyflakes
14
2914.3.4 by Dafydd Harries
respond to Andrew's review
15
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
16
class Flakiness:
17
    COMPILE_FAILED = 0
18
    FLAKY = 1
19
    GOOD = 2
20
2914.3.4 by Dafydd Harries
respond to Andrew's review
21
2914.3.2 by Dafydd Harries
refactor check_file/check_files
22
class PyflakesResult:
23
    def __init__(self, filename, flakiness, messages):
24
        self.filename = filename
25
        self.flakiness = flakiness
26
        self.messages = messages
27
2914.3.3 by Dafydd Harries
refactor flaky.py some more
28
    def make_report(self):
2914.3.4 by Dafydd Harries
respond to Andrew's review
29
        """Generate a text report for the result.
30
31
        Yields a line of text for each line of the report.
32
        """
33
2914.3.3 by Dafydd Harries
refactor flaky.py some more
34
        if self.flakiness == Flakiness.GOOD:
35
            return
36
37
        if self.flakiness == Flakiness.COMPILE_FAILED:
38
            yield '%s: Failed to compile:' % self.filename
39
40
            for message in self.messages:
41
                yield '    ' + str(message)
42
        elif self.flakiness == Flakiness.FLAKY:
43
            yield '%s:' % self.filename
44
45
            for message in self.messages:
46
                yield '    line ' + str(message)[len(self.filename)+1:]
47
48
        yield ''
49
2914.3.4 by Dafydd Harries
respond to Andrew's review
50
2914.3.3 by Dafydd Harries
refactor flaky.py some more
51
class PyflakesStatistics:
2914.3.4 by Dafydd Harries
respond to Andrew's review
52
    """Counts of pyflakes messages over multiple Python files."""
53
2914.3.3 by Dafydd Harries
refactor flaky.py some more
54
    message_classes = {
55
        pyflakes.messages.UndefinedName: 'messages_undefined_name',
56
        pyflakes.messages.UnusedImport: 'messages_unused_import',
57
        pyflakes.messages.ImportStarUsed: 'messages_import_star',
58
        pyflakes.messages.RedefinedWhileUnused: 'messages_redefined_unused',
59
        }
60
61
    def __init__(self):
62
        self.files_total = 0
63
        self.files_compile_failed = 0
64
        self.files_flaky = 0
65
        self.files_good = 0
66
        self.messages_total = 0
67
        self.messages_undefined_name = 0
68
        self.messages_unused_import = 0
69
        self.messages_import_star = 0
70
        self.messages_redefined_unused = 0
71
72
    def add_result(self, result):
73
        self.files_total += 1
74
75
        if result.flakiness == Flakiness.GOOD:
76
            self.files_good += 1
77
        elif result.flakiness == Flakiness.COMPILE_FAILED:
78
            self.files_compile_failed += 1
79
        elif result.flakiness == Flakiness.FLAKY:
80
            self.files_flaky += 1
81
            statistic = None
82
83
            for message in result.messages:
84
                self.messages_total += 1
2914.3.4 by Dafydd Harries
respond to Andrew's review
85
86
                # Increment the appropriate self.messages_* count.
2914.3.3 by Dafydd Harries
refactor flaky.py some more
87
                attr = PyflakesStatistics.message_classes[message.__class__]
88
                statistic = getattr(self, attr)
89
                setattr(self, attr, statistic + 1)
90
91
    def make_summary(self):
92
        return [
93
            'Files checked: %d' % self.files_total,
94
            'Files that failed to compile: %d' %
95
                self.files_compile_failed,
96
            'Good files: %d' % self.files_good,
97
            'Flaky files: %d' % self.files_flaky,
98
            ' - Undefined name: %d' % self.messages_undefined_name,
99
            ' - Unused imports: %d' % self.messages_unused_import,
100
            ' - * imported: %d' % self.messages_import_star,
101
            ' - Unused name redefined: %d' % self.messages_redefined_unused,
102
            ' - Problems total: %d' % self.messages_total,
103
            ]
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
104
2914.3.4 by Dafydd Harries
respond to Andrew's review
105
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
106
def find_python_files(top_path):
107
    for dirpath, dirnames, filenames in os.walk(top_path):
108
        for filename in filenames:
109
            if filename.endswith('.py'):
110
                yield os.path.join(dirpath, filename)
111
2914.3.4 by Dafydd Harries
respond to Andrew's review
112
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
113
def check_file(filename):
2914.3.2 by Dafydd Harries
refactor check_file/check_files
114
    """Return a list of pyflakes messages for a Python file."""
115
2914.3.4 by Dafydd Harries
respond to Andrew's review
116
    source = open(filename).read()
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
117
118
    try:
2914.3.4 by Dafydd Harries
respond to Andrew's review
119
        tree = compiler.parse(source)
120
    except (SyntaxError, IndentationError):
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
121
        tb_info = traceback.format_exception(*sys.exc_info())
2914.3.2 by Dafydd Harries
refactor check_file/check_files
122
        messages = [message[:-1] for message in tb_info]
123
        return PyflakesResult(filename, Flakiness.COMPILE_FAILED, messages)
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
124
    else:
125
        checker = pyflakes.Checker(tree, filename)
126
        messages = sorted(checker.messages, key=lambda message: message.lineno)
127
2914.3.2 by Dafydd Harries
refactor check_file/check_files
128
        if messages:
129
            return PyflakesResult(filename, Flakiness.FLAKY, messages)
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
130
        else:
2914.3.2 by Dafydd Harries
refactor check_file/check_files
131
            return PyflakesResult(filename, Flakiness.GOOD, messages)
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
132
2914.3.4 by Dafydd Harries
respond to Andrew's review
133
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
134
def main(argv):
135
    if len(argv) < 2:
136
        print >>sys.stderr, 'Usage: %s path...' % argv[0]
137
        return 1
138
139
    files = []
140
141
    for path in argv[1:]:
142
        if os.path.isdir(path):
143
            files.extend(find_python_files(argv[1]))
144
        else:
145
            files.append(path)
146
147
    sys.stderr.write('Running pyflakes checks\n')
148
    results = []
149
2914.3.2 by Dafydd Harries
refactor check_file/check_files
150
    for filename in files:
2914.3.3 by Dafydd Harries
refactor flaky.py some more
151
        results.append(check_file(filename))
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
152
        sys.stderr.write('.')
153
        sys.stderr.flush()
154
155
    sys.stderr.write('\nDone\n\n')
2914.3.3 by Dafydd Harries
refactor flaky.py some more
156
157
    for result in results:
158
        for line in result.make_report():
159
            print line
160
161
    statistics = PyflakesStatistics()
162
163
    for result in results:
164
        statistics.add_result(result)
165
166
    for line in statistics.make_summary():
167
        print line
168
169
    if statistics.files_compile_failed + statistics.files_flaky > 0:
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
170
        return 1
171
    else:
172
        return 0
173
2914.3.4 by Dafydd Harries
respond to Andrew's review
174
2914.3.1 by Dafydd Harries
Add pyflakes scripts.
175
if __name__ == '__main__':
176
    sys.exit(main(sys.argv))
177