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