mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			207 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import contextlib
 | 
						|
import functools
 | 
						|
import importlib
 | 
						|
import re
 | 
						|
import sys
 | 
						|
import warnings
 | 
						|
 | 
						|
 | 
						|
def import_deprecated(name):
 | 
						|
    """Import *name* while suppressing DeprecationWarning."""
 | 
						|
    with warnings.catch_warnings():
 | 
						|
        warnings.simplefilter('ignore', category=DeprecationWarning)
 | 
						|
        return importlib.import_module(name)
 | 
						|
 | 
						|
 | 
						|
def check_syntax_warning(testcase, statement, errtext='',
 | 
						|
                         *, lineno=1, offset=None):
 | 
						|
    # Test also that a warning is emitted only once.
 | 
						|
    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)
 | 
						|
 | 
						|
    # SyntaxWarning should be converted to SyntaxError when raised,
 | 
						|
    # since the latter contains more information and provides better
 | 
						|
    # error report.
 | 
						|
    with warnings.catch_warnings(record=True) as warns:
 | 
						|
        warnings.simplefilter('error', SyntaxWarning)
 | 
						|
        check_syntax_error(testcase, statement, errtext,
 | 
						|
                           lineno=lineno, offset=offset)
 | 
						|
    # No warnings are leaked when a SyntaxError is raised.
 | 
						|
    testcase.assertEqual(warns, [])
 | 
						|
 | 
						|
 | 
						|
def ignore_warnings(*, category):
 | 
						|
    """Decorator to suppress deprecation 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),)
 | 
						|
        # Preserve backward compatibility
 | 
						|
        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.
 | 
						|
    """
 | 
						|
    # Clear the warning registry of the calling module
 | 
						|
    # in order to re-raise the warnings.
 | 
						|
    frame = sys._getframe(2)
 | 
						|
    registry = frame.f_globals.get('__warningregistry__')
 | 
						|
    if registry:
 | 
						|
        registry.clear()
 | 
						|
    with warnings.catch_warnings(record=True) as w:
 | 
						|
        # Set filter "always" to record all warnings.  Because
 | 
						|
        # test_warnings swap the module, we need to look up in
 | 
						|
        # the sys.modules dictionary.
 | 
						|
        sys.modules['warnings'].simplefilter("always")
 | 
						|
        yield WarningsRecorder(w)
 | 
						|
    # Filter the recorded warnings
 | 
						|
    reraise = list(w)
 | 
						|
    missing = []
 | 
						|
    for msg, cat in filters:
 | 
						|
        seen = False
 | 
						|
        for w in reraise[:]:
 | 
						|
            warning = w.message
 | 
						|
            # Filter out the matching messages
 | 
						|
            if (re.match(msg, str(warning), re.I) and
 | 
						|
                issubclass(warning.__class__, cat)):
 | 
						|
                seen = True
 | 
						|
                reraise.remove(w)
 | 
						|
        if not seen and not quiet:
 | 
						|
            # This filter caught nothing
 | 
						|
            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,
 | 
						|
    )
 |