GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — `catch_warnings` context manager causes all warnings to be printed every time, even after exiting · Issue #73858 · python/cpython

catch_warnings context manager causes all warnings to be printed every time, even after exiting #73858

New issue
Copy link
New issue
Copy link
Open
Open
catch_warnings context manager causes all warnings to be printed every time, even after exiting#73858
Copy link
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

gerritholl
mannequin
opened on Feb 27, 2017
Issue body actions
BPO 29672
Nosy @pitrou, @gerritholl, @embray, @serhiy-storchaka, @segevfiner
PRs
  • [WIP] gh-73858: Save and restore module warning registries in catch_warnings #8232
  • 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:

    assignee = None
    closed_at = None
    created_at = <Date 2017-02-27.22:29:56.490>
    labels = ['type-bug', 'library']
    title = '`catch_warnings` context manager causes all warnings to be printed every time, even after exiting'
    updated_at = <Date 2021-04-02.21:55:37.433>
    user = 'https://github.com/gerritholl'

    bugs.python.org fields:

    activity = <Date 2021-04-02.21:55:37.433>
    actor = 'taldcroft'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2017-02-27.22:29:56.490>
    creator = 'Gerrit.Holl'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 29672
    keywords = ['patch']
    message_count = 10.0
    messages = ['288677', '288678', '288680', '288709', '298588', '298822', '320662', '321380', '321393', '390103']
    nosy_count = 6.0
    nosy_names = ['pitrou', 'Gerrit.Holl', 'erik.bray', 'serhiy.storchaka', 'Segev Finer', 'taldcroft']
    pr_nums = ['8232']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue29672'
    versions = []

    Reacted by Juan Nunez-Iglesias, David Lord, Richard Shadrach, Finite State Machine, rtobar, Brandon Mills, Leandro Lucarella and Ho Yin Chau

    Activity

    Next
    1. gerritholl commented on Feb 27, 2017

      @gerritholl
      gerrithollmannequin
      on Feb 27, 2017
      MannequinAuthor
      More actions

      Entering the catch_warnings context 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

    2. gerritholl commented on Feb 27, 2017

      @gerritholl
      gerrithollmannequin
      on Feb 27, 2017
      MannequinAuthor
      More actions

      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.

    3. gerritholl commented on Feb 27, 2017

      @gerritholl
      gerrithollmannequin
      on Feb 27, 2017
      MannequinAuthor
      More actions

      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.

    4. gerritholl
      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
    5. gerritholl commented on Feb 28, 2017

      @gerritholl
      gerrithollmannequin
      on Feb 28, 2017
      MannequinAuthor
      More actions

      To resolve this, the catch_warnings context manager upon exiting should not only reset filters, but also _filters_version, and perhaps an associated dictionary? Not sure if I'm understanding the code in warnings.c correctly, and whether, for this change, it would suffice to change warnings.py or whether warnings.c would need to be updated as well.

      Reacted by Finite State Machine
    6. gerritholl commented on Jul 18, 2017

      @gerritholl
      gerrithollmannequin
      on Jul 18, 2017
      MannequinAuthor
      More actions

      I 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?

    7. gerritholl
      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
    8. segevfiner commented on Jul 21, 2017

      @segevfiner
      segevfinermannequin
      on Jul 21, 2017
      Mannequin
      More actions

      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.

    9. segevfiner
      added
      stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
      3.7 (EOL)end of lifeend of life
      type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
      on Jul 21, 2017
    10. embray commented on Jun 28, 2018

      @embray
      embray
      on Jun 28, 2018
      Contributor
      More actions

      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.

    11. segevfiner commented on Jul 10, 2018

      @segevfiner
      segevfinermannequin
      on Jul 10, 2018
      Mannequin
      More actions

      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).

    12. embray commented on Jul 10, 2018

      @embray
      embray
      on Jul 10, 2018
      Contributor
      More actions

      Yes, I think catch_warnings should 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...

    13. taldcroft commented on Apr 2, 2021

      @taldcroft
      taldcroftmannequin
      on Apr 2, 2021
      Mannequin
      More actions

      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_version in 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 warnings source 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 eliegoudout
    14. 19 remaining items

    15. rtobar commented on Mar 21, 2025

      @rtobar
      rtobar
      on Mar 21, 2025
      Contributor
      More actions

      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.py and _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_warnings is called at least twice even deeper down in my dependency chain (pandas in this particular case).

    16. serhiy-storchaka
      added this to warnings issues ⚠️on Jul 3, 2026
    17. github-project-automation
      moved this to Todo in warnings issues ⚠️on Jul 3, 2026
    18. llucax
      added 11 commits that reference this issue on Sep 18, 2026

      Add a dedup history preserving `catch_warnings`

      0420830

      Add `ignoring_warnings()`

      9be65aa

      Add `ignoring_warnings()`

      c9967cc

      Silence internal deprecations without resetting the warnings history

      75d2e73

      Silence internal deprecations without resetting the warnings history

      dda26fd

      Silence internal deprecations without resetting the warnings history

      326d986

      Silence internal deprecations without resetting the warnings history

      5c544de

      Add a `warnings` module for ignoring, asserting and aliasing (frequen…

      1c76d73

      Silence internal deprecations without resetting the warnings history

      b1694f3

      Silence internal deprecations without resetting the warnings history

      d8eee23

      Silence internal deprecations without resetting the warnings history

      a96d958
    19. hchau630 commented on Nov 1, 2026

      @hchau630
      hchau630
      on Nov 1, 2026
      More actions

      also encountering this issue. I'm surprised it hasn't been fixed after so many years, the bug occurs every time you raise a warning while using a package that uses catch_warnings (in my case, the package in question is matplotlib), so it should be a very widespread issue.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

      Projects

      • warnings issues ⚠️
        Status
        Todo
        Show more project fields

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.