`warnings.simplefilter("once")` and `warnings.warn()` print all occurrences of matching warnings, regardless of location
Bug report
Bug description:
With warnings.simplefilter("module") and warnings.warn(), I ran main.py which runs file1.py(module) and file2.py(module) as shown below:
*Memos:
-
The doc says
"module" print the first occurrence of matching warnings for each module where the warning is issued (regardless of line number). - I also used warnings.filterwarnings("module").
- I ran it on Windows and Linux.
my_project
|-main.py
|-file1.py(module)
└-file2.py(module)
main.py:
import warnings
warnings.simplefilter("module")
import file1, file2
file1.py:
import warnings
warnings.warn("Warning 1")
warnings.warn("Warning 2")
warnings.warn("Warning 3")
file2.py:
import warnings
warnings.warn("Warning 1")
warnings.warn("Warning 2")
warnings.warn("Warning 3")
Then, "module" print the first occurrence of matching warnings for each module where the warning is issued (regardless of line number)` as shown below:
...\my_project\file1.py:3: UserWarning: Warning 1
warnings.warn("Warning 1")
...\my_project\file1.py:4: UserWarning: Warning 2
warnings.warn("Warning 2")
...\my_project\file1.py:6: UserWarning: Warning 3
warnings.warn("Warning 3")
...\my_project\file2.py:3: UserWarning: Warning 1
warnings.warn("Warning 1")
...\my_project\file2.py:4: UserWarning: Warning 2
warnings.warn("Warning 2")
...\my_project\file2.py:6: UserWarning: Warning 3
warnings.warn("Warning 3")
Now with warnings.simplefilter("once") and warnings.warn(), I ran main.py which runs file1.py(module) and file2.py(module) as shown below:
*Memos:
-
The doc says
"once" print only the first occurrence of matching warnings, regardless of location. - I also used
warnings.filterwarnings("once"). - I ran it on Windows and Linux.
import warnings
warnings.simplefilter("once")
import file1, file2
But "once" print all occurrences of matching warnings, regardless of location as shown below:
...\my_project\file1.py:3: UserWarning: Warning 1
warnings.warn("Warning 1")
...\my_project\file1.py:4: UserWarning: Warning 2
warnings.warn("Warning 2")
...\my_project\file1.py:6: UserWarning: Warning 3
warnings.warn("Warning 3")
...\my_project\file2.py:3: UserWarning: Warning 1
warnings.warn("Warning 1")
...\my_project\file2.py:4: UserWarning: Warning 2
warnings.warn("Warning 2")
...\my_project\file2.py:6: UserWarning: Warning 3
warnings.warn("Warning 3")
CPython versions tested on:
3.11
Operating systems tested on:
Linux, Windows
I can confirm this behaviour. But this seems weird that no one has ever noticed it so I'm wondering whether there is something I'm misunderstanding.
cc @ncoghlan
There's a docs ambiguity here, since it doesn't explicitly state how the three filters that suppress repeated warnings determine if a warning is a repeat:
-
default: only full(message, category, module, lineno)matches are considered repeats -
module: any warnings that match on(message, category, module)are considered repeats -
once: any warnings that match on(message, category)are considered repeats
Unlike the initial check against the filter definition, these definitions are not affected by which fields are defined in the filter string. This is why a filter like default::DeprecationWarning works the way it does: the given action is applied to every reported deprecation warning, but they're not all considered to be the same deprecation warning.
error, always, ignore aren't affected by the ambiguity since they don't check for repeats in the first place
So in the example, all 6 warnings are considered distinct, since they all have different messages. If you drop the distinguishing numbers from each of them, you'll see once and module behaving as you expect.
That's a genuine flaw in the docs, but the behaviour is as expected, so I'll adjust the labels accordingly.
I will take a look! @corona10
Thanks for the docs update @byungchanKo99! The main PR has been merged, and the backport PRs will automatically merge once their CI runs complete.
It may be a while before the change goes lives on docs.python.org, though (almost always within 24 hours, but most often faster than that - building the full docs set with all its translations can take a while)
Closing since completed and backported. Thank you all!