Skip to content

Commit 8c3bb7c

Browse files
datapythonistaPingviinituutti
authored andcommitted
CI: Linting with azure instead of travis (pandas-dev#22854)
1 parent 9b22943 commit 8c3bb7c

13 files changed

+245
-101
lines changed

.travis.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ matrix:
5252
- python-gtk2
5353
- dist: trusty
5454
env:
55-
- JOB="3.6, lint, coverage" ENV_FILE="ci/deps/travis-36.yaml" PATTERN="not slow and not network" PANDAS_TESTING_MODE="deprecate" COVERAGE=true LINT=true
55+
- JOB="3.6, coverage" ENV_FILE="ci/deps/travis-36.yaml" PATTERN="not slow and not network" PANDAS_TESTING_MODE="deprecate" COVERAGE=true
5656
- dist: trusty
5757
env:
5858
- JOB="3.7, NumPy dev" ENV_FILE="ci/deps/travis-37-numpydev.yaml" PATTERN="not slow and not network" TEST_ARGS="-W error" PANDAS_TESTING_MODE="deprecate"
@@ -108,7 +108,6 @@ script:
108108
- source activate pandas-dev
109109
- ci/run_build_docs.sh
110110
- ci/run_tests.sh
111-
- ci/code_checks.sh
112111

113112
after_script:
114113
- echo "after_script start"

azure-pipelines.yml

+101
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,104 @@ jobs:
2323
parameters:
2424
name: WindowsPy27
2525
vmImage: vs2017-win2016
26+
27+
- job: 'Checks_and_doc'
28+
pool:
29+
vmImage: ubuntu-16.04
30+
timeoutInMinutes: 90
31+
steps:
32+
- script: |
33+
# XXX next command should avoid redefining the path in every step, but
34+
# made the process crash as it couldn't find deactivate
35+
#echo '##vso[task.prependpath]$HOME/miniconda3/bin'
36+
echo '##vso[task.setvariable variable=CONDA_ENV]pandas-dev'
37+
echo '##vso[task.setvariable variable=ENV_FILE]environment.yml'
38+
echo '##vso[task.setvariable variable=AZURE]true'
39+
displayName: 'Setting environment variables'
40+
41+
# Do not require a conda environment
42+
- script: |
43+
export PATH=$HOME/miniconda3/bin:$PATH
44+
ci/code_checks.sh patterns
45+
displayName: 'Looking for unwanted patterns'
46+
condition: true
47+
48+
- script: |
49+
export PATH=$HOME/miniconda3/bin:$PATH
50+
sudo apt-get install -y libc6-dev-i386
51+
ci/incremental/install_miniconda.sh
52+
ci/incremental/setup_conda_environment.sh
53+
displayName: 'Set up environment'
54+
55+
# Do not require pandas
56+
- script: |
57+
export PATH=$HOME/miniconda3/bin:$PATH
58+
source activate pandas-dev
59+
ci/code_checks.sh lint
60+
displayName: 'Linting'
61+
condition: true
62+
63+
- script: |
64+
export PATH=$HOME/miniconda3/bin:$PATH
65+
source activate pandas-dev
66+
ci/code_checks.sh dependencies
67+
displayName: 'Dependencies consistency'
68+
condition: true
69+
70+
- script: |
71+
export PATH=$HOME/miniconda3/bin:$PATH
72+
source activate pandas-dev
73+
ci/incremental/build.sh
74+
displayName: 'Build'
75+
condition: true
76+
77+
# Require pandas
78+
- script: |
79+
export PATH=$HOME/miniconda3/bin:$PATH
80+
source activate pandas-dev
81+
ci/code_checks.sh code
82+
displayName: 'Checks on imported code'
83+
condition: true
84+
85+
- script: |
86+
export PATH=$HOME/miniconda3/bin:$PATH
87+
source activate pandas-dev
88+
ci/code_checks.sh doctests
89+
displayName: 'Running doctests'
90+
condition: true
91+
92+
- script: |
93+
export PATH=$HOME/miniconda3/bin:$PATH
94+
source activate pandas-dev
95+
ci/code_checks.sh docstrings
96+
displayName: 'Docstring validation'
97+
condition: true
98+
99+
- script: |
100+
export PATH=$HOME/miniconda3/bin:$PATH
101+
source activate pandas-dev
102+
pytest --capture=no --strict scripts
103+
displayName: 'Testing docstring validaton script'
104+
condition: true
105+
106+
- script: |
107+
export PATH=$HOME/miniconda3/bin:$PATH
108+
source activate pandas-dev
109+
git remote add upstream https://github.com/pandas-dev/pandas.git
110+
git fetch upstream
111+
if git diff upstream/master --name-only | grep -q "^asv_bench/"; then
112+
cd asv_bench
113+
asv machine --yes
114+
ASV_OUTPUT="$(asv dev)"
115+
if [[ $(echo "$ASV_OUTPUT" | grep "failed") ]]; then
116+
echo "##vso[task.logissue type=error]Benchmarks run with errors"
117+
echo $ASV_OUTPUT
118+
exit 1
119+
else
120+
echo "Benchmarks run without errors"
121+
fi
122+
else
123+
echo "Benchmarks did not run, no changes detected"
124+
fi
125+
displayName: 'Running benchmarks'
126+
condition: true

ci/code_checks.sh

+62-23
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,48 @@
55
# This script is intended for both the CI and to check locally that code standards are
66
# respected. We are currently linting (PEP-8 and similar), looking for patterns of
77
# 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.
1010
#
1111
# Usage:
1212
# $ ./ci/code_checks.sh # run all checks
1313
# $ ./ci/code_checks.sh lint # run linting only
1414
# $ ./ci/code_checks.sh patterns # check for patterns that should not exist
15+
# $ ./ci/code_checks.sh code # checks on imported code
1516
# $ ./ci/code_checks.sh doctests # run doctests
17+
# $ ./ci/code_checks.sh docstrings # validate docstring errors
1618
# $ ./ci/code_checks.sh dependencies # check that dependencies are consistent
1719

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; }
2222

2323
BASE_DIR="$(dirname $0)/.."
2424
RET=0
2525
CHECK=$1
2626

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
2750

2851
### LINTING ###
2952
if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then
@@ -35,30 +58,30 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then
3558

3659
# pandas/_libs/src is C code, so no need to search there.
3760
MSG='Linting .py code' ; echo $MSG
38-
flake8 .
61+
flake8 --format="$FLAKE8_FORMAT" .
3962
RET=$(($RET + $?)) ; echo $MSG "DONE"
4063

4164
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
4366
RET=$(($RET + $?)) ; echo $MSG "DONE"
4467

4568
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
4770
RET=$(($RET + $?)) ; echo $MSG "DONE"
4871

4972
echo "flake8-rst --version"
5073
flake8-rst --version
5174

5275
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"
5477
RET=$(($RET + $?)) ; echo $MSG "DONE"
5578

5679
# Check that cython casting is of the form `<type>obj` as opposed to `<type> obj`;
5780
# it doesn't make a difference, but we want to be internally consistent.
5881
# Note: this grep pattern is (intended to be) equivalent to the python
5982
# regex r'(?<![ ->])> '
6083
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
6285
RET=$(($RET + $?)) ; echo $MSG "DONE"
6386

6487
# readability/casting: Warnings about C casting instead of C++ casting
@@ -88,43 +111,48 @@ if [[ -z "$CHECK" || "$CHECK" == "patterns" ]]; then
88111

89112
# Check for imports from pandas.core.common instead of `import pandas.core.common as com`
90113
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
92115
RET=$(($RET + $?)) ; echo $MSG "DONE"
93116

94117
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/
96119
RET=$(($RET + $?)) ; echo $MSG "DONE"
97120

98121
# Check for the following code in testing: `np.testing` and `np.array_equal`
99122
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/
101124
RET=$(($RET + $?)) ; echo $MSG "DONE"
102125

103126
# Check for the following code in the extension array base tests: `tm.assert_frame_equal` and `tm.assert_series_equal`
104127
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
106129
RET=$(($RET + $?)) ; echo $MSG "DONE"
107130

108131
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
110133
RET=$(($RET + $?)) ; echo $MSG "DONE"
111134

112135
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
114137
RET=$(($RET + $?)) ; echo $MSG "DONE"
115138

116139
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/
118141
RET=$(($RET + $?)) ; echo $MSG "DONE"
119142

120143
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
122145
RET=$(($RET + $?)) ; echo $MSG "DONE"
123146

124147
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
126149
RET=$(($RET + $?)) ; echo $MSG "DONE"
127150

