Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STY: use pytest.raises context manager (indexes/multi) #25175

Merged
merged 2 commits into from
Feb 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pandas/compat/numpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
_np_version_under1p13 = _nlv < LooseVersion('1.13')
_np_version_under1p14 = _nlv < LooseVersion('1.14')
_np_version_under1p15 = _nlv < LooseVersion('1.15')
_np_version_under1p16 = _nlv < LooseVersion('1.16')


if _nlv < '1.12':
Expand Down Expand Up @@ -64,5 +65,6 @@ def np_array_datetime64_compat(arr, *args, **kwargs):
__all__ = ['np',
'_np_version_under1p13',
'_np_version_under1p14',
'_np_version_under1p15'
'_np_version_under1p15',
'_np_version_under1p16'
]
99 changes: 43 additions & 56 deletions pandas/tests/indexes/multi/test_analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest

from pandas.compat import lrange
from pandas.compat.numpy import _np_version_under1p16

import pandas as pd
from pandas import Index, MultiIndex, date_range, period_range
Expand All @@ -13,8 +14,11 @@
def test_shift(idx):

# GH8083 test the base class for shift
pytest.raises(NotImplementedError, idx.shift, 1)
pytest.raises(NotImplementedError, idx.shift, 1, 2)
msg = "Not supported for type MultiIndex"
with pytest.raises(NotImplementedError, match=msg):
idx.shift(1)
with pytest.raises(NotImplementedError, match=msg):
idx.shift(1, 2)


def test_groupby(idx):
Expand Down Expand Up @@ -50,25 +54,26 @@ def test_truncate():
result = index.truncate(before=1, after=2)
assert len(result.levels[0]) == 2

# after < before
pytest.raises(ValueError, index.truncate, 3, 1)
msg = "after < before"
with pytest.raises(ValueError, match=msg):
index.truncate(3, 1)


def test_where():
i = MultiIndex.from_tuples([('A', 1), ('A', 2)])

with pytest.raises(NotImplementedError):
msg = r"\.where is not supported for MultiIndex operations"
with pytest.raises(NotImplementedError, match=msg):
i.where(True)


def test_where_array_like():
@pytest.mark.parametrize('klass', [list, tuple, np.array, pd.Series])
def test_where_array_like(klass):
i = MultiIndex.from_tuples([('A', 1), ('A', 2)])
klasses = [list, tuple, np.array, pd.Series]
cond = [False, True]

for klass in klasses:
with pytest.raises(NotImplementedError):
i.where(klass(cond))
msg = r"\.where is not supported for MultiIndex operations"
with pytest.raises(NotImplementedError, match=msg):
i.where(klass(cond))


# TODO: reshape
Expand Down Expand Up @@ -141,7 +146,8 @@ def test_take(idx):
# if not isinstance(idx,
# (DatetimeIndex, PeriodIndex, TimedeltaIndex)):
# GH 10791
with pytest.raises(AttributeError):
msg = "'MultiIndex' object has no attribute 'freq'"
with pytest.raises(AttributeError, match=msg):
idx.freq


Expand Down Expand Up @@ -199,7 +205,8 @@ def test_take_fill_value():
with pytest.raises(ValueError, match=msg):
idx.take(np.array([1, 0, -5]), fill_value=True)

with pytest.raises(IndexError):
msg = "index -5 is out of bounds for size 4"
with pytest.raises(IndexError, match=msg):
idx.take(np.array([1, -5]))


Expand All @@ -215,13 +222,15 @@ def test_sub(idx):
first = idx

# - now raises (previously was set op difference)
with pytest.raises(TypeError):
msg = "cannot perform __sub__ with this index type: MultiIndex"
with pytest.raises(TypeError, match=msg):
first - idx[-3:]
with pytest.raises(TypeError):
with pytest.raises(TypeError, match=msg):
idx[-3:] - first
with pytest.raises(TypeError):
with pytest.raises(TypeError, match=msg):
idx[-3:] - first.tolist()
with pytest.raises(TypeError):
msg = "cannot perform __rsub__ with this index type: MultiIndex"
with pytest.raises(TypeError, match=msg):
first.tolist() - idx[-3:]


Expand Down Expand Up @@ -272,50 +281,28 @@ def test_map_dictlike(idx, mapper):
np.arccos, np.arctan, np.sinh, np.cosh, np.tanh,
np.arcsinh, np.arccosh, np.arctanh, np.deg2rad,
np.rad2deg
])
def test_numpy_ufuncs(func):
], ids=lambda func: func.__name__)
def test_numpy_ufuncs(idx, func):
# test ufuncs of numpy. see:
# http://docs.scipy.org/doc/numpy/reference/ufuncs.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this broke some PY2 tests: https://api.travis-ci.org/v3/job/489376151/log.txt (ok to just skip them for now)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on it.

