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