lib-cli-exit-tools 2.2.0__py3-none-any.whl → 2.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lib_cli_exit_tools/__init__conf__.py +1 -1
- {lib_cli_exit_tools-2.2.0.dist-info → lib_cli_exit_tools-2.2.2.dist-info}/METADATA +74 -25
- {lib_cli_exit_tools-2.2.0.dist-info → lib_cli_exit_tools-2.2.2.dist-info}/RECORD +6 -6
- {lib_cli_exit_tools-2.2.0.dist-info → lib_cli_exit_tools-2.2.2.dist-info}/WHEEL +0 -0
- {lib_cli_exit_tools-2.2.0.dist-info → lib_cli_exit_tools-2.2.2.dist-info}/entry_points.txt +0 -0
- {lib_cli_exit_tools-2.2.0.dist-info → lib_cli_exit_tools-2.2.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -24,7 +24,7 @@ name = "lib_cli_exit_tools"
|
|
|
24
24
|
#: Human-readable summary shown in CLI help output.
|
|
25
25
|
title = "CLI exit handling helpers: clean signals, exit codes, and error printing"
|
|
26
26
|
#: Current release version pulled from ``pyproject.toml`` by automation.
|
|
27
|
-
version = "2.2.
|
|
27
|
+
version = "2.2.2"
|
|
28
28
|
#: Repository homepage presented to users.
|
|
29
29
|
homepage = "https://github.com/bitranox/lib_cli_exit_tools"
|
|
30
30
|
#: Author attribution surfaced in CLI output.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lib_cli_exit_tools
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: CLI exit handling helpers: clean signals, exit codes, and error printing
|
|
5
5
|
Project-URL: Homepage, https://github.com/bitranox/lib_cli_exit_tools
|
|
6
6
|
Project-URL: Repository, https://github.com/bitranox/lib_cli_exit_tools.git
|
|
@@ -23,15 +23,15 @@ Requires-Dist: build>=1.3.0; extra == 'dev'
|
|
|
23
23
|
Requires-Dist: codecov-cli>=11.2.6; extra == 'dev'
|
|
24
24
|
Requires-Dist: coverage[toml]>=7.13.0; extra == 'dev'
|
|
25
25
|
Requires-Dist: hypothesis>=6.148.7; extra == 'dev'
|
|
26
|
-
Requires-Dist: import-linter>=2.
|
|
26
|
+
Requires-Dist: import-linter>=2.9; extra == 'dev'
|
|
27
27
|
Requires-Dist: pip-audit>=2.10.0; extra == 'dev'
|
|
28
28
|
Requires-Dist: pyright>=1.1.407; extra == 'dev'
|
|
29
29
|
Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
|
|
30
30
|
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
31
31
|
Requires-Dist: pytest>=9.0.2; extra == 'dev'
|
|
32
|
-
Requires-Dist:
|
|
32
|
+
Requires-Dist: rtoml>=0.13.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: ruff>=0.14.9; extra == 'dev'
|
|
33
34
|
Requires-Dist: textual>=6.8.0; extra == 'dev'
|
|
34
|
-
Requires-Dist: tomli>=2.3.0; (python_version < '3.11') and extra == 'dev'
|
|
35
35
|
Requires-Dist: twine>=6.2.0; extra == 'dev'
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
|
|
@@ -55,6 +55,20 @@ Small helpers for robust CLI exit handling:
|
|
|
55
55
|
- Consistent exception → exit code mapping
|
|
56
56
|
- Concise error printing with optional traceback and subprocess stdout/stderr capture
|
|
57
57
|
|
|
58
|
+
## Why lib_cli_exit_tools?
|
|
59
|
+
|
|
60
|
+
Building CLI applications that behave correctly in shell pipelines, CI/CD systems, and across platforms is surprisingly tricky. This library solves five common pain points:
|
|
61
|
+
|
|
62
|
+
1. **Correct Exit Codes** — Exceptions are automatically mapped to platform-appropriate exit codes (POSIX errno or BSD sysexits). `FileNotFoundError` returns `2`, `PermissionError` returns `13` on POSIX, and `KeyboardInterrupt` returns `130` — matching shell conventions without manual bookkeeping.
|
|
63
|
+
|
|
64
|
+
2. **Portable Signal Handling** — SIGINT (Ctrl+C), SIGTERM, and Windows SIGBREAK are translated into structured Python exceptions with deterministic exit codes. Your CLI behaves consistently whether terminated by a user, a process manager, or a CI runner.
|
|
65
|
+
|
|
66
|
+
3. **Clean Error Output** — Uncaught exceptions produce concise, coloured error messages by default. Toggle `--traceback` for full Rich-formatted stack traces during debugging — no code changes required.
|
|
67
|
+
|
|
68
|
+
4. **Pipeline-Friendly** — `BrokenPipeError` is handled gracefully (exit 141 by default, matching `128 + SIGPIPE`), so piping output to `head` or other truncating tools doesn't produce noisy tracebacks.
|
|
69
|
+
|
|
70
|
+
5. **Zero Boilerplate** — Wrap any Click command with `run_cli()` and get signal handling, exit-code translation, and stream flushing in one call. Configuration is centralised and test-friendly via context managers.
|
|
71
|
+
|
|
58
72
|
## Install
|
|
59
73
|
|
|
60
74
|
Requires Python 3.10 or newer.
|
|
@@ -77,6 +91,35 @@ lib-cli-exit-tools fail # intentionally trigger RuntimeError to test error path
|
|
|
77
91
|
# Aliases are also generated: `cli-exit-tools`, `lib_cli_exit_tools`
|
|
78
92
|
```
|
|
79
93
|
|
|
94
|
+
## CLI Reference
|
|
95
|
+
|
|
96
|
+
The library installs three equivalent console scripts: `lib-cli-exit-tools` (primary), `cli-exit-tools`, and `lib_cli_exit_tools`. All invoke `lib_cli_exit_tools.cli:main`.
|
|
97
|
+
|
|
98
|
+
### Global Options
|
|
99
|
+
|
|
100
|
+
| Option | Default | Description |
|
|
101
|
+
|--------|---------|-------------|
|
|
102
|
+
| `--traceback` / `--no-traceback` | `False` | Show full Python traceback on errors |
|
|
103
|
+
| `--version` | — | Show program version and exit |
|
|
104
|
+
| `-h`, `--help` | — | Show help message and exit |
|
|
105
|
+
|
|
106
|
+
### Commands
|
|
107
|
+
|
|
108
|
+
#### `info`
|
|
109
|
+
Display package metadata (name, version, homepage, author).
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
lib-cli-exit-tools info
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### `fail`
|
|
116
|
+
Intentionally raise `RuntimeError('i should fail')` to validate error handling paths.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
lib-cli-exit-tools fail
|
|
120
|
+
lib-cli-exit-tools --traceback fail # show full traceback
|
|
121
|
+
```
|
|
122
|
+
|
|
80
123
|
### Examples
|
|
81
124
|
|
|
82
125
|
The snippets below move from a minimal “hello world” through a production-ready
|
|
@@ -109,7 +152,7 @@ Run it with:
|
|
|
109
152
|
python hello.py
|
|
110
153
|
```
|
|
111
154
|
|
|
112
|
-
#### 2.
|
|
155
|
+
#### 2. Traceback-mode helper using `cli_session`
|
|
113
156
|
|
|
114
157
|
```python
|
|
115
158
|
from __future__ import annotations
|
|
@@ -120,22 +163,22 @@ from lib_cli_exit_tools import cli_session, run_cli
|
|
|
120
163
|
|
|
121
164
|
|
|
122
165
|
@click.command()
|
|
123
|
-
@click.option("--
|
|
124
|
-
def cli(
|
|
125
|
-
with cli_session(overrides={"traceback":
|
|
166
|
+
@click.option("--traceback", is_flag=True, help="Show full tracebacks on error")
|
|
167
|
+
def cli(traceback: bool) -> int:
|
|
168
|
+
with cli_session(overrides={"traceback": traceback}) as execute:
|
|
126
169
|
return execute(failable, argv=[])
|
|
127
170
|
|
|
128
171
|
|
|
129
172
|
@click.command()
|
|
130
173
|
def failable() -> None:
|
|
131
|
-
raise RuntimeError("toggle --
|
|
174
|
+
raise RuntimeError("toggle --traceback to see the full traceback")
|
|
132
175
|
|
|
133
176
|
|
|
134
177
|
if __name__ == "__main__":
|
|
135
178
|
raise SystemExit(run_cli(cli))
|
|
136
179
|
```
|
|
137
180
|
|
|
138
|
-
Invoking `python cli.py --
|
|
181
|
+
Invoking `python cli.py --traceback` enables coloured tracebacks just for that
|
|
139
182
|
run and resets the configuration afterwards.
|
|
140
183
|
|
|
141
184
|
#### 3. Full-featured multi-command CLI
|
|
@@ -154,21 +197,21 @@ from lib_cli_exit_tools import SignalSpec, cli_session, default_signal_specs
|
|
|
154
197
|
@dataclass(slots=True)
|
|
155
198
|
class Settings:
|
|
156
199
|
pretty: bool
|
|
157
|
-
|
|
200
|
+
traceback: bool
|
|
158
201
|
|
|
159
202
|
|
|
160
203
|
@click.group()
|
|
161
204
|
@click.option("--pretty/--no-pretty", default=True)
|
|
162
|
-
@click.option("--
|
|
205
|
+
@click.option("--traceback", is_flag=True, help="Show full tracebacks on error")
|
|
163
206
|
@click.pass_context
|
|
164
|
-
def cli(ctx: click.Context, pretty: bool,
|
|
165
|
-
ctx.obj = Settings(pretty=pretty,
|
|
207
|
+
def cli(ctx: click.Context, pretty: bool, traceback: bool) -> None:
|
|
208
|
+
ctx.obj = Settings(pretty=pretty, traceback=traceback)
|
|
166
209
|
|
|
167
210
|
|
|
168
211
|
@cli.command()
|
|
169
212
|
@click.pass_obj
|
|
170
213
|
def info(settings: Settings) -> None:
|
|
171
|
-
payload = {"
|
|
214
|
+
payload = {"traceback": settings.traceback, "pretty": settings.pretty}
|
|
172
215
|
click.echo(json.dumps(payload, indent=2 if settings.pretty else None))
|
|
173
216
|
|
|
174
217
|
|
|
@@ -308,9 +351,12 @@ config.broken_pipe_exit_code = 0 # treat BrokenPipeError as a benign truncat
|
|
|
308
351
|
|
|
309
352
|
Field reference:
|
|
310
353
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
354
|
+
| Field | Type | Default | Description |
|
|
355
|
+
|-------|------|---------|-------------|
|
|
356
|
+
| `traceback` | `bool` | `False` | When `True`, `handle_cli_exception` renders a full Rich traceback to stderr. The bundled CLI toggles this via `--traceback/--no-traceback`. |
|
|
357
|
+
| `exit_code_style` | `"errno"` \| `"sysexits"` | `"errno"` | Controls exit code mapping. `errno` returns POSIX/Windows-style codes; `sysexits` returns BSD-style semantic codes (EX_USAGE, EX_NOINPUT, etc.). |
|
|
358
|
+
| `broken_pipe_exit_code` | `int` | `141` | Exit status for `BrokenPipeError` (default mirrors `128 + SIGPIPE`). Set to `0` to treat truncation as success. |
|
|
359
|
+
| `traceback_force_color` | `bool` | `False` | Force Rich to emit ANSI-coloured tracebacks even when stderr is not a TTY. Useful for CI logs. |
|
|
314
360
|
|
|
315
361
|
Remember that `config` is module-level—if you call the library from multiple threads or embed it in another CLI, configure it once during bootstrap before handing control to user code. When you need temporary overrides (for tests or nested CLIs), wrap the change with the built-in context manager so state is restored automatically:
|
|
316
362
|
|
|
@@ -397,22 +443,25 @@ Parameters:
|
|
|
397
443
|
- `exception_handler`: Callable receiving the raised exception and returning an exit code; defaults to ``handle_cli_exception``.
|
|
398
444
|
- `signal_installer`: Callable mirroring ``install_signal_handlers`` for embedding scenarios.
|
|
399
445
|
|
|
400
|
-
### `cli_session(*, summary_limit=500, verbose_limit=10_000, overrides=None)`
|
|
401
|
-
Context manager that snapshots
|
|
446
|
+
### `cli_session(*, summary_limit=500, verbose_limit=10_000, overrides=None, restore=True)`
|
|
447
|
+
Context manager that snapshots `lib_cli_exit_tools.config`, optionally
|
|
402
448
|
applies temporary overrides, and yields a callable compatible with
|
|
403
|
-
|
|
449
|
+
`run_cli`.
|
|
404
450
|
|
|
405
451
|
Parameters:
|
|
406
|
-
- `summary_limit
|
|
407
|
-
- `verbose_limit
|
|
408
|
-
- `overrides
|
|
452
|
+
- `summary_limit` (`int`, default `500`): Character budget when tracebacks are disabled.
|
|
453
|
+
- `verbose_limit` (`int`, default `10_000`): Character budget when tracebacks are enabled.
|
|
454
|
+
- `overrides` (`Mapping[str, object] | None`, default `None`): Mapping of configuration field/value pairs applied during the session. When `traceback` is supplied and `traceback_force_color` is omitted, colour output is automatically forced.
|
|
455
|
+
- `restore` (`bool`, default `True`): When `True`, configuration state is restored after the session. Set to `False` to leave overrides in place once the context exits.
|
|
409
456
|
|
|
410
457
|
Use it to restore configuration automatically—even when the wrapped command
|
|
411
458
|
raises:
|
|
412
459
|
|
|
413
460
|
```python
|
|
461
|
+
from lib_cli_exit_tools import cli_session
|
|
462
|
+
|
|
414
463
|
with cli_session(overrides={"traceback": True}) as run:
|
|
415
|
-
exit_code = run(
|
|
464
|
+
exit_code = run(my_click_command, argv=["--help"])
|
|
416
465
|
```
|
|
417
466
|
|
|
418
467
|
### `handle_cli_exception(exc, *, signal_specs=None, echo=None) -> int`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
lib_cli_exit_tools/__init__.py,sha256=Z-VXcrmjZCgJZ8NW0UCVIc0HBOsjQicCbzgHj7r22eA,1867
|
|
2
|
-
lib_cli_exit_tools/__init__conf__.py,sha256=
|
|
2
|
+
lib_cli_exit_tools/__init__conf__.py,sha256=to8gHcedeLf0Tg2RY3NEnAl6xIpKqPcC7vJCAaHJLZY,2521
|
|
3
3
|
lib_cli_exit_tools/__main__.py,sha256=wODJaNu_NyO7tknvlpPArq0MaDwDum8zqyb73-qshzo,257
|
|
4
4
|
lib_cli_exit_tools/cli.py,sha256=k7LC08nVfse4i9RbsOGKTc9y-rrVbR1nOSKiwBvNxrE,9322
|
|
5
5
|
lib_cli_exit_tools/lib_cli_exit_tools.py,sha256=-_kjKGiWyMQ715KxOqrS6uA57SXOgJmMeowU7AmtC8A,2525
|
|
@@ -11,8 +11,8 @@ lib_cli_exit_tools/application/runner.py,sha256=AlCWX5o4VTRzsCom9EgnEK0iVCIZwyId
|
|
|
11
11
|
lib_cli_exit_tools/core/__init__.py,sha256=aR7OIBWOQ1PsA33blOTgLrq5ffKDCuaMVBS5mbrDAZ8,531
|
|
12
12
|
lib_cli_exit_tools/core/configuration.py,sha256=Ro6R2cmOIFhdOUogjK1VOxEJInx24Wgme0t-ucYJGEg,5658
|
|
13
13
|
lib_cli_exit_tools/core/exit_codes.py,sha256=nqx-e6h-ji-FiECPnDV8b0yrjcLPJyU-3xf4zhfRCBE,12322
|
|
14
|
-
lib_cli_exit_tools-2.2.
|
|
15
|
-
lib_cli_exit_tools-2.2.
|
|
16
|
-
lib_cli_exit_tools-2.2.
|
|
17
|
-
lib_cli_exit_tools-2.2.
|
|
18
|
-
lib_cli_exit_tools-2.2.
|
|
14
|
+
lib_cli_exit_tools-2.2.2.dist-info/METADATA,sha256=GCpsPdPf2U_RHvVKoIpDQ3ybxI321wYU2UkKxMrT3Dk,25942
|
|
15
|
+
lib_cli_exit_tools-2.2.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
16
|
+
lib_cli_exit_tools-2.2.2.dist-info/entry_points.txt,sha256=8R-_3UT0KcQ7HQ7idDx6rlG77GhHb0E2N5QnN41dj-M,161
|
|
17
|
+
lib_cli_exit_tools-2.2.2.dist-info/licenses/LICENSE,sha256=6s9SL2InRrwynPjJYiER7ONHBshbGj_yC5EBzfo7l9I,1072
|
|
18
|
+
lib_cli_exit_tools-2.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|