Skip to content

Honor kill_after_timeout with output streams - #2189

Merged
Byron merged 2 commits into
gitpython-developers:mainfrom
pick7:codex/output-stream-timeout
Jul 26, 2026
Merged

Honor kill_after_timeout with output streams#2189
Byron merged 2 commits into
gitpython-developers:mainfrom
pick7:codex/output-stream-timeout

Conversation

@pick7

@pick7 pick7 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Start the existing timeout watchdog when output_stream is used.
  • Keep the watchdog active until the subprocess has actually exited.
  • Add a regression test where stdout closes before the child process sleeps.

Fixes #1762.

Validation

  • .venv/bin/python -m pytest -o addopts= test/test_git.py
  • .venv/bin/python -m ruff check git/cmd.py test/test_git.py
  • .venv/bin/python -m ruff format --check git/cmd.py test/test_git.py
  • .venv/bin/python -m mypy git/cmd.py

AI agent disclosure

This pull request was prepared and submitted by OpenAI Codex acting as an AI agent through the contributor account.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes Git.execute(..., kill_after_timeout=...) so timeouts are enforced even when output_stream is provided, aligning behavior with the documented intent and closing the gap described in #1762.

Changes:

  • Start and manage the existing timeout watchdog during the output_stream execution path, keeping it active until the subprocess exits.
  • Refactor timeout error construction into a helper used by both communicate() and output_stream paths.
  • Add a regression test where the child closes stdout early and then sleeps, ensuring kill_after_timeout still triggers.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
git/cmd.py Starts/cancels the timeout watchdog for output_stream runs and centralizes timeout error creation.
test/test_git.py Adds a non-Windows regression test to confirm kill_after_timeout is honored with output_stream.
Comments suppressed due to low confidence (1)

git/cmd.py:1490

  • communicate() starts the watchdog timer but only cancels it on the success path. If proc.communicate() raises (e.g., due to an I/O error), the timer remains scheduled and can later kill the process (or a reused PID) after execute() has already failed. Cancel the watchdog in a finally to ensure it is always cleaned up.
            def communicate() -> Tuple[AnyStr, AnyStr]:
                assert watchdog is not None
                assert kill_check is not None
                watchdog.start()
                out, err = proc.communicate()
                watchdog.cancel()
                if kill_check.is_set():
                    err = make_timeout_error()
                return out, err

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread git/cmd.py
The timeout error message formats `timeout` with `%d`, but `kill_after_timeout` is typed as `float` and is commonly passed as a non-integer (e.g., 0.1). This can produce a misleading message (truncation to 0) and may raise a formatting error depending on Python behavior. Format it as a float (or generic number) instead.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

@Byron Byron left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks a lot, this circumstantially looks good to me.

@Byron
Byron merged commit 2e5b13f into gitpython-developers:main Jul 26, 2026
48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants