Skip to content

gh-128384: Use a context variable for warnings.catch_warnings #130010

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 47 commits into from
Apr 9, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
ba99f2e
Make _contextvars a builtin module.
nascheme Dec 28, 2024
6d00c2a
Add 'context' parameter to Thread.
nascheme Dec 21, 2024
a868fe9
Tweak blurb markup.
nascheme Feb 7, 2025
16fa2c3
Doc markup fix.
nascheme Feb 7, 2025
f0ccc8d
Use contextvar for catch_warnings().
nascheme Dec 27, 2024
bcadd20
Add blurb.
nascheme Feb 11, 2025
0cfe578
Add "_warnings_context" as identifier.
nascheme Feb 11, 2025
928c2df
Fix test_support for context var filters.
nascheme Feb 11, 2025
65751d9
Regenerate 'configure' script.
nascheme Feb 11, 2025
09e72b8
Rename flag to `thread_inherit_context`.
nascheme Feb 11, 2025
75f1b38
Merge branch 'main' into thread_inherit_context
nascheme Feb 11, 2025
872920d
Regenerate 'configure' script.
nascheme Feb 11, 2025
5b6b59e
Merge branch 'thread_inherit_context' into gh-128384-warnings-contextvar
nascheme Feb 11, 2025
9e955dc
Use separate flag `thread_safe_warnings`.
nascheme Feb 12, 2025
3a56c64
Add doc for ``thread_safe_warnings`` flag.
nascheme Feb 12, 2025
daa3d52
Create _py_warnings.py for Python implementation.
nascheme Feb 18, 2025
83419e4
Add _warnings_context to _warnings module.
nascheme Feb 18, 2025
15443e8
Remove '_warnings_context' global string.
nascheme Feb 18, 2025
983e7ee
Rename flag to 'context_aware_warnings'.
nascheme Feb 18, 2025
e5e660c
Use catch_warnings() for module under test.
nascheme Feb 18, 2025
e054a57
Don't pass 'module' to catch_warnings().
nascheme Feb 18, 2025
2466cec
Correct error in warnings module docs.
nascheme Feb 19, 2025
165a573
Use PyObject_GetAttr.
nascheme Feb 19, 2025
af8728d
Typo fix for docstring.
nascheme Feb 19, 2025
1c02b7e
Avoid DECREF calls on None.
nascheme Feb 19, 2025
dba89e0
Add warnings.py module (missed in previous commit).
nascheme Feb 19, 2025
2c48fc5
Add comment about why 'context' is passed in test.
nascheme Feb 19, 2025
53eb72d
Revise "decimal' docs, adding note about flag.
nascheme Feb 21, 2025
9cb6f73
Merge branch 'thread_inherit_context' into gh-128384-warnings-contextvar
nascheme Feb 21, 2025
f79daaa
Fix race in filter_search().
nascheme Feb 25, 2025
5ca1d39
Add note to free-threading howto.
nascheme Mar 11, 2025
9420a9d
Merge branch 'main' into gh-128384-warnings-contextvar
nascheme Mar 11, 2025
bad0fdb
Doc fixes for missing refs.
nascheme Mar 12, 2025
bb35c2e
Add "_py_warnings" to stdlib_module_names.h.
nascheme Mar 12, 2025
adf32cb
Improve error text in Python/_warnings.c
nascheme Mar 17, 2025
47d0b6f
Avoid unused-variable warning in _warnings.c.
nascheme Mar 17, 2025
b880dd1
Minor code improvement to _warnings.c.
nascheme Mar 17, 2025
5a1115b
Merge 'origin/main' into gh-128384-warnings-contextvar
nascheme Mar 17, 2025
ae701e3
Merge branch 'origin/main' into gh-128384-warnings-contextvar
nascheme Mar 18, 2025
153c6b1
Merge 'origin/main' into gh-128384-warnings-contextvar
nascheme Mar 26, 2025
9220223
Add extra unit tests.
nascheme Mar 27, 2025
c2c90cb
Use asyncio events to get deterministic execution.
nascheme Mar 27, 2025
c1def22
Merge 'origin/main' into gh-128384-warnings-contextvar
nascheme Apr 9, 2025
4e461d9
Add unit test for asyncio tasks.
nascheme Apr 9, 2025
543927b
Update Doc/howto/free-threading-python.rst
nascheme Apr 9, 2025
4f11910
Use asyncio.gather() rather than create_task().
nascheme Apr 9, 2025
42d157b
Call resetwarnings() in a few places.
nascheme Apr 9, 2025
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
Prev Previous commit
Next Next commit
Fix race in filter_search().
Using the critical section seems the easiest fix for this.  Add a
unit test that fails TSAN check if the fix is not applied.
  • Loading branch information
