From 2a56823c5bdb304cd5f3e7a994493fcae6893db4 Mon Sep 17 00:00:00 2001
From: Simon Hawkins <simonjayhawkins@gmail.com>
Date: Tue, 5 Feb 2019 23:43:16 +0000
Subject: [PATCH 1/2] STY: use pytest.raises context manager (indexes/multi)

---
 pandas/tests/indexes/multi/test_analytics.py  | 92 ++++++++-----------
 pandas/tests/indexes/multi/test_compat.py     |  6 +-
 .../tests/indexes/multi/test_constructor.py   | 67 +++++++-------
 pandas/tests/indexes/multi/test_contains.py   | 23 +++--
 pandas/tests/indexes/multi/test_drop.py       | 21 +++--
 pandas/tests/indexes/multi/test_get_set.py    | 15 +--
 pandas/tests/indexes/multi/test_indexing.py   | 53 +++++++----
 pandas/tests/indexes/multi/test_integrity.py  | 15 +--
 8 files changed, 153 insertions(+), 139 deletions(-)

diff --git a/pandas/tests/indexes/multi/test_analytics.py b/pandas/tests/indexes/multi/test_analytics.py
index dca6180f39664..9857aae2698d5 100644
--- a/pandas/tests/indexes/multi/test_analytics.py
+++ b/pandas/tests/indexes/multi/test_analytics.py
@@ -13,8 +13,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):
@@ -50,25 +53,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
@@ -141,7 +145,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
 
 
@@ -199,7 +204,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]))
 
 
@@ -215,13 +221,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:]
 
 
@@ -272,50 +280,22 @@ 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 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)
+    msg = "'tuple' object has no attribute '{}'".format(func.__name__)
+    with pytest.raises(AttributeError, 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)
diff --git a/pandas/tests/indexes/multi/test_compat.py b/pandas/tests/indexes/multi/test_compat.py
index f405fc659c709..89685b9feec27 100644
--- a/pandas/tests/indexes/multi/test_compat.py
+++ b/pandas/tests/indexes/multi/test_compat.py
@@ -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()
diff --git a/pandas/tests/indexes/multi/test_constructor.py b/pandas/tests/indexes/multi/test_constructor.py
index e6678baf8a996..055d54c613260 100644
--- a/pandas/tests/indexes/multi/test_constructor.py
+++ b/pandas/tests/indexes/multi/test_constructor.py
@@ -1,7 +1,6 @@
 # -*- coding: utf-8 -*-
 
 from collections import OrderedDict
-import re
 
 import numpy as np
 import pytest
@@ -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=[])
 
 
@@ -42,8 +41,8 @@ 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()
@@ -51,11 +50,11 @@ def test_constructor_nonhashable_names():
                     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)
 
 
@@ -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):
@@ -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', [
@@ -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')
 
 
@@ -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():
@@ -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)
diff --git a/pandas/tests/indexes/multi/test_contains.py b/pandas/tests/indexes/multi/test_contains.py
index b73ff11a4dd4e..56836b94a6b03 100644
--- a/pandas/tests/indexes/multi/test_contains.py
+++ b/pandas/tests/indexes/multi/test_contains.py
@@ -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')
diff --git a/pandas/tests/indexes/multi/test_drop.py b/pandas/tests/indexes/multi/test_drop.py
index 0cf73d3d752ad..5a4594dce8d66 100644
--- a/pandas/tests/indexes/multi/test_drop.py
+++ b/pandas/tests/indexes/multi/test_drop.py
@@ -31,13 +31,17 @@ def test_drop(idx):
     tm.assert_index_equal(dropped, expected)
 
     index = MultiIndex.from_tuples([('bar', 'two')])
-    pytest.raises(KeyError, idx.drop, [('bar', 'two')])
-    pytest.raises(KeyError, idx.drop, index)
-    pytest.raises(KeyError, idx.drop, ['foo', 'two'])
+    with pytest.raises(KeyError, match=r"^10$"):
+        idx.drop([('bar', 'two')])
+    with pytest.raises(KeyError, match=r"^10$"):
+        idx.drop(index)
+    with pytest.raises(KeyError, match=r"^'two'$"):
+        idx.drop(['foo', 'two'])
 
     # partially correct argument
     mixed_index = MultiIndex.from_tuples([('qux', 'one'), ('bar', 'two')])
-    pytest.raises(KeyError, idx.drop, mixed_index)
+    with pytest.raises(KeyError, match=r"^10$"):
+        idx.drop(mixed_index)
 
     # error='ignore'
     dropped = idx.drop(index, errors='ignore')
@@ -59,7 +63,8 @@ def test_drop(idx):
 
     # mixed partial / full drop / error='ignore'
     mixed_index = ['foo', ('qux', 'one'), 'two']
