Visitar URL original
`logging.captureWarnings` and `warnings.catch_warnings` do not play well together · Issue #139355 · python/cpython · GitHub
Skip to content

logging.captureWarnings and warnings.catch_warnings do not play well together #139355

Description

@braingram

Bug report

Bug description:

When logging.captureWarnings(True) is called within a warnings.catch_warnings(record=True) context warnings emitted during the context are not recorded.

import logging, warnings
with warnings.catch_warnings(record=True) as rec:
    logging.captureWarnings(True)
    warnings.warn("foo")
assert len(rec) == 1  # fails since len(rec) == 0

one work-around for this is to enable captureWarnings outside the context

import logging, warnings
logging.captureWarnings(True)
with warnings.catch_warnings(record=True) as rec:
    warnings.warn("foo")
assert len(rec) == 1

I tested the above examples on 3.10, 3.13 and 3.14.0b2.

However on 3.14.0b2 with PYTHON_CONTEXT_AWARE_WARNINGS=1 (to pull in the changes from #130010) the second example (enabling captureWarnings outside the catch_warnings) no longer works.

CPython versions tested on:

3.13

Operating systems tested on:

macOS

Activity

  1. picnixz commented on Sep 26, 2025

    @picnixz
    Member

    The docs say:

    If capture is True, warnings issued by the warnings module will be redirected to the logging system. Specifically, a warning will be formatted using warnings.formatwarning() and the resulting string logged to a logger named 'py.warnings' with a severity of WARNING.

    AFAIU, calling logging.captureWarnings(True) means that the first example works as intended (the responsibility for handling warnings is left to logging). For the second example, do you mean that we have both a logging warning and a non-logging warning? (from warnings)?

    Thus I don't know if it's a bug or a docs issue here.

    cc @vsajip

  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Sep 26, 2025
  3. changed the title [-]enabling logging.captureWarnings inside warnings.catch_warnings causes warnings to not be recorded[/-] [+]`logging.captureWarnings` and `warnings.catch_warnings` do not play well together[/+] on Sep 26, 2025
  4. braingram commented on Sep 26, 2025

    @braingram
    Author

    AFAIU, calling logging.captureWarnings(True) means that the first example works as intended (the responsibility for handling warnings is left to logging). For the second example, do you mean that we have both a logging warning and a non-logging warning? (from warnings)?

    There's no logging message in the second example:

    import logging, warnings
    logging.captureWarnings(True)
    with warnings.catch_warnings(record=True) as rec:
        warnings.warn("foo")
    assert len(rec) == 1

    for maybe 2 reasons. One is that the warning doesn't appear to "prime" the logging machinery (I'm not sure what's happening here). For this minimal example:

    import logging, warnings
    logging.captureWarnings(True)
    warnings.warn("foo")

    I see no log messages and no warning. However if I add a logging.warning:

    import logging, warnings
    logging.warning("bar")
    logging.captureWarnings(True)
    warnings.warn("foo")

    I now see 2 logging messages and a warning:

    WARNING:root:bar
    WARNING:py.warnings:...:...: UserWarning: foo
      warnings.warn("foo")
    

    If I then update the example adding the logging.warning:

    import logging, warnings
    logging.warning("bar")
    logging.captureWarnings(True)
    with warnings.catch_warnings(record=True) as rec:
        warnings.warn("foo")
    assert len(rec) == 1

    it shows only the added logging.warning message and no warning (but the assert passes). The output is:

    WARNING:root:bar
    

    which I think points to the 2nd reason the "foo" is not shown in the log or warned due to the catch_warnings doing what I think is expected here (catching and recording the warnings).

    Thanks for the documentation excerpt. To revisit this example:

    import logging, warnings
    logging.warning("bar")
    logging.captureWarnings(True)
    warnings.warn("foo")

    where 2 log messages are shown and 1 warning. I think this is the behavior I would expect where captureWarnings is allowing warnings to be logged but not preventing them from also being warnings.

    Maybe the fact that this producing no log and no warning is a separate bug?

    import logging, warnings
    logging.captureWarnings(True)
    warnings.warn("foo")
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/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions