1 | #!/usr/bin/env python2
|
2 | from __future__ import print_function
|
3 | """Our wrapper around pyflakes 2.4.0.
|
4 |
|
5 | Newer versions dropped support for Python 2.
|
6 |
|
7 | All versions: https://pypi.org/simple/pyflakes/
|
8 |
|
9 | Change log: https://github.com/PyCQA/pyflakes/blob/main/NEWS.rst
|
10 | """
|
11 |
|
12 | import argparse
|
13 | import sys
|
14 |
|
15 | from pyflakes import api
|
16 | from pyflakes import reporter
|
17 |
|
18 | from display import ansi
|
19 |
|
20 | # Our config for flake8
|
21 | # local fatal_errors='E901,E999,F821,F822,F823,F401'
|
22 |
|
23 | # From flake8/src/flake8/plugins/pyflakes.py
|
24 | # "RaiseNotImplemented": "F901",
|
25 | # "UndefinedName": "F821",
|
26 | # "UndefinedLocal": "F823",
|
27 | # "UnusedImport": "F401",
|
28 |
|
29 | FATAL_CLASS_NAMES = [
|
30 | "RaiseNotImplemented",
|
31 | "UndefinedName",
|
32 | "UndefinedLocal",
|
33 | "UnusedImport",
|
34 | ]
|
35 |
|
36 | # Other useful ones
|
37 | # "RedefinedWhileUnused": "F811",
|
38 |
|
39 |
|
40 | class OilsReporter(reporter.Reporter):
|
41 |
|
42 | def __init__(self):
|
43 | # Warnings and errors both go to stdout
|
44 | reporter.Reporter.__init__(self, sys.stdout, sys.stdout)
|
45 | self.num_fatal_errors = 0
|
46 |
|
47 | def flake(self, message):
|
48 | """Pyflakes found something wrong with the code.
|
49 |
|
50 | @param: A L{pyflakes.messages.Message}.
|
51 | """
|
52 | type_name = type(message).__name__
|
53 |
|
54 | # Suppress some errors for now to reducenoise
|
55 | if type_name == 'UnusedVariable':
|
56 | if message.filename.endswith('_test.py'):
|
57 | return
|
58 |
|
59 | var_name = message.message_args[0]
|
60 | if var_name == 'e':
|
61 | return
|
62 | if var_name.startswith('unused'):
|
63 | return
|
64 |
|
65 | if type_name in FATAL_CLASS_NAMES:
|
66 | self.num_fatal_errors += 1
|
67 | color = self._stdout.isatty()
|
68 | else:
|
69 | color = False
|
70 |
|
71 | if color:
|
72 | self._stdout.write(ansi.RED + ansi.BOLD)
|
73 | self._stdout.write(str(message))
|
74 | self._stdout.write(ansi.RESET)
|
75 | else:
|
76 | self._stdout.write(str(message))
|
77 |
|
78 | self._stdout.write('\n')
|
79 |
|
80 |
|
81 | def main(args):
|
82 | parser = argparse.ArgumentParser(
|
83 | prog=None, description='Check Python source files for errors')
|
84 | #parser.add_argument('-V', '--version', action='version', version=_get_version())
|
85 | parser.add_argument(
|
86 | 'path',
|
87 | nargs='*',
|
88 | help='Path(s) of Python file(s) to check. STDIN if not given.')
|
89 | paths = parser.parse_args(args).path
|
90 |
|
91 | rep = OilsReporter()
|
92 |
|
93 | api.checkRecursive(paths, rep)
|
94 | return 0 if rep.num_fatal_errors == 0 else 1
|
95 |
|
96 |
|
97 | if __name__ == '__main__':
|
98 | try:
|
99 | sys.exit(main(sys.argv[1:]))
|
100 | except KeyboardInterrupt as e:
|
101 | print('%s: interrupted with Ctrl-C' % sys.argv[0], file=sys.stderr)
|
102 | sys.exit(1)
|
103 | except RuntimeError as e:
|
104 | print('FATAL: %s' % e, file=sys.stderr)
|
105 | sys.exit(1)
|