Skip to content

Commit 3a31e8b

Browse files
committed
Don't remove, just deprecate assert_raises_regex
1 parent d9dffc5 commit 3a31e8b

File tree

2 files changed

+142
-1
lines changed

2 files changed

+142
-1
lines changed

pandas/tests/util/test_testing.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,3 +877,13 @@ def test_datapath_missing(datapath, request):
877877
)
878878

879879
assert result == expected
880+
881+
882+
def test_assert_raises_regex_deprecated():
883+
# see gh-23592
884+
885+
with tm.assert_produces_warning(FutureWarning):
886+
msg = "Not equal!"
887+
888+
with tm.assert_raises_regex(AssertionError, msg):
889+
assert 1 == 2, msg

pandas/util/testing.py

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import pandas.compat as compat
2121
from pandas.compat import (
2222
PY2, PY3, Counter, StringIO, callable, filter, httplib, lmap, lrange, lzip,
23-
map, range, string_types, u, unichr, zip)
23+
map, raise_with_traceback, range, string_types, u, unichr, zip)
2424

2525
from pandas.core.dtypes.common import (
2626
is_bool, is_categorical_dtype, is_datetimelike_v_numeric,
@@ -2512,6 +2512,137 @@ def wrapper(*args, **kwargs):
25122512
with_connectivity_check = network
25132513

25142514

2515+
def assert_raises_regex(_exception, _regexp, _callable=None,
2516+
*args, **kwargs):
2517+
r"""
2518+
Check that the specified Exception is raised and that the error message
2519+
matches a given regular expression pattern. This may be a regular
2520+
expression object or a string containing a regular expression suitable
2521+
for use by `re.search()`. This is a port of the `assertRaisesRegexp`
2522+
function from unittest in Python 2.7.
2523+
2524+
.. deprecated:: 0.24.0
2525+
Use `pytest.raises` instead.
2526+
2527+
Examples
2528+
--------
2529+
>>> assert_raises_regex(ValueError, 'invalid literal for.*XYZ', int, 'XYZ')
2530+
>>> import re
2531+
>>> assert_raises_regex(ValueError, re.compile('literal'), int, 'XYZ')
2532+
2533+
If an exception of a different type is raised, it bubbles up.
2534+
2535+
>>> assert_raises_regex(TypeError, 'literal', int, 'XYZ')
2536+
Traceback (most recent call last):
2537+
...
2538+
ValueError: invalid literal for int() with base 10: 'XYZ'
2539+
>>> dct = dict()
2540+
>>> assert_raises_regex(KeyError, 'pear', dct.__getitem__, 'apple')
2541+
Traceback (most recent call last):
2542+
...
2543+
AssertionError: "pear" does not match "'apple'"
2544+
2545+
You can also use this in a with statement.
2546+
2547+
>>> with assert_raises_regex(TypeError, r'unsupported operand type\(s\)'):
2548+
... 1 + {}
2549+
>>> with assert_raises_regex(TypeError, 'banana'):
2550+
... 'apple'[0] = 'b'
2551+
Traceback (most recent call last):
2552+
...
2553+
AssertionError: "banana" does not match "'str' object does not support \
2554+
item assignment"
2555+
"""
2556+
warnings.warn(("assert_raises_regex has been deprecated and will "
2557+
"be removed in the next release. Please use "
2558+
"`pytest.raises` instead."), FutureWarning, stacklevel=2)
2559+
2560+
manager = _AssertRaisesContextmanager(exception=_exception, regexp=_regexp)
2561+
if _callable is not None:
2562+
with manager:
2563+
_callable(*args, **kwargs)
2564+
else:
2565+
return manager
2566+
2567+
2568+
class _AssertRaisesContextmanager(object):
2569+
"""
2570+
Context manager behind `assert_raises_regex`.
2571+
"""
2572+
2573+
def __init__(self, exception, regexp=None):
2574+
"""
2575+
Initialize an _AssertRaisesContextManager instance.
2576+
2577+
Parameters
2578+
----------
2579+
exception : class
2580+
The expected Exception class.
2581+
regexp : str, default None
2582+
The regex to compare against the Exception message.
2583+
"""
2584+
2585+
self.exception = exception
2586+
2587+
if regexp is not None and not hasattr(regexp, "search"):
2588+
regexp = re.compile(regexp, re.DOTALL)
2589+
2590+
self.regexp = regexp
2591+
2592+
def __enter__(self):
2593+
return self
2594+
2595+
def __exit__(self, exc_type, exc_value, trace_back):
2596+
expected = self.exception
2597+
2598+
if not exc_type:
2599+
exp_name = getattr(expected, "__name__", str(expected))
2600+
raise AssertionError("{name} not raised.".format(name=exp_name))
2601+
2602+
return self.exception_matches(exc_type, exc_value, trace_back)
2603+
2604+
def exception_matches(self, exc_type, exc_value, trace_back):
2605+
"""
2606+
Check that the Exception raised matches the expected Exception
2607+
and expected error message regular expression.
2608+
2609+
Parameters
2610+
----------
2611+
exc_type : class
2612+
The type of Exception raised.
2613+
exc_value : Exception
2614+
The instance of `exc_type` raised.
2615+
trace_back : stack trace object
2616+
The traceback object associated with `exc_value`.
2617+
2618+
Returns
2619+
-------
2620+
is_matched : bool
2621+
Whether or not the Exception raised matches the expected
2622+
Exception class and expected error message regular expression.
2623+
2624+
Raises
2625+
------
2626+
AssertionError : The error message provided does not match
2627+
the expected error message regular expression.
2628+
"""
2629+
2630+
if issubclass(exc_type, self.exception):
2631+
if self.regexp is not None:
2632+
val = str(exc_value)
2633+
2634+
if not self.regexp.search(val):
2635+
msg = '"{pat}" does not match "{val}"'.format(
2636+
pat=self.regexp.pattern, val=val)
2637+
e = AssertionError(msg)
2638+
raise_with_traceback(e, trace_back)
2639+
2640+
return True
2641+
else:
2642+
# Failed, so allow Exception to bubble up.
2643+
return False
2644+
2645+
25152646
@contextmanager
25162647
def assert_produces_warning(expected_warning=Warning, filter_level="always",
25172648
clear=None, check_stacklevel=True):

0 commit comments

Comments
 (0)