1"""Python part of the warnings subsystem.""" 2 3import sys 4 5 6__all__ = ["warn", "warn_explicit", "showwarning", 7 "formatwarning", "filterwarnings", "simplefilter", 8 "resetwarnings", "catch_warnings"] 9 10def showwarning(message, category, filename, lineno, file=None, line=None): 11 """Hook to write a warning to a file; replace if you like.""" 12 msg = WarningMessage(message, category, filename, lineno, file, line) 13 _showwarnmsg_impl(msg) 14 15def formatwarning(message, category, filename, lineno, line=None): 16 """Function to format a warning the standard way.""" 17 msg = WarningMessage(message, category, filename, lineno, None, line) 18 return _formatwarnmsg_impl(msg) 19 20def _showwarnmsg_impl(msg): 21 file = msg.file 22 if file is None: 23 file = sys.stderr 24 if file is None: 25 # sys.stderr is None when run with pythonw.exe: 26 # warnings get lost 27 return 28 text = _formatwarnmsg(msg) 29 try: 30 file.write(text) 31 except OSError: 32 # the file (probably stderr) is invalid - this warning gets lost. 33 pass 34 35def _formatwarnmsg_impl(msg): 36 s = ("%s:%s: %s: %s\n" 37 % (msg.filename, msg.lineno, msg.category.__name__, 38 msg.message)) 39 40 if msg.line is None: 41 try: 42 import linecache 43 line = linecache.getline(msg.filename, msg.lineno) 44 except Exception: 45 # When a warning is logged during Python shutdown, linecache 46 # and the import machinery don't work anymore 47 line = None 48 linecache = None 49 else: 50 line = msg.line 51 if line: 52 line = line.strip() 53 s += " %s\n" % line 54 55 if msg.source is not None: 56 try: 57 import tracemalloc 58 tb = tracemalloc.get_object_traceback(msg.source) 59 except Exception: 60 # When a warning is logged during Python shutdown, tracemalloc 61 # and the import machinery don't work anymore 62 tb = None 63 64 if tb is not None: 65 s += 'Object allocated at (most recent call first):\n' 66 for frame in tb: 67 s += (' File "%s", lineno %s\n' 68 % (frame.filename, frame.lineno)) 69 70 try: 71 if linecache is not None: 72 line = linecache.getline(frame.filename, frame.lineno) 73 else: 74 line = None 75 except Exception: 76 line = None 77 if line: 78 line = line.strip() 79 s += ' %s\n' % line 80 return s 81 82# Keep a reference to check if the function was replaced 83_showwarning_orig = showwarning 84 85def _showwarnmsg(msg): 86 """Hook to write a warning to a file; replace if you like.""" 87 try: 88 sw = showwarning 89 except NameError: 90 pass 91 else: 92 if sw is not _showwarning_orig: 93 # warnings.showwarning() was replaced 94 if not callable(sw): 95 raise TypeError("warnings.showwarning() must be set to a " 96 "function or method") 97 98 sw(msg.message, msg.category, msg.filename, msg.lineno, 99 msg.file, msg.line) 100 return 101 _showwarnmsg_impl(msg) 102 103# Keep a reference to check if the function was replaced 104_formatwarning_orig = formatwarning 105 106def _formatwarnmsg(msg): 107 """Function to format a warning the standard way.""" 108 try: 109 fw = formatwarning 110 except NameError: 111 pass 112 else: 113 if fw is not _formatwarning_orig: 114 # warnings.formatwarning() was replaced 115 return fw(msg.message, msg.category, 116 msg.filename, msg.lineno, line=msg.line) 117 return _formatwarnmsg_impl(msg) 118 119def filterwarnings(action, message="", category=Warning, module="", lineno=0, 120 append=False): 121 """Insert an entry into the list of warnings filters (at the front). 122 123 'action' -- one of "error", "ignore", "always", "default", "module", 124 or "once" 125 'message' -- a regex that the warning message must match 126 'category' -- a class that the warning must be a subclass of 127 'module' -- a regex that the module name must match 128 'lineno' -- an integer line number, 0 matches all warnings 129 'append' -- if true, append to the list of filters 130 """ 131 import re 132 assert action in ("error", "ignore", "always", "default", "module", 133 "once"), "invalid action: %r" % (action,) 134 assert isinstance(message, str), "message must be a string" 135 assert isinstance(category, type), "category must be a class" 136 assert issubclass(category, Warning), "category must be a Warning subclass" 137 assert isinstance(module, str), "module must be a string" 138 assert isinstance(lineno, int) and lineno >= 0, \ 139 "lineno must be an int >= 0" 140 _add_filter(action, re.compile(message, re.I), category, 141 re.compile(module), lineno, append=append) 142 143def simplefilter(action, category=Warning, lineno=0, append=False): 144 """Insert a simple entry into the list of warnings filters (at the front). 145 146 A simple filter matches all modules and messages. 147 'action' -- one of "error", "ignore", "always", "default", "module", 148 or "once" 149 'category' -- a class that the warning must be a subclass of 150 'lineno' -- an integer line number, 0 matches all warnings 151 'append' -- if true, append to the list of filters 152 """ 153 assert action in ("error", "ignore", "always", "default", "module", 154 "once"), "invalid action: %r" % (action,) 155 assert isinstance(lineno, int) and lineno >= 0, \ 156 "lineno must be an int >= 0" 157 _add_filter(action, None, category, None, lineno, append=append) 158 159def _add_filter(*item, append): 160 # Remove possible duplicate filters, so new one will be placed 161 # in correct place. If append=True and duplicate exists, do nothing. 162 if not append: 163 try: 164 filters.remove(item) 165 except ValueError: 166 pass 167 filters.insert(0, item) 168 else: 169 if item not in filters: 170 filters.append(item) 171 _filters_mutated() 172 173def resetwarnings(): 174 """Clear the list of warning filters, so that no filters are active.""" 175 filters[:] = [] 176 _filters_mutated() 177 178class _OptionError(Exception): 179 """Exception used by option processing helpers.""" 180 pass 181 182# Helper to process -W options passed via sys.warnoptions 183def _processoptions(args): 184 for arg in args: 185 try: 186 _setoption(arg) 187 except _OptionError as msg: 188 print("Invalid -W option ignored:", msg, file=sys.stderr) 189 190# Helper for _processoptions() 191def _setoption(arg): 192 import re 193 parts = arg.split(':') 194 if len(parts) > 5: 195 raise _OptionError("too many fields (max 5): %r" % (arg,)) 196 while len(parts) < 5: 197 parts.append('') 198 action, message, category, module, lineno = [s.strip() 199 for s in parts] 200 action = _getaction(action) 201 message = re.escape(message) 202 category = _getcategory(category) 203 module = re.escape(module) 204 if module: 205 module = module + '$' 206 if lineno: 207 try: 208 lineno = int(lineno) 209 if lineno < 0: 210 raise ValueError 211 except (ValueError, OverflowError): 212 raise _OptionError("invalid lineno %r" % (lineno,)) 213 else: 214 lineno = 0 215 filterwarnings(action, message, category, module, lineno) 216 217# Helper for _setoption() 218def _getaction(action): 219 if not action: 220 return "default" 221 if action == "all": return "always" # Alias 222 for a in ('default', 'always', 'ignore', 'module', 'once', 'error'): 223 if a.startswith(action): 224 return a 225 raise _OptionError("invalid action: %r" % (action,)) 226 227# Helper for _setoption() 228def _getcategory(category): 229 import re 230 if not category: 231 return Warning 232 if re.match("^[a-zA-Z0-9_]+$", category): 233 try: 234 cat = eval(category) 235 except NameError: 236 raise _OptionError("unknown warning category: %r" % (category,)) 237 else: 238 i = category.rfind(".") 239 module = category[:i] 240 klass = category[i+1:] 241 try: 242 m = __import__(module, None, None, [klass]) 243 except ImportError: 244 raise _OptionError("invalid module name: %r" % (module,)) 245 try: 246 cat = getattr(m, klass) 247 except AttributeError: 248 raise _OptionError("unknown warning category: %r" % (category,)) 249 if not issubclass(cat, Warning): 250 raise _OptionError("invalid warning category: %r" % (category,)) 251 return cat 252 253 254def _is_internal_frame(frame): 255 """Signal whether the frame is an internal CPython implementation detail.""" 256 filename = frame.f_code.co_filename 257 return 'importlib' in filename and '_bootstrap' in filename 258 259 260def _next_external_frame(frame): 261 """Find the next frame that doesn't involve CPython internals.""" 262 frame = frame.f_back 263 while frame is not None and _is_internal_frame(frame): 264 frame = frame.f_back 265 return frame 266 267 268# Code typically replaced by _warnings 269def warn(message, category=None, stacklevel=1, source=None): 270 """Issue a warning, or maybe ignore it or raise an exception.""" 271 # Check if message is already a Warning object 272 if isinstance(message, Warning): 273 category = message.__class__ 274 # Check category argument 275 if category is None: 276 category = UserWarning 277 if not (isinstance(category, type) and issubclass(category, Warning)): 278 raise TypeError("category must be a Warning subclass, " 279 "not '{:s}'".format(type(category).__name__)) 280 # Get context information 281 try: 282 if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)): 283 # If frame is too small to care or if the warning originated in 284 # internal code, then do not try to hide any frames. 285 frame = sys._getframe(stacklevel) 286 else: 287 frame = sys._getframe(1) 288 # Look for one frame less since the above line starts us off. 289 for x in range(stacklevel-1): 290 frame = _next_external_frame(frame) 291 if frame is None: 292 raise ValueError 293 except ValueError: 294 globals = sys.__dict__ 295 lineno = 1 296 else: 297 globals = frame.f_globals 298 lineno = frame.f_lineno 299 if '__name__' in globals: 300 module = globals['__name__'] 301 else: 302 module = "<string>" 303 filename = globals.get('__file__') 304 if filename: 305 fnl = filename.lower() 306 if fnl.endswith(".pyc"): 307 filename = filename[:-1] 308 else: 309 if module == "__main__": 310 try: 311 filename = sys.argv[0] 312 except AttributeError: 313 # embedded interpreters don't have sys.argv, see bug #839151 314 filename = '__main__' 315 if not filename: 316 filename = module 317 registry = globals.setdefault("__warningregistry__", {}) 318 warn_explicit(message, category, filename, lineno, module, registry, 319 globals, source) 320 321def warn_explicit(message, category, filename, lineno, 322 module=None, registry=None, module_globals=None, 323 source=None): 324 lineno = int(lineno) 325 if module is None: 326 module = filename or "<unknown>" 327 if module[-3:].lower() == ".py": 328 module = module[:-3] # XXX What about leading pathname? 329 if registry is None: 330 registry = {} 331 if registry.get('version', 0) != _filters_version: 332 registry.clear() 333 registry['version'] = _filters_version 334 if isinstance(message, Warning): 335 text = str(message) 336 category = message.__class__ 337 else: 338 text = message 339 message = category(message) 340 key = (text, category, lineno) 341 # Quick test for common case 342 if registry.get(key): 343 return 344 # Search the filters 345 for item in filters: 346 action, msg, cat, mod, ln = item 347 if ((msg is None or msg.match(text)) and 348 issubclass(category, cat) and 349 (mod is None or mod.match(module)) and 350 (ln == 0 or lineno == ln)): 351 break 352 else: 353 action = defaultaction 354 # Early exit actions 355 if action == "ignore": 356 registry[key] = 1 357 return 358 359 # Prime the linecache for formatting, in case the 360 # "file" is actually in a zipfile or something. 361 import linecache 362 linecache.getlines(filename, module_globals) 363 364 if action == "error": 365 raise message 366 # Other actions 367 if action == "once": 368 registry[key] = 1 369 oncekey = (text, category) 370 if onceregistry.get(oncekey): 371 return 372 onceregistry[oncekey] = 1 373 elif action == "always": 374 pass 375 elif action == "module": 376 registry[key] = 1 377 altkey = (text, category, 0) 378 if registry.get(altkey): 379 return 380 registry[altkey] = 1 381 elif action == "default": 382 registry[key] = 1 383 else: 384 # Unrecognized actions are errors 385 raise RuntimeError( 386 "Unrecognized action (%r) in warnings.filters:\n %s" % 387 (action, item)) 388 # Print message and context 389 msg = WarningMessage(message, category, filename, lineno, source) 390 _showwarnmsg(msg) 391 392 393class WarningMessage(object): 394 395 _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", 396 "line", "source") 397 398 def __init__(self, message, category, filename, lineno, file=None, 399 line=None, source=None): 400 local_values = locals() 401 for attr in self._WARNING_DETAILS: 402 setattr(self, attr, local_values[attr]) 403 self._category_name = category.__name__ if category else None 404 405 def __str__(self): 406 return ("{message : %r, category : %r, filename : %r, lineno : %s, " 407 "line : %r}" % (self.message, self._category_name, 408 self.filename, self.lineno, self.line)) 409 410 411class catch_warnings(object): 412 413 """A context manager that copies and restores the warnings filter upon 414 exiting the context. 415 416 The 'record' argument specifies whether warnings should be captured by a 417 custom implementation of warnings.showwarning() and be appended to a list 418 returned by the context manager. Otherwise None is returned by the context 419 manager. The objects appended to the list are arguments whose attributes 420 mirror the arguments to showwarning(). 421 422 The 'module' argument is to specify an alternative module to the module 423 named 'warnings' and imported under that name. This argument is only useful 424 when testing the warnings module itself. 425 426 """ 427 428 def __init__(self, *, record=False, module=None): 429 """Specify whether to record warnings and if an alternative module 430 should be used other than sys.modules['warnings']. 431 432 For compatibility with Python 3.0, please consider all arguments to be 433 keyword-only. 434 435 """ 436 self._record = record 437 self._module = sys.modules['warnings'] if module is None else module 438 self._entered = False 439 440 def __repr__(self): 441 args = [] 442 if self._record: 443 args.append("record=True") 444 if self._module is not sys.modules['warnings']: 445 args.append("module=%r" % self._module) 446 name = type(self).__name__ 447 return "%s(%s)" % (name, ", ".join(args)) 448 449 def __enter__(self): 450 if self._entered: 451 raise RuntimeError("Cannot enter %r twice" % self) 452 self._entered = True 453 self._filters = self._module.filters 454 self._module.filters = self._filters[:] 455 self._module._filters_mutated() 456 self._showwarning = self._module.showwarning 457 self._showwarnmsg_impl = self._module._showwarnmsg_impl 458 if self._record: 459 log = [] 460 self._module._showwarnmsg_impl = log.append 461 # Reset showwarning() to the default implementation to make sure 462 # that _showwarnmsg() calls _showwarnmsg_impl() 463 self._module.showwarning = self._module._showwarning_orig 464 return log 465 else: 466 return None 467 468 def __exit__(self, *exc_info): 469 if not self._entered: 470 raise RuntimeError("Cannot exit %r without entering first" % self) 471 self._module.filters = self._filters 472 self._module._filters_mutated() 473 self._module.showwarning = self._showwarning 474 self._module._showwarnmsg_impl = self._showwarnmsg_impl 475 476 477# filters contains a sequence of filter 5-tuples 478# The components of the 5-tuple are: 479# - an action: error, ignore, always, default, module, or once 480# - a compiled regex that must match the warning message 481# - a class representing the warning category 482# - a compiled regex that must match the module that is being warned 483# - a line number for the line being warning, or 0 to mean any line 484# If either if the compiled regexs are None, match anything. 485_warnings_defaults = False 486try: 487 from _warnings import (filters, _defaultaction, _onceregistry, 488 warn, warn_explicit, _filters_mutated) 489 defaultaction = _defaultaction 490 onceregistry = _onceregistry 491 _warnings_defaults = True 492except ImportError: 493 filters = [] 494 defaultaction = "default" 495 onceregistry = {} 496 497 _filters_version = 1 498 499 def _filters_mutated(): 500 global _filters_version 501 _filters_version += 1 502 503 504# Module initialization 505_processoptions(sys.warnoptions) 506if not _warnings_defaults: 507 silence = [ImportWarning, PendingDeprecationWarning] 508 silence.append(DeprecationWarning) 509 for cls in silence: 510 simplefilter("ignore", category=cls) 511 bytes_warning = sys.flags.bytes_warning 512 if bytes_warning > 1: 513 bytes_action = "error" 514 elif bytes_warning: 515 bytes_action = "default" 516 else: 517 bytes_action = "ignore" 518 simplefilter(bytes_action, category=BytesWarning, append=1) 519 # resource usage warnings are enabled by default in pydebug mode 520 if hasattr(sys, 'gettotalrefcount'): 521 resource_action = "always" 522 else: 523 resource_action = "ignore" 524 simplefilter(resource_action, category=ResourceWarning, append=1) 525 526del _warnings_defaults 527