151+
fi
152+
153+
### CODE ###
154+
if [[ -z "$CHECK" || "$CHECK" == "code" ]]; then
155+
128156
MSG='Check for modules that pandas should not import' ; echo $MSG
129157
python -c "
130158
import sys
@@ -135,7 +163,7 @@ blacklist = {'bs4', 'gcsfs', 'html5lib', 'ipython', 'jinja2' 'hypothesis',
135163
'tables', 'xlrd', 'xlsxwriter', 'xlwt'}
136164
mods = blacklist & set(m.split('.')[0] for m in sys.modules)
137165
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)))
139167
sys.exit(len(mods))
140168
"
141169
RET=$(($RET + $?)) ; echo $MSG "DONE"
@@ -157,7 +185,7 @@ if [[ -z "$CHECK" || "$CHECK" == "doctests" ]]; then
157185

158186
MSG='Doctests generic.py' ; echo $MSG
159187
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"
161189
RET=$(($RET + $?)) ; echo $MSG "DONE"
162190

163191
MSG='Doctests top-level reshaping functions' ; echo $MSG
@@ -178,11 +206,22 @@ if [[ -z "$CHECK" || "$CHECK" == "doctests" ]]; then
178206

179207
fi
180208

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+
181218
### DEPENDENCIES ###
182219
if [[ -z "$CHECK" || "$CHECK" == "dependencies" ]]; then
220+
183221
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
185223
RET=$(($RET + $?)) ; echo $MSG "DONE"
224+
186225
fi
187226

188227
exit $RET

ci/deps/travis-36.yaml

-9
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,9 @@ dependencies:
77
- cython>=0.28.2
88
- dask
99
- fastparquet
10-
- flake8>=3.5
11-
- flake8-comprehensions
12-
- flake8-rst>=0.6.0
1310
- gcsfs
1411
- geopandas
1512
- html5lib
16-
- ipython
17-
- isort
18-
- jinja2
19-
- lxml
2013
- matplotlib
2114
- nomkl
2215
- numexpr
@@ -32,7 +25,6 @@ dependencies:
3225
- s3fs
3326
- scikit-learn
3427
- scipy
35-
- seaborn
3628
- sqlalchemy
3729
- statsmodels
3830
- xarray
@@ -48,6 +40,5 @@ dependencies:
4840
- pip:
4941
- brotlipy
5042
- coverage
51-
- cpplint
5243
- pandas-datareader
5344
- python-dateutil

environment.yml

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dependencies:
1010
- pytz
1111

1212
# development
13+
- asv
1314
- cython>=0.28.2
1415
- flake8
1516
- flake8-comprehensions
@@ -48,3 +49,5 @@ dependencies:
4849
- xlrd
4950
- xlsxwriter
5051
- xlwt
52+
- pip:
53+
- cpplint

pandas/core/frame.py

-4
Original file line numberDiff line numberDiff line change
@@ -1392,10 +1392,6 @@ def to_gbq(self, destination_table, project_id=None, chunksize=None,
13921392
If table exists, drop it, recreate it, and insert data.
13931393
``'append'``
13941394
If table exists, insert data. Create if does not exist.
1395-
private_key : str, optional
1396-
Service account private key in JSON format. Can be file path
1397-
or string contents. This is useful for remote server
1398-
authentication (eg. Jupyter/IPython notebook on remote host).
13991395
auth_local_webserver : bool, default False
14001396
Use the `local webserver flow`_ instead of the `console flow`_
14011397
when getting user credentials.

pandas/core/panel.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,10 @@ class Panel(NDFrame):
125125
axis=1
126126
minor_axis : Index or array-like
127127
axis=2
128-
dtype : dtype, default None
129-
Data type to force, otherwise infer
130128
copy : boolean, default False
131129
Copy data from inputs. Only affects DataFrame / 2d ndarray input
130+
dtype : dtype, default None
131+
Data type to force, otherwise infer
132132
"""
133133

134134
@property

pandas/core/tools/timedeltas.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def to_timedelta(arg, unit='ns', box=True, errors='raise'):
5050
timedelta64 or numpy.array of timedelta64
5151
Output type returned if parsing succeeded.
5252
53-
See also
53+
See Also
5454
--------
5555
DataFrame.astype : Cast argument to a specified dtype.
5656
to_datetime : Convert argument to datetime.

0 commit comments

Comments
 (0)