Skip to content

Commit a4efb67

Browse files
simonjayhawkinsPingviinituutti
authored andcommitted
STY: use pytest.raises context manager (indexes/multi) (pandas-dev#25175)
1 parent 5458e22 commit a4efb67

File tree

9 files changed

+167
-142
lines changed

9 files changed

+167
-142
lines changed

pandas/compat/numpy/__init__.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
_np_version_under1p13 = _nlv < LooseVersion('1.13')
1313
_np_version_under1p14 = _nlv < LooseVersion('1.14')
1414
_np_version_under1p15 = _nlv < LooseVersion('1.15')
15+
_np_version_under1p16 = _nlv < LooseVersion('1.16')
1516

1617

1718
if _nlv < '1.12':
@@ -64,5 +65,6 @@ def np_array_datetime64_compat(arr, *args, **kwargs):
6465
__all__ = ['np',
6566
'_np_version_under1p13',
6667
'_np_version_under1p14',
67-
'_np_version_under1p15'
68+
'_np_version_under1p15',
69+
'_np_version_under1p16'
6870
]

pandas/tests/indexes/multi/test_analytics.py

+43-56
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pytest
55

66
from pandas.compat import lrange
7+
from pandas.compat.numpy import _np_version_under1p16
78

89
import pandas as pd
910
from pandas import Index, MultiIndex, date_range, period_range
@@ -13,8 +14,11 @@
1314
def test_shift(idx):
1415

1516
# GH8083 test the base class for shift
16-
pytest.raises(NotImplementedError, idx.shift, 1)
17-
pytest.raises(NotImplementedError, idx.shift, 1, 2)
17+
msg = "Not supported for type MultiIndex"
18+
with pytest.raises(NotImplementedError, match=msg):
19+
idx.shift(1)
20+
with pytest.raises(NotImplementedError, match=msg):
21+
idx.shift(1, 2)
1822

1923

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

53-
# after < before
54-
pytest.raises(ValueError, index.truncate, 3, 1)
57+
msg = "after < before"
58+
with pytest.raises(ValueError, match=msg):
59+
index.truncate(3, 1)
5560

5661

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

60-
with pytest.raises(NotImplementedError):
65+
msg = r"\.where is not supported for MultiIndex operations"
66+
with pytest.raises(NotImplementedError, match=msg):
6167
i.where(True)
6268

6369

64-
def test_where_array_like():
70+
@pytest.mark.parametrize('klass', [list, tuple, np.array, pd.Series])
71+
def test_where_array_like(klass):
6572
i = MultiIndex.from_tuples([('A', 1), ('A', 2)])
66-
klasses = [list, tuple, np.array, pd.Series]
6773
cond = [False, True]
68-
69-
for klass in klasses:
70-
with pytest.raises(NotImplementedError):
71-
i.where(klass(cond))
74+
msg = r"\.where is not supported for MultiIndex operations"
75+
with pytest.raises(NotImplementedError, match=msg):
76+
i.where(klass(cond))
7277

7378

7479
# TODO: reshape
@@ -141,7 +146,8 @@ def test_take(idx):
141146
# if not isinstance(idx,
142147
# (DatetimeIndex, PeriodIndex, TimedeltaIndex)):
143148
# GH 10791
144-
with pytest.raises(AttributeError):
149+
msg = "'MultiIndex' object has no attribute 'freq'"
150+
with pytest.raises(AttributeError, match=msg):
145151
idx.freq
146152

147153

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

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

205212

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

217224
# - now raises (previously was set op difference)
218-
with pytest.raises(TypeError):
225+
msg = "cannot perform __sub__ with this index type: MultiIndex"
226+
with pytest.raises(TypeError, match=msg):
219227
first - idx[-3:]
220-
with pytest.raises(TypeError):
228+
with pytest.raises(TypeError, match=msg):
221229
idx[-3:] - first
222-
with pytest.raises(TypeError):
230+
with pytest.raises(TypeError, match=msg):
223231
idx[-3:] - first.tolist()
224-
with pytest.raises(TypeError):
232+
msg = "cannot perform __rsub__ with this index type: MultiIndex"
233+
with pytest.raises(TypeError, match=msg):
225234
first.tolist() - idx[-3:]
226235

227236

@@ -272,50 +281,28 @@ def test_map_dictlike(idx, mapper):
272281
np.arccos, np.arctan, np.sinh, np.cosh, np.tanh,
273282
np.arcsinh, np.arccosh, np.arctanh, np.deg2rad,
274283
np.rad2deg
275-
])
276-
def test_numpy_ufuncs(func):
284+
], ids=lambda func: func.__name__)
285+
def test_numpy_ufuncs(idx, func):
277286
# test ufuncs of numpy. see:
278287
# http://docs.scipy.org/doc/numpy/reference/ufuncs.html
279288

280-
# copy and paste from idx fixture as pytest doesn't support
281-
# parameters and fixtures at the same time.
282-
major_axis = Index(['foo', 'bar', 'baz', 'qux'])
283-
minor_axis = Index(['one', 'two'])
284-
major_codes = np.array([0, 0, 1, 2, 3, 3])
285-
minor_codes = np.array([0, 1, 0, 1, 0, 1])
286-
index_names = ['first', 'second']
287-
288-
idx = MultiIndex(
289-
levels=[major_axis, minor_axis],
290-
codes=[major_codes, minor_codes],
291-
names=index_names,
292-
verify_integrity=False
293-
)
294-
295-
with pytest.raises(Exception):
296-
with np.errstate(all='ignore'):
297-
func(idx)
289+
if _np_version_under1p16:
290+
expected_exception = AttributeError
291+
msg = "'tuple' object has no attribute '{}'".format(func.__name__)
292+
else:
293+
expected_exception = TypeError
294+
msg = ("loop of ufunc does not support argument 0 of type tuple which"
295+
" has no callable {} method").format(func.__name__)
296+
with pytest.raises(expected_exception, match=msg):
297+
func(idx)
298298

299299

300300
@pytest.mark.parametrize('func', [
301301
np.isfinite, np.isinf, np.isnan, np.signbit
302-
])
303-
def test_numpy_type_funcs(func):
304-
# for func in [np.isfinite, np.isinf, np.isnan, np.signbit]:
305-
# copy and paste from idx fixture as pytest doesn't support
306-
# parameters and fixtures at the same time.
307-
major_axis = Index(['foo', 'bar', 'baz', 'qux'])
308-
minor_axis = Index(['one', 'two'])
309-
major_codes = np.array([0, 0, 1, 2, 3, 3])
310-
minor_codes = np.array([0, 1, 0, 1, 0, 1])
311-
index_names = ['first', 'second']
312-
313-
idx = MultiIndex(
314-
levels=[major_axis, minor_axis],
315-
codes=[major_codes, minor_codes],
316-
names=index_names,
317-
verify_integrity=False
318-
)
319-
320-
with pytest.raises(Exception):
302+
], ids=lambda func: func.__name__)
303+
def test_numpy_type_funcs(idx, func):
304+
msg = ("ufunc '{}' not supported for the input types, and the inputs"
305+
" could not be safely coerced to any supported types according to"
306+
" the casting rule ''safe''").format(func.__name__)
307+
with pytest.raises(TypeError, match=msg):
321308
func(idx)

pandas/tests/indexes/multi/test_compat.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,6 @@ def test_compat(indices):
124124

125125
def test_pickle_compat_construction(holder):
126126
# this is testing for pickle compat
127-
if holder is None:
128-
return
129-
130127
# need an object to create with
131-
pytest.raises(TypeError, holder)
128+
with pytest.raises(TypeError, match="Must pass both levels and codes"):
129+
holder()

pandas/tests/indexes/multi/test_constructor.py

+32-35
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# -*- coding: utf-8 -*-
22

33
from collections import OrderedDict
4-
import re
54

65
import numpy as np
76
import pytest
@@ -30,10 +29,10 @@ def test_constructor_no_levels():
3029
with pytest.raises(ValueError, match=msg):
3130
MultiIndex(levels=[], codes=[])
3231

33-
both_re = re.compile('Must pass both levels and codes')
34-
with pytest.raises(TypeError, match=both_re):
32+
msg = "Must pass both levels and codes"
33+
with pytest.raises(TypeError, match=msg):
3534
MultiIndex(levels=[])
36-
with pytest.raises(TypeError, match=both_re):
35+
with pytest.raises(TypeError, match=msg):
3736
MultiIndex(codes=[])
3837

3938

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

4948
# With .rename()
5049
mi = MultiIndex(levels=[[1, 2], [u'one', u'two']],
5150
codes=[[0, 0, 1, 1], [0, 1, 0, 1]],
5251
names=('foo', 'bar'))
5352
renamed = [['foor'], ['barr']]
54-
with pytest.raises(TypeError, match=message):
53+
with pytest.raises(TypeError, match=msg):
5554
mi.rename(names=renamed)
5655

5756
# With .set_names()
58-
with pytest.raises(TypeError, match=message):
57+
with pytest.raises(TypeError, match=msg):
5958
mi.set_names(names=renamed)
6059

6160

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

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

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

255255

256-
@pytest.mark.parametrize('invalid_array', [
257-
(1),
258-
([1]),
259-
([1, 2]),
260-
([[1], 2]),
261-
('a'),
262-
(['a']),
263-
(['a', 'b']),
264-
([['a'], 'b']),
265-
])
266-
def test_from_arrays_invalid_input(invalid_array):
267-
invalid_inputs = [1, [1], [1, 2], [[1], 2],
268-
'a', ['a'], ['a', 'b'], [['a'], 'b']]
269-
for i in invalid_inputs:
270-
pytest.raises(TypeError, MultiIndex.from_arrays, arrays=i)
256+
@pytest.mark.parametrize('invalid_sequence_of_arrays', [
257+
1, [1], [1, 2], [[1], 2], 'a', ['a'], ['a', 'b'], [['a'], 'b']])
258+
def test_from_arrays_invalid_input(invalid_sequence_of_arrays):
259+
msg = (r"Input must be a list / sequence of array-likes|"
260+
r"Input must be list-like|"
261+
r"object of type 'int' has no len\(\)")
262+
with pytest.raises(TypeError, match=msg):
263+
MultiIndex.from_arrays(arrays=invalid_sequence_of_arrays)
271264

272265

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

334327
li = [(0, 0, 1), (0, 1, 0), (1, 0, 0)]
335-
with pytest.raises(ValueError):
328+
msg = "Names should be list-like for a MultiIndex"
329+
with pytest.raises(ValueError, match=msg):
336330
pd.Index(li, name='abc')
337-
with pytest.raises(ValueError):
331+
with pytest.raises(ValueError, match=msg):
338332
pd.Index(li, name='a')
339333

340334

@@ -398,7 +392,10 @@ def test_from_product_empty_three_levels(N):
398392
[['a'], 'b'],
399393
])
400394
def test_from_product_invalid_input(invalid_input):
401-
pytest.raises(TypeError, MultiIndex.from_product, iterables=invalid_input)
395+
msg = (r"Input must be a list / sequence of iterables|"
396+
"Input must be list-like")
397+
with pytest.raises(TypeError, match=msg):
398+
MultiIndex.from_product(iterables=invalid_input)
402399

403400

404401
def test_from_product_datetimeindex():
@@ -563,15 +560,15 @@ def test_from_frame_valid_names(names_in, names_out):
563560
assert mi.names == names_out
564561

565562

566-
@pytest.mark.parametrize('names_in,names_out', [
567-
('bad_input', ValueError("Names should be list-like for a MultiIndex")),
568-
(['a', 'b', 'c'], ValueError("Length of names must match number of "
569-
"levels in MultiIndex."))
563+
@pytest.mark.parametrize('names,expected_error_msg', [
564+
('bad_input', "Names should be list-like for a MultiIndex"),
565+
(['a', 'b', 'c'],
566+
"Length of names must match number of levels in MultiIndex")
570567
])
571-
def test_from_frame_invalid_names(names_in, names_out):
568+
def test_from_frame_invalid_names(names, expected_error_msg):
572569
# GH 22420
573570
df = pd.DataFrame([['a', 'a'], ['a', 'b'], ['b', 'a'], ['b', 'b']],
574571
columns=pd.MultiIndex.from_tuples([('L1', 'x'),
575572
('L2', 'y')]))
576-
with pytest.raises(type(names_out), match=names_out.args[0]):
577-
pd.MultiIndex.from_frame(df, names=names_in)
573+
with pytest.raises(ValueError, match=expected_error_msg):
574+
pd.MultiIndex.from_frame(df, names=names)

pandas/tests/indexes/multi/test_contains.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,24 @@ def test_isin_level_kwarg():
8383
tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=1))
8484
tm.assert_numpy_array_equal(expected, idx.isin(vals_1, level=-1))
8585

86-
pytest.raises(IndexError, idx.isin, vals_0, level=5)
87-
pytest.raises(IndexError, idx.isin, vals_0, level=-5)
88-
89-
pytest.raises(KeyError, idx.isin, vals_0, level=1.0)
90-
pytest.raises(KeyError, idx.isin, vals_1, level=-1.0)
91-
pytest.raises(KeyError, idx.isin, vals_1, level='A')
86+
msg = "Too many levels: Index has only 2 levels, not 6"
87+
with pytest.raises(IndexError, match=msg):
88+
idx.isin(vals_0, level=5)
89+
msg = ("Too many levels: Index has only 2 levels, -5 is not a valid level"
90+
" number")
91+
with pytest.raises(IndexError, match=msg):
92+
idx.isin(vals_0, level=-5)
93+
94+
with pytest.raises(KeyError, match=r"'Level 1\.0 not found'"):
95+
idx.isin(vals_0, level=1.0)
96+
with pytest.raises(KeyError, match=r"'Level -1\.0 not found'"):
97+
idx.isin(vals_1, level=-1.0)
98+
with pytest.raises(KeyError, match="'Level A not found'"):
99+
idx.isin(vals_1, level='A')
92100

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

97-
pytest.raises(KeyError, idx.isin, vals_1, level='C')
105+
with pytest.raises(KeyError, match="'Level C not found'"):
106+
idx.isin(vals_1, level='C')

0 commit comments

Comments
 (0)