@@ -324,11 +324,13 @@ the warning using the :class:`catch_warnings` context manager::
324
324
While within the context manager all warnings will simply be ignored. This
325
325
allows you to use known-deprecated code without having to see the warning while
326
326
not suppressing the warning for other code that might not be aware of its use
327
- of deprecated code. Note: this can only be guaranteed in a single-threaded
328
- application. If two or more threads use the :class: `catch_warnings ` context
329
- manager at the same time, the behavior is undefined.
327
+ of deprecated code.
330
328
329
+ .. note ::
331
330
331
+ See :ref: `warning-concurrent-safe ` for details on the
332
+ concurrency-safety of the :class: `catch_warnings ` context manager when
333
+ used in programs using multiple threads or async functions.
332
334
333
335
.. _warning-testing :
334
336
@@ -364,10 +366,13 @@ the warning has been cleared.
364
366
Once the context manager exits, the warnings filter is restored to its state
365
367
when the context was entered. This prevents tests from changing the warnings
366
368
filter in unexpected ways between tests and leading to indeterminate test
367
- results. The :func: `showwarning ` function in the module is also restored to
368
- its original value. Note: this can only be guaranteed in a single-threaded
369
- application. If two or more threads use the :class: `catch_warnings ` context
370
- manager at the same time, the behavior is undefined.
369
+ results.
370
+
371
+ .. note ::
372
+
373
+ See :ref: `warning-concurrent-safe ` for details on the
374
+ concurrency-safety of the :class: `catch_warnings ` context manager when
375
+ used in programs using multiple threads or async functions.
371
376
372
377
When testing multiple operations that raise the same kind of warning, it
373
378
is important to test them in a manner that confirms each operation is raising
@@ -615,12 +620,71 @@ Available Context Managers
615
620
616
621
.. note ::
617
622
618
- The :class: `catch_warnings ` manager works by replacing and
619
- then later restoring the module's
620
- :func: `showwarning ` function and internal list of filter
621
- specifications. This means the context manager is modifying
622
- global state and therefore is not thread-safe.
623
+ See :ref: `warning-concurrent-safe ` for details on the
624
+ concurrency-safety of the :class: `catch_warnings ` context manager when
625
+ used in programs using multiple threads or async functions.
626
+
623
627
624
628
.. versionchanged :: 3.11
625
629
626
630
Added the *action *, *category *, *lineno *, and *append * parameters.
631
+
632
+
633
+ .. _warning-concurrent-safe :
634
+
635
+ Concurrent safety of Context Managers
636
+ -------------------------------------
637
+
638
+ The behavior of :class: `catch_warnings ` context manager depends on the
639
+ :data: `sys.flags.context_aware_warnings ` flag. If the flag is true, the
640
+ context manager behaves in a concurrent-safe fashion and otherwise not.
641
+ Concurrent-safe means that it is both thread-safe and safe to use within
642
+ :ref: `asyncio coroutines <coroutine >` and tasks. Being thread-safe means
643
+ that behavior is predictable in a multi-threaded program. The flag defaults
644
+ to true for free-threaded builds and false otherwise.
645
+
646
+ If the :data: `~sys.flags.context_aware_warnings ` flag is false, then
647
+ :class: `catch_warnings ` will modify the global attributes of the
648
+ :mod: `warnings ` module. This is not safe if used within a concurrent program
649
+ (using multiple threads or using asyncio coroutines). For example, if two
650
+ or more threads use the :class: `catch_warnings ` class at the same time, the
651
+ behavior is undefined.
652
+
653
+ If the flag is true, :class: `catch_warnings ` will not modify global
654
+ attributes and will instead use a :class: `~contextvars.ContextVar ` to
655
+ store the newly established warning filtering state. A context variable
656
+ provides thread-local storage and it makes the use of :class: `catch_warnings `
657
+ thread-safe.
658
+
659
+ The *record * parameter of the context handler also behaves differently
660
+ depending on the value of the flag. When *record * is true and the flag is
661
+ false, the context manager works by replacing and then later restoring the
662
+ module's :func: `showwarning ` function. That is not concurrent-safe.
663
+
664
+ When *record * is true and the flag is true, the :func: `showwarning ` function
665
+ is not replaced. Instead, the recording status is indicated by an internal
666
+ property in the context variable. In this case, the :func: `showwarning `
667
+ function will not be restored when exiting the context handler.
668
+
669
+ The :data: `~sys.flags.context_aware_warnings ` flag can be set the :option: `-X
670
+ context_aware_warnings<-X> ` command-line option or by the
671
+ :envvar: `PYTHON_CONTEXT_AWARE_WARNINGS ` environment variable.
672
+
673
+ .. note ::
674
+
675
+ It is likely that most programs that desire thread-safe
676
+ behaviour of the warnings module will also want to set the
677
+ :data: `~sys.flags.thread_inherit_context ` flag to true. That flag
678
+ causes threads created by :class: `threading.Thread ` to start
679
+ with a copy of the context variables from the thread starting
680
+ it. When true, the context established by :class: `catch_warnings `
681
+ in one thread will also apply to new threads started by it. If false,
682
+ new threads will start with an empty warnings context variable,
683
+ meaning that any filtering that was established by a
684
+ :class: `catch_warnings ` context manager will no longer be active.
685
+
686
+ .. versionchanged :: 3.14
687
+
688
+ Added the :data: `sys.flags.context_aware_warnings ` flag and the use of a
689
+ context variable for :class: `catch_warnings ` if the flag is true. Previous
690
+ versions of Python acted as if the flag was always set to false.
0 commit comments