Repository navigation
catch_warnings context manager causes all warnings to be printed every time, even after exiting #73858
Description
Activity
Entering the
catch_warningscontext manager is causing warnings to be printed over and over again, rather than just once as it should. Without such a context manager, the behaviour is as expected:$ cat ./mwe.py #!/usr/bin/env python3.5 import warnings for i in range(3): try: print(i, __warningregistry__) except NameError: print(i, "first warning") warnings.warn("I don't like this.", UserWarning) print(i, __warningregistry__) # with warnings.catch_warnings(): # pass print(i, __warningregistry__) warnings.warn("I don't like this.", UserWarning) $ ./mwe.py 0 first warning ./mwe.py:10: UserWarning: I don't like this. warnings.warn("I don't like this.", UserWarning) 0 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 10): True} 0 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 10): True} ./mwe.py:15: UserWarning: I don't like this. warnings.warn("I don't like this.", UserWarning) 1 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True} 1 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True} 1 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True} 2 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True} 2 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True} 2 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True}Uncommenting the context manager causes the warning to be printed every time:
$ ./mwe.py 0 first warning ./mwe.py:10: UserWarning: I don't like this. warnings.warn("I don't like this.", UserWarning) 0 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 10): True} 0 {'version': 0, ("I don't like this.", <class 'UserWarning'>, 10): True} ./mwe.py:15: UserWarning: I don't like this. warnings.warn("I don't like this.", UserWarning) 1 {'version': 2, ("I don't like this.", <class 'UserWarning'>, 15): True} ./mwe.py:10: UserWarning: I don't like this. warnings.warn("I don't like this.", UserWarning) 1 {'version': 2, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True} 1 {'version': 2, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True} ./mwe.py:15: UserWarning: I don't like this. warnings.warn("I don't like this.", UserWarning) 2 {'version': 4, ("I don't like this.", <class 'UserWarning'>, 15): True} ./mwe.py:10: UserWarning: I don't like this. warnings.warn("I don't like this.", UserWarning) 2 {'version': 4, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True} 2 {'version': 4, ("I don't like this.", <class 'UserWarning'>, 15): True, ("I don't like this.", <class 'UserWarning'>, 10): True} ./mwe.py:15: UserWarning: I don't like this. warnings.warn("I don't like this.", UserWarning)I think this is undesirable. There is code deep inside a module that I'm using that is using the context manager, and as a consequence, I get warnings printed every time that should be printed only once.
See also on Stack Overflow: http://stackoverflow.com/q/42496579/974555
I suppose this is a consequence of the change in:
http://bugs.python.org/issue4180
and although I can see why the warnings filter would be reset when entering the context manager, I don't think it is desirable to have side effects for modules that are entirely unrelated.
To clarify, this behaviour crosses module boundaries. So even if some piece of code many layers deep buried in a module uses this context manager, it has global consequences.
- changed the title
[-]`catch_warnings` context manager causes warnings to be reprinted[/-][+]`catch_warnings` context manager should reset warning registry to previous state upon exiting, to prevent warnings from being reprinted[/+]on Feb 28, 2017 To resolve this, the
catch_warningscontext manager upon exiting should not only resetfilters, but also_filters_version, and perhaps an associated dictionary? Not sure if I'm understanding the code inwarnings.ccorrectly, and whether, for this change, it would suffice to changewarnings.pyor whetherwarnings.cwould need to be updated as well.Reacted by Finite State MachineI get bitten by this frequently, and find myself patching many libraries just to avoid them from calling .catch_warnings.
Does anyone know whether to fix this it would suffice to edit warnings.py, or would I need to dig into _warnings.c as well?
- changed the title
[-]`catch_warnings` context manager should reset warning registry to previous state upon exiting, to prevent warnings from being reprinted[/-][+]`catch_warnings` context manager causes all warnings to be printed every time, even after exiting[/+]on Jul 18, 2017 I think you will need to save and restore _filters_version and _onceregistry. Since _filters_version is a static variable in _warnings.c you will probably also have to modify it somehow to make it accessible to warnings.py.
- addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory3.7 (EOL)end of lifeend of lifetype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Jul 21, 2017 I just encountered this as well. The way catch_warnings is implemented is a bit "dumb" in how it treats _filter_version (it calls _filters_mutated even if the active filters are not actually changed when entering catch_warnings).
More significantly, _filter_version is not fine-grained enough. If some warning was already displayed, calling catch_warnings() should not later cause that same warning to be displayed again unless the filters were modified in such a way, during catch_warnings(), that that warning should be displayed (e.g. changed to 'always').
I'm not really sure what to do about that though. Maybe the "filter version" should be per-warning? Currently the value assigned to each warning in __warningregistry__ is not used (it is just set to True), so maybe that could actually be used for this.
Hmm, I originally missed the per module __warningregistry__... Need to read the code more closely...
What should the behavior be? We can add a flag that will make all warning actions be "always" when catch_warnings is in effect. But that doesn't feel right with the way catch_warnings currently behaves or what is expected of it.
Another idea would be to add a callback that is called whenever we set a module registry, allowing catch_warnings to backup the original registry of each module and restore them all on exit (Also the _onceregistry and _filters_version).
Yes, I think
catch_warningsshould back up and restore the relevant__warningregistry__. At which point it's not even clear to me what value there is in the _filter_version...I encountered this issue today and want to +1 getting some attention on this.
The disconnected nature of this issue makes it especially difficult to understand -- any package in the stack can change this hidden global variable
_filters_versionin the warnings module that then impacts the local behavior of warnings in the user script.The only way I was able to finally understand that an update to an obscure dependency was breaking our regression testing was by reading the
warningssource code and then monkey patching it to print diagnostic information.Even a documentation update would be useful. This could explain not only
catch_warnings(), but in general the unexpected feature that if any package anywhere in the stack sets a warning filter, then that globally resets whether a warning has been seen before (via the call to_filters_mutated()).Reacted by eliegoudout18 remaining items
- added a commit that references this issue
on Nov 20, 2023 Like many before me, I've found myself bitten by this today. As others mentioned, debugging this problem to finally land into this open issue takes quite some effort, including reading
warnings.pyand_warnings.c. Unfortunately I don't think there's much I can do: I have a fairly complex application where, deep within the main loop,catch_warningsis called at least twice even deeper down in my dependency chain (pandas in this particular case).- added 11 commits that reference this issue
on Sep 18, 2026
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsTodo
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields: