Give back the stream that was in place when capturing was suspended - #14996
Give back the stream that was in place when capturing was suspended#14996livingstaccato wants to merge 1 commit into
Conversation
`SysCaptureBase.suspend` handed `sys.stdout` back to the stream saved before capturing started, and `resume` reinstated `tmpfile`, the stream capture installed at `start`. Neither read what was actually there, so a stream installed after `start` -- `contextlib.redirect_stdout`, `click.testing.CliRunner.isolation`, a fixture of one's own -- was discarded on the first suspend/resume cycle, and everything written afterwards went to pytest's buffer rather than to the caller that installed it. Under `log_cli = true` that is a per-record event: the live-log handler sits on the root logger and suspends capturing around every record it writes, so one log record emitted at any depth was enough to cost a test its redirect. The failure is silent, and assertions about absent output pass vacuously. `suspend` now records the stream that is in place and `resume` returns it. Suspending while suspended is left alone, since what sits there then is what `suspend` itself installed. `done` is unchanged and still restores the stream capture replaced, so a swap left behind by a test cannot outlive it. Fixes pytest-dev#14995
82a62a1 to
81e4088
Compare
|
We should use a distinct stream instead of this ai confusion Work on distinct streams is in progress |
I appreciate you and the response, and apologize for any churn I may have caused - thanks. I made an effort to make sure multiple LLMs agreed upon things until they nitpick. But - I'm not that familiar with the actual pytest code, so If this is the wrong code for the wrong thing and there's low value then please go ahead and close it. |
|
I'll have my LLMs take another stab at it though if you want. |
|
please dont - i had to wast a significant portion of my vacations opensource time to throw out ill advised llm prompts people unfamiliar with the project keep spamming us with wrong solutions one after another - its unbearable if you want to actually contribute - actually prepare - else the llms will jsut create something that makes our work worse and most of us have access to opus and fable from opensource maintainer grants i'd much rater prompt myself rather than veryfying how bandyl other prompts mess up and closing them |
Fixes #14995.
SysCaptureBase.suspendhandedsys.stdoutback to the stream saved before capturing started, andresumereinstatedtmpfile, the stream capture installed atstart. Neither read what was actually there, so a stream installed afterstart—contextlib.redirect_stdout,click.testing.CliRunner.isolation, a fixture of one's own — was discarded on the first suspend/resume cycle, and everything written afterwards went to pytest's buffer rather than to the caller that installed it.Under
log_cli = truethat is a per-record event: the live-log handler sits on the root logger and suspends capturing around every record it writes, so one log record emitted at any depth costs a test its redirect. The failure is silent, and assertions about absent output pass vacuously.The change
Suspending while suspended is left alone, since what sits there then is what
suspenditself installed rather than a stream worth remembering.doneis unchanged and still restores the stream capture replaced, so a swap left behind by a test cannot outlive it.Tests
Five added to
testing/test_capture.py. Four sit besidetest_simple_resume_suspendand driveSysCapturedirectly; one usespytesterto cover thelog_clipath this actually reaches users through.Three of the five fail without the change. The two that pass either way are the ones asserting existing behaviour is preserved —
resumereturningtmpfilewhen nothing swapped it, anddonerestoring the original stream.Verification
Against
mainat 3fd8675:testing/test_capture.py+testing/logging/pre-commitThe only delta is the five added tests. The failure and error are present on
mainbeforehand and are unrelated to capture:testing/test_doctest.py::TestDoctests::test_fixture_doctest_skip_has_line_numberandtesting/test_legacypath.py::test_cache_makedir.On the "pytest owns the streams" reading
The one counter-argument is that pytest owns
sys.stdoutfor the duration of a test, so anything swapping it underneath is unsupported andresumeis entitled to reset. Three things stand against it.contextlib.redirect_stdoutis standard library. Under that reading it is unsupported inside any test run with--log-cli, which is documented nowhere and is unlikely to be the intent. No third-party code is required to hit this.pytest's own design already separates the two operations.
donerestores the pre-capture stream;resumerestorestmpfile. That distinction only makes sense ifresumeis the inverse ofsuspendrather than a reset — andglobal_and_fixture_disabled, the caller that produces this, describes itself as temporarily disabling capture.There is precedent in the same context manager. #7148 was an imbalance in
global_and_fixture_disabled— resuming capture it had not suspended — and was accepted and fixed in #7651. This is the same shape: a pair that does not restore what it displaced.The change is four lines and moves nothing else. The full suite is unchanged apart from the tests added here, so correctness here costs nothing elsewhere.