Skip to content

Commit 2a56823

Browse files
STY: use pytest.raises context manager (indexes/multi)
1 parent e3b0950 commit 2a56823

File tree

8 files changed

+153
-139
lines changed

8 files changed

+153
-139
lines changed

pandas/tests/indexes/multi/test_analytics.py

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
def test_shift(idx):
1414

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

1922

2023
def test_groupby(idx):
@@ -50,25 +53,26 @@ def test_truncate():
5053
result = index.truncate(before=1, after=2)
5154
assert len(result.levels[0]) == 2
5255

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

5660

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

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

6368

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

7377

7478
# TODO: reshape
@@ -141,7 +145,8 @@ def test_take(idx):
141145
# if not isinstance(idx,
142146
# (DatetimeIndex, PeriodIndex, TimedeltaIndex)):
143147
# GH 10791
144-
with pytest.raises(AttributeError):
148+
msg = "'MultiIndex' object has no attribute 'freq'"
149+
with pytest.raises(AttributeError, match=msg):
145150
idx.freq
146151

147152

@@ -199,7 +204,8 @@ def test_take_fill_value():
199204
with pytest.raises(ValueError, match=msg):
200205
idx.take(np.array([1, 0, -5]), fill_value=True)
201206

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

205211

@@ -215,13 +221,15 @@ def test_sub(idx):
215221
first = idx
216222

217223
# - now raises (previously was set op difference)
218-
with pytest.raises(TypeError):
224+
msg = "cannot perform __sub__ with this index type: MultiIndex"
225+
with pytest.raises(TypeError, match=msg):
219226
first - idx[-3:]
220-
with pytest.raises(TypeError):
227+
with pytest.raises(TypeError, match=msg):
221228
idx[-3:] - first
222-
with pytest.raises(TypeError):
229+
with pytest.raises(TypeError, match=msg):
223230
idx[-3:] - first.tolist()
224-
with pytest.raises(TypeError):
231+
msg = "cannot perform __rsub__ with this index type: MultiIndex"
232+
with pytest.raises(TypeError, match=msg):
225233
first.tolist() - idx[-3:]
226234

227235

@@ -272,50 +280,22 @@ def test_map_dictlike(idx, mapper):
272280
np.arccos, np.arctan, np.sinh, np.cosh, np.tanh,
273281
np.arcsinh, np.arccosh, np.arctanh, np.deg2rad,
274282
np.rad2deg
275-
])
276-
def test_numpy_ufuncs(func):
283+
], ids=lambda func: func.__name__)
284+
def test_numpy_ufuncs(idx, func):
277285
# test ufuncs of numpy. see:
278286
# http://docs.scipy.org/doc/numpy/reference/ufuncs.html
279287

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)
288+
msg = "'tuple' object has no attribute '{}'".format(func.__name__)
289+
with pytest.raises(AttributeError, match=msg):
290+
func(idx)
298291

299292

300293
@pytest.mark.parametrize('func', [
301294
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):
295+
], ids=lambda func: func.__name__)
296+
def test_numpy_type_funcs(idx, func):
297+
msg = ("ufunc '{}' not supported for the input types, and the inputs"
298+
" could not be safely coerced to any supported types according to"
299+
" the casting rule ''safe''").format(func.__name__)
300+
with pytest.raises(TypeError, match=msg):
321301
func(idx)

pandas/tests/indexes/multi/test_compat.py

Lines changed: 2 additions & 4 deletions
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

Lines changed: 32 additions & 35 deletions
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

Lines changed: 16 additions & 7 deletions
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')

pandas/tests/indexes/multi/test_drop.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,17 @@ def test_drop(idx):
3131
tm.assert_index_equal(dropped, expected)
3232

3333
index = MultiIndex.from_tuples([('bar', 'two')])
34-
pytest.raises(KeyError, idx.drop, [('bar', 'two')])
35-
pytest.raises(KeyError, idx.drop, index)
36-
pytest.raises(KeyError, idx.drop, ['foo', 'two'])
34+
with pytest.raises(KeyError, match=r"^10$"):
35+
idx.drop([('bar', 'two')])
36+
with pytest.raises(KeyError, match=r"^10$"):
37+
idx.drop(index)
38+
with pytest.raises(KeyError, match=r"^'two'$"):
39+
idx.drop(['foo', 'two'])
3740

3841
# partially correct argument
3942
mixed_index = MultiIndex.from_tuples([('qux', 'one'), ('bar', 'two')])
40-
pytest.raises(KeyError, idx.drop, mixed_index)
43+
with pytest.raises(KeyError, match=r"^10$"):
44+
idx.drop(mixed_index)
4145

4246
# error='ignore'
4347
dropped = idx.drop(index, errors='ignore')
@@ -59,7 +63,8 @@ def test_drop(idx):
5963

6064
# mixed partial / full drop / error='ignore'
6165
mixed_index = ['foo', ('qux', 'one'), 'two']
62-
pytest.raises(KeyError, idx.drop, mixed_index)
66+
with pytest.raises(KeyError, match=r"^'two'$"):
67+
idx.drop(mixed_index)
6368
dropped = idx.drop(mixed_index, errors='ignore')
6469
expected = idx[[2, 3, 5]]
6570
tm.assert_index_equal(dropped, expected)
@@ -98,10 +103,12 @@ def test_droplevel_list():
98103
expected = index[:2]
99104
assert dropped.equals(expected)
100105

101-
with pytest.raises(ValueError):
106+
msg = ("Cannot remove 3 levels from an index with 3 levels: at least one"
107+
" level must be left")
108+
with pytest.raises(ValueError, match=msg):
102109
index[:2].droplevel(['one', 'two', 'three'])
103110

104-
with pytest.raises(KeyError):
111+
with pytest.raises(KeyError, match="'Level four not found'"):
105112
index[:2].droplevel(['one', 'four'])
106113

107114

0 commit comments

Comments
 (0)