-    pytest.raises(KeyError, idx.drop, mixed_index)
+    with pytest.raises(KeyError, match=r"^'two'$"):
+        idx.drop(mixed_index)
     dropped = idx.drop(mixed_index, errors='ignore')
     expected = idx[[2, 3, 5]]
     tm.assert_index_equal(dropped, expected)
@@ -98,10 +103,12 @@ def test_droplevel_list():
     expected = index[:2]
     assert dropped.equals(expected)
 
-    with pytest.raises(ValueError):
+    msg = ("Cannot remove 3 levels from an index with 3 levels: at least one"
+           " level must be left")
+    with pytest.raises(ValueError, match=msg):
         index[:2].droplevel(['one', 'two', 'three'])
 
-    with pytest.raises(KeyError):
+    with pytest.raises(KeyError, match="'Level four not found'"):
         index[:2].droplevel(['one', 'four'])
 
 
diff --git a/pandas/tests/indexes/multi/test_get_set.py b/pandas/tests/indexes/multi/test_get_set.py
index d201cb2eb178b..62911c7032aca 100644
--- a/pandas/tests/indexes/multi/test_get_set.py
+++ b/pandas/tests/indexes/multi/test_get_set.py
@@ -25,7 +25,9 @@ def test_get_level_number_integer(idx):
     idx.names = [1, 0]
     assert idx._get_level_number(1) == 0
     assert idx._get_level_number(0) == 1
-    pytest.raises(IndexError, idx._get_level_number, 2)
+    msg = "Too many levels: Index has only 2 levels, not 3"
+    with pytest.raises(IndexError, match=msg):
+        idx._get_level_number(2)
     with pytest.raises(KeyError, match='Level fourth not found'):
         idx._get_level_number('fourth')
 
@@ -62,7 +64,7 @@ def test_get_value_duplicates():
                        names=['tag', 'day'])
 
     assert index.get_loc('D') == slice(0, 3)
-    with pytest.raises(KeyError):
+    with pytest.raises(KeyError, match=r"^'D'$"):
         index._engine.get_value(np.array([]), 'D')
 
 
@@ -125,7 +127,8 @@ def test_set_name_methods(idx, index_names):
     ind = idx.set_names(new_names)
     assert idx.names == index_names
     assert ind.names == new_names
-    with pytest.raises(ValueError, match="^Length"):
+    msg = "Length of names must match number of levels in MultiIndex"
+    with pytest.raises(ValueError, match=msg):
         ind.set_names(new_names + new_names)
     new_names2 = [name + "SUFFIX2" for name in new_names]
     res = ind.set_names(new_names2, inplace=True)
@@ -163,10 +166,10 @@ def test_set_levels_codes_directly(idx):
     minor_codes = [(x + 1) % 1 for x in minor_codes]
     new_codes = [major_codes, minor_codes]
 
-    with pytest.raises(AttributeError):
+    msg = "can't set attribute"
+    with pytest.raises(AttributeError, match=msg):
         idx.levels = new_levels
-
-    with pytest.raises(AttributeError):
+    with pytest.raises(AttributeError, match=msg):
         idx.codes = new_codes
 
 
diff --git a/pandas/tests/indexes/multi/test_indexing.py b/pandas/tests/indexes/multi/test_indexing.py
index c40ecd9e82a07..e32fa97574155 100644
--- a/pandas/tests/indexes/multi/test_indexing.py
+++ b/pandas/tests/indexes/multi/test_indexing.py
@@ -112,13 +112,14 @@ def test_slice_locs_not_contained():
 def test_putmask_with_wrong_mask(idx):
     # GH18368
 
-    with pytest.raises(ValueError):
+    msg = "putmask: mask and data must be the same size"
+    with pytest.raises(ValueError, match=msg):
         idx.putmask(np.ones(len(idx) + 1, np.bool), 1)
 
-    with pytest.raises(ValueError):
+    with pytest.raises(ValueError, match=msg):
         idx.putmask(np.ones(len(idx) - 1, np.bool), 1)
 
-    with pytest.raises(ValueError):
+    with pytest.raises(ValueError, match=msg):
         idx.putmask('foo', 1)
 
 
@@ -176,9 +177,12 @@ def test_get_indexer():
 
 def test_get_indexer_nearest():
     midx = MultiIndex.from_tuples([('a', 1), ('b', 2)])
-    with pytest.raises(NotImplementedError):
+    msg = ("method='nearest' not implemented yet for MultiIndex; see GitHub"
+           " issue 9365")
+    with pytest.raises(NotImplementedError, match=msg):
         midx.get_indexer(['a'], method='nearest')
-    with pytest.raises(NotImplementedError):
+    msg = "tolerance not implemented yet for MultiIndex"
+    with pytest.raises(NotImplementedError, match=msg):
         midx.get_indexer(['a'], method='pad', tolerance=2)
 
 
@@ -254,17 +258,22 @@ def test_getitem_bool_index_single(ind1, ind2):
 def test_get_loc(idx):
     assert idx.get_loc(('foo', 'two')) == 1
     assert idx.get_loc(('baz', 'two')) == 3
-    pytest.raises(KeyError, idx.get_loc, ('bar', 'two'))
-    pytest.raises(KeyError, idx.get_loc, 'quux')
+    with pytest.raises(KeyError, match=r"^10$"):
+        idx.get_loc(('bar', 'two'))
+    with pytest.raises(KeyError, match=r"^'quux'$"):
+        idx.get_loc('quux')
 
-    pytest.raises(NotImplementedError, idx.get_loc, 'foo',
-                  method='nearest')
+    msg = ("only the default get_loc method is currently supported for"
+           " MultiIndex")
+    with pytest.raises(NotImplementedError, match=msg):
+        idx.get_loc('foo', method='nearest')
 
     # 3 levels
     index = MultiIndex(levels=[Index(lrange(4)), Index(lrange(4)), Index(
         lrange(4))], codes=[np.array([0, 0, 1, 2, 2, 2, 3, 3]), np.array(
             [0, 1, 0, 0, 0, 1, 0, 1]), np.array([1, 0, 1, 1, 0, 0, 1, 0])])
-    pytest.raises(KeyError, index.get_loc, (1, 1))
+    with pytest.raises(KeyError, match=r"^\(1, 1\)$"):
+        index.get_loc((1, 1))
     assert index.get_loc((2, 0)) == slice(3, 5)
 
 
@@ -297,11 +306,14 @@ def test_get_loc_level():
     assert loc == expected
     assert new_index is None
 
-    pytest.raises(KeyError, index.get_loc_level, (2, 2))
+    with pytest.raises(KeyError, match=r"^\(2, 2\)$"):
+        index.get_loc_level((2, 2))
     # GH 22221: unused label
-    pytest.raises(KeyError, index.drop(2).get_loc_level, 2)
+    with pytest.raises(KeyError, match=r"^2$"):
+        index.drop(2).get_loc_level(2)
     # Unused label on unsorted level:
-    pytest.raises(KeyError, index.drop(1, level=2).get_loc_level, 2, 2)
+    with pytest.raises(KeyError, match=r"^2$"):
+        index.drop(1, level=2).get_loc_level(2, level=2)
 
     index = MultiIndex(levels=[[2000], lrange(4)], codes=[np.array(
         [0, 0, 0, 0]), np.array([0, 1, 2, 3])])
@@ -342,8 +354,10 @@ def test_get_loc_cast_bool():
     assert idx.get_loc((0, 1)) == 1
     assert idx.get_loc((1, 0)) == 2
 
-    pytest.raises(KeyError, idx.get_loc, (False, True))
-    pytest.raises(KeyError, idx.get_loc, (True, False))
+    with pytest.raises(KeyError, match=r"^\(False, True\)$"):
+        idx.get_loc((False, True))
+    with pytest.raises(KeyError, match=r"^\(True, False\)$"):
+        idx.get_loc((True, False))
 
 
 @pytest.mark.parametrize('level', [0, 1])
@@ -361,9 +375,12 @@ def test_get_loc_missing_nan():
     # GH 8569
     idx = MultiIndex.from_arrays([[1.0, 2.0], [3.0, 4.0]])
     assert isinstance(idx.get_loc(1), slice)
-    pytest.raises(KeyError, idx.get_loc, 3)
-    pytest.raises(KeyError, idx.get_loc, np.nan)
-    pytest.raises(KeyError, idx.get_loc, [np.nan])
+    with pytest.raises(KeyError, match=r"^3\.0$"):
+        idx.get_loc(3)
+    with pytest.raises(KeyError, match=r"^nan$"):
+        idx.get_loc(np.nan)
+    with pytest.raises(KeyError, match=r"^\[nan\]$"):
+        idx.get_loc([np.nan])
 
 
 def test_get_indexer_categorical_time():
diff --git a/pandas/tests/indexes/multi/test_integrity.py b/pandas/tests/indexes/multi/test_integrity.py
index c1638a9cde660..a7dc093147725 100644
--- a/pandas/tests/indexes/multi/test_integrity.py
+++ b/pandas/tests/indexes/multi/test_integrity.py
@@ -159,7 +159,8 @@ def test_isna_behavior(idx):
     # should not segfault GH5123
     # NOTE: if MI representation changes, may make sense to allow
     # isna(MI)
-    with pytest.raises(NotImplementedError):
+    msg = "isna is not defined for MultiIndex"
+    with pytest.raises(NotImplementedError, match=msg):
         pd.isna(idx)
 
 