# copy and paste from idx fixture as pytest doesn't support
# parameters and fixtures at the same time.
major_axis = Index(['foo', 'bar', 'baz', 'qux'])
minor_axis = Index(['one', 'two'])
major_codes = np.array([0, 0, 1, 2, 3, 3])
minor_codes = np.array([0, 1, 0, 1, 0, 1])
index_names = ['first', 'second']

idx = MultiIndex(
levels=[major_axis, minor_axis],
codes=[major_codes, minor_codes],
names=index_names,
verify_integrity=False
)

with pytest.raises(Exception):
with np.errstate(all='ignore'):
func(idx)
if _np_version_under1p16:
expected_exception = AttributeError
msg = "'tuple' object has no attribute '{}'".format(func.__name__)
else:
expected_exception = TypeError
msg = ("loop of ufunc does not support argument 0 of type tuple which"
" has no callable {} method").format(func.__name__)
with pytest.raises(expected_exception, match=msg):
func(idx)


@pytest.mark.parametrize('func', [
np.isfinite, np.isinf, np.isnan, np.signbit
])
def test_numpy_type_funcs(func):
# for func in [np.isfinite, np.isinf, np.isnan, np.signbit]:
# copy and paste from idx fixture as pytest doesn't support
# parameters and fixtures at the same time.
major_axis = Index(['foo', 'bar', 'baz', 'qux'])
minor_axis = Index(['one', 'two'])
major_codes = np.array([0, 0, 1, 2, 3, 3])
minor_codes = np.array([0, 1, 0, 1, 0, 1])
index_names = ['first', 'second']

idx = MultiIndex(
levels=[major_axis, minor_axis],
codes=[major_codes, minor_codes],
names=index_names,
verify_integrity=False
)

with pytest.raises(Exception):
], ids=lambda func: func.__name__)
def test_numpy_type_funcs(idx, func):
msg = ("ufunc '{}' not supported for the input types, and the inputs"
" could not be safely coerced to any supported types according to"
" the casting rule ''safe''").format(func.__name__)
with pytest.raises(TypeError, match=msg):
func(idx)
6 changes: 2 additions & 4 deletions pandas/tests/indexes/multi/test_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,6 @@ def test_compat(indices):

def test_pickle_compat_construction(holder):
# this is testing for pickle compat
if holder is None:
return

# need an object to create with
pytest.raises(TypeError, holder)
with pytest.raises(TypeError, match="Must pass both levels and codes"):
holder()
67 changes: 32 additions & 35 deletions pandas/tests/indexes/multi/test_constructor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-

from collections import OrderedDict
import re

import numpy as np
import pytest
Expand Down Expand Up @@ -30,10 +29,10 @@ def test_constructor_no_levels():
with pytest.raises(ValueError, match=msg):
MultiIndex(levels=[], codes=[])

both_re = re.compile('Must pass both levels and codes')
with pytest.raises(TypeError, match=both_re):
msg = "Must pass both levels and codes"
with pytest.raises(TypeError, match=msg):
MultiIndex(levels=[])
with pytest.raises(TypeError, match=both_re):
with pytest.raises(TypeError, match=msg):
MultiIndex(codes=[])


Expand All @@ -42,20 +41,20 @@ def test_constructor_nonhashable_names():
levels = [[1, 2], [u'one', u'two']]
codes = [[0, 0, 1, 1], [0, 1, 0, 1]]
names = (['foo'], ['bar'])
message = "MultiIndex.name must be a hashable type"
with pytest.raises(TypeError, match=message):
msg = r"MultiIndex\.name must be a hashable type"
with pytest.raises(TypeError, match=msg):
MultiIndex(levels=levels, codes=codes, names=names)

# With .rename()
mi = MultiIndex(levels=[[1, 2], [u'one', u'two']],
codes=[[0, 0, 1, 1], [0, 1, 0, 1]],
names=('foo', 'bar'))
renamed = [['foor'], ['barr']]
with pytest.raises(TypeError, match=message):
with pytest.raises(TypeError, match=msg):
mi.rename(names=renamed)

# With .set_names()
with pytest.raises(TypeError, match=message):
with pytest.raises(TypeError, match=msg):
mi.set_names(names=renamed)


Expand All @@ -67,8 +66,9 @@ def test_constructor_mismatched_codes_levels(idx):
with pytest.raises(ValueError, match=msg):
MultiIndex(levels=levels, codes=codes)

length_error = re.compile('>= length of level')
label_error = re.compile(r'Unequal code lengths: \[4, 2\]')
length_error = (r"On level 0, code max \(3\) >= length of level \(1\)\."
" NOTE: this index is in an inconsistent state")
label_error = r"Unequal code lengths: \[4, 2\]"

# important to check that it's looking at the right thing.
with pytest.raises(ValueError, match=length_error):
Expand Down Expand Up @@ -253,21 +253,14 @@ def test_from_arrays_empty():
tm.assert_index_equal(result, expected)