nascheme committed Feb 25, 2025
commit f79daaa392c854880ce8af16ee0d0f17503f3a56
32 changes: 32 additions & 0 deletions Lib/test/test_free_threading/test_races.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import time
import unittest
import _testinternalcapi
import warnings

from test.support import threading_helper

Expand Down Expand Up @@ -286,5 +287,36 @@ def set_recursion_limit():
do_race(something_recursive, set_recursion_limit)


@threading_helper.requires_working_threading()
class TestWarningsRaces(TestBase):
def setUp(self):
self.saved_filters = warnings.filters[:]
# Add multiple filters to the list to increase odds of race.
for lineno in range(20):
warnings.filterwarnings('ignore', message='not matched', category=Warning, lineno=lineno)
# Override showwarning() so that we don't actually show warnings.
def showwarning(*args):
pass
warnings.showwarning = showwarning

def tearDown(self):
warnings.filters[:] = self.saved_filters
warnings.showwarning = warnings._showwarning_orig

def test_racing_warnings_filter(self):
# Modifying the warnings.filters list while another thread is using
# warn() should not crash or race.
def modify_filters():
time.sleep(0)
warnings.filters[:] = [('ignore', None, UserWarning, None, 0)]
time.sleep(0)
warnings.filters[:] = self.saved_filters

def emit_warning():
warnings.warn('dummy message', category=UserWarning)

do_race(modify_filters, emit_warning)


if __name__ == "__main__":
unittest.main()
30 changes: 20 additions & 10 deletions Python/_warnings.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,10 @@ filter_search(PyInterpreterState *interp, PyObject *category,
PyObject *text, Py_ssize_t lineno,
PyObject *module, char *list_name, PyObject *filters,
PyObject **item, PyObject **matched_action) {
/* filters list could change while we are iterating over it. */
bool result = true;
*matched_action = NULL;
/* Avoid the filters list changing while we iterate over it. */
Py_BEGIN_CRITICAL_SECTION(filters);
for (Py_ssize_t i = 0; i < PyList_GET_SIZE(filters); i++) {
PyObject *tmp_item, *action, *msg, *cat, *mod, *ln_obj;
Py_ssize_t ln;
Expand All @@ -434,7 +437,8 @@ filter_search(PyInterpreterState *interp, PyObject *category,
if (!PyTuple_Check(tmp_item) || PyTuple_GET_SIZE(tmp_item) != 5) {
PyErr_Format(PyExc_ValueError,
"warnings.%s item %zd isn't a 5-tuple", list_name, i);
return false;
result = false;
break;
}

/* Python code: action, msg, cat, mod, ln = item */
Expand All @@ -450,43 +454,49 @@ filter_search(PyInterpreterState *interp, PyObject *category,
"action must be a string, not '%.200s'",
Py_TYPE(action)->tp_name);
Py_DECREF(tmp_item);
return false;
result = false;
break;
}

good_msg = check_matched(interp, msg, text);
if (good_msg == -1) {
Py_DECREF(tmp_item);
return false;
result = false;
break;
}

good_mod = check_matched(interp, mod, module);
if (good_mod == -1) {
Py_DECREF(tmp_item);
return false;
result = false;
break;
}

is_subclass = PyObject_IsSubclass(category, cat);
if (is_subclass == -1) {
Py_DECREF(tmp_item);
return false;
result = false;
break;
}

ln = PyLong_AsSsize_t(ln_obj);
if (ln == -1 && PyErr_Occurred()) {
Py_DECREF(tmp_item);
return false;
result = false;
break;
}

if (good_msg && is_subclass && good_mod && (ln == 0 || lineno == ln)) {
*item = tmp_item;
*matched_action = action;
return true;
result = true;
break;
}

Py_DECREF(tmp_item);
}
*matched_action = NULL;
return true;
Py_END_CRITICAL_SECTION();
return result;
}

/* The item is a new reference. */
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy