RustPython/RustPython · error · TypeError

warnings.showwarning() must be set to a function or method

Error message

warnings.showwarning() must be set to a function or method

What it means

When a warning is emitted, _py_warnings._showwarnmsg reads warnings.showwarning; if it was replaced and is not callable (None, a string, a number), TypeError is raised at display time. The check applies only when the current showwarning differs from the original implementation, so any non-callable monkeypatch of warnings triggers it lazily on the next warn(), far from the assignment that caused it.

Source

Thrown at Lib/_py_warnings.py:227

                  f'allocation traceback\n')
    return s


# Keep a reference to check if the function was replaced
_showwarning_orig = showwarning


def _showwarnmsg(msg):
    """Hook to write a warning to a file; replace if you like."""
    try:
        sw = _wm.showwarning
    except AttributeError:
        pass
    else:
        if sw is not _showwarning_orig:
            # warnings.showwarning() was replaced
            if not callable(sw):
                raise TypeError("warnings.showwarning() must be set to a "
                                "function or method")

            sw(msg.message, msg.category, msg.filename, msg.lineno,
               msg.file, msg.line)
            return
    _wm._showwarnmsg_impl(msg)


# Keep a reference to check if the function was replaced
_formatwarning_orig = formatwarning


def _formatwarnmsg(msg):
    """Function to format a warning the standard way."""
    try:
        fw = _wm.formatwarning
    except AttributeError:
        pass

View on GitHub (pinned to aaeab4f754)

Solutions

  1. To silence warnings use the supported filter API: `warnings.filterwarnings('ignore')` - never assign to showwarning
  2. If you must replace it, assign a callable with signature (message, category, filename, lineno, file=None, line=None)
  3. Save and restore the original via warnings.catch_warnings() so state never leaks between tests

Example fix

# before
import warnings
warnings.showwarning = None       # later: TypeError at warn() time
warnings.warn('deprecated')

# after
warnings.filterwarnings('ignore')  # supported way to silence
warnings.warn('deprecated')

# or a proper replacement:
import logging
def _sw(message, category, filename, lineno, file=None, line=None):
    logging.getLogger('py.warnings').warning('%s:%s: %s: %s', filename, lineno, category.__name__, message)
warnings.showwarning = _sw
Defensive patterns

Strategy: validation

Validate before calling

import warnings

def showwarning_usable() -> bool:
    return callable(getattr(warnings, 'showwarning', None))

Try / catch

try:
    warnings.warn(msg)
except TypeError:
    warnings.showwarning = warnings._showwarning_orig  # restore default
    warnings.warn(msg)

Prevention

When it happens

Trigger: `warnings.showwarning = None` (a common but wrong attempt to silence warnings) followed by any `warnings.warn(...)`; assigning a logging format string or config dict to warnings.showwarning.

Common situations: Libraries trying to suppress warnings by clobbering showwarning; test harnesses monkeypatching warnings without restoring; serialized/restored module state that loses the function reference.

Related errors


AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17). Data as JSON: /api/errors/b5f6bf2bcf6466a4. Report an issue: GitHub.