5
5
# This script is intended for both the CI and to check locally that code standards are
6
6
# respected. We are currently linting (PEP-8 and similar), looking for patterns of
7
7
# common mistakes (sphinx directives with missing blank lines, old style classes,
8
- # unwanted imports...), and we also run doctests here (currently some files only).
9
- # In the future we may want to add the validation of docstrings and other checks here .
8
+ # unwanted imports...), we run doctests here (currently some files only), and we
9
+ # validate formatting error in docstrings.
10
10
#
11
11
# Usage:
12
12
# $ ./ci/code_checks.sh # run all checks
13
13
# $ ./ci/code_checks.sh lint # run linting only
14
14
# $ ./ci/code_checks.sh patterns # check for patterns that should not exist
15
+ # $ ./ci/code_checks.sh code # checks on imported code
15
16
# $ ./ci/code_checks.sh doctests # run doctests
17
+ # $ ./ci/code_checks.sh docstrings # validate docstring errors
16
18
# $ ./ci/code_checks.sh dependencies # check that dependencies are consistent
17
19
18
- echo " inside $0 "
19
- [[ $LINT ]] || { echo " NOT Linting. To lint use: LINT=true $0 $1 " ; exit 0; }
20
- [[ -z " $1 " || " $1 " == " lint" || " $1 " == " patterns" || " $1 " == " doctests" || " $1 " == " dependencies" ]] \
21
- || { echo " Unknown command $1 . Usage: $0 [lint|patterns|doctests|dependencies]" ; exit 9999; }
20
+ [[ -z " $1 " || " $1 " == " lint" || " $1 " == " patterns" || " $1 " == " code" || " $1 " == " doctests" || " $1 " == " docstrings" || " $1 " == " dependencies" ]] || \
21
+ { echo " Unknown command $1 . Usage: $0 [lint|patterns|code|doctests|docstrings|dependencies]" ; exit 9999; }
22
22
23
23
BASE_DIR=" $( dirname $0 ) /.."
24
24
RET=0
25
25
CHECK=$1
26
26
27
+ function invgrep {
28
+ # grep with inverse exist status and formatting for azure-pipelines
29
+ #
30
+ # This function works exactly as grep, but with opposite exit status:
31
+ # - 0 (success) when no patterns are found
32
+ # - 1 (fail) when the patterns are found
33
+ #
34
+ # This is useful for the CI, as we want to fail if one of the patterns
35
+ # that we want to avoid is found by grep.
36
+ if [[ " $AZURE " == " true" ]]; then
37
+ set -o pipefail
38
+ grep -n " $@ " | awk -F " :" ' {print "##vso[task.logissue type=error;sourcepath=" $1 ";linenumber=" $2 ";] Found unwanted pattern: " $3}'
39
+ else
40
+ grep " $@ "
41
+ fi
42
+ return $(( ! $? ))
43
+ }
44
+
45
+ if [[ " $AZURE " == " true" ]]; then
46
+ FLAKE8_FORMAT=" ##vso[task.logissue type=error;sourcepath=%(path)s;linenumber=%(row)s;columnnumber=%(col)s;code=%(code)s;]%(text)s"
47
+ else
48
+ FLAKE8_FORMAT=" default"
49
+ fi
27
50
28
51
# ## LINTING ###
29
52
if [[ -z " $CHECK " || " $CHECK " == " lint" ]]; then
@@ -35,30 +58,30 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then
35
58
36
59
# pandas/_libs/src is C code, so no need to search there.
37
60
MSG=' Linting .py code' ; echo $MSG
38
- flake8 .
61
+ flake8 --format= " $FLAKE8_FORMAT " .
39
62
RET=$(( $RET + $? )) ; echo $MSG " DONE"
40
63
41
64
MSG=' Linting .pyx code' ; echo $MSG
42
- flake8 pandas --filename=* .pyx --select=E501,E302,E203,E111,E114,E221,E303,E128,E231,E126,E265,E305,E301,E127,E261,E271,E129,W291,E222,E241,E123,F403,C400,C401,C402,C403,C404,C405,C406,C407,C408,C409,C410,C411
65
+ flake8 --format= " $FLAKE8_FORMAT " pandas --filename=* .pyx --select=E501,E302,E203,E111,E114,E221,E303,E128,E231,E126,E265,E305,E301,E127,E261,E271,E129,W291,E222,E241,E123,F403,C400,C401,C402,C403,C404,C405,C406,C407,C408,C409,C410,C411
43
66
RET=$(( $RET + $? )) ; echo $MSG " DONE"
44
67
45
68
MSG=' Linting .pxd and .pxi.in' ; echo $MSG
46
- flake8 pandas/_libs --filename=* .pxi.in,* .pxd --select=E501,E302,E203,E111,E114,E221,E303,E231,E126,F403
69
+ flake8 --format= " $FLAKE8_FORMAT " pandas/_libs --filename=* .pxi.in,* .pxd --select=E501,E302,E203,E111,E114,E221,E303,E231,E126,F403
47
70
RET=$(( $RET + $? )) ; echo $MSG " DONE"
48
71
49
72
echo " flake8-rst --version"
50
73
flake8-rst --version
51
74
52
75
MSG=' Linting code-blocks in .rst documentation' ; echo $MSG
53
- flake8-rst doc/source --filename=* .rst
76
+ flake8-rst doc/source --filename=* .rst --format= " $FLAKE8_FORMAT "
54
77
RET=$(( $RET + $? )) ; echo $MSG " DONE"
55
78
56
79
# Check that cython casting is of the form `<type>obj` as opposed to `<type> obj`;
57
80
# it doesn't make a difference, but we want to be internally consistent.
58
81
# Note: this grep pattern is (intended to be) equivalent to the python
59
82
# regex r'(?<![ ->])> '
60
83
MSG=' Linting .pyx code for spacing conventions in casting' ; echo $MSG
61
- ! grep -r -E --include ' *.pyx' --include ' *.pxi.in' ' [a-zA-Z0-9*]> ' pandas/_libs
84
+ invgrep -r -E --include ' *.pyx' --include ' *.pxi.in' ' [a-zA-Z0-9*]> ' pandas/_libs
62
85
RET=$(( $RET + $? )) ; echo $MSG " DONE"
63
86
64
87
# readability/casting: Warnings about C casting instead of C++ casting
@@ -88,43 +111,48 @@ if [[ -z "$CHECK" || "$CHECK" == "patterns" ]]; then
88
111
89
112
# Check for imports from pandas.core.common instead of `import pandas.core.common as com`
90
113
MSG=' Check for non-standard imports' ; echo $MSG
91
- ! grep -R --include=" *.py*" -E " from pandas.core.common import " pandas
114
+ invgrep -R --include=" *.py*" -E " from pandas.core.common import " pandas
92
115
RET=$(( $RET + $? )) ; echo $MSG " DONE"
93
116
94
117
MSG=' Check for pytest warns' ; echo $MSG
95
- ! grep -r -E --include ' *.py' ' pytest\.warns' pandas/tests/
118
+ invgrep -r -E --include ' *.py' ' pytest\.warns' pandas/tests/
96
119
RET=$(( $RET + $? )) ; echo $MSG " DONE"
97
120
98
121
# Check for the following code in testing: `np.testing` and `np.array_equal`
99
122
MSG=' Check for invalid testing' ; echo $MSG
100
- ! grep -r -E --include ' *.py' --exclude testing.py ' (numpy|np)(\.testing|\.array_equal)' pandas/tests/
123
+ invgrep -r -E --include ' *.py' --exclude testing.py ' (numpy|np)(\.testing|\.array_equal)' pandas/tests/
101
124
RET=$(( $RET + $? )) ; echo $MSG " DONE"
102
125
103
126
# Check for the following code in the extension array base tests: `tm.assert_frame_equal` and `tm.assert_series_equal`
104
127
MSG=' Check for invalid EA testing' ; echo $MSG
105
- ! grep -r -E --include ' *.py' --exclude base.py ' tm.assert_(series|frame)_equal' pandas/tests/extension/base
128
+ invgrep -r -E --include ' *.py' --exclude base.py ' tm.assert_(series|frame)_equal' pandas/tests/extension/base
106
129
RET=$(( $RET + $? )) ; echo $MSG " DONE"
107
130
108
131
MSG=' Check for deprecated messages without sphinx directive' ; echo $MSG
109
- ! grep -R --include=" *.py" --include=" *.pyx" -E " (DEPRECATED|DEPRECATE|Deprecated)(:|,|\.)" pandas
132
+ invgrep -R --include=" *.py" --include=" *.pyx" -E " (DEPRECATED|DEPRECATE|Deprecated)(:|,|\.)" pandas
110
133
RET=$(( $RET + $? )) ; echo $MSG " DONE"
111
134
112
135
MSG=' Check for old-style classes' ; echo $MSG
113
- ! grep -R --include=" *.py" -E " class\s\S*[^)]:" pandas scripts
136
+ invgrep -R --include=" *.py" -E " class\s\S*[^)]:" pandas scripts
114
137
RET=$(( $RET + $? )) ; echo $MSG " DONE"
115
138
116
139
MSG=' Check for backticks incorrectly rendering because of missing spaces' ; echo $MSG
117
- ! grep -R --include=" *.rst" -E " [a-zA-Z0-9]\`\` ?[a-zA-Z0-9]" doc/source/
140
+ invgrep -R --include=" *.rst" -E " [a-zA-Z0-9]\`\` ?[a-zA-Z0-9]" doc/source/
118
141
RET=$(( $RET + $? )) ; echo $MSG " DONE"
119
142
120
143
MSG=' Check for incorrect sphinx directives' ; echo $MSG
121
- ! grep -R --include=" *.py" --include=" *.pyx" --include=" *.rst" -E " \.\. (autosummary|contents|currentmodule|deprecated|function|image|important|include|ipython|literalinclude|math|module|note|raw|seealso|toctree|versionadded|versionchanged|warning):[^:]" ./pandas ./doc/source
144
+ invgrep -R --include=" *.py" --include=" *.pyx" --include=" *.rst" -E " \.\. (autosummary|contents|currentmodule|deprecated|function|image|important|include|ipython|literalinclude|math|module|note|raw|seealso|toctree|versionadded|versionchanged|warning):[^:]" ./pandas ./doc/source
122
145
RET=$(( $RET + $? )) ; echo $MSG " DONE"
123
146
124
147
MSG=' Check that the deprecated `assert_raises_regex` is not used (`pytest.raises(match=pattern)` should be used instead)' ; echo $MSG
125
- ! grep -R --exclude=* .pyc --exclude=testing.py --exclude=test_testing.py assert_raises_regex pandas
148
+ invgrep -R --exclude=* .pyc --exclude=testing.py --exclude=test_testing.py assert_raises_regex pandas
126
149
RET=$(( $RET + $? )) ; echo $MSG " DONE"
127
150
151
+ fi
152
+
153
+ # ## CODE ###
154
+ if [[ -z " $CHECK " || " $CHECK " == " code" ]]; then
155
+
128
156
MSG=' Check for modules that pandas should not import' ; echo $MSG
129
157
python -c "
130
158
import sys
@@ -135,7 +163,7 @@ blacklist = {'bs4', 'gcsfs', 'html5lib', 'ipython', 'jinja2' 'hypothesis',
135
163
'tables', 'xlrd', 'xlsxwriter', 'xlwt'}
136
164
mods = blacklist & set(m.split('.')[0] for m in sys.modules)
137
165
if mods:
138
- sys.stderr.write('pandas should not import: {}\n'.format(', '.join(mods)))
166
+ sys.stderr.write('err: pandas should not import: {}\n'.format(', '.join(mods)))
139
167
sys.exit(len(mods))
140
168
"
141
169
RET=$(( $RET + $? )) ; echo $MSG " DONE"
@@ -157,7 +185,7 @@ if [[ -z "$CHECK" || "$CHECK" == "doctests" ]]; then
157
185
158
186
MSG=' Doctests generic.py' ; echo $MSG
159
187
pytest -q --doctest-modules pandas/core/generic.py \
160
- -k" -_set_axis_name -_xs -describe -droplevel -groupby -interpolate -pct_change -pipe -reindex -reindex_axis -to_json -transpose -values -xs"
188
+ -k" -_set_axis_name -_xs -describe -droplevel -groupby -interpolate -pct_change -pipe -reindex -reindex_axis -to_json -transpose -values -xs -to_clipboard "
161
189
RET=$(( $RET + $? )) ; echo $MSG " DONE"
162
190
163
191
MSG=' Doctests top-level reshaping functions' ; echo $MSG
@@ -178,11 +206,22 @@ if [[ -z "$CHECK" || "$CHECK" == "doctests" ]]; then
178
206
179
207
fi
180
208
209
+ # ## DOCSTRINGS ###
210
+ if [[ -z " $CHECK " || " $CHECK " == " docstrings" ]]; then
211
+
212
+ MSG=' Validate docstrings (GL06, SS04, PR03, PR05, EX04)' ; echo $MSG
213
+ $BASE_DIR /scripts/validate_docstrings.py --format=azure --errors=GL06,SS04,PR03,PR05,EX04
214
+ RET=$(( $RET + $? )) ; echo $MSG " DONE"
215
+
216
+ fi
217
+
181
218
# ## DEPENDENCIES ###
182
219
if [[ -z " $CHECK " || " $CHECK " == " dependencies" ]]; then
220
+
183
221
MSG=' Check that requirements-dev.txt has been generated from environment.yml' ; echo $MSG
184
- $BASE_DIR /scripts/generate_pip_deps_from_conda.py --compare
222
+ $BASE_DIR /scripts/generate_pip_deps_from_conda.py --compare --azure
185
223
RET=$(( $RET + $? )) ; echo $MSG " DONE"
224
+
186
225
fi
187
226
188
227
exit $RET
0 commit comments