Skip to content

gh-91230: Concise catch_warnings with simplefilter #91435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Doc/library/warnings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ Available Functions
Available Context Managers
--------------------------

.. class:: catch_warnings(*, record=False, module=None)
.. class:: catch_warnings(*, record=False, module=None, action=None, category=Warning, lineno=0, append=False)

A context manager that copies and, upon exit, restores the warnings filter
and the :func:`showwarning` function.
Expand All @@ -507,10 +507,18 @@ Available Context Managers
protected. This argument exists primarily for testing the :mod:`warnings`
module itself.

If the *action* argument is not ``None``, the remaining arguments are
passed to :func:`simplefilter` as if it were called immediately on
entering the context.

.. note::

The :class:`catch_warnings` manager works by replacing and
then later restoring the module's
:func:`showwarning` function and internal list of filter
specifications. This means the context manager is modifying
global state and therefore is not thread-safe.

.. versionchanged:: 3.11

Added the *action*, *category*, *lineno*, and *append* parameters.
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.11.rst
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,13 @@ venv
Third party code that also creates new virtual environments should do the same.
(Contributed by Miro Hrončok in :issue:`45413`.)

warnings
--------

* :func:`warnings.catch_warnings` now accepts arguments for :func:`warnings.simplefilter`,
providing a more concise way to locally ignore warnings or convert them to errors.
(Contributed by Zac Hatfield-Dodds in :issue:`47074`.)

zipfile
-------

Expand Down
19 changes: 19 additions & 0 deletions Lib/test/test_warnings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,25 @@ def test_append_duplicate(self):
"appended duplicate changed order of filters"
)

def test_catchwarnings_with_simplefilter_ignore(self):
with original_warnings.catch_warnings(module=self.module):
self.module.resetwarnings()
self.module.simplefilter("error")
with self.module.catch_warnings(
module=self.module, action="ignore"
):
self.module.warn("This will be ignored")

def test_catchwarnings_with_simplefilter_error(self):
with original_warnings.catch_warnings(module=self.module):
self.module.resetwarnings()
with self.module.catch_warnings(
module=self.module, action="error", category=FutureWarning
):
self.module.warn("Other types of warnings are not errors")
self.assertRaises(FutureWarning,
self.module.warn, FutureWarning("msg"))

class CFilterTests(FilterTests, unittest.TestCase):
module = c_warnings

Expand Down
12 changes: 11 additions & 1 deletion Lib/warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,9 +432,13 @@ class catch_warnings(object):
named 'warnings' and imported under that name. This argument is only useful
when testing the warnings module itself.

If the 'action' argument is not None, the remaining arguments are passed
to warnings.simplefilter() as if it were called immediately on entering the
context.
"""

def __init__(self, *, record=False, module=None):
def __init__(self, *, record=False, module=None,
action=None, category=Warning, lineno=0, append=False):
"""Specify whether to record warnings and if an alternative module
should be used other than sys.modules['warnings'].

Expand All @@ -445,6 +449,10 @@ def __init__(self, *, record=False, module=None):
self._record = record
self._module = sys.modules['warnings'] if module is None else module
self._entered = False
if action is None:
self._filter = None
else:
self._filter = (action, category, lineno, append)

def __repr__(self):
args = []
Expand All @@ -464,6 +472,8 @@ def __enter__(self):
self._module._filters_mutated()
self._showwarning = self._module.showwarning
self._showwarnmsg_impl = self._module._showwarnmsg_impl
if self._filter is not None:
simplefilter(*self._filter)
if self._record:
log = []
self._module._showwarnmsg_impl = log.append
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:func:`warnings.catch_warnings` now accepts arguments for
:func:`warnings.simplefilter`, providing a more concise way to
locally ignore warnings or convert them to errors.