mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									86533776c2
								
							
						
					
					
						commit
						1eaf0742d8
					
				
					 11 changed files with 208 additions and 126 deletions
				
			
		|  | @ -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 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Brett Cannon
						Brett Cannon