Skip to content

Commit 07dd9e9

Browse files
author
Leonardo
authored
Merge pull request #11834 from ethereum/improve-pylint-all
Improve `pylint_all.sh`
2 parents a39eb7a + 7ad45a2 commit 07dd9e9

File tree

2 files changed

+79
-33
lines changed

2 files changed

+79
-33
lines changed

scripts/pylint_all.py

Lines changed: 78 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,102 @@
11
#! /usr/bin/env python3
22

33
"""
4-
Performs pylint on all python files in the project repo's {test,script,docs} directory recursively.
5-
6-
This script is meant to be run from the CI but can also be easily in local dev environment,
7-
where you can optionally pass `-d` as command line argument to let this script abort on first error.
4+
Runs pylint on all Python files in project directories known to contain Python scripts.
85
"""
96

10-
from os import path, walk, system
11-
from sys import argv, exit as exitwith
7+
from argparse import ArgumentParser
8+
from os import path, walk
9+
from sys import exit
10+
from textwrap import dedent
11+
import subprocess
12+
import sys
1213

13-
PROJECT_ROOT = path.dirname(path.realpath(__file__))
14-
PYLINT_RCFILE = "{}/pylintrc".format(PROJECT_ROOT)
14+
PROJECT_ROOT = path.dirname(path.dirname(path.realpath(__file__)))
15+
PYLINT_RCFILE = f"{PROJECT_ROOT}/scripts/pylintrc"
1516

1617
SGR_INFO = "\033[1;32m"
1718
SGR_CLEAR = "\033[0m"
1819

1920
def pylint_all_filenames(dev_mode, rootdirs):
2021
""" Performs pylint on all python files within given root directory (recursively). """
22+
23+
BARE_COMMAND = [
24+
"pylint",
25+
f"--rcfile={PYLINT_RCFILE}",
26+
"--output-format=colorized",
27+
"--score=n"
28+
]
29+
2130
filenames = []
2231
for rootdir in rootdirs:
2332
for rootpath, _, filenames_w in walk(rootdir):
2433
for filename in filenames_w:
2534
if filename.endswith('.py'):
2635
filenames.append(path.join(rootpath, filename))
2736

28-
checked_count = 0
29-
failed = []
30-
for filename in filenames:
31-
checked_count += 1
32-
cmdline = "pylint --rcfile=\"{}\" \"{}\"".format(PYLINT_RCFILE, filename)
33-
print("{}[{}/{}] Running pylint on file: {}{}".format(SGR_INFO, checked_count, len(filenames),
34-
filename, SGR_CLEAR))
35-
exit_code = system(cmdline)
36-
if exit_code != 0:
37-
if dev_mode:
38-
return 1, checked_count
39-
failed.append(filename)
40-
41-
return len(failed), len(filenames)
37+
if not dev_mode:
38+
# NOTE: We could just give pylint the directories and it would find the files on its
39+
# own but it would treat them as packages, which would result in lots of import errors.
40+
command_line = BARE_COMMAND + filenames
41+
return subprocess.run(command_line, check=False).returncode == 0
42+
43+
for i, filename in enumerate(filenames):
44+
command_line = BARE_COMMAND + [filename]
45+
print(
46+
f"{SGR_INFO}"
47+
f"[{i + 1}/{len(filenames)}] "
48+
f"Running pylint on file: {filename}{SGR_CLEAR}"
49+
)
50+
51+
process = subprocess.run(command_line, check=False)
52+
53+
if process.returncode != 0:
54+
return False
55+
56+
print()
57+
return True
58+
59+
60+
def parse_command_line():
61+
script_description = dedent("""
62+
Runs pylint on all Python files in project directories known to contain Python scripts.
63+
64+
This script is meant to be run from the CI but can also be easily used in the local dev
65+
environment.
66+
""")
67+
68+
parser = ArgumentParser(description=script_description)
69+
parser.add_argument(
70+
'-d', '--dev-mode',
71+
dest='dev_mode',
72+
default=False,
73+
action='store_true',
74+
help=(
75+
"Abort on first error. "
76+
"In this mode every script is passed to pylint separately. "
77+
)
78+
)
79+
return parser.parse_args()
80+
4281

4382
def main():
44-
""" Collects all python script root dirs and runs pylint on them. You can optionally
45-
pass `-d` as command line argument to let this script abort on first error. """
46-
dev_mode = len(argv) == 2 and argv[1] == "-d"
47-
failed_count, total_count = pylint_all_filenames(dev_mode, [
48-
path.abspath(path.dirname(__file__) + "/../docs"),
49-
path.abspath(path.dirname(__file__) + "/../scripts"),
50-
path.abspath(path.dirname(__file__) + "/../test")])
51-
if failed_count != 0:
52-
exitwith("pylint failed on {}/{} files.".format(failed_count, total_count))
83+
options = parse_command_line()
84+
85+
rootdirs = [
86+
f"{PROJECT_ROOT}/docs",
87+
f"{PROJECT_ROOT}/scripts",
88+
f"{PROJECT_ROOT}/test",
89+
]
90+
success = pylint_all_filenames(options.dev_mode, rootdirs)
91+
92+
if not success:
93+
exit(1)
5394
else:
54-
print("Successfully tested {} files.".format(total_count))
95+
print("No problems found.")
96+
5597

5698
if __name__ == "__main__":
57-
main()
99+
try:
100+
main()
101+
except KeyboardInterrupt:
102+
exit("Interrupted by user. Exiting.")

scripts/pylintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ disable=
2121
bad-indentation,
2222
bad-whitespace,
2323
consider-using-sys-exit,
24+
duplicate-code,
2425
invalid-name,
2526
missing-docstring,
2627
mixed-indentation,

0 commit comments

Comments
 (0)