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