Tighten complexity/length gates and refactor to satisfy them#29
Merged
Conversation
Make the lint gates enforce small, single-screen functions (the friction a coding agent hits most), then refactor the functions that exceeded the new limits without changing behavior. Gates: - ruff: add C90 (mccabe) to select; set mccabe.max-complexity=10, pylint.max-statements=40, max-branches=12, max-returns=6, and lower max-args 10 -> 8. Narrow the commands/** ignore to [FBT001, FBT003, PLR0913] so command *bodies* are held to the same length/branch limits as the rest of the package (only the Typer-signature realities stay exempt). - xenon: tighten --max-modules B -> A, so no module may average worse than grade A. (xenon measures branching only; raw length/arg limits live in ruff.) Refactors (behavior-preserving): - commands/stream.py: replace the ~250-line nested-closure command body with a module-level _SourceOptions, a _StreamSession class, and _validate_sources/_dispatch helpers; collapse the duplicated run/ run_parallel lifecycle into one _guarded helper. - commands/init.py, llm.py, agent.py: lift logic out of the nested command closures into module-level helpers. - agent/session.py: bundle the static run config into a frozen AgentRunConfig (run_session 10 args -> 6) and extract _session_update_message/ _receive_loop; name the untyped-SDK boundary with type aliases so Any stays in one place. - timeparse.py, code_gen/stream.py: small readability extractions to bring their module-average complexity to grade A. Verified: ruff, ruff-format, mypy, pyright (strict + tests), xenon, vulture, deptry, import-linter, build/twine all pass; 903 tests pass at 99% coverage with 100% patch coverage.
alexkroman
pushed a commit
that referenced
this pull request
Jun 6, 2026
FileSource.__iter__ delegates to the _ffmpeg_chunks() generator with a plain `for` loop. Closing the outer generator early (the streaming code stops pulling chunks) raises GeneratorExit at its `yield`, but a plain loop does not forward that into the inner generator, so ffmpeg's terminate/wait/close cleanup ran only at GC instead of synchronously — leaking the child process until collection and defeating the KeyboardInterrupt-during-wait handling. This regressed in the #29 refactor that split _ffmpeg_chunks() out of __iter__. Wrap the delegation in try/finally and close the inner generator explicitly so the subprocess teardown happens deterministically on early stop. The two test_streaming_sources cleanup tests pass again.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Make the lint gates enforce small, single-screen functions (the friction a
coding agent hits most), then refactor the functions that exceeded the new
limits without changing behavior.
Gates:
pylint.max-statements=40, max-branches=12, max-returns=6, and lower
max-args 10 -> 8. Narrow the commands/** ignore to [FBT001, FBT003,
PLR0913] so command bodies are held to the same length/branch limits
as the rest of the package (only the Typer-signature realities stay
exempt).
grade A. (xenon measures branching only; raw length/arg limits live in
ruff.)
Refactors (behavior-preserving):
a module-level _SourceOptions, a _StreamSession class, and
_validate_sources/_dispatch helpers; collapse the duplicated run/
run_parallel lifecycle into one _guarded helper.
closures into module-level helpers.
(run_session 10 args -> 6) and extract _session_update_message/
_receive_loop; name the untyped-SDK boundary with type aliases so Any
stays in one place.
their module-average complexity to grade A.
Verified: ruff, ruff-format, mypy, pyright (strict + tests), xenon,
vulture, deptry, import-linter, build/twine all pass; 903 tests pass at
99% coverage with 100% patch coverage.