@pytest.mark.parametrize('invalid_array', [
(1),
([1]),
([1, 2]),
([[1], 2]),
('a'),
(['a']),
(['a', 'b']),
([['a'], 'b']),
])
def test_from_arrays_invalid_input(invalid_array):
invalid_inputs = [1, [1], [1, 2], [[1], 2],
'a', ['a'], ['a', 'b'], [['a'], 'b']]
for i in invalid_inputs:
pytest.raises(TypeError, MultiIndex.from_arrays, arrays=i)
@pytest.mark.parametrize('invalid_sequence_of_arrays', [
1, [1], [1, 2], [[1], 2], 'a', ['a'], ['a', 'b'], [['a'], 'b']])
def test_from_arrays_invalid_input(invalid_sequence_of_arrays):
msg = (r"Input must be a list / sequence of array-likes|"
r"Input must be list-like|"
r"object of type 'int' has no len\(\)")
with pytest.raises(TypeError, match=msg):
MultiIndex.from_arrays(arrays=invalid_sequence_of_arrays)


@pytest.mark.parametrize('idx1, idx2', [
Expand Down Expand Up @@ -332,9 +325,10 @@ def test_tuples_with_name_string():
# GH 15110 and GH 14848

li = [(0, 0, 1), (0, 1, 0), (1, 0, 0)]
with pytest.raises(ValueError):
msg = "Names should be list-like for a MultiIndex"
with pytest.raises(ValueError, match=msg):
pd.Index(li, name='abc')
with pytest.raises(ValueError):
with pytest.raises(ValueError, match=msg):
pd.Index(li, name='a')


Expand Down Expand Up @@ -398,7 +392,10 @@ def test_from_product_empty_three_levels(N):
[['a'], 'b'],
])
def test_from_product_invalid_input(invalid_input):
pytest.raises(TypeError, MultiIndex.from_product, iterables=invalid_input)
msg = (r"Input must be a list / sequence of iterables|"
"Input must be list-like")
with pytest.raises(TypeError, match=msg):
MultiIndex.from_product(iterables=invalid_input)


def test_from_product_datetimeindex():
Expand Down Expand Up @@ -563,15 +560,15 @@ def test_from_frame_valid_names(names_in, names_out):
assert mi.names == names_out


@pytest.mark.parametrize('names_in,names_out', [
('bad_input', ValueError("Names should be list-like for a MultiIndex")),
(['a', 'b', 'c'], ValueError("Length of names must match number of "
"levels in MultiIndex."))
@pytest.mark.parametrize('names,expected_error_msg', [
('bad_input', "Names should be list-like for a MultiIndex"),
(['a', 'b', 'c'],
"Length of names must match number of levels in MultiIndex")
])
def test_from_frame_invalid_names(names_in, names_out):
def test_from_frame_invalid_names(names, expected_error_msg):
# GH 22420
df = pd.DataFrame([['a', 'a'], ['a', 'b'], ['b', 'a'], ['b', 'b']],
columns=pd.MultiIndex.from_tuples([('L1', 'x'),
('L2', 'y')]))
with pytest.raises(type(names_out), match=names_out.args[0]):
pd.MultiIndex.from_frame(df, names=names_in)
with pytest.raises(ValueError, match=expected_error_msg):
pd.MultiIndex.from_frame(df, names=names)
23 changes: 16 additions & 7 deletions pandas/tests/indexes/multi/test_contains.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,24 @@ def test_isin_level_kwarg():
tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=1))
tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=-1))

pytest.raises(IndexError, idx.isin, vals_0, level=5)
pytest.raises(IndexError, idx.isin, vals_0, level=-5)

pytest.raises(KeyError, idx.isin, vals_0, level=1.0)
pytest.raises(KeyError, idx.isin, vals_1, level=-1.0)
pytest.raises(KeyError, idx.isin, vals_1, level='A')
msg = "Too many levels: Index has only 2 levels, not 6"
with pytest.raises(IndexError, match=msg):
idx.isin(vals_0, level=5)
msg = ("Too many levels: Index has only 2 levels, -5 is not a valid level"
" number")
with pytest.raises(IndexError, match=msg):
idx.isin(vals_0, level=-5)

with pytest.raises(KeyError, match=r"'Level 1\.0 not found'"):
idx.isin(vals_0, level=1.0)
with pytest.raises(KeyError, match=r"'Level -1\.0 not found'"):
idx.isin(vals_1, level=-1.0)
with pytest.raises(KeyError, match="'Level A not found'"):
idx.isin(vals_1, level='A')

idx.names = ['A', 'B']
tm.assert_numpy_array_equal(expected, idx.isin(vals_0, level='A'))
tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level='B'))

pytest.raises(KeyError, idx.isin, vals_1, level='C')
with pytest.raises(KeyError, match="'Level C not found'"):
idx.isin(vals_1, level='C')
Loading