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