(root)/
Python-3.11.7/
Lib/
test/
support/
warnings_helper.py
       1  import contextlib
       2  import functools
       3  import importlib
       4  import re
       5  import sys
       6  import warnings
       7  
       8  
       9  def 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  
      16  def 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  
      46  def 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  
      62  class ESC[4;38;5;81mWarningsRecorder(ESC[4;38;5;149mobject):
      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
      86  def 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
     110  def 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
     135  def 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  
     152  def _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
     192  def save_restore_warnings_filters():
     193      old_filters = warnings.filters[:]
     194      try:
     195          yield
     196      finally:
     197          warnings.filters[:] = old_filters
     198  
     199  
     200  def _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      )