Share one canonical stream-drain loop across consume variants (#115) - #153
Conversation
Reviewer's GuideRefactors stream consumption to use a single canonical drain loop, extracts shared tee-profile-worker concurrency scaffolding into a helpers module, and updates tests and docs to match the new structure and behaviour. Sequence diagram for canonical stream-drain loop with and without linessequenceDiagram
actor Caller
participant Streams as _streams
participant Drain as _drain
participant Decoder as feed_decoder
participant Lines as _emit_completed_lines
Caller->>Streams: _consume_stream(stream, config, on_line)
alt [on_line is None]
Streams->>Streams: _consume_stream_without_lines(stream, config)
Streams->>Drain: _drain(stream, config)
Drain-->>Streams: captured_text_or_None
else [on_line is not None]
Streams->>Streams: _consume_stream_with_lines(stream, config, on_line)
Streams->>Decoder: decoder_factory(errors)
Streams->>Drain: _drain(stream, config, on_chunk=feed_decoder)
loop for each chunk
Drain->>Decoder: feed_decoder(chunk)
Decoder->>Lines: _emit_completed_lines(pending_text, on_line)
Lines-->>Decoder: pending_text
end
Drain-->>Streams: captured
Streams->>Decoder: decoder.decode(b"", final=True)
Streams->>Lines: _emit_completed_lines(pending_text, on_line)
Lines-->>Streams: pending_text
Streams-->>Caller: captured
end
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
5cc9d09 to
82def0b
Compare
82def0b to
72bc930
Compare
72bc930 to
c99c36a
Compare
c99c36a to
4ae8e04
Compare
f4de308 to
70dd1fc
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cuprum/unittests/test_stream_drain_property_based.py`:
- Line 111: Replace all bare assertions at line 111, line 131, line 156, and
line 179 in the test_stream_drain_property_based.py file with assertions that
include explicit messages. Each assertion message should provide context about
the payload or chunk data being tested to make Hypothesis counterexamples
diagnosable without requiring test reruns. The format should be assert
<condition>, "<descriptive message including payload/chunk context>" for each of
the four locations.
In `@docs/developers-guide.md`:
- Line 66: Change the hyphenated term "multi-byte" to the non-hyphenated form
"multibyte" in the text "(including split multi-byte UTF-8 sequences and invalid
bytes)" to maintain consistency with the repository's established technical
terminology.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 6b70c2ee-fbda-4d63-8b44-556d8bd59b11
📒 Files selected for processing (4)
cuprum/_streams.pycuprum/unittests/__snapshots__/test_maturin_build.ambrcuprum/unittests/test_stream_drain_property_based.pydocs/developers-guide.md
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 18 minutes Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (11)
WalkthroughThe PR centralises subprocess stream draining in ChangesCanonical stream draining
Stream validation
Documentation and guidance
Test tooling
Poem
Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (2 errors, 1 warning)
✅ Passed checks (17 passed)
📋 Issue PlannerBuilt with CodeRabbit's Coding Plans for faster development and fewer bugs. View plan used: ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== test file lines 100-200 ==="
sed -n '100,220p' cuprum/unittests/test_stream_drain_property_based.py
echo ""
echo "=== full test file (last 120 lines) ==="
tail -130 cuprum/unittests/test_stream_drain_property_based.py
echo ""
echo "=== developers-guide.md concurrency section ==="
grep -n -i "concurr\|cancel\|await\|shared\|interleav\|sink\|buffer\|StreamReader" docs/developers-guide.md
echo ""
echo "=== check for multi-byte (hyphenated) anywhere in docs/ ==="
rg "multi-byte" docs/ || echo "NONE FOUND"
echo ""
echo "=== assertion lines in test file (assert statements) ==="
grep -n "assert " cuprum/unittests/test_stream_drain_property_based.pyLength of output: 15340
No further work is required and no new issues need to be raised. |
|
@coderabbitai resume |
✅ Action performedReviews resumed. |
Use Oxford spelling in prose now covered by the inherited spelling gate, refresh its generated configuration, and remove the duplicate design heading revealed by Markdown formatting.
Remove the extra blank line in the developers guide and collapse duplicate artefact headings in the behavioural parity execplan so the Markdown quality gates pass.
Document the configured incremental decoder and keep the parity ExecPlan consistent with the existing stream-drain baseline. Run each pytest target pattern as one batch, retain Whitaker resource limits, and use the structured output options API in behavioural coverage.
Compare whole and chunked callback output with an independent decoded-line oracle. Include a line-bearing example so a skipped callback cannot satisfy the property vacuously.
Remove the stale interpreter guard now that maturin 1.13.3 and PyO3 0.29 build CPython 3.15 wheels. Keep Syrupy's unused-snapshot check strict by ensuring the snapshot owner runs in the 3.15 CI job. Record the evidence showing why the earlier xdist run masked the unused snapshot.
Describe the current Python-then-Rust execution order of `make test` so Rust contributors run the documented gate from the correct location.
Expand each target pattern through normal shell pathname expansion so `PYTEST_TARGETS` remains data when callers override it.
Use per-drain incremental decoding for text-only echo sinks so UTF-8 characters spanning reads and incomplete tails follow the configured error policy. Keep buffered sinks on the raw-byte path. Quote overrideable pytest target patterns before shell expansion so target values cannot be re-parsed as shell syntax.
Exercise echo-only decoding across a split UTF-8 character and retain a raw-byte assertion for buffered sinks. Align the line-emission property oracle with the existing CR/LF callback contract so arbitrary payloads do not reinterpret other Unicode line boundaries.
Keep the canonical stream-drain loop focused on read, capture, echo, and callback dispatch by moving text-sink decoder setup and EOF flushing into private helpers.
3ba9e98 to
1e43be6
Compare
Summary
This branch factors the near-duplicate
_consume_stream_*variants onto one canonical stream-drain loop.Closes #115.
_consume_stream_without_linesand_consume_stream_with_lineseach owned a copy of thestream is Noneguard, buffer setup, read/echo loop, and final decode; the_with_linesvariant only layered incremental line emission on top. A fix to the loop in one variant was easy to forget in the other. The branch introduces a canonical_drain(stream, config, *, on_chunk=None)coroutine owning the read/echo/buffer mechanics; the line-emitting variant supplies anon_chunkcallback feeding the incremental decoder, and the public_consume_streamdispatch remains the single entry point.Review walkthrough
_draincoroutine and the two thin variants.Pipeline.run_sync()behaviour through real subprocess I/O, including concurrent final stdout/stderr capture and a shared echo sink.Validation
make check-fmt: passmake lint: passmake typecheck: passmake test: pass (596 passed, 45 skipped; Rust suite 4 passed)make markdownlint: passmake nixie: passrg "multi-byte" docs/: no matchescoderabbit review --agent: pending at PR creation (rate-limited); will be re-run and clearedNotes
The private
_consume_streamunit property module was removed after review feedback; the added coverage now exercises the refactor through publicPipelinebehaviour and real subprocess I/O. The wheel-build snapshot drops that removed test module from its recorded file list.Summary by Sourcery
Canonically centralize the subprocess stream read/echo/capture loop behind a new
_drainhelper and expand property-based tests and documentation around it, while refactoring tee-profile-worker concurrency tests into shared scaffolding and focused modules.Enhancements:
_draincoroutine used by both line-emitting and non-line-emitting stream consumers to keep capture and echo behaviour consistent.Documentation:
_drainstream-drain loop, its reuse policy, and the updated layout of tee-profile-worker concurrency tests in the developer guide.Tests:
_EnvBackendSelectorconcurrency coverage into dedicated test modules for lock reentrancy, selector reentrancy, concurrent worker completion, and backend environment preservation, reusing common helpers.References