Skip to content

Comments

Fix caplog handler level restoration (swev-id: pytest-dev__pytest-7571)#38

Open
casey-brooks wants to merge 2 commits intopytest-dev__pytest-7571from
fix/caplog-restore-handler-level-7571
Open

Fix caplog handler level restoration (swev-id: pytest-dev__pytest-7571)#38
casey-brooks wants to merge 2 commits intopytest-dev__pytest-7571from
fix/caplog-restore-handler-level-7571

Conversation

@casey-brooks
Copy link

Summary

Observed Failure and Reproduction

  • on the base branch, create two tests where the first calls caplog.set_level(42) and the second asserts caplog.handler.level == logging.NOTSET
  • the second test inherits level 42 from the previous run, causing assertions and log capture expectations to fail without any stack trace (state leakage only)

Testing

  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/pytest testing/logging/test_fixture.py
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/pytest testing/logging
  • .venv/bin/flake8 src/_pytest/logging.py testing/logging/test_fixture.py

@casey-brooks casey-brooks requested a review from a team December 25, 2025 21:29
@casey-brooks
Copy link
Author

Local Validation

  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/pytest testing/logging/test_fixture.py
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/pytest testing/logging
  • .venv/bin/flake8 src/_pytest/logging.py testing/logging/test_fixture.py

Copy link

@noa-lucent noa-lucent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resetting the shared caplog handler before every phase breaks callers that configure logging during setup; please limit the reset to the first phase (setup) and cover the scenario with a regression test.


def _runtest_for(self, item: nodes.Item, when: str) -> Generator[None, None, None]:
"""Implements the internals of pytest_runtest_xxx() hook."""
if self.log_level is None:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[major] Resetting the shared handler unconditionally here runs on every phase (setup/call/teardown). That wipes out levels a test deliberately applies earlier in the same test, for example a fixture that calls during setup so the test body runs with that filtering. On the base branch that works because the handler keeps the level until finalization; with this change the call phase starts at , so those fixtures silently lose their effect. Please gate the reset so it only runs for the first phase of each test (e.g. ), and add a regression test covering a fixture that calls during setup to prove the level remains active for the test body.}

@casey-brooks
Copy link
Author

Local Validation (update)

  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/pytest testing/logging/test_fixture.py (18 passed)
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 .venv/bin/pytest testing/logging (61 passed)
  • .venv/bin/flake8 src/_pytest/logging.py testing/logging/test_fixture.py

Copy link

@noa-lucent noa-lucent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Resetting only during setup preserves fixture-configured levels, and the added regression test covers that scenario alongside the broader handler restoration cases.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants