"""Python part of the warnings subsystem."""
__all__ = ["warn", "warn_explicit", "showwarning",
"formatwarning", "filterwarnings", "simplefilter",
"resetwarnings", "catch_warnings"]
def showwarning(message, category, filename, lineno, file=None, line=None):
"""Hook to write a warning to a file; replace if you like."""
msg = WarningMessage(message, category, filename, lineno, file, line)
def formatwarning(message, category, filename, lineno, line=None):
"""Function to format a warning the standard way."""
msg = WarningMessage(message, category, filename, lineno, None, line)
return _formatwarnmsg_impl(msg)
def _showwarnmsg_impl(msg):
# sys.stderr is None when run with pythonw.exe:
text = _formatwarnmsg(msg)
# the file (probably stderr) is invalid - this warning gets lost.
def _formatwarnmsg_impl(msg):
category = msg.category.__name__
s = f"{msg.filename}:{msg.lineno}: {category}: {msg.message}\n"
line = linecache.getline(msg.filename, msg.lineno)
# When a warning is logged during Python shutdown, linecache
# and the import machinery don't work anymore
if msg.source is not None:
# Logging a warning should not raise a new exception:
# catch Exception, not only ImportError and RecursionError.
# don't suggest to enable tracemalloc if it's not available
tracing = tracemalloc.is_tracing()
tb = tracemalloc.get_object_traceback(msg.source)
# When a warning is logged during Python shutdown, tracemalloc
# and the import machinery don't work anymore
s += 'Object allocated at (most recent call last):\n'
s += (' File "%s", lineno %s\n'
% (frame.filename, frame.lineno))
if linecache is not None:
line = linecache.getline(frame.filename, frame.lineno)
s += (f'{category}: Enable tracemalloc to get the object '
f'allocation traceback\n')
# Keep a reference to check if the function was replaced
_showwarning_orig = showwarning
"""Hook to write a warning to a file; replace if you like."""
if sw is not _showwarning_orig:
# warnings.showwarning() was replaced
raise TypeError("warnings.showwarning() must be set to a "
sw(msg.message, msg.category, msg.filename, msg.lineno,
# Keep a reference to check if the function was replaced
_formatwarning_orig = formatwarning
"""Function to format a warning the standard way."""
if fw is not _formatwarning_orig:
# warnings.formatwarning() was replaced
return fw(msg.message, msg.category,
msg.filename, msg.lineno, msg.line)
return _formatwarnmsg_impl(msg)
def filterwarnings(action, message="", category=Warning, module="", lineno=0,
"""Insert an entry into the list of warnings filters (at the front).
'action' -- one of "error", "ignore", "always", "default", "module",
'message' -- a regex that the warning message must match
'category' -- a class that the warning must be a subclass of
'module' -- a regex that the module name must match
'lineno' -- an integer line number, 0 matches all warnings
'append' -- if true, append to the list of filters
assert action in ("error", "ignore", "always", "default", "module",
"once"), "invalid action: %r" % (action,)
assert isinstance(message, str), "message must be a string"
assert isinstance(category, type), "category must be a class"
assert issubclass(category, Warning), "category must be a Warning subclass"
assert isinstance(module, str), "module must be a string"
assert isinstance(lineno, int) and lineno >= 0, \
"lineno must be an int >= 0"
message = re.compile(message, re.I)
module = re.compile(module)
_add_filter(action, message, category, module, lineno, append=append)
def simplefilter(action, category=Warning, lineno=0, append=False):
"""Insert a simple entry into the list of warnings filters (at the front).
A simple filter matches all modules and messages.
'action' -- one of "error", "ignore", "always", "default", "module",
'category' -- a class that the warning must be a subclass of
'lineno' -- an integer line number, 0 matches all warnings
'append' -- if true, append to the list of filters
assert action in ("error", "ignore", "always", "default", "module",
"once"), "invalid action: %r" % (action,)
assert isinstance(lineno, int) and lineno >= 0, \
"lineno must be an int >= 0"
_add_filter(action, None, category, None, lineno, append=append)
def _add_filter(*item, append):
# Remove possible duplicate filters, so new one will be placed
# in correct place. If append=True and duplicate exists, do nothing.
"""Clear the list of warning filters, so that no filters are active."""
class _OptionError(Exception):
"""Exception used by option processing helpers."""
# Helper to process -W options passed via sys.warnoptions
def _processoptions(args):
except _OptionError as msg:
print("Invalid -W option ignored:", msg, file=sys.stderr)
# Helper for _processoptions()
raise _OptionError("too many fields (max 5): %r" % (arg,))
action, message, category, module, lineno = [s.strip()
action = _getaction(action)
category = _getcategory(category)
message = re.escape(message)
module = re.escape(module) + r'\Z'
except (ValueError, OverflowError):
raise _OptionError("invalid lineno %r" % (lineno,)) from None
filterwarnings(action, message, category, module, lineno)
# Helper for _setoption()
if action == "all": return "always" # Alias
for a in ('default', 'always', 'ignore', 'module', 'once', 'error'):
raise _OptionError("invalid action: %r" % (action,))
# Helper for _setoption()
def _getcategory(category):
module, _, klass = category.rpartition('.')
m = __import__(module, None, None, [klass])
raise _OptionError("invalid module name: %r" % (module,)) from None
raise _OptionError("unknown warning category: %r" % (category,)) from None
if not issubclass(cat, Warning):
raise _OptionError("invalid warning category: %r" % (category,))
def _is_internal_frame(frame):
"""Signal whether the frame is an internal CPython implementation detail."""
filename = frame.f_code.co_filename
return 'importlib' in filename and '_bootstrap' in filename
def _next_external_frame(frame):
"""Find the next frame that doesn't involve CPython internals."""
while frame is not None and _is_internal_frame(frame):
# Code typically replaced by _warnings
def warn(message, category=None, stacklevel=1, source=None):
"""Issue a warning, or maybe ignore it or raise an exception."""
# Check if message is already a Warning object
if isinstance(message, Warning):
category = message.__class__
# Check category argument
if not (isinstance(category, type) and issubclass(category, Warning)):
raise TypeError("category must be a Warning subclass, "
"not '{:s}'".format(type(category).__name__))
# Get context information
if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)):
# If frame is too small to care or if the warning originated in
# internal code, then do not try to hide any frames.
frame = sys._getframe(stacklevel)
# Look for one frame less since the above line starts us off.
for x in range(stacklevel-1):
frame = _next_external_frame(frame)
globals = frame.f_globals
filename = frame.f_code.co_filename
if '__name__' in globals:
module = globals['__name__']
registry = globals.setdefault("__warningregistry__", {})
warn_explicit(message, category, filename, lineno, module, registry,
def warn_explicit(message, category, filename, lineno,
module=None, registry=None, module_globals=None,
module = filename or "<unknown>"
if module[-3:].lower() == ".py":
module = module[:-3] # XXX What about leading pathname?
if registry.get('version', 0) != _filters_version:
registry['version'] = _filters_version
if isinstance(message, Warning):
category = message.__class__
message = category(message)
key = (text, category, lineno)
# Quick test for common case
action, msg, cat, mod, ln = item
if ((msg is None or msg.match(text)) and
issubclass(category, cat) and
(mod is None or mod.match(module)) and
(ln == 0 or lineno == ln)):
# Prime the linecache for formatting, in case the
# "file" is actually in a zipfile or something.
linecache.getlines(filename, module_globals)
oncekey = (text, category)
if onceregistry.get(oncekey):
onceregistry[oncekey] = 1
altkey = (text, category, 0)
elif action == "default":
# Unrecognized actions are errors
"Unrecognized action (%r) in warnings.filters:\n %s" %
# Print message and context
msg = WarningMessage(message, category, filename, lineno, source)
class WarningMessage(object):
_WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
def __init__(self, message, category, filename, lineno, file=None,
self._category_name = category.__name__ if category else None
return ("{message : %r, category : %r, filename : %r, lineno : %s, "
"line : %r}" % (self.message, self._category_name,
self.filename, self.lineno, self.line))
class catch_warnings(object):
"""A context manager that copies and restores the warnings filter upon
The 'record' argument specifies whether warnings should be captured by a
custom implementation of warnings.showwarning() and be appended to a list
returned by the context manager. Otherwise None is returned by the context
manager. The objects appended to the list are arguments whose attributes
mirror the arguments to showwarning().
The 'module' argument is to specify an alternative module to the module
named 'warnings' and imported under that name. This argument is only useful
when testing the warnings module itself.
def __init__(self, *, record=False, module=None):
"""Specify whether to record warnings and if an alternative module
should be used other than sys.modules['warnings'].
For compatibility with Python 3.0, please consider all arguments to be
self._module = sys.modules['warnings'] if module is None else module
args.append("record=True")
if self._module is not sys.modules['warnings']:
args.append("module=%r" % self._module)
name = type(self).__name__
return "%s(%s)" % (name, ", ".join(args))
raise RuntimeError("Cannot enter %r twice" % self)
self._filters = self._module.filters
self._module.filters = self._filters[:]
self._module._filters_mutated()
self._showwarning = self._module.showwarning
self._showwarnmsg_impl = self._module._showwarnmsg_impl
self._module._showwarnmsg_impl = log.append
# Reset showwarning() to the default implementation to make sure
# that _showwarnmsg() calls _showwarnmsg_impl()
self._module.showwarning = self._module._showwarning_orig
def __exit__(self, *exc_info):
raise RuntimeError("Cannot exit %r without entering first" % self)
self._module.filters = self._filters
self._module._filters_mutated()
self._module.showwarning = self._showwarning
self._module._showwarnmsg_impl = self._showwarnmsg_impl
# Private utility function called by _PyErr_WarnUnawaitedCoroutine
def _warn_unawaited_coroutine(coro):
f"coroutine '{coro.__qualname__}' was never awaited\n"
if coro.cr_origin is not None:
import linecache, traceback
for filename, lineno, funcname in reversed(coro.cr_origin):
line = linecache.getline(filename, lineno)
yield (filename, lineno, funcname, line)
msg_lines.append("Coroutine created at (most recent call last)\n")
msg_lines += traceback.format_list(list(extract()))
msg = "".join(msg_lines).rstrip("\n")
# Passing source= here means that if the user happens to have tracemalloc