1 """Python part of the warnings subsystem.""" 2 3 # Note: function level imports should *not* be used 4 # in this module as it may cause import lock deadlock. 5 # See bug 683658. 6 import linecache 7 import sys 8 import types 9 10 __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings", 11 "resetwarnings", "catch_warnings"] 12 13 14 def warnpy3k(message, category=None, stacklevel=1): 15 """Issue a deprecation warning for Python 3.x related changes. 16 17 Warnings are omitted unless Python is started with the -3 option. 18 """ 19 if sys.py3kwarning: 20 if category is None: 21 category = DeprecationWarning 22 warn(message, category, stacklevel+1) 23 24 def _show_warning(message, category, filename, lineno, file=None, line=None): 25 """Hook to write a warning to a file; replace if you like.""" 26 if file is None: 27 file = sys.stderr 28 try: 29 file.write(formatwarning(message, category, filename, lineno, line)) 30 except IOError: 31 pass # the file (probably stderr) is invalid - this warning gets lost. 32 # Keep a working version around in case the deprecation of the old API is 33 # triggered. 34 showwarning = _show_warning 35 36 def formatwarning(message, category, filename, lineno, line=None): 37 """Function to format a warning the standard way.""" 38 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message) 39 line = linecache.getline(filename, lineno) if line is None else line 40 if line: 41 line = line.strip() 42 s += " %s\n" % line 43 return s 44 45 def filterwarnings(action, message="", category=Warning, module="", lineno=0, 46 append=0): 47 """Insert an entry into the list of warnings filters (at the front). 48 49 'action' -- one of "error", "ignore", "always", "default", "module", 50 or "once" 51 'message' -- a regex that the warning message must match 52 'category' -- a class that the warning must be a subclass of 53 'module' -- a regex that the module name must match 54 'lineno' -- an integer line number, 0 matches all warnings 55 'append' -- if true, append to the list of filters 56 """ 57 import re 58 assert action in ("error", "ignore", "always", "default", "module", 59 "once"), "invalid action: %r" % (action,) 60 assert isinstance(message, basestring), "message must be a string" 61 assert isinstance(category, (type, types.ClassType)), \ 62 "category must be a class" 63 assert issubclass(category, Warning), "category must be a Warning subclass" 64 assert isinstance(module, basestring), "module must be a string" 65 assert isinstance(lineno, int) and lineno >= 0, \ 66 "lineno must be an int >= 0" 67 item = (action, re.compile(message, re.I), category, 68 re.compile(module), lineno) 69 if append: 70 filters.append(item) 71 else: 72 filters.insert(0, item) 73 74 def simplefilter(action, category=Warning, lineno=0, append=0): 75 """Insert a simple entry into the list of warnings filters (at the front). 76 77 A simple filter matches all modules and messages. 78 'action' -- one of "error", "ignore", "always", "default", "module", 79 or "once" 80 'category' -- a class that the warning must be a subclass of 81 'lineno' -- an integer line number, 0 matches all warnings 82 'append' -- if true, append to the list of filters 83 """ 84 assert action in ("error", "ignore", "always", "default", "module", 85 "once"), "invalid action: %r" % (action,) 86 assert isinstance(lineno, int) and lineno >= 0, \ 87 "lineno must be an int >= 0" 88 item = (action, None, category, None, lineno) 89 if append: 90 filters.append(item) 91 else: 92 filters.insert(0, item) 93 94 def resetwarnings(): 95 """Clear the list of warning filters, so that no filters are active.""" 96 filters[:] = [] 97 98 class _OptionError(Exception): 99 """Exception used by option processing helpers.""" 100 pass 101 102 # Helper to process -W options passed via sys.warnoptions 103 def _processoptions(args): 104 for arg in args: 105 try: 106 _setoption(arg) 107 except _OptionError, msg: 108 print >>sys.stderr, "Invalid -W option ignored:", msg 109 110 # Helper for _processoptions() 111 def _setoption(arg): 112 import re 113 parts = arg.split(':') 114 if len(parts) > 5: 115 raise _OptionError("too many fields (max 5): %r" % (arg,)) 116 while len(parts) < 5: 117 parts.append('') 118 action, message, category, module, lineno = [s.strip() 119 for s in parts] 120 action = _getaction(action) 121 message = re.escape(message) 122 category = _getcategory(category) 123 module = re.escape(module) 124 if module: 125 module = module + '$' 126 if lineno: 127 try: 128 lineno = int(lineno) 129 if lineno < 0: 130 raise ValueError 131 except (ValueError, OverflowError): 132 raise _OptionError("invalid lineno %r" % (lineno,)) 133 else: 134 lineno = 0 135 filterwarnings(action, message, category, module, lineno) 136 137 # Helper for _setoption() 138 def _getaction(action): 139 if not action: 140 return "default" 141 if action == "all": return "always" # Alias 142 for a in ('default', 'always', 'ignore', 'module', 'once', 'error'): 143 if a.startswith(action): 144 return a 145 raise _OptionError("invalid action: %r" % (action,)) 146 147 # Helper for _setoption() 148 def _getcategory(category): 149 import re 150 if not category: 151 return Warning 152 if re.match("^[a-zA-Z0-9_]+$", category): 153 try: 154 cat = eval(category) 155 except NameError: 156 raise _OptionError("unknown warning category: %r" % (category,)) 157 else: 158 i = category.rfind(".") 159 module = category[:i] 160 klass = category[i+1:] 161 try: 162 m = __import__(module, None, None, [klass]) 163 except ImportError: 164 raise _OptionError("invalid module name: %r" % (module,)) 165 try: 166 cat = getattr(m, klass) 167 except AttributeError: 168 raise _OptionError("unknown warning category: %r" % (category,)) 169 if not issubclass(cat, Warning): 170 raise _OptionError("invalid warning category: %r" % (category,)) 171 return cat 172 173 174 # Code typically replaced by _warnings 175 def warn(message, category=None, stacklevel=1): 176 """Issue a warning, or maybe ignore it or raise an exception.""" 177 # Check if message is already a Warning object 178 if isinstance(message, Warning): 179 category = message.__class__ 180 # Check category argument 181 if category is None: 182 category = UserWarning 183 assert issubclass(category, Warning) 184 # Get context information 185 try: 186 caller = sys._getframe(stacklevel) 187 except ValueError: 188 globals = sys.__dict__ 189 lineno = 1 190 else: 191 globals = caller.f_globals 192 lineno = caller.f_lineno 193 if '__name__' in globals: 194 module = globals['__name__'] 195 else: 196 module = "<string>" 197 filename = globals.get('__file__') 198 if filename: 199 fnl = filename.lower() 200 if fnl.endswith((".pyc", ".pyo")): 201 filename = filename[:-1] 202 else: 203 if module == "__main__": 204 try: 205 filename = sys.argv[0] 206 except AttributeError: 207 # embedded interpreters don't have sys.argv, see bug #839151 208 filename = '__main__' 209 if not filename: 210 filename = module 211 registry = globals.setdefault("__warningregistry__", {}) 212 warn_explicit(message, category, filename, lineno, module, registry, 213 globals) 214 215 def warn_explicit(message, category, filename, lineno, 216 module=None, registry=None, module_globals=None): 217 lineno = int(lineno) 218 if module is None: 219 module = filename or "<unknown>" 220 if module[-3:].lower() == ".py": 221 module = module[:-3] # XXX What about leading pathname? 222 if registry is None: 223 registry = {} 224 if isinstance(message, Warning): 225 text = str(message) 226 category = message.__class__ 227 else: 228 text = message 229 message = category(message) 230 key = (text, category, lineno) 231 # Quick test for common case 232 if registry.get(key): 233 return 234 # Search the filters 235 for item in filters: 236 action, msg, cat, mod, ln = item 237 if ((msg is None or msg.match(text)) and 238 issubclass(category, cat) and 239 (mod is None or mod.match(module)) and 240 (ln == 0 or lineno == ln)): 241 break 242 else: 243 action = defaultaction 244 # Early exit actions 245 if action == "ignore": 246 registry[key] = 1 247 return 248 249 # Prime the linecache for formatting, in case the 250 # "file" is actually in a zipfile or something. 251 linecache.getlines(filename, module_globals) 252 253 if action == "error": 254 raise message 255 # Other actions 256 if action == "once": 257 registry[key] = 1 258 oncekey = (text, category) 259 if onceregistry.get(oncekey): 260 return 261 onceregistry[oncekey] = 1 262 elif action == "always": 263 pass 264 elif action == "module": 265 registry[key] = 1 266 altkey = (text, category, 0) 267 if registry.get(altkey): 268 return 269 registry[altkey] = 1 270 elif action == "default": 271 registry[key] = 1 272 else: 273 # Unrecognized actions are errors 274 raise RuntimeError( 275 "Unrecognized action (%r) in warnings.filters:\n %s" % 276 (action, item)) 277 # Print message and context 278 showwarning(message, category, filename, lineno) 279 280 281 class WarningMessage(object): 282 283 """Holds the result of a single showwarning() call.""" 284 285 _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", 286 "line") 287 288 def __init__(self, message, category, filename, lineno, file=None, 289 line=None): 290 local_values = locals() 291 for attr in self._WARNING_DETAILS: 292 setattr(self, attr, local_values[attr]) 293 self._category_name = category.__name__ if category else None 294 295 def __str__(self): 296 return ("{message : %r, category : %r, filename : %r, lineno : %s, " 297 "line : %r}" % (self.message, self._category_name, 298 self.filename, self.lineno, self.line)) 299 300 301 class catch_warnings(object): 302 303 """A context manager that copies and restores the warnings filter upon 304 exiting the context. 305 306 The 'record' argument specifies whether warnings should be captured by a 307 custom implementation of warnings.showwarning() and be appended to a list 308 returned by the context manager. Otherwise None is returned by the context 309 manager. The objects appended to the list are arguments whose attributes 310 mirror the arguments to showwarning(). 311 312 The 'module' argument is to specify an alternative module to the module 313 named 'warnings' and imported under that name. This argument is only useful 314 when testing the warnings module itself. 315 316 """ 317 318 def __init__(self, record=False, module=None): 319 """Specify whether to record warnings and if an alternative module 320 should be used other than sys.modules['warnings']. 321 322 For compatibility with Python 3.0, please consider all arguments to be 323 keyword-only. 324 325 """ 326 self._record = record 327 self._module = sys.modules['warnings'] if module is None else module 328 self._entered = False 329 330 def __repr__(self): 331 args = [] 332 if self._record: 333 args.append("record=True") 334 if self._module is not sys.modules['warnings']: 335 args.append("module=%r" % self._module) 336 name = type(self).__name__ 337 return "%s(%s)" % (name, ", ".join(args)) 338 339 def __enter__(self): 340 if self._entered: 341 raise RuntimeError("Cannot enter %r twice" % self) 342 self._entered = True 343 self._filters = self._module.filters 344 self._module.filters = self._filters[:] 345 self._showwarning = self._module.showwarning 346 if self._record: 347 log = [] 348 def showwarning(*args, **kwargs): 349 log.append(WarningMessage(*args, **kwargs)) 350 self._module.showwarning = showwarning 351 return log 352 else: 353 return None 354 355 def __exit__(self, *exc_info): 356 if not self._entered: 357 raise RuntimeError("Cannot exit %r without entering first" % self) 358 self._module.filters = self._filters 359 self._module.showwarning = self._showwarning 360 361 362 # filters contains a sequence of filter 5-tuples 363 # The components of the 5-tuple are: 364 # - an action: error, ignore, always, default, module, or once 365 # - a compiled regex that must match the warning message 366 # - a class representing the warning category 367 # - a compiled regex that must match the module that is being warned 368 # - a line number for the line being warning, or 0 to mean any line 369 # If either if the compiled regexs are None, match anything. 370 _warnings_defaults = False 371 try: 372 from _warnings import (filters, default_action, once_registry, 373 warn, warn_explicit) 374 defaultaction = default_action 375 onceregistry = once_registry 376 _warnings_defaults = True 377 except ImportError: 378 filters = [] 379 defaultaction = "default" 380 onceregistry = {} 381 382 383 # Module initialization 384 _processoptions(sys.warnoptions) 385 if not _warnings_defaults: 386 silence = [ImportWarning, PendingDeprecationWarning] 387 # Don't silence DeprecationWarning if -3 or -Q was used. 388 if not sys.py3kwarning and not sys.flags.division_warning: 389 silence.append(DeprecationWarning) 390 for cls in silence: 391 simplefilter("ignore", category=cls) 392 bytes_warning = sys.flags.bytes_warning 393 if bytes_warning > 1: 394 bytes_action = "error" 395 elif bytes_warning: 396 bytes_action = "default" 397 else: 398 bytes_action = "ignore" 399 simplefilter(bytes_action, category=BytesWarning, append=1) 400 del _warnings_defaults 401