(root)/
Python-3.12.0/
Lib/
warnings.py
       1  """Python part of the warnings subsystem."""
       2  
       3  import sys
       4  
       5  
       6  __all__ = ["warn", "warn_explicit", "showwarning",
       7             "formatwarning", "filterwarnings", "simplefilter",
       8             "resetwarnings", "catch_warnings"]
       9  
      10  def 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  
      15  def 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  
      20  def _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  
      35  def _formatwarnmsg_impl(msg):
      36      category = msg.category.__name__
      37      s =  f"{msg.filename}:{msg.lineno}: {category}: {msg.message}\n"
      38  
      39      if msg.line is None:
      40          try:
      41              import linecache
      42              line = linecache.getline(msg.filename, msg.lineno)
      43          except Exception:
      44              # When a warning is logged during Python shutdown, linecache
      45              # and the import machinery don't work anymore
      46              line = None
      47              linecache = None
      48      else:
      49          line = msg.line
      50      if line:
      51          line = line.strip()
      52          s += "  %s\n" % line
      53  
      54      if msg.source is not None:
      55          try:
      56              import tracemalloc
      57          # Logging a warning should not raise a new exception:
      58          # catch Exception, not only ImportError and RecursionError.
      59          except Exception:
      60              # don't suggest to enable tracemalloc if it's not available
      61              tracing = True
      62              tb = None
      63          else:
      64              tracing = tracemalloc.is_tracing()
      65              try:
      66                  tb = tracemalloc.get_object_traceback(msg.source)
      67              except Exception:
      68                  # When a warning is logged during Python shutdown, tracemalloc
      69                  # and the import machinery don't work anymore
      70                  tb = None
      71  
      72          if tb is not None:
      73              s += 'Object allocated at (most recent call last):\n'
      74              for frame in tb:
      75                  s += ('  File "%s", lineno %s\n'
      76                        % (frame.filename, frame.lineno))
      77  
      78                  try:
      79                      if linecache is not None:
      80                          line = linecache.getline(frame.filename, frame.lineno)
      81                      else:
      82                          line = None
      83                  except Exception:
      84                      line = None
      85                  if line:
      86                      line = line.strip()
      87                      s += '    %s\n' % line
      88          elif not tracing:
      89              s += (f'{category}: Enable tracemalloc to get the object '
      90                    f'allocation traceback\n')
      91      return s
      92  
      93  # Keep a reference to check if the function was replaced
      94  _showwarning_orig = showwarning
      95  
      96  def _showwarnmsg(msg):
      97      """Hook to write a warning to a file; replace if you like."""
      98      try:
      99          sw = showwarning
     100      except NameError:
     101          pass
     102      else:
     103          if sw is not _showwarning_orig:
     104              # warnings.showwarning() was replaced
     105              if not callable(sw):
     106                  raise TypeError("warnings.showwarning() must be set to a "
     107                                  "function or method")
     108  
     109              sw(msg.message, msg.category, msg.filename, msg.lineno,
     110                 msg.file, msg.line)
     111              return
     112      _showwarnmsg_impl(msg)
     113  
     114  # Keep a reference to check if the function was replaced
     115  _formatwarning_orig = formatwarning
     116  
     117  def _formatwarnmsg(msg):
     118      """Function to format a warning the standard way."""
     119      try:
     120          fw = formatwarning
     121      except NameError:
     122          pass
     123      else:
     124          if fw is not _formatwarning_orig:
     125              # warnings.formatwarning() was replaced
     126              return fw(msg.message, msg.category,
     127                        msg.filename, msg.lineno, msg.line)
     128      return _formatwarnmsg_impl(msg)
     129  
     130  def filterwarnings(action, message="", category=Warning, module="", lineno=0,
     131                     append=False):
     132      """Insert an entry into the list of warnings filters (at the front).
     133  
     134      'action' -- one of "error", "ignore", "always", "default", "module",
     135                  or "once"
     136      'message' -- a regex that the warning message must match
     137      'category' -- a class that the warning must be a subclass of
     138      'module' -- a regex that the module name must match
     139      'lineno' -- an integer line number, 0 matches all warnings
     140      'append' -- if true, append to the list of filters
     141      """
     142      assert action in ("error", "ignore", "always", "default", "module",
     143                        "once"), "invalid action: %r" % (action,)
     144      assert isinstance(message, str), "message must be a string"
     145      assert isinstance(category, type), "category must be a class"
     146      assert issubclass(category, Warning), "category must be a Warning subclass"
     147      assert isinstance(module, str), "module must be a string"
     148      assert isinstance(lineno, int) and lineno >= 0, \
     149             "lineno must be an int >= 0"
     150  
     151      if message or module:
     152          import re
     153  
     154      if message:
     155          message = re.compile(message, re.I)
     156      else:
     157          message = None
     158      if module:
     159          module = re.compile(module)
     160      else:
     161          module = None
     162  
     163      _add_filter(action, message, category, module, lineno, append=append)
     164  
     165  def simplefilter(action, category=Warning, lineno=0, append=False):
     166      """Insert a simple entry into the list of warnings filters (at the front).
     167  
     168      A simple filter matches all modules and messages.
     169      'action' -- one of "error", "ignore", "always", "default", "module",
     170                  or "once"
     171      'category' -- a class that the warning must be a subclass of
     172      'lineno' -- an integer line number, 0 matches all warnings
     173      'append' -- if true, append to the list of filters
     174      """
     175      assert action in ("error", "ignore", "always", "default", "module",
     176                        "once"), "invalid action: %r" % (action,)
     177      assert isinstance(lineno, int) and lineno >= 0, \
     178             "lineno must be an int >= 0"
     179      _add_filter(action, None, category, None, lineno, append=append)
     180  
     181  def _add_filter(*item, append):
     182      # Remove possible duplicate filters, so new one will be placed
     183      # in correct place. If append=True and duplicate exists, do nothing.
     184      if not append:
     185          try:
     186              filters.remove(item)
     187          except ValueError:
     188              pass
     189          filters.insert(0, item)
     190      else:
     191          if item not in filters:
     192              filters.append(item)
     193      _filters_mutated()
     194  
     195  def resetwarnings():
     196      """Clear the list of warning filters, so that no filters are active."""
     197      filters[:] = []
     198      _filters_mutated()
     199  
     200  class ESC[4;38;5;81m_OptionError(ESC[4;38;5;149mException):
     201      """Exception used by option processing helpers."""
     202      pass
     203  
     204  # Helper to process -W options passed via sys.warnoptions
     205  def _processoptions(args):
     206      for arg in args:
     207          try:
     208              _setoption(arg)
     209          except _OptionError as msg:
     210              print("Invalid -W option ignored:", msg, file=sys.stderr)
     211  
     212  # Helper for _processoptions()
     213  def _setoption(arg):
     214      parts = arg.split(':')
     215      if len(parts) > 5:
     216          raise _OptionError("too many fields (max 5): %r" % (arg,))
     217      while len(parts) < 5:
     218          parts.append('')
     219      action, message, category, module, lineno = [s.strip()
     220                                                   for s in parts]
     221      action = _getaction(action)
     222      category = _getcategory(category)
     223      if message or module:
     224          import re
     225      if message:
     226          message = re.escape(message)
     227      if module:
     228          module = re.escape(module) + r'\Z'
     229      if lineno:
     230          try:
     231              lineno = int(lineno)
     232              if lineno < 0:
     233                  raise ValueError
     234          except (ValueError, OverflowError):
     235              raise _OptionError("invalid lineno %r" % (lineno,)) from None
     236      else:
     237          lineno = 0
     238      filterwarnings(action, message, category, module, lineno)
     239  
     240  # Helper for _setoption()
     241  def _getaction(action):
     242      if not action:
     243          return "default"
     244      if action == "all": return "always" # Alias
     245      for a in ('default', 'always', 'ignore', 'module', 'once', 'error'):
     246          if a.startswith(action):
     247              return a
     248      raise _OptionError("invalid action: %r" % (action,))
     249  
     250  # Helper for _setoption()
     251  def _getcategory(category):
     252      if not category:
     253          return Warning
     254      if '.' not in category:
     255          import builtins as m
     256          klass = category
     257      else:
     258          module, _, klass = category.rpartition('.')
     259          try:
     260              m = __import__(module, None, None, [klass])
     261          except ImportError:
     262              raise _OptionError("invalid module name: %r" % (module,)) from None
     263      try:
     264          cat = getattr(m, klass)
     265      except AttributeError:
     266          raise _OptionError("unknown warning category: %r" % (category,)) from None
     267      if not issubclass(cat, Warning):
     268          raise _OptionError("invalid warning category: %r" % (category,))
     269      return cat
     270  
     271  
     272  def _is_internal_filename(filename):
     273      return 'importlib' in filename and '_bootstrap' in filename
     274  
     275  
     276  def _is_filename_to_skip(filename, skip_file_prefixes):
     277      return any(filename.startswith(prefix) for prefix in skip_file_prefixes)
     278  
     279  
     280  def _is_internal_frame(frame):
     281      """Signal whether the frame is an internal CPython implementation detail."""
     282      return _is_internal_filename(frame.f_code.co_filename)
     283  
     284  
     285  def _next_external_frame(frame, skip_file_prefixes):
     286      """Find the next frame that doesn't involve Python or user internals."""
     287      frame = frame.f_back
     288      while frame is not None and (
     289              _is_internal_filename(filename := frame.f_code.co_filename) or
     290              _is_filename_to_skip(filename, skip_file_prefixes)):
     291          frame = frame.f_back
     292      return frame
     293  
     294  
     295  # Code typically replaced by _warnings
     296  def warn(message, category=None, stacklevel=1, source=None,
     297           *, skip_file_prefixes=()):
     298      """Issue a warning, or maybe ignore it or raise an exception."""
     299      # Check if message is already a Warning object
     300      if isinstance(message, Warning):
     301          category = message.__class__
     302      # Check category argument
     303      if category is None:
     304          category = UserWarning
     305      if not (isinstance(category, type) and issubclass(category, Warning)):
     306          raise TypeError("category must be a Warning subclass, "
     307                          "not '{:s}'".format(type(category).__name__))
     308      if not isinstance(skip_file_prefixes, tuple):
     309          # The C version demands a tuple for implementation performance.
     310          raise TypeError('skip_file_prefixes must be a tuple of strs.')
     311      if skip_file_prefixes:
     312          stacklevel = max(2, stacklevel)
     313      # Get context information
     314      try:
     315          if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)):
     316              # If frame is too small to care or if the warning originated in
     317              # internal code, then do not try to hide any frames.
     318              frame = sys._getframe(stacklevel)
     319          else:
     320              frame = sys._getframe(1)
     321              # Look for one frame less since the above line starts us off.
     322              for x in range(stacklevel-1):
     323                  frame = _next_external_frame(frame, skip_file_prefixes)
     324                  if frame is None:
     325                      raise ValueError
     326      except ValueError:
     327          globals = sys.__dict__
     328          filename = "sys"
     329          lineno = 1
     330      else:
     331          globals = frame.f_globals
     332          filename = frame.f_code.co_filename
     333          lineno = frame.f_lineno
     334      if '__name__' in globals:
     335          module = globals['__name__']
     336      else:
     337          module = "<string>"
     338      registry = globals.setdefault("__warningregistry__", {})
     339      warn_explicit(message, category, filename, lineno, module, registry,
     340                    globals, source)
     341  
     342  def warn_explicit(message, category, filename, lineno,
     343                    module=None, registry=None, module_globals=None,
     344                    source=None):
     345      lineno = int(lineno)
     346      if module is None:
     347          module = filename or "<unknown>"
     348          if module[-3:].lower() == ".py":
     349              module = module[:-3] # XXX What about leading pathname?
     350      if registry is None:
     351          registry = {}
     352      if registry.get('version', 0) != _filters_version:
     353          registry.clear()
     354          registry['version'] = _filters_version
     355      if isinstance(message, Warning):
     356          text = str(message)
     357          category = message.__class__
     358      else:
     359          text = message
     360          message = category(message)
     361      key = (text, category, lineno)
     362      # Quick test for common case
     363      if registry.get(key):
     364          return
     365      # Search the filters
     366      for item in filters:
     367          action, msg, cat, mod, ln = item
     368          if ((msg is None or msg.match(text)) and
     369              issubclass(category, cat) and
     370              (mod is None or mod.match(module)) and
     371              (ln == 0 or lineno == ln)):
     372              break
     373      else:
     374          action = defaultaction
     375      # Early exit actions
     376      if action == "ignore":
     377          return
     378  
     379      # Prime the linecache for formatting, in case the
     380      # "file" is actually in a zipfile or something.
     381      import linecache
     382      linecache.getlines(filename, module_globals)
     383  
     384      if action == "error":
     385          raise message
     386      # Other actions
     387      if action == "once":
     388          registry[key] = 1
     389          oncekey = (text, category)
     390          if onceregistry.get(oncekey):
     391              return
     392          onceregistry[oncekey] = 1
     393      elif action == "always":
     394          pass
     395      elif action == "module":
     396          registry[key] = 1
     397          altkey = (text, category, 0)
     398          if registry.get(altkey):
     399              return
     400          registry[altkey] = 1
     401      elif action == "default":
     402          registry[key] = 1
     403      else:
     404          # Unrecognized actions are errors
     405          raise RuntimeError(
     406                "Unrecognized action (%r) in warnings.filters:\n %s" %
     407                (action, item))
     408      # Print message and context
     409      msg = WarningMessage(message, category, filename, lineno, source)
     410      _showwarnmsg(msg)
     411  
     412  
     413  class ESC[4;38;5;81mWarningMessage(ESC[4;38;5;149mobject):
     414  
     415      _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
     416                          "line", "source")
     417  
     418      def __init__(self, message, category, filename, lineno, file=None,
     419                   line=None, source=None):
     420          self.message = message
     421          self.category = category
     422          self.filename = filename
     423          self.lineno = lineno
     424          self.file = file
     425          self.line = line
     426          self.source = source
     427          self._category_name = category.__name__ if category else None
     428  
     429      def __str__(self):
     430          return ("{message : %r, category : %r, filename : %r, lineno : %s, "
     431                      "line : %r}" % (self.message, self._category_name,
     432                                      self.filename, self.lineno, self.line))
     433  
     434  
     435  class ESC[4;38;5;81mcatch_warnings(ESC[4;38;5;149mobject):
     436  
     437      """A context manager that copies and restores the warnings filter upon
     438      exiting the context.
     439  
     440      The 'record' argument specifies whether warnings should be captured by a
     441      custom implementation of warnings.showwarning() and be appended to a list
     442      returned by the context manager. Otherwise None is returned by the context
     443      manager. The objects appended to the list are arguments whose attributes
     444      mirror the arguments to showwarning().
     445  
     446      The 'module' argument is to specify an alternative module to the module
     447      named 'warnings' and imported under that name. This argument is only useful
     448      when testing the warnings module itself.
     449  
     450      If the 'action' argument is not None, the remaining arguments are passed
     451      to warnings.simplefilter() as if it were called immediately on entering the
     452      context.
     453      """
     454  
     455      def __init__(self, *, record=False, module=None,
     456                   action=None, category=Warning, lineno=0, append=False):
     457          """Specify whether to record warnings and if an alternative module
     458          should be used other than sys.modules['warnings'].
     459  
     460          For compatibility with Python 3.0, please consider all arguments to be
     461          keyword-only.
     462  
     463          """
     464          self._record = record
     465          self._module = sys.modules['warnings'] if module is None else module
     466          self._entered = False
     467          if action is None:
     468              self._filter = None
     469          else:
     470              self._filter = (action, category, lineno, append)
     471  
     472      def __repr__(self):
     473          args = []
     474          if self._record:
     475              args.append("record=True")
     476          if self._module is not sys.modules['warnings']:
     477              args.append("module=%r" % self._module)
     478          name = type(self).__name__
     479          return "%s(%s)" % (name, ", ".join(args))
     480  
     481      def __enter__(self):
     482          if self._entered:
     483              raise RuntimeError("Cannot enter %r twice" % self)
     484          self._entered = True
     485          self._filters = self._module.filters
     486          self._module.filters = self._filters[:]
     487          self._module._filters_mutated()
     488          self._showwarning = self._module.showwarning
     489          self._showwarnmsg_impl = self._module._showwarnmsg_impl
     490          if self._filter is not None:
     491              simplefilter(*self._filter)
     492          if self._record:
     493              log = []
     494              self._module._showwarnmsg_impl = log.append
     495              # Reset showwarning() to the default implementation to make sure
     496              # that _showwarnmsg() calls _showwarnmsg_impl()
     497              self._module.showwarning = self._module._showwarning_orig
     498              return log
     499          else:
     500              return None
     501  
     502      def __exit__(self, *exc_info):
     503          if not self._entered:
     504              raise RuntimeError("Cannot exit %r without entering first" % self)
     505          self._module.filters = self._filters
     506          self._module._filters_mutated()
     507          self._module.showwarning = self._showwarning
     508          self._module._showwarnmsg_impl = self._showwarnmsg_impl
     509  
     510  
     511  _DEPRECATED_MSG = "{name!r} is deprecated and slated for removal in Python {remove}"
     512  
     513  def _deprecated(name, message=_DEPRECATED_MSG, *, remove, _version=sys.version_info):
     514      """Warn that *name* is deprecated or should be removed.
     515  
     516      RuntimeError is raised if *remove* specifies a major/minor tuple older than
     517      the current Python version or the same version but past the alpha.
     518  
     519      The *message* argument is formatted with *name* and *remove* as a Python
     520      version (e.g. "3.11").
     521  
     522      """
     523      remove_formatted = f"{remove[0]}.{remove[1]}"
     524      if (_version[:2] > remove) or (_version[:2] == remove and _version[3] != "alpha"):
     525          msg = f"{name!r} was slated for removal after Python {remove_formatted} alpha"
     526          raise RuntimeError(msg)
     527      else:
     528          msg = message.format(name=name, remove=remove_formatted)
     529          warn(msg, DeprecationWarning, stacklevel=3)
     530  
     531  
     532  # Private utility function called by _PyErr_WarnUnawaitedCoroutine
     533  def _warn_unawaited_coroutine(coro):
     534      msg_lines = [
     535          f"coroutine '{coro.__qualname__}' was never awaited\n"
     536      ]
     537      if coro.cr_origin is not None:
     538          import linecache, traceback
     539          def extract():
     540              for filename, lineno, funcname in reversed(coro.cr_origin):
     541                  line = linecache.getline(filename, lineno)
     542                  yield (filename, lineno, funcname, line)
     543          msg_lines.append("Coroutine created at (most recent call last)\n")
     544          msg_lines += traceback.format_list(list(extract()))
     545      msg = "".join(msg_lines).rstrip("\n")
     546      # Passing source= here means that if the user happens to have tracemalloc
     547      # enabled and tracking where the coroutine was created, the warning will
     548      # contain that traceback. This does mean that if they have *both*
     549      # coroutine origin tracking *and* tracemalloc enabled, they'll get two
     550      # partially-redundant tracebacks. If we wanted to be clever we could
     551      # probably detect this case and avoid it, but for now we don't bother.
     552      warn(msg, category=RuntimeWarning, stacklevel=2, source=coro)
     553  
     554  
     555  # filters contains a sequence of filter 5-tuples
     556  # The components of the 5-tuple are:
     557  # - an action: error, ignore, always, default, module, or once
     558  # - a compiled regex that must match the warning message
     559  # - a class representing the warning category
     560  # - a compiled regex that must match the module that is being warned
     561  # - a line number for the line being warning, or 0 to mean any line
     562  # If either if the compiled regexs are None, match anything.
     563  try:
     564      from _warnings import (filters, _defaultaction, _onceregistry,
     565                             warn, warn_explicit, _filters_mutated)
     566      defaultaction = _defaultaction
     567      onceregistry = _onceregistry
     568      _warnings_defaults = True
     569  except ImportError:
     570      filters = []
     571      defaultaction = "default"
     572      onceregistry = {}
     573  
     574      _filters_version = 1
     575  
     576      def _filters_mutated():
     577          global _filters_version
     578          _filters_version += 1
     579  
     580      _warnings_defaults = False
     581  
     582  
     583  # Module initialization
     584  _processoptions(sys.warnoptions)
     585  if not _warnings_defaults:
     586      # Several warning categories are ignored by default in regular builds
     587      if not hasattr(sys, 'gettotalrefcount'):
     588          filterwarnings("default", category=DeprecationWarning,
     589                         module="__main__", append=1)
     590          simplefilter("ignore", category=DeprecationWarning, append=1)
     591          simplefilter("ignore", category=PendingDeprecationWarning, append=1)
     592          simplefilter("ignore", category=ImportWarning, append=1)
     593          simplefilter("ignore", category=ResourceWarning, append=1)
     594  
     595  del _warnings_defaults