-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpylint.sh
executable file
·220 lines (175 loc) · 6.27 KB
/
pylint.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#!/usr/bin/env bash
################################################################################
# pylint.sh
#
# Quick TensorFlow Pylint run for use on Macs and other machines that don't
# have the oomph to scan 3500 files with pylint. Based on code from
# tensorflow/tools/ci_build/ci_sanity.sh
#
# Note that, before committing a large change, you should run a full ci-sanity
# check -- see the "bbd" alias in aliases.sh.
#
# Run this script from the root of your TensorFlow source code tree, using the
# Anaconda virtualenv that buildenv.sh creates.
#
# Usage:
# conda activate tfbuild && ~/tf-dev-conf/pylint.sh
################################################################################
# CONSTANTS
# Number of cores on current machine
_N_CORES=`getconf _NPROCESSORS_ONLN`
# Location of this script. May need to be modified if the path has funky stuff
# like symlinks.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PYLINTRC_FILE="${PWD}/tensorflow/tools/ci_build/pylintrc"
PYLINT_BIN="pylint"
################################################################################
# FUNCTIONS
# Magic git command to find the files that your PR will change
get_changed_files() {
git whatchanged --name-only --pretty="" origin..HEAD
# Also list files not yet checked in
git ls-files --modified
}
# Simplified version of the function by the same name in the original script
# Only does incremental listing, and gets everything in the PR
get_py_files_to_check() {
CHANGED_PY_FILES=$(get_changed_files | grep '.*\.py$')
# Do not include files removed in the last non-merge commit.
PY_FILES=""
for PY_FILE in ${CHANGED_PY_FILES}; do
if [[ -f "${PY_FILE}" ]]; then
PY_FILES="${PY_FILES} ${PY_FILE}"
fi
done
echo "${PY_FILES}"
}
die() {
echo $@
exit 1
}
# Greatly simplified version of the function in ci_sanity.sh by the same name
# actually runs outside the CI server.
do_pylint() {
# TODO: Keep this whitelist synchronized with the original script
ERROR_WHITELIST="^tensorflow/python/framework/function_test\.py.*\[E1123.*noinline "\
"^tensorflow/python/platform/default/_gfile\.py.*\[E0301.*non-iterator "\
"^tensorflow/python/platform/default/_googletest\.py.*\[E0102.*function\salready\sdefined "\
"^tensorflow/python/feature_column/feature_column_test\.py.*\[E0110.*abstract-class-instantiated "\
"^tensorflow/contrib/layers/python/layers/feature_column\.py.*\[E0110.*abstract-class-instantiated "\
"^tensorflow/contrib/eager/python/evaluator\.py.*\[E0202.*method-hidden "\
"^tensorflow/contrib/eager/python/metrics_impl\.py.*\[E0202.*method-hidden "\
"^tensorflow/contrib/rate/rate\.py.*\[E0202.*method-hidden "\
"^tensorflow/python/platform/gfile\.py.*\[E0301.*non-iterator "\
"^tensorflow/python/keras/callbacks\.py.*\[E1133.*not-an-iterable "\
"^tensorflow/python/keras/engine/base_layer.py.*\[E0203.*access-member-before-definition "\
"^tensorflow/python/keras/layers/recurrent\.py.*\[E0203.*access-member-before-definition "\
"^tensorflow/python/kernel_tests/constant_op_eager_test.py.*\[E0303.*invalid-length-returned "\
"^tensorflow/python/keras/utils/data_utils.py.*\[E1102.*not-callable"
echo "ERROR_WHITELIST=\"${ERROR_WHITELIST}\""
PYTHON_SRC_FILES=$(get_py_files_to_check)
if [[ -z ${PYTHON_SRC_FILES} ]]; then
echo ""
echo "do_pylint found no Python files to check. Returning."
return 0
fi
if [[ ! -f "${PYLINTRC_FILE}" ]]; then
die "ERROR: Cannot find pylint rc file at ${PYLINTRC_FILE}"
fi
NUM_SRC_FILES=$(echo ${PYTHON_SRC_FILES} | wc -w)
NUM_CPUS=${_N_CORES}
echo "Running pylint on ${NUM_SRC_FILES} files with ${NUM_CPUS} "\
"parallel jobs..."
echo ""
PYLINT_START_TIME=$(date +'%s')
OUTPUT_FILE="$(mktemp)_pylint_output.log"
ERRORS_FILE="$(mktemp)_pylint_errors.log"
NONWL_ERRORS_FILE="$(mktemp)_pylint_nonwl_errors.log"
echo "(Output file is ${OUTPUT_FILE})"
rm -rf ${OUTPUT_FILE}
rm -rf ${ERRORS_FILE}
rm -rf ${NONWL_ERRORS_FILE}
touch ${NONWL_ERRORS_FILE}
${PYLINT_BIN} --rcfile="${PYLINTRC_FILE}" --output-format=parseable \
--jobs=${NUM_CPUS} ${PYTHON_SRC_FILES} > ${OUTPUT_FILE} 2>&1
PYLINT_END_TIME=$(date +'%s')
echo ""
echo "pylint took $((PYLINT_END_TIME - PYLINT_START_TIME)) s"
echo ""
grep -E '(\[E|\[W0311|\[W0312)' ${OUTPUT_FILE} > ${ERRORS_FILE}
N_ERRORS=0
while read -r LINE; do
IS_WHITELISTED=0
for WL_REGEX in ${ERROR_WHITELIST}; do
if echo ${LINE} | grep -q "${WL_REGEX}"; then
echo "Found a whitelisted error:"
echo " ${LINE}"
IS_WHITELISTED=1
fi
done
if [[ ${IS_WHITELISTED} == "0" ]]; then
echo "${LINE}" >> ${NONWL_ERRORS_FILE}
echo "" >> ${NONWL_ERRORS_FILE}
((N_ERRORS++))
fi
done <${ERRORS_FILE}
echo ""
if [[ ${N_ERRORS} != 0 ]]; then
echo "FAIL: Found ${N_ERRORS} non-whitelited pylint errors:"
cat "${NONWL_ERRORS_FILE}"
return 1
else
echo "PASS: No non-whitelisted pylint errors were found."
return 0
fi
}
# Keep the skeleton of the top-level driver program around for its
# pretty-printing of results.
SANITY_STEPS=("do_pylint")
SANITY_STEPS_DESC=("Run pylint on all changed *.py files")
FAIL_COUNTER=0
PASS_COUNTER=0
STEP_EXIT_CODES=()
# Execute all the sanity build steps
COUNTER=0
while [[ ${COUNTER} -lt "${#SANITY_STEPS[@]}" ]]; do
INDEX=COUNTER
((INDEX++))
echo ""
echo "=== Sanity check step ${INDEX} of ${#SANITY_STEPS[@]}: "\
"${SANITY_STEPS[COUNTER]} (${SANITY_STEPS_DESC[COUNTER]}) ==="
echo ""
${SANITY_STEPS[COUNTER]}
RESULT=$?
if [[ ${RESULT} != "0" ]]; then
((FAIL_COUNTER++))
else
((PASS_COUNTER++))
fi
STEP_EXIT_CODES+=(${RESULT})
echo ""
((COUNTER++))
done
# Print summary of build results
COUNTER=0
echo "==== Summary of sanity check results ===="
while [[ ${COUNTER} -lt "${#SANITY_STEPS[@]}" ]]; do
INDEX=COUNTER
((INDEX++))
echo "${INDEX}. ${SANITY_STEPS[COUNTER]}: ${SANITY_STEPS_DESC[COUNTER]}"
if [[ ${STEP_EXIT_CODES[COUNTER]} == "0" ]]; then
printf " ${COLOR_GREEN}PASS${COLOR_NC}\n"
else
printf " ${COLOR_RED}FAIL${COLOR_NC}\n"
fi
((COUNTER++))
done
echo
echo "${FAIL_COUNTER} failed; ${PASS_COUNTER} passed."
echo
if [[ ${FAIL_COUNTER} == "0" ]]; then
printf "Sanity checks ${COLOR_GREEN}PASSED${COLOR_NC}\n"
else
printf "Sanity checks ${COLOR_RED}FAILED${COLOR_NC}\n"
exit 1
fi