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