You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: changelog.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,6 +13,9 @@
13
13
- Add a `--theme=auto` value that selects the `dark` or `light` palette from the detected terminal background. Accepted on every `@command` and `@group`; the `--theme` default stays `dark`.
14
14
- Detect the terminal background from the `CLITHEME` and `COLORFGBG` environment variables, and, when a `ThemeOption` is built with `query_background=True`, from a live xterm OSC 11 terminal query.
15
15
- Add `resolve_background` and `query_osc_background` to `click_extra.color`, and `resolve_auto_theme` and the `AUTO_THEME` constant to `click_extra.theme`.
16
+
- Add `run_lanes(func, lanes)` to `click_extra.execution`: a fan-out that runs each lane's items serially while running distinct lanes concurrently, sized by the resolved `--jobs` count. `run_jobs` is its single-item-per-lane special case.
17
+
- Add `resolve_jobs(ctx, count)` to `click_extra.execution`, exposing the worker-count policy shared by `run_jobs` and `run_lanes` for callers that need the resolved count before fanning out. Both helpers gain a `serial_at_debug` keyword that collapses to sequential at `DEBUG` verbosity.
18
+
- Publish `format_cli_prompt` in `click_extra.testing` (was the private `_format_cli_prompt`): render a themed, copy-pasteable prompt simulating a CLI invocation.
Copy file name to clipboardExpand all lines: docs/execution.md
+29Lines changed: 29 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -147,6 +147,35 @@ assert "Baked APPLE" in result.stdout
147
147
148
148
The pool is thread-based, which fits the I/O- and subprocess-bound work CLIs usually parallelize (each child releases the GIL). With a single worker the run stays lazy, so a caller can stop on the first result, for example to abort on the first failure.
149
149
150
+
## Running lanes in parallel
151
+
152
+
Sometimes work cannot all run concurrently: a subset must be serialized relative to itself (a shared lock, a rate limit, one mailbox file read at a time, one package-manager backend) while still overlapping with unrelated subsets. `run_lanes(func, lanes)` groups items into *lanes*: a lane's own items run serially and in order on a single worker, while distinct lanes run concurrently up to the resolved `--jobs` count. `run_jobs` is the degenerate case where every lane holds a single item.
153
+
154
+
```{click:source}
155
+
from click import command, echo
156
+
from click_extra import jobs_option, run_lanes
157
+
158
+
@command
159
+
@jobs_option
160
+
def bake():
161
+
"""Bake several trays: items on a tray bake in order, trays bake in parallel."""
162
+
trays = (("apple", "banana"), ("cherry",))
163
+
for baked in run_lanes(str.upper, trays):
164
+
echo(f"Baked {baked}")
165
+
```
166
+
167
+
```{click:run}
168
+
result = invoke(bake, args=["--jobs", "2"])
169
+
assert result.exit_code == 0
170
+
assert "Baked APPLE" in result.stdout
171
+
```
172
+
173
+
Concurrency is sized by the number of lanes (one worker per lane), and results are yielded in lane-submission order. Because a lane runs entirely on one worker, a stateful resource bound to that lane (a per-lane cache, a connection) is touched by only one thread and needs no lock.
174
+
175
+
## Resolving the job count
176
+
177
+
`run_jobs` and `run_lanes` decide their worker count internally, but a caller that must know it *before* fanning out (for example to pick a progress-rendering mode) can call `resolve_jobs(ctx, count)` directly. It returns the same number those helpers use: `1` (sequential) when there is no context, a single item, or `--jobs 1`, otherwise the resolved count capped at `count`. Passing `serial_at_debug=True` also collapses to sequential at `DEBUG` verbosity, where coherent per-worker log narration matters more than the speed-up; both helpers forward this flag.
178
+
150
179
## Zero exit code
151
180
152
181
A pre-configured `-0`/`--zero-exit` option flag, following the convention popularized by linters and static analysers: they exit with a non-zero code whenever they report findings, so automation can gate on it. Setting this flag flips that behavior, so the CLI returns `0` as long as it ran to completion, reserving non-zero codes for actual execution failures.
0 commit comments