Skip to content

fix(utils): #3852 ensure sarge Capture.flush exists on Py 3.13+#3980

Draft
jstvz wants to merge 2 commits into
devfrom
triage/fix-tranche1-3852
Draft

fix(utils): #3852 ensure sarge Capture.flush exists on Py 3.13+#3980
jstvz wants to merge 2 commits into
devfrom
triage/fix-tranche1-3852

Conversation

@jstvz
Copy link
Copy Markdown
Contributor

@jstvz jstvz commented May 14, 2026

Summary

Fixes #3852.

sarge.Capture lost its flush() method under newer Python/pipe semantics, surfacing as a noisy AttributeError on shutdown when CumulusCI captures subprocess output. This adds a one-shot monkey-patch at cumulusci/utils/__init__.py import time: if sarge.Capture has no flush attribute, install a no-op flush() so callers that probe the attribute do not crash. No functional change to sarge behavior.

Test plan

  • cumulusci/utils/tests/test_sarge_patch.py::test_sarge_capture_has_flush_after_import passes.
  • xfail marker on cumulusci/tests/triage/test_issue_3852.py removed in the GREEN commit; test now passes.
  • uv run pytest cumulusci/utils/tests/ -q clean.

Provenance

Reproduced and characterized in the v5 triage evidence pack (PR #3979). See docs/triage/v5/repro-results.md (### #3852) for the full narrative.

jstvz added 2 commits May 14, 2026 10:57
sarge==0.1.7.post1 ships without Capture.flush, and Python 3.13+ logging
calls flush() during interpreter shutdown after refresh_oauth_token, which
surfaces a cosmetic AttributeError. Add a regression test that asserts
sarge.Capture exposes a callable, no-op flush() after importing
cumulusci.utils.

Currently failing: the fix lands in the next commit.

Refs #3852
pyproject.toml pins ``sarge`` with no version constraint, so the
installed version is 0.1.7.post1, whose Capture class lacks a flush()
method. The upstream fix is unreleased on sarge's master branch.

Python 3.13+ interpreter-shutdown logging path calls flush() on
captured streams that CumulusCI hands to logging handlers via
sarge.Command(stdout=Capture(...)). After refresh_oauth_token (which
calls sfdx_info → sfdx() → sarge.Command with Capture) the shutdown
logger therefore emits a cosmetic ``AttributeError: 'Capture' object
has no attribute 'flush'``. Functionally a no-op, but noisy and
confusing.

Install an idempotent shim at the cumulusci.utils import site that
adds Capture.flush = lambda self: None only if sarge does not already
provide flush(). When sarge eventually ships its own flush(), the
guard skips the patch automatically.

Refs #3852
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.

1 participant