|
import contextlib |
|
import functools |
|
import re |
|
import sys |
|
import warnings |
|
|
|
|
|
def check_syntax_warning(testcase, statement, errtext='', |
|
*, lineno=1, offset=None): |
|
|
|
from test.support import check_syntax_error |
|
with warnings.catch_warnings(record=True) as warns: |
|
warnings.simplefilter('always', SyntaxWarning) |
|
compile(statement, '<testcase>', 'exec') |
|
testcase.assertEqual(len(warns), 1, warns) |
|
|
|
warn, = warns |
|
testcase.assertTrue(issubclass(warn.category, SyntaxWarning), |
|
warn.category) |
|
if errtext: |
|
testcase.assertRegex(str(warn.message), errtext) |
|
testcase.assertEqual(warn.filename, '<testcase>') |
|
testcase.assertIsNotNone(warn.lineno) |
|
if lineno is not None: |
|
testcase.assertEqual(warn.lineno, lineno) |
|
|
|
|
|
|
|
|
|
with warnings.catch_warnings(record=True) as warns: |
|
warnings.simplefilter('error', SyntaxWarning) |
|
check_syntax_error(testcase, statement, errtext, |
|
lineno=lineno, offset=offset) |
|
|
|
testcase.assertEqual(warns, []) |
|
|
|
|
|
def ignore_warnings(*, category): |
|
"""Decorator to suppress warnings. |
|
|
|
Use of context managers to hide warnings make diffs |
|
more noisy and tools like 'git blame' less useful. |
|
""" |
|
def decorator(test): |
|
@functools.wraps(test) |
|
def wrapper(self, *args, **kwargs): |
|
with warnings.catch_warnings(): |
|
warnings.simplefilter('ignore', category=category) |
|
return test(self, *args, **kwargs) |
|
return wrapper |
|
return decorator |
|
|
|
|
|
class WarningsRecorder(object): |
|
"""Convenience wrapper for the warnings list returned on |
|
entry to the warnings.catch_warnings() context manager. |
|
""" |
|
def __init__(self, warnings_list): |
|
self._warnings = warnings_list |
|
self._last = 0 |
|
|
|
def __getattr__(self, attr): |
|
if len(self._warnings) > self._last: |
|
return getattr(self._warnings[-1], attr) |
|
elif attr in warnings.WarningMessage._WARNING_DETAILS: |
|
return None |
|
raise AttributeError("%r has no attribute %r" % (self, attr)) |
|
|
|
@property |
|
def warnings(self): |
|
return self._warnings[self._last:] |
|
|
|
def reset(self): |
|
self._last = len(self._warnings) |
|
|
|
|
|
@contextlib.contextmanager |
|
def check_warnings(*filters, **kwargs): |
|
"""Context manager to silence warnings. |
|
|
|
Accept 2-tuples as positional arguments: |
|
("message regexp", WarningCategory) |
|
|
|
Optional argument: |
|
- if 'quiet' is True, it does not fail if a filter catches nothing |
|
(default True without argument, |
|
default False if some filters are defined) |
|
|
|
Without argument, it defaults to: |
|
check_warnings(("", Warning), quiet=True) |
|
""" |
|
quiet = kwargs.get('quiet') |
|
if not filters: |
|
filters = (("", Warning),) |
|
|
|
if quiet is None: |
|
quiet = True |
|
return _filterwarnings(filters, quiet) |
|
|
|
|
|
@contextlib.contextmanager |
|
def check_no_warnings(testcase, message='', category=Warning, force_gc=False): |
|
"""Context manager to check that no warnings are emitted. |
|
|
|
This context manager enables a given warning within its scope |
|
and checks that no warnings are emitted even with that warning |
|
enabled. |
|
|
|
If force_gc is True, a garbage collection is attempted before checking |
|
for warnings. This may help to catch warnings emitted when objects |
|
are deleted, such as ResourceWarning. |
|
|
|
Other keyword arguments are passed to warnings.filterwarnings(). |
|
""" |
|
from test.support import gc_collect |
|
with warnings.catch_warnings(record=True) as warns: |
|
warnings.filterwarnings('always', |
|
message=message, |
|
category=category) |
|
yield |
|
if force_gc: |
|
gc_collect() |
|
testcase.assertEqual(warns, []) |
|
|
|
|
|
@contextlib.contextmanager |
|
def check_no_resource_warning(testcase): |
|
"""Context manager to check that no ResourceWarning is emitted. |
|
|
|
Usage: |
|
|
|
with check_no_resource_warning(self): |
|
f = open(...) |
|
... |
|
del f |
|
|
|
You must remove the object which may emit ResourceWarning before |
|
the end of the context manager. |
|
""" |
|
with check_no_warnings(testcase, category=ResourceWarning, force_gc=True): |
|
yield |
|
|
|
|
|
def _filterwarnings(filters, quiet=False): |
|
"""Catch the warnings, then check if all the expected |
|
warnings have been raised and re-raise unexpected warnings. |
|
If 'quiet' is True, only re-raise the unexpected warnings. |
|
""" |
|
|
|
|
|
frame = sys._getframe(2) |
|
registry = frame.f_globals.get('__warningregistry__') |
|
if registry: |
|
registry.clear() |
|
with warnings.catch_warnings(record=True) as w: |
|
|
|
|
|
|
|
sys.modules['warnings'].simplefilter("always") |
|
yield WarningsRecorder(w) |
|
|
|
reraise = list(w) |
|
missing = [] |
|
for msg, cat in filters: |
|
seen = False |
|
for w in reraise[:]: |
|
warning = w.message |
|
|
|
if (re.match(msg, str(warning), re.I) and |
|
issubclass(warning.__class__, cat)): |
|
seen = True |
|
reraise.remove(w) |
|
if not seen and not quiet: |
|
|
|
missing.append((msg, cat.__name__)) |
|
if reraise: |
|
raise AssertionError("unhandled warning %s" % reraise[0]) |
|
if missing: |
|
raise AssertionError("filter (%r, %s) did not catch any warning" % |
|
missing[0]) |
|
|
|
|
|
@contextlib.contextmanager |
|
def save_restore_warnings_filters(): |
|
old_filters = warnings.filters[:] |
|
try: |
|
yield |
|
finally: |
|
warnings.filters[:] = old_filters |
|
|
|
|
|
def _warn_about_deprecation(): |
|
warnings.warn( |
|
"This is used in test_support test to ensure" |
|
" support.ignore_deprecations_from() works as expected." |
|
" You should not be seeing this.", |
|
DeprecationWarning, |
|
stacklevel=0, |
|
) |
|
|