Skip to content

Commit 4f4cc61

Browse files
gfyoungjreback
authored andcommitted
TST: Add skip_on_exception decorator (#326)
We have tests that might fail for reasons beyond our control. This decorator catches those exceptions and skips those tests when such an error is raised.
1 parent 73e3394 commit 4f4cc61

File tree

8 files changed

+123
-133
lines changed

8 files changed

+123
-133
lines changed

pandas_datareader/_testing.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Utilities for testing purposes.
3+
"""
4+
5+
from functools import wraps
6+
7+
8+
def skip_on_exception(exp):
9+
"""
10+
Skip a test if a specific Exception is raised. This is because
11+
the Exception is raised for reasons beyond our control (e.g.
12+
flakey 3rd-party API).
13+
14+
Parameters
15+
----------
16+
exp : The Exception under which to execute try-except.
17+
"""
18+
19+
from pytest import skip
20+
21+
def outer_wrapper(f):
22+
23+
@wraps(f)
24+
def wrapper(*args, **kwargs):
25+
try:
26+
f(*args, **kwargs)
27+
except exp as e:
28+
skip(e)
29+
30+
return wrapper
31+
32+
return outer_wrapper

pandas_datareader/tests/google/test_options.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import pandas_datareader.data as web
1010
from pandas_datareader._utils import RemoteDataError
11+
from pandas_datareader._testing import skip_on_exception
1112

1213

1314
class TestGoogleOptions(object):
@@ -17,12 +18,9 @@ def setup_class(cls):
1718
# GOOG has monthlies
1819
cls.goog = web.Options('GOOG', 'google')
1920

21+
@skip_on_exception(RemoteDataError)
2022
def test_get_options_data(self):
21-
try:
22-
options = self.goog.get_options_data(
23-
expiry=self.goog.expiry_dates[0])
24-
except RemoteDataError as e: # pragma: no cover
25-
raise pytest.skip(e)
23+
options = self.goog.get_options_data(expiry=self.goog.expiry_dates[0])
2624

2725
assert isinstance(options, pd.DataFrame)
2826
assert len(options) > 10
@@ -48,11 +46,9 @@ def test_get_options_data_yearmonth(self):
4846
with pytest.raises(NotImplementedError):
4947
self.goog.get_options_data(month=1, year=2016)
5048

49+
@skip_on_exception(RemoteDataError)
5150
def test_expiry_dates(self):
52-
try:
53-
dates = self.goog.expiry_dates
54-
except RemoteDataError as e: # pragma: no cover
55-
pytest.skip(e)
51+
dates = self.goog.expiry_dates
5652

5753
assert len(dates) == 2
5854
assert isinstance(dates, list)

pandas_datareader/tests/test_edgar.py

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import pandas_datareader.data as web
66

77
from pandas_datareader._utils import RemoteDataError
8+
from pandas_datareader._testing import skip_on_exception
89

910

1011
class TestEdgarIndex(object):
@@ -15,58 +16,47 @@ def setup_class(cls):
1516
# Disabling tests until re-write.
1617
pytest.skip("Disabling tests until re-write.")
1718

19+
@skip_on_exception(RemoteDataError)
1820
def test_get_full_index(self):
19-
try:
20-
ed = web.DataReader('full', 'edgar-index')
21-
assert len(ed) > 1000
21+
ed = web.DataReader('full', 'edgar-index')
22+
assert len(ed) > 1000
2223

23-
exp_columns = pd.Index(['cik', 'company_name', 'form_type',
24-
'date_filed', 'filename'], dtype='object')
25-
tm.assert_index_equal(ed.columns, exp_columns)
26-
27-
except RemoteDataError as e:
28-
pytest.skip(e)
24+
exp_columns = pd.Index(['cik', 'company_name', 'form_type',
25+
'date_filed', 'filename'], dtype='object')
26+
tm.assert_index_equal(ed.columns, exp_columns)
2927

28+
@skip_on_exception(RemoteDataError)
3029
def test_get_nonzip_index_and_low_date(self):
31-
try:
32-
ed = web.DataReader('daily', 'edgar-index', '1994-06-30',
33-
'1994-07-02')
34-
assert len(ed) > 200
35-
assert ed.index.nlevels == 2
36-
37-
dti = ed.index.get_level_values(0)
38-
assert isinstance(dti, pd.DatetimeIndex)
39-
exp_columns = pd.Index(['company_name', 'form_type',
40-
'filename'], dtype='object')
41-
tm.assert_index_equal(ed.columns, exp_columns)
42-
43-
except RemoteDataError as e:
44-
pytest.skip(e)
45-
30+
ed = web.DataReader('daily', 'edgar-index', '1994-06-30',
31+
'1994-07-02')
32+
assert len(ed) > 200
33+
assert ed.index.nlevels == 2
34+
35+
dti = ed.index.get_level_values(0)
36+
assert isinstance(dti, pd.DatetimeIndex)
37+
exp_columns = pd.Index(['company_name', 'form_type',
38+
'filename'], dtype='object')
39+
tm.assert_index_equal(ed.columns, exp_columns)
40+
41+
@skip_on_exception(RemoteDataError)
4642
def test_get_gz_index_and_no_date(self):
4743
# TODO: Rewrite, as this test causes Travis to timeout.
4844

49-
try:
50-
ed = web.DataReader('daily', 'edgar-index')
51-
assert len(ed) > 2000
52-
except RemoteDataError as e:
53-
pytest.skip(e)
45+
ed = web.DataReader('daily', 'edgar-index')
46+
assert len(ed) > 2000
5447

48+
@skip_on_exception(RemoteDataError)
5549
def test_6_digit_date(self):
56-
try:
57-
ed = web.DataReader('daily', 'edgar-index', start='1998-05-18',
58-
end='1998-05-18')
59-
assert len(ed) < 1200
60-
assert ed.index.nlevels == 2
61-
62-
dti = ed.index.get_level_values(0)
63-
assert isinstance(dti, pd.DatetimeIndex)
64-
assert dti[0] == pd.Timestamp('1998-05-18')
65-
assert dti[-1] == pd.Timestamp('1998-05-18')
66-
67-
exp_columns = pd.Index(['company_name', 'form_type',
68-
'filename'], dtype='object')
69-
tm.assert_index_equal(ed.columns, exp_columns)
70-
71-
except RemoteDataError as e:
72-
pytest.skip(e)
50+
ed = web.DataReader('daily', 'edgar-index', start='1998-05-18',
51+
end='1998-05-18')
52+
assert len(ed) < 1200
53+
assert ed.index.nlevels == 2
54+
55+
dti = ed.index.get_level_values(0)
56+
assert isinstance(dti, pd.DatetimeIndex)
57+
assert dti[0] == pd.Timestamp('1998-05-18')
58+
assert dti[-1] == pd.Timestamp('1998-05-18')
59+
60+
exp_columns = pd.Index(['company_name', 'form_type',
61+
'filename'], dtype='object')
62+
tm.assert_index_equal(ed.columns, exp_columns)

pandas_datareader/tests/test_enigma.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pandas_datareader as pdr
77
import pandas_datareader.data as web
8+
from pandas_datareader._testing import skip_on_exception
89

910
TEST_API_KEY = os.getenv('ENIGMA_API_KEY')
1011

@@ -15,21 +16,17 @@ class TestEnigma(object):
1516
def setup_class(cls):
1617
pytest.importorskip("lxml")
1718

19+
@skip_on_exception(HTTPError)
1820
def test_enigma_datareader(self):
19-
try:
20-
df = web.DataReader('enigma.inspections.restaurants.fl',
21-
'enigma', access_key=TEST_API_KEY)
22-
assert 'serialid' in df.columns
23-
except HTTPError as e: # pragma: no cover
24-
pytest.skip(e)
21+
df = web.DataReader('enigma.inspections.restaurants.fl',
22+
'enigma', access_key=TEST_API_KEY)
23+
assert 'serialid' in df.columns
2524

25+
@skip_on_exception(HTTPError)
2626
def test_enigma_get_data_enigma(self):
27-
try:
28-
df = pdr.get_data_enigma(
29-
'enigma.inspections.restaurants.fl', TEST_API_KEY)
30-
assert 'serialid' in df.columns
31-
except HTTPError as e: # pragma: no cover
32-
pytest.skip(e)
27+
df = pdr.get_data_enigma(
28+
'enigma.inspections.restaurants.fl', TEST_API_KEY)
29+
assert 'serialid' in df.columns
3330

3431
def test_bad_key(self):
3532
with pytest.raises(HTTPError):

pandas_datareader/tests/test_eurostat.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
import pandas.util.testing as tm
44
import pandas_datareader.data as web
55

6+
from pandas_datareader._utils import RemoteDataError
67
from pandas_datareader.compat import assert_raises_regex
8+
from pandas_datareader._testing import skip_on_exception
79

810

911
class TestEurostat(object):
1012

13+
@skip_on_exception(RemoteDataError)
1114
def test_get_cdh_e_fos(self):
1215
# Employed doctorate holders in non managerial and non professional
1316
# occupations by fields of science (%)
@@ -32,6 +35,7 @@ def test_get_cdh_e_fos(self):
3235
expected = pd.DataFrame(values, index=exp_idx, columns=exp_col)
3336
tm.assert_frame_equal(df, expected)
3437

38+
@skip_on_exception(RemoteDataError)
3539
def test_get_sts_cobp_a(self):
3640
# Building permits - annual data (2010 = 100)
3741
df = web.DataReader('sts_cobp_a', 'eurostat',
@@ -64,6 +68,7 @@ def test_get_sts_cobp_a(self):
6468
result = df[expected.name]
6569
tm.assert_series_equal(result, expected)
6670

71+
@skip_on_exception(RemoteDataError)
6772
def test_get_nrg_pc_202(self):
6873
# see gh-149
6974

@@ -86,6 +91,7 @@ def test_get_nrg_pc_202(self):
8691

8792
tm.assert_series_equal(df[name], exp)
8893

94+
@skip_on_exception(RemoteDataError)
8995
def test_get_prc_hicp_manr_exceeds_limit(self):
9096
# see gh-149
9197
msg = 'Query size exceeds maximum limit'
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
import pytest
21
import pandas_datareader.data as web
32

43
from pandas_datareader._utils import RemoteDataError
4+
from pandas_datareader._testing import skip_on_exception
55

66

77
class TestNasdaqSymbols(object):
88

9+
@skip_on_exception(RemoteDataError)
910
def test_get_symbols(self):
10-
try:
11-
symbols = web.DataReader('symbols', 'nasdaq')
12-
except RemoteDataError as e:
13-
pytest.skip(e)
14-
11+
symbols = web.DataReader('symbols', 'nasdaq')
1512
assert 'IBM' in symbols.index

pandas_datareader/tests/test_wb.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import pandas.util.testing as tm
99
from pandas_datareader.wb import (search, download, get_countries,
1010
get_indicators, WorldBankReader)
11+
from pandas_datareader._testing import skip_on_exception
1112
from pandas_datareader.compat import assert_raises_regex
1213

1314

@@ -140,6 +141,7 @@ def test_wdi_download_error_handling(self):
140141
assert isinstance(result, pd.DataFrame)
141142
assert len(result) == 2
142143

144+
@skip_on_exception(ValueError)
143145
def test_wdi_download_w_retired_indicator(self):
144146

145147
cntry_codes = ['CA', 'MX', 'US']
@@ -156,32 +158,25 @@ def test_wdi_download_w_retired_indicator(self):
156158

157159
inds = ['GDPPCKD']
158160

159-
try:
160-
result = download(country=cntry_codes, indicator=inds,
161-
start=2003, end=2004, errors='ignore')
162-
# If for some reason result actually ever has data, it's cause WB
163-
# fixed the issue with this ticker. Find another bad one.
164-
except ValueError as e:
165-
pytest.skip("No indicators returned data: {0}".format(e))
161+
result = download(country=cntry_codes, indicator=inds,
162+
start=2003, end=2004, errors='ignore')
166163

167-
# if it ever gets here, it means WB unretired the indicator.
164+
# If it ever gets here, it means WB unretired the indicator.
168165
# even if they dropped it completely, it would still get caught above
169166
# or the WB API changed somehow in a really unexpected way.
170167
if len(result) > 0: # pragma: no cover
171168
pytest.skip("Invalid results")
172169

170+
@skip_on_exception(ValueError)
173171
def test_wdi_download_w_crash_inducing_countrycode(self):
174172

175173
cntry_codes = ['CA', 'MX', 'US', 'XXX']
176174
inds = ['NY.GDP.PCAP.CD']
177175

178-
try:
179-
result = download(country=cntry_codes, indicator=inds,
180-
start=2003, end=2004, errors='ignore')
181-
except ValueError as e:
182-
pytest.skip("No indicators returned data: {0}".format(e))
176+
result = download(country=cntry_codes, indicator=inds,
177+
start=2003, end=2004, errors='ignore')
183178

184-
# if it ever gets here, it means the country code XXX got used by WB
179+
# If it ever gets here, it means the country code XXX got used by WB
185180
# or the WB API changed somehow in a really unexpected way.
186181
if len(result) > 0: # pragma: no cover
187182
pytest.skip("Invalid results")

0 commit comments

Comments
 (0)