diff options
| author | Brett Cannon <bcannon@gmail.com> | 2008-09-02 01:25:16 (GMT) | 
|---|---|---|
| committer | Brett Cannon <bcannon@gmail.com> | 2008-09-02 01:25:16 (GMT) | 
| commit | 1eaf0742d877fd9d84d6ed82a04bc33b027e9ad0 (patch) | |
| tree | 1c1ee3a5dee04f5f4657b707e9d54ca2e28b1505 /Lib/warnings.py | |
| parent | 86533776c291c031853609ceaeda96eb2808e4ee (diff) | |
| download | cpython-1eaf0742d877fd9d84d6ed82a04bc33b027e9ad0.zip cpython-1eaf0742d877fd9d84d6ed82a04bc33b027e9ad0.tar.gz cpython-1eaf0742d877fd9d84d6ed82a04bc33b027e9ad0.tar.bz2  | |
Move test.test_support.catch_warning() to the warnings module, rename it
catch_warnings(), and clean up the API.
While expanding the test suite, a bug was found where a warning about the
'line' argument to showwarning() was not letting functions with '*args' go
without a warning.
Closes issue 3602.
Code review by Benjamin Peterson.
Diffstat (limited to 'Lib/warnings.py')
| -rw-r--r-- | Lib/warnings.py | 75 | 
1 files changed, 74 insertions, 1 deletions
diff --git a/Lib/warnings.py b/Lib/warnings.py index 2e5c512..b699c43 100644 --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -272,7 +272,8 @@ def warn_explicit(message, category, filename, lineno,          fxn_code = showwarning.__func__.func_code      if fxn_code:          args = fxn_code.co_varnames[:fxn_code.co_argcount] -        if 'line' not in args: +        CO_VARARGS = 0x4 +        if 'line' not in args and not fxn_code.co_flags & CO_VARARGS:              showwarning_msg = ("functions overriding warnings.showwarning() "                                  "must support the 'line' argument")              if message == showwarning_msg: @@ -283,6 +284,78 @@ def warn_explicit(message, category, filename, lineno,      showwarning(message, category, filename, lineno) +class WarningMessage(object): + +    """Holds the result of a single showwarning() call.""" + +    _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", +                        "line") + +    def __init__(self, message, category, filename, lineno, file=None, +                    line=None): +        local_values = locals() +        for attr in self._WARNING_DETAILS: +            setattr(self, attr, local_values[attr]) +        self._category_name = category.__name__ if category else None + +    def __str__(self): +        return ("{message : %r, category : %r, filename : %r, lineno : %s, " +                    "line : %r}" % (self.message, self._category_name, +                                    self.filename, self.lineno, self.line)) + + +class WarningsRecorder(list): + +    """Record the result of various showwarning() calls.""" + +    # Explicitly stated arguments so as to not trigger DeprecationWarning +    # about adding 'line'. +    def showwarning(self, *args, **kwargs): +        self.append(WarningMessage(*args, **kwargs)) + +    def __getattr__(self, attr): +        return getattr(self[-1], attr) + +    def reset(self): +        del self[:] + + +class catch_warnings(object): + +    """Guard the warnings filter from being permanently changed and optionally +    record the details of any warnings that are issued. + +    Context manager returns an instance of warnings.WarningRecorder which is a +    list of WarningMessage instances. Attributes on WarningRecorder are +    redirected to the last created WarningMessage instance. + +    """ + +    def __init__(self, record=False, module=None): +        """Specify whether to record warnings and if an alternative module +        should be used other than sys.modules['warnings']. + +        For compatibility with Python 3.0, please consider all arguments to be +        keyword-only. + +        """ +        self._recorder = WarningsRecorder() if record else None +        self._module = sys.modules['warnings'] if module is None else module + +    def __enter__(self): +        self._filters = self._module.filters +        self._module.filters = self._filters[:] +        self._showwarning = self._module.showwarning +        if self._recorder is not None: +            self._recorder.reset()  # In case the instance is being reused. +            self._module.showwarning = self._recorder.showwarning +        return self._recorder + +    def __exit__(self, *exc_info): +        self._module.filters = self._filters +        self._module.showwarning = self._showwarning + +  # filters contains a sequence of filter 5-tuples  # The components of the 5-tuple are:  # - an action: error, ignore, always, default, module, or once  | 
