1import contextlib 2import functools 3import importlib 4import re 5import sys 6import warnings 7 8 9def import_deprecated(name): 10 """Import *name* while suppressing DeprecationWarning.""" 11 with warnings.catch_warnings(): 12 warnings.simplefilter('ignore', category=DeprecationWarning) 13 return importlib.import_module(name) 14 15 16def check_syntax_warning(testcase, statement, errtext='', 17 *, lineno=1, offset=None): 18 # Test also that a warning is emitted only once. 19 from test.support import check_syntax_error 20 with warnings.catch_warnings(record=True) as warns: 21 warnings.simplefilter('always', SyntaxWarning) 22 compile(statement, '<testcase>', 'exec') 23 testcase.assertEqual(len(warns), 1, warns) 24 25 warn, = warns 26 testcase.assertTrue(issubclass(warn.category, SyntaxWarning), 27 warn.category) 28 if errtext: 29 testcase.assertRegex(str(warn.message), errtext) 30 testcase.assertEqual(warn.filename, '<testcase>') 31 testcase.assertIsNotNone(warn.lineno) 32 if lineno is not None: 33 testcase.assertEqual(warn.lineno, lineno) 34 35 # SyntaxWarning should be converted to SyntaxError when raised, 36 # since the latter contains more information and provides better 37 # error report. 38 with warnings.catch_warnings(record=True) as warns: 39 warnings.simplefilter('error', SyntaxWarning) 40 check_syntax_error(testcase, statement, errtext, 41 lineno=lineno, offset=offset) 42 # No warnings are leaked when a SyntaxError is raised. 43 testcase.assertEqual(warns, []) 44 45 46def ignore_warnings(*, category): 47 """Decorator to suppress warnings. 48 49 Use of context managers to hide warnings make diffs 50 more noisy and tools like 'git blame' less useful. 51 """ 52 def decorator(test): 53 @functools.wraps(test) 54 def wrapper(self, *args, **kwargs): 55 with warnings.catch_warnings(): 56 warnings.simplefilter('ignore', category=category) 57 return test(self, *args, **kwargs) 58 return wrapper 59 return decorator 60 61 62class WarningsRecorder(object): 63 """Convenience wrapper for the warnings list returned on 64 entry to the warnings.catch_warnings() context manager. 65 """ 66 def __init__(self, warnings_list): 67 self._warnings = warnings_list 68 self._last = 0 69 70 def __getattr__(self, attr): 71 if len(self._warnings) > self._last: 72 return getattr(self._warnings[-1], attr) 73 elif attr in warnings.WarningMessage._WARNING_DETAILS: 74 return None 75 raise AttributeError("%r has no attribute %r" % (self, attr)) 76 77 @property 78 def warnings(self): 79 return self._warnings[self._last:] 80 81 def reset(self): 82 self._last = len(self._warnings) 83 84 85@contextlib.contextmanager 86def check_warnings(*filters, **kwargs): 87 """Context manager to silence warnings. 88 89 Accept 2-tuples as positional arguments: 90 ("message regexp", WarningCategory) 91 92 Optional argument: 93 - if 'quiet' is True, it does not fail if a filter catches nothing 94 (default True without argument, 95 default False if some filters are defined) 96 97 Without argument, it defaults to: 98 check_warnings(("", Warning), quiet=True) 99 """ 100 quiet = kwargs.get('quiet') 101 if not filters: 102 filters = (("", Warning),) 103 # Preserve backward compatibility 104 if quiet is None: 105 quiet = True 106 return _filterwarnings(filters, quiet) 107 108 109@contextlib.contextmanager 110def check_no_warnings(testcase, message='', category=Warning, force_gc=False): 111 """Context manager to check that no warnings are emitted. 112 113 This context manager enables a given warning within its scope 114 and checks that no warnings are emitted even with that warning 115 enabled. 116 117 If force_gc is True, a garbage collection is attempted before checking 118 for warnings. This may help to catch warnings emitted when objects 119 are deleted, such as ResourceWarning. 120 121 Other keyword arguments are passed to warnings.filterwarnings(). 122 """ 123 from test.support import gc_collect 124 with warnings.catch_warnings(record=True) as warns: 125 warnings.filterwarnings('always', 126 message=message, 127 category=category) 128 yield 129 if force_gc: 130 gc_collect() 131 testcase.assertEqual(warns, []) 132 133 134@contextlib.contextmanager 135def check_no_resource_warning(testcase): 136 """Context manager to check that no ResourceWarning is emitted. 137 138 Usage: 139 140 with check_no_resource_warning(self): 141 f = open(...) 142 ... 143 del f 144 145 You must remove the object which may emit ResourceWarning before 146 the end of the context manager. 147 """ 148 with check_no_warnings(testcase, category=ResourceWarning, force_gc=True): 149 yield 150 151 152def _filterwarnings(filters, quiet=False): 153 """Catch the warnings, then check if all the expected 154 warnings have been raised and re-raise unexpected warnings. 155 If 'quiet' is True, only re-raise the unexpected warnings. 156 """ 157 # Clear the warning registry of the calling module 158 # in order to re-raise the warnings. 159 frame = sys._getframe(2) 160 registry = frame.f_globals.get('__warningregistry__') 161 if registry: 162 registry.clear() 163 with warnings.catch_warnings(record=True) as w: 164 # Set filter "always" to record all warnings. Because 165 # test_warnings swap the module, we need to look up in 166 # the sys.modules dictionary. 167 sys.modules['warnings'].simplefilter("always") 168 yield WarningsRecorder(w) 169 # Filter the recorded warnings 170 reraise = list(w) 171 missing = [] 172 for msg, cat in filters: 173 seen = False 174 for w in reraise[:]: 175 warning = w.message 176 # Filter out the matching messages 177 if (re.match(msg, str(warning), re.I) and 178 issubclass(warning.__class__, cat)): 179 seen = True 180 reraise.remove(w) 181 if not seen and not quiet: 182 # This filter caught nothing 183 missing.append((msg, cat.__name__)) 184 if reraise: 185 raise AssertionError("unhandled warning %s" % reraise[0]) 186 if missing: 187 raise AssertionError("filter (%r, %s) did not catch any warning" % 188 missing[0]) 189 190 191@contextlib.contextmanager 192def save_restore_warnings_filters(): 193 old_filters = warnings.filters[:] 194 try: 195 yield 196 finally: 197 warnings.filters[:] = old_filters 198 199 200def _warn_about_deprecation(): 201 warnings.warn( 202 "This is used in test_support test to ensure" 203 " support.ignore_deprecations_from() works as expected." 204 " You should not be seeing this.", 205 DeprecationWarning, 206 stacklevel=0, 207 ) 208