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