Skip to content

Commit

Permalink
TST: Add skip_on_exception decorator (#326)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
gfyoung authored and jreback committed May 12, 2017
1 parent 73e3394 commit 4f4cc61
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 133 deletions.
32 changes: 32 additions & 0 deletions pandas_datareader/_testing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Utilities for testing purposes.
"""

from functools import wraps


def skip_on_exception(exp):
"""
Skip a test if a specific Exception is raised. This is because
the Exception is raised for reasons beyond our control (e.g.
flakey 3rd-party API).
Parameters
----------
exp : The Exception under which to execute try-except.
"""

from pytest import skip

def outer_wrapper(f):

@wraps(f)
def wrapper(*args, **kwargs):
try:
f(*args, **kwargs)
except exp as e:
skip(e)

return wrapper

return outer_wrapper
14 changes: 5 additions & 9 deletions pandas_datareader/tests/google/test_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import pandas_datareader.data as web
from pandas_datareader._utils import RemoteDataError
from pandas_datareader._testing import skip_on_exception


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

@skip_on_exception(RemoteDataError)
def test_get_options_data(self):
try:
options = self.goog.get_options_data(
expiry=self.goog.expiry_dates[0])
except RemoteDataError as e: # pragma: no cover
raise pytest.skip(e)
options = self.goog.get_options_data(expiry=self.goog.expiry_dates[0])

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

@skip_on_exception(RemoteDataError)
def test_expiry_dates(self):
try:
dates = self.goog.expiry_dates
except RemoteDataError as e: # pragma: no cover
pytest.skip(e)
dates = self.goog.expiry_dates

assert len(dates) == 2
assert isinstance(dates, list)
Expand Down
82 changes: 36 additions & 46 deletions pandas_datareader/tests/test_edgar.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pandas_datareader.data as web

from pandas_datareader._utils import RemoteDataError
from pandas_datareader._testing import skip_on_exception


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

@skip_on_exception(RemoteDataError)
def test_get_full_index(self):
try:
ed = web.DataReader('full', 'edgar-index')
assert len(ed) > 1000
ed = web.DataReader('full', 'edgar-index')
assert len(ed) > 1000

exp_columns = pd.Index(['cik', 'company_name', 'form_type',
'date_filed', 'filename'], dtype='object')
tm.assert_index_equal(ed.columns, exp_columns)

except RemoteDataError as e:
pytest.skip(e)
exp_columns = pd.Index(['cik', 'company_name', 'form_type',
'date_filed', 'filename'], dtype='object')
tm.assert_index_equal(ed.columns, exp_columns)

@skip_on_exception(RemoteDataError)
def test_get_nonzip_index_and_low_date(self):
try:
ed = web.DataReader('daily', 'edgar-index', '1994-06-30',
'1994-07-02')
assert len(ed) > 200
assert ed.index.nlevels == 2

dti = ed.index.get_level_values(0)
assert isinstance(dti, pd.DatetimeIndex)
exp_columns = pd.Index(['company_name', 'form_type',
'filename'], dtype='object')
tm.assert_index_equal(ed.columns, exp_columns)

except RemoteDataError as e:
pytest.skip(e)

ed = web.DataReader('daily', 'edgar-index', '1994-06-30',
'1994-07-02')
assert len(ed) > 200
assert ed.index.nlevels == 2

dti = ed.index.get_level_values(0)
assert isinstance(dti, pd.DatetimeIndex)
exp_columns = pd.Index(['company_name', 'form_type',
'filename'], dtype='object')
tm.assert_index_equal(ed.columns, exp_columns)

@skip_on_exception(RemoteDataError)
def test_get_gz_index_and_no_date(self):
# TODO: Rewrite, as this test causes Travis to timeout.

try:
ed = web.DataReader('daily', 'edgar-index')
assert len(ed) > 2000
except RemoteDataError as e:
pytest.skip(e)
ed = web.DataReader('daily', 'edgar-index')
assert len(ed) > 2000

@skip_on_exception(RemoteDataError)
def test_6_digit_date(self):
try:
ed = web.DataReader('daily', 'edgar-index', start='1998-05-18',
end='1998-05-18')
assert len(ed) < 1200
assert ed.index.nlevels == 2

dti = ed.index.get_level_values(0)
assert isinstance(dti, pd.DatetimeIndex)
assert dti[0] == pd.Timestamp('1998-05-18')
assert dti[-1] == pd.Timestamp('1998-05-18')

exp_columns = pd.Index(['company_name', 'form_type',
'filename'], dtype='object')
tm.assert_index_equal(ed.columns, exp_columns)

except RemoteDataError as e:
pytest.skip(e)
ed = web.DataReader('daily', 'edgar-index', start='1998-05-18',
end='1998-05-18')
assert len(ed) < 1200
assert ed.index.nlevels == 2

dti = ed.index.get_level_values(0)
assert isinstance(dti, pd.DatetimeIndex)
assert dti[0] == pd.Timestamp('1998-05-18')
assert dti[-1] == pd.Timestamp('1998-05-18')

exp_columns = pd.Index(['company_name', 'form_type',
'filename'], dtype='object')
tm.assert_index_equal(ed.columns, exp_columns)
21 changes: 9 additions & 12 deletions pandas_datareader/tests/test_enigma.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import pandas_datareader as pdr
import pandas_datareader.data as web
from pandas_datareader._testing import skip_on_exception

TEST_API_KEY = os.getenv('ENIGMA_API_KEY')

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

@skip_on_exception(HTTPError)
def test_enigma_datareader(self):
try:
df = web.DataReader('enigma.inspections.restaurants.fl',
'enigma', access_key=TEST_API_KEY)
assert 'serialid' in df.columns
except HTTPError as e: # pragma: no cover
pytest.skip(e)
df = web.DataReader('enigma.inspections.restaurants.fl',
'enigma', access_key=TEST_API_KEY)
assert 'serialid' in df.columns

@skip_on_exception(HTTPError)
def test_enigma_get_data_enigma(self):
try:
df = pdr.get_data_enigma(
'enigma.inspections.restaurants.fl', TEST_API_KEY)
assert 'serialid' in df.columns
except HTTPError as e: # pragma: no cover
pytest.skip(e)
df = pdr.get_data_enigma(
'enigma.inspections.restaurants.fl', TEST_API_KEY)
assert 'serialid' in df.columns

def test_bad_key(self):
with pytest.raises(HTTPError):
Expand Down
6 changes: 6 additions & 0 deletions pandas_datareader/tests/test_eurostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
import pandas.util.testing as tm
import pandas_datareader.data as web

from pandas_datareader._utils import RemoteDataError
from pandas_datareader.compat import assert_raises_regex
from pandas_datareader._testing import skip_on_exception


class TestEurostat(object):

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

@skip_on_exception(RemoteDataError)
def test_get_sts_cobp_a(self):
# Building permits - annual data (2010 = 100)
df = web.DataReader('sts_cobp_a', 'eurostat',
Expand Down Expand Up @@ -64,6 +68,7 @@ def test_get_sts_cobp_a(self):
result = df[expected.name]
tm.assert_series_equal(result, expected)

@skip_on_exception(RemoteDataError)
def test_get_nrg_pc_202(self):
# see gh-149

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

tm.assert_series_equal(df[name], exp)

@skip_on_exception(RemoteDataError)
def test_get_prc_hicp_manr_exceeds_limit(self):
# see gh-149
msg = 'Query size exceeds maximum limit'
Expand Down
9 changes: 3 additions & 6 deletions pandas_datareader/tests/test_nasdaq.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import pytest
import pandas_datareader.data as web

from pandas_datareader._utils import RemoteDataError
from pandas_datareader._testing import skip_on_exception


class TestNasdaqSymbols(object):

@skip_on_exception(RemoteDataError)
def test_get_symbols(self):
try:
symbols = web.DataReader('symbols', 'nasdaq')
except RemoteDataError as e:
pytest.skip(e)

symbols = web.DataReader('symbols', 'nasdaq')
assert 'IBM' in symbols.index
23 changes: 9 additions & 14 deletions pandas_datareader/tests/test_wb.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pandas.util.testing as tm
from pandas_datareader.wb import (search, download, get_countries,
get_indicators, WorldBankReader)
from pandas_datareader._testing import skip_on_exception
from pandas_datareader.compat import assert_raises_regex


Expand Down Expand Up @@ -140,6 +141,7 @@ def test_wdi_download_error_handling(self):
assert isinstance(result, pd.DataFrame)
assert len(result) == 2

@skip_on_exception(ValueError)
def test_wdi_download_w_retired_indicator(self):

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

inds = ['GDPPCKD']

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

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

@skip_on_exception(ValueError)
def test_wdi_download_w_crash_inducing_countrycode(self):

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

try:
result = download(country=cntry_codes, indicator=inds,
start=2003, end=2004, errors='ignore')
except ValueError as e:
pytest.skip("No indicators returned data: {0}".format(e))
result = download(country=cntry_codes, indicator=inds,
start=2003, end=2004, errors='ignore')

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

0 comments on commit 4f4cc61

Please sign in to comment.