Skip to content

fix(cli): ignore broken pipe during status line cleanup - #1158

Open
binggao1230 wants to merge 2 commits into
canonical:mainfrom
binggao1230:fix-1150-statusline-broken-pipe
Open

fix(cli): ignore broken pipe during status line cleanup#1158
binggao1230 wants to merge 2 commits into
canonical:mainfrom
binggao1230:fix-1150-statusline-broken-pipe

Conversation

@binggao1230

Copy link
Copy Markdown

Summary

  • ignore BrokenPipeError while StatusLine.stop() writes/flushed terminal cleanup output
  • always restore the wrapped print and input builtins during status line shutdown
  • add a regression test for closed stdout pipes during cleanup

Closes #1150

Tests

  • uv run pytest tests/test_status_line.py::TestStatusLineInit::test_stop_ignores_broken_pipe_and_restores_builtins -q
  • uv run pytest tests/test_status_line.py -q
  • uvx --with tox-uv tox run -e lock
  • uvx --with tox-uv tox run -e lint
  • uvx --with tox-uv tox run -e unit -- tests/test_status_line.py

Notes

  • uvx --with tox-uv tox run -e unit on this macOS machine reached 222 passed but failed two unrelated helper tests: test_is_in_snap_private_dir and test_parse_filename_snap_private. Those tests expect /tmp/job.yaml to remain under /tmp; on macOS Path.resolve() maps it under /private/tmp, so it no longer matches SNAP_PRIVATE_DIRS = ["/tmp"].

AI assistance was used under my direction.

@ajzobro

ajzobro commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

While the proposed code does appear to attempt to address the original problem, it does not seem to cure the issue:

Cancel job dd1a3d49-258a-4ec4-afc1-d923e254f2d8 before exiting (y)es/(N)o/(c)ontinue? ^C^CTraceback (most recent call last):
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/__init__.py", line 1689, in do_poll
    time.sleep(10)
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/__init__.py", line 115, in cli
    tfcli.run()
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/__init__.py", line 171, in run
    self.args.func()
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/__init__.py", line 1546, in poll_output
    self.poll(LogType.STANDARD_OUTPUT)
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/__init__.py", line 1517, in poll
    self.do_poll(job_id, log_type)
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/__init__.py", line 1698, in do_poll
    choice = input(
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/status_line.py", line 279, in input
    result = _original_input(prompt)
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/__init__.py", line 117, in cli
    sys.exit("Received KeyboardInterrupt")
SystemExit: Received KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/test/projects/testflinger/gaoflow/cli/.venv/bin/testflinger", line 10, in <module>
    sys.exit(cli())
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/__init__.py", line 121, in cli
    StatusLine.stop()
  File "/home/test/projects/testflinger/gaoflow/cli/testflinger_cli/status_line.py", line 81, in stop
    cls._timer_thread.join(timeout=2.0)
  File "/home/test/.local/share/uv/python/cpython-3.10.19-linux-x86_64-gnu/lib/python3.10/threading.py", line 1100, in join
    self._wait_for_tstate_lock(timeout=max(timeout, 0))
  File "/home/test/.local/share/uv/python/cpython-3.10.19-linux-x86_64-gnu/lib/python3.10/threading.py", line 1116, in _wait_for_tstate_lock
    if lock.acquire(block, timeout):
KeyboardInterrupt

@binggao1230

Copy link
Copy Markdown
Author

Thanks for the repro. The remaining traceback was from a second Ctrl-C interrupting StatusLine.stop() while it was waiting on the timer thread.

I pushed 7382f9c8, which moves the join into the cleanup guard and ignores KeyboardInterrupt there the same way the existing change ignores a closed output pipe. The finally still restores the original print/input builtins.

Verified with:

  • uv run pytest tests/test_status_line.py::TestStatusLineInit -q
  • uv run pytest tests/test_status_line.py -q
  • uv run ruff format --check testflinger_cli/status_line.py tests/test_status_line.py
  • uv run ruff check testflinger_cli/status_line.py tests/test_status_line.py

@ajzobro ajzobro added this to the 26.10.15 milestone Jul 2, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in a week.

@github-actions github-actions Bot added the Stale label Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] traceback when using CTRL-C to exit a polling session

2 participants