@@ -168,16 +169,16 @@ def test_large_multiindex_error():
     df_below_1000000 = pd.DataFrame(
         1, index=pd.MultiIndex.from_product([[1, 2], range(499999)]),
         columns=['dest'])
-    with pytest.raises(KeyError):
+    with pytest.raises(KeyError, match=r"^\(-1, 0\)$"):
         df_below_1000000.loc[(-1, 0), 'dest']
-    with pytest.raises(KeyError):
+    with pytest.raises(KeyError, match=r"^\(3, 0\)$"):
         df_below_1000000.loc[(3, 0), 'dest']
     df_above_1000000 = pd.DataFrame(
         1, index=pd.MultiIndex.from_product([[1, 2], range(500001)]),
         columns=['dest'])
-    with pytest.raises(KeyError):
+    with pytest.raises(KeyError, match=r"^\(-1, 0\)$"):
         df_above_1000000.loc[(-1, 0), 'dest']
-    with pytest.raises(KeyError):
+    with pytest.raises(KeyError, match=r"^\(3, 0\)$"):
         df_above_1000000.loc[(3, 0), 'dest']
 
 
@@ -260,7 +261,9 @@ def test_hash_error(indices):
 def test_mutability(indices):
     if not len(indices):
         return
-    pytest.raises(TypeError, indices.__setitem__, 0, indices[0])
+    msg = "Index does not support mutable operations"
+    with pytest.raises(TypeError, match=msg):
+        indices[0] = indices[0]
 
 
 def test_wrong_number_names(indices):

From b8060b84b2d4507fee900ddf3d48de9b3a44616d Mon Sep 17 00:00:00 2001
From: Simon Hawkins <simonjayhawkins@gmail.com>
Date: Wed, 6 Feb 2019 00:40:45 +0000
Subject: [PATCH 2/2] fix ci failures

---
 pandas/compat/numpy/__init__.py              |  4 +++-
 pandas/tests/indexes/multi/test_analytics.py | 11 +++++++++--
 pandas/tests/indexes/multi/test_drop.py      |  3 ++-
 pandas/tests/indexes/multi/test_indexing.py  |  3 ++-
 4 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/pandas/compat/numpy/__init__.py b/pandas/compat/numpy/__init__.py
index 5e67cf2ee2837..bc9af01a97467 100644
--- a/pandas/compat/numpy/__init__.py
+++ b/pandas/compat/numpy/__init__.py
@@ -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':
@@ -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'
            ]
diff --git a/pandas/tests/indexes/multi/test_analytics.py b/pandas/tests/indexes/multi/test_analytics.py
index 9857aae2698d5..beec8e544f94b 100644
--- a/pandas/tests/indexes/multi/test_analytics.py
+++ b/pandas/tests/indexes/multi/test_analytics.py
@@ -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
@@ -285,8 +286,14 @@ def test_numpy_ufuncs(idx, func):
     # test ufuncs of numpy. see:
     # http://docs.scipy.org/doc/numpy/reference/ufuncs.html
 
-    msg = "'tuple' object has no attribute '{}'".format(func.__name__)
-    with pytest.raises(AttributeError, match=msg):
+    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)
 
 
diff --git a/pandas/tests/indexes/multi/test_drop.py b/pandas/tests/indexes/multi/test_drop.py
index 5a4594dce8d66..ac167c126fd13 100644
--- a/pandas/tests/indexes/multi/test_drop.py
+++ b/pandas/tests/indexes/multi/test_drop.py
@@ -4,7 +4,7 @@
 import numpy as np
 import pytest
 
-from pandas.compat import lrange
+from pandas.compat import PY2, lrange
 from pandas.errors import PerformanceWarning
 
 import pandas as pd
@@ -12,6 +12,7 @@
 import pandas.util.testing as tm
 
 
+@pytest.mark.skipif(PY2, reason="pytest.raises match regex fails")
 def test_drop(idx):
     dropped = idx.drop([('foo', 'two'), ('qux', 'one')])
 
diff --git a/pandas/tests/indexes/multi/test_indexing.py b/pandas/tests/indexes/multi/test_indexing.py
index e32fa97574155..c2af3b2050d8d 100644
--- a/pandas/tests/indexes/multi/test_indexing.py
+++ b/pandas/tests/indexes/multi/test_indexing.py
@@ -6,7 +6,7 @@
 import numpy as np
 import pytest
 
-from pandas.compat import lrange
+from pandas.compat import PY2, lrange
 
 import pandas as pd
 from pandas import (
@@ -255,6 +255,7 @@ def test_getitem_bool_index_single(ind1, ind2):
     tm.assert_index_equal(idx[ind2], expected)
 
 
+@pytest.mark.skipif(PY2, reason="pytest.raises match regex fails")
 def test_get_loc(idx):
     assert idx.get_loc(('foo', 'two')) == 1
     assert idx.get_loc(('baz', 'two')) == 3