lib-cli-exit-tools 1.3.1__tar.gz → 1.5.0__tar.gz
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-1.3.1 → lib_cli_exit_tools-1.5.0}/AGENTS.md +4 -24
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/CHANGELOG.md +10 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/PKG-INFO +17 -11
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/README.md +9 -3
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/docs/system-design/module_reference.md +54 -59
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/notebooks/Quickstart.ipynb +73 -1
- lib_cli_exit_tools-1.5.0/notebooks/Quickstart.ipynb.Backup +281 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/packaging/brew/Formula/lib-cli-exit-tools.rb +1 -1
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/packaging/conda/recipe/meta.yaml +1 -1
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/packaging/nix/flake.nix +1 -1
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/pyproject.toml +8 -8
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/src/lib_cli_exit_tools/__init__.py +2 -0
- lib_cli_exit_tools-1.5.0/src/lib_cli_exit_tools/adapters/__init__.py +16 -0
- lib_cli_exit_tools-1.5.0/src/lib_cli_exit_tools/adapters/signals.py +177 -0
- lib_cli_exit_tools-1.5.0/src/lib_cli_exit_tools/application/__init__.py +16 -0
- lib_cli_exit_tools-1.5.0/src/lib_cli_exit_tools/application/runner.py +324 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/src/lib_cli_exit_tools/cli.py +26 -3
- lib_cli_exit_tools-1.5.0/src/lib_cli_exit_tools/core/__init__.py +16 -0
- lib_cli_exit_tools-1.5.0/src/lib_cli_exit_tools/core/configuration.py +58 -0
- lib_cli_exit_tools-1.5.0/src/lib_cli_exit_tools/core/exit_codes.py +149 -0
- lib_cli_exit_tools-1.5.0/src/lib_cli_exit_tools/lib_cli_exit_tools.py +75 -0
- lib_cli_exit_tools-1.5.0/tests/adapters/test_signals.py +75 -0
- lib_cli_exit_tools-1.5.0/tests/application/test_runner.py +247 -0
- lib_cli_exit_tools-1.5.0/tests/cli/test_cli_entrypoints.py +118 -0
- lib_cli_exit_tools-1.5.0/tests/conftest.py +36 -0
- lib_cli_exit_tools-1.5.0/tests/core/test_exit_codes.py +151 -0
- lib_cli_exit_tools-1.3.1/src/lib_cli_exit_tools/lib_cli_exit_tools.py +0 -749
- lib_cli_exit_tools-1.3.1/tests/test_cli.py +0 -85
- lib_cli_exit_tools-1.3.1/tests/test_cli_extra.py +0 -32
- lib_cli_exit_tools-1.3.1/tests/test_exit_tools.py +0 -167
- lib_cli_exit_tools-1.3.1/tests/test_extend_cli.py +0 -111
- lib_cli_exit_tools-1.3.1/tests/test_lib_extra.py +0 -110
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/.env.example +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/.github/workflows/ci.yml +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/.github/workflows/codeql.yml +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/.github/workflows/release.yml +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/.gitignore +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/CONTRIBUTING.md +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/DEVELOPMENT.md +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/INSTALL.md +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/LICENSE +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/Makefile +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/codecov.yml +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/packaging/README.md +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/qlty.toml +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/__init__.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/_utils.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/build.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/bump.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/bump_major.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/bump_minor.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/bump_patch.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/bump_version.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/clean.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/dev.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/generate_nix_flake.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/install.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/menu.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/push.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/release.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/run_cli.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/test.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/scripts/version_current.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/src/lib_cli_exit_tools/__init__conf__.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/src/lib_cli_exit_tools/__main__.py +0 -0
- {lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/src/lib_cli_exit_tools/py.typed +0 -0
|
@@ -13,6 +13,8 @@ Review the system prompt files in `/media/srv-main/softdev/*/projects/softwarest
|
|
|
13
13
|
- python_structure_template.md
|
|
14
14
|
- self_documenting.md
|
|
15
15
|
- self_documenting_template.md
|
|
16
|
+
- python_jupyter_notebooks.md
|
|
17
|
+
- python_testing.md
|
|
16
18
|
|
|
17
19
|
always apply those Rules :
|
|
18
20
|
|
|
@@ -41,18 +43,6 @@ when writing or refracturing Python scripts, apply those Rules :
|
|
|
41
43
|
- `packaging/`: Conda, Homebrew, and Nix specs kept in sync via scripts.
|
|
42
44
|
- `tests/`: placeholder suite skipping until logging features exist.
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
## Build, Test, and Development Commands
|
|
46
|
-
|
|
47
|
-
- `make help` — list all targets with one‑line docs.
|
|
48
|
-
- `make test` — run ruff (lint + format check), pyright, pytest with coverage (enabled by default), and upload to Codecov (if configured via `.env`).
|
|
49
|
-
- Auto‑bootstrap: `make test` installs dev tools (`pip install -e .[dev]`) if linters/test deps are missing. Use `SKIP_BOOTSTRAP=1 make test` to disable.
|
|
50
|
-
- Coverage control: `COVERAGE=on|auto|off` (default `on` locally). Uses a unique `COVERAGE_FILE` each run to avoid DB locks.
|
|
51
|
-
- Before uploading to Codecov the harness creates an allow-empty commit (`test: auto commit before Codecov upload`) so the report attaches to a revision. Reset or amend if you do not want to keep it.
|
|
52
|
-
- `make build` — build Python wheel/sdist and attempt Conda/Homebrew/Nix builds (auto‑installs missing tools when needed).
|
|
53
|
-
- `make push` — runs the full `scripts/test.py` flow, prompts for/accepts a commit message (or `COMMIT_MESSAGE`), creates an allow-empty commit if needed, then pushes to the selected remote.
|
|
54
|
-
- `make clean` — remove caches, coverage, and build artifacts (includes `dist/` and `build/`).
|
|
55
|
-
|
|
56
46
|
### Versioning & Releases
|
|
57
47
|
|
|
58
48
|
- Single source of truth for the package version is `pyproject.toml` (`[project].version`).
|
|
@@ -84,13 +74,6 @@ when writing or refracturing Python scripts, apply those Rules :
|
|
|
84
74
|
|
|
85
75
|
## Coding Style & Naming Conventions
|
|
86
76
|
|
|
87
|
-
## Testing Guidelines
|
|
88
|
-
|
|
89
|
-
- Unit and integration-style tests live under `tests/`; keep them up to date when adding features.
|
|
90
|
-
- Extend coverage for new CLI or library behaviour (the suite exercises CLI commands, package metadata, and automation scripts).
|
|
91
|
-
- When adding functionality, replace or remove placeholders and ensure `make test` remains green.
|
|
92
|
-
- write good doctests which clearly show how the function works and what are the intensions. Use it as an enhancement of the inline documentation
|
|
93
|
-
|
|
94
77
|
## Commit & Pull Request Guidelines
|
|
95
78
|
|
|
96
79
|
## Architecture Overview
|
|
@@ -119,13 +102,10 @@ when writing or refracturing Python scripts, apply those Rules :
|
|
|
119
102
|
- run "make test" before any push to avoid lint/test breakage.
|
|
120
103
|
- after push, monitor errors in the github actions and try to correct the errors
|
|
121
104
|
|
|
122
|
-
## Jupyter Notebooks
|
|
123
|
-
use at least nbformat >=4.5
|
|
124
|
-
- "nbformat": 4,
|
|
125
|
-
- "nbformat_minor": 5
|
|
126
|
-
|
|
127
105
|
---
|
|
128
106
|
|
|
107
|
+
# ONLY ON USER REQEST !!!! :
|
|
108
|
+
|
|
129
109
|
# 📘 Documentation Review & Enhancement Prompt
|
|
130
110
|
|
|
131
111
|
You are a **senior software developer specializing in code documentation and system design clarity**. Your task is to review, correct, and enhance all documentation (external and inline) across the codebase with the following principles and workflow.
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.5.0] - 2025-09-26
|
|
4
|
+
|
|
5
|
+
- Refracture
|
|
6
|
+
|
|
7
|
+
## [1.4.0] - 2025-09-26
|
|
8
|
+
|
|
9
|
+
- Reafracture, TestSuite
|
|
10
|
+
|
|
3
11
|
## [1.3.1] - 2025-09-26
|
|
4
12
|
|
|
5
13
|
- patch colored traceback
|
|
@@ -51,6 +59,8 @@
|
|
|
51
59
|
- Metadata lookup in `__init__conf__` resolved once and reused.
|
|
52
60
|
- Coverage gate relaxed to 80% and removed `# pragma: no cover` comments.
|
|
53
61
|
- Quickstart notebook defaults to install from GitHub; added cell IDs; last cell prints exit code example instead of exiting.
|
|
62
|
+
- Repartitioned the exit tooling into `core`, `adapters`, and `application` packages with `lib_cli_exit_tools` now acting as a facade to preserve import paths.
|
|
63
|
+
- `run_cli` accepts injectable `exception_handler` and `signal_installer` hooks; CLI rich-click configuration now runs during `main()` execution instead of at import time.
|
|
54
64
|
|
|
55
65
|
### Fixed
|
|
56
66
|
- Pyright 3.10 compatibility in `__init__conf__` by typing to a minimal metadata protocol; resolved unknown `.get` errors.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lib_cli_exit_tools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
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
|
|
@@ -18,15 +18,15 @@ Classifier: Typing :: Typed
|
|
|
18
18
|
Requires-Python: >=3.10
|
|
19
19
|
Requires-Dist: rich-click>=1.9.1
|
|
20
20
|
Provides-Extra: dev
|
|
21
|
-
Requires-Dist: build>=1.
|
|
21
|
+
Requires-Dist: build>=1.3; extra == 'dev'
|
|
22
22
|
Requires-Dist: codecov>=2.1.13; extra == 'dev'
|
|
23
23
|
Requires-Dist: pyright>=1.1; extra == 'dev'
|
|
24
|
-
Requires-Dist: pytest-cov>=
|
|
25
|
-
Requires-Dist: pytest>=8.
|
|
26
|
-
Requires-Dist: ruff>=0.
|
|
27
|
-
Requires-Dist: textual>=0
|
|
28
|
-
Requires-Dist: tomli>=2.
|
|
29
|
-
Requires-Dist: twine>=
|
|
24
|
+
Requires-Dist: pytest-cov>=7.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.4; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.13; extra == 'dev'
|
|
27
|
+
Requires-Dist: textual>=6.1.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: tomli>=2.2.1; extra == 'dev'
|
|
29
|
+
Requires-Dist: twine>=6.2; extra == 'dev'
|
|
30
30
|
Description-Content-Type: text/markdown
|
|
31
31
|
|
|
32
32
|
# lib_cli_exit_tools
|
|
@@ -65,6 +65,7 @@ Console script:
|
|
|
65
65
|
lib_cli_exit_tools --help
|
|
66
66
|
cli-exit-tools --help # alias
|
|
67
67
|
lib_cli_exit_tools info
|
|
68
|
+
lib_cli_exit_tools fail # intentionally trigger RuntimeError to test error paths
|
|
68
69
|
```
|
|
69
70
|
|
|
70
71
|
### Embed in your own CLI
|
|
@@ -155,7 +156,7 @@ Mutable dataclass-like singleton holding process-wide settings. Configure it dur
|
|
|
155
156
|
- `broken_pipe_exit_code` (`int`): Overrides the exit status for `BrokenPipeError` (default `141`).
|
|
156
157
|
- `traceback_force_color` (`bool`): Forces Rich-coloured tracebacks even when stderr is not a TTY.
|
|
157
158
|
|
|
158
|
-
### `run_cli(cli, argv=None, *, prog_name=None, signal_specs=None, install_signals=True) -> int`
|
|
159
|
+
### `run_cli(cli, argv=None, *, prog_name=None, signal_specs=None, install_signals=True, exception_handler=None, signal_installer=None) -> int`
|
|
159
160
|
Wrap a Click command or group so every invocation shares the same signal handling and exit-code policy. Returns the numeric exit code instead of exiting the process.
|
|
160
161
|
|
|
161
162
|
Parameters:
|
|
@@ -164,6 +165,8 @@ Parameters:
|
|
|
164
165
|
- `prog_name`: Override the program name shown in help/version output.
|
|
165
166
|
- `signal_specs`: Iterable of `SignalSpec` objects to customise signal handling; defaults to `default_signal_specs()`.
|
|
166
167
|
- `install_signals`: Set `False` when the host application already manages signal handlers.
|
|
168
|
+
- `exception_handler`: Optional callable receiving the raised exception and returning an exit code; defaults to ``handle_cli_exception``.
|
|
169
|
+
- `signal_installer`: Optional callable mirroring ``install_signal_handlers`` for embedding scenarios.
|
|
167
170
|
|
|
168
171
|
### `handle_cli_exception(exc, *, signal_specs=None, echo=None) -> int`
|
|
169
172
|
Translate exceptions raised by Click commands into deterministic exit codes, honouring configured signal mappings and traceback policy.
|
|
@@ -187,6 +190,9 @@ Parameters:
|
|
|
187
190
|
- `length_limit`: Maximum characters for summary output.
|
|
188
191
|
- `stream`: Target text stream; defaults to `sys.stderr`.
|
|
189
192
|
|
|
193
|
+
### `i_should_fail()`
|
|
194
|
+
Deterministically raise `RuntimeError('i should fail')` to exercise error-handling paths. Useful for smoke-testing exit-code translation, CLI traceback toggles, and log formatting without inventing ad-hoc failing commands.
|
|
195
|
+
|
|
190
196
|
### `flush_streams() -> None`
|
|
191
197
|
Best-effort flush of `sys.stdout` and `sys.stderr`, ensuring buffered output is written before exit.
|
|
192
198
|
|
|
@@ -222,9 +228,9 @@ When `run_cli` executes your Click command it will:
|
|
|
222
228
|
2. Optionally install handlers that raise the exceptions above.
|
|
223
229
|
3. Execute the command with `standalone_mode=False`.
|
|
224
230
|
4. Funnel any exception through `handle_cli_exception`.
|
|
225
|
-
5. Restore prior signal handlers and flush streams before returning.
|
|
231
|
+
5. Restore prior signal handlers and flush streams before returning (or rely on any injected replacements).
|
|
226
232
|
|
|
227
|
-
This behaviour keeps CLI wiring consistent across projects embedding `lib_cli_exit_tools
|
|
233
|
+
This behaviour keeps CLI wiring consistent across projects embedding `lib_cli_exit_tools` while still allowing custom hooks when needed.
|
|
228
234
|
|
|
229
235
|
### Advanced CLI wiring
|
|
230
236
|
|
|
@@ -34,6 +34,7 @@ Console script:
|
|
|
34
34
|
lib_cli_exit_tools --help
|
|
35
35
|
cli-exit-tools --help # alias
|
|
36
36
|
lib_cli_exit_tools info
|
|
37
|
+
lib_cli_exit_tools fail # intentionally trigger RuntimeError to test error paths
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
### Embed in your own CLI
|
|
@@ -124,7 +125,7 @@ Mutable dataclass-like singleton holding process-wide settings. Configure it dur
|
|
|
124
125
|
- `broken_pipe_exit_code` (`int`): Overrides the exit status for `BrokenPipeError` (default `141`).
|
|
125
126
|
- `traceback_force_color` (`bool`): Forces Rich-coloured tracebacks even when stderr is not a TTY.
|
|
126
127
|
|
|
127
|
-
### `run_cli(cli, argv=None, *, prog_name=None, signal_specs=None, install_signals=True) -> int`
|
|
128
|
+
### `run_cli(cli, argv=None, *, prog_name=None, signal_specs=None, install_signals=True, exception_handler=None, signal_installer=None) -> int`
|
|
128
129
|
Wrap a Click command or group so every invocation shares the same signal handling and exit-code policy. Returns the numeric exit code instead of exiting the process.
|
|
129
130
|
|
|
130
131
|
Parameters:
|
|
@@ -133,6 +134,8 @@ Parameters:
|
|
|
133
134
|
- `prog_name`: Override the program name shown in help/version output.
|
|
134
135
|
- `signal_specs`: Iterable of `SignalSpec` objects to customise signal handling; defaults to `default_signal_specs()`.
|
|
135
136
|
- `install_signals`: Set `False` when the host application already manages signal handlers.
|
|
137
|
+
- `exception_handler`: Optional callable receiving the raised exception and returning an exit code; defaults to ``handle_cli_exception``.
|
|
138
|
+
- `signal_installer`: Optional callable mirroring ``install_signal_handlers`` for embedding scenarios.
|
|
136
139
|
|
|
137
140
|
### `handle_cli_exception(exc, *, signal_specs=None, echo=None) -> int`
|
|
138
141
|
Translate exceptions raised by Click commands into deterministic exit codes, honouring configured signal mappings and traceback policy.
|
|
@@ -156,6 +159,9 @@ Parameters:
|
|
|
156
159
|
- `length_limit`: Maximum characters for summary output.
|
|
157
160
|
- `stream`: Target text stream; defaults to `sys.stderr`.
|
|
158
161
|
|
|
162
|
+
### `i_should_fail()`
|
|
163
|
+
Deterministically raise `RuntimeError('i should fail')` to exercise error-handling paths. Useful for smoke-testing exit-code translation, CLI traceback toggles, and log formatting without inventing ad-hoc failing commands.
|
|
164
|
+
|
|
159
165
|
### `flush_streams() -> None`
|
|
160
166
|
Best-effort flush of `sys.stdout` and `sys.stderr`, ensuring buffered output is written before exit.
|
|
161
167
|
|
|
@@ -191,9 +197,9 @@ When `run_cli` executes your Click command it will:
|
|
|
191
197
|
2. Optionally install handlers that raise the exceptions above.
|
|
192
198
|
3. Execute the command with `standalone_mode=False`.
|
|
193
199
|
4. Funnel any exception through `handle_cli_exception`.
|
|
194
|
-
5. Restore prior signal handlers and flush streams before returning.
|
|
200
|
+
5. Restore prior signal handlers and flush streams before returning (or rely on any injected replacements).
|
|
195
201
|
|
|
196
|
-
This behaviour keeps CLI wiring consistent across projects embedding `lib_cli_exit_tools
|
|
202
|
+
This behaviour keeps CLI wiring consistent across projects embedding `lib_cli_exit_tools` while still allowing custom hooks when needed.
|
|
197
203
|
|
|
198
204
|
### Advanced CLI wiring
|
|
199
205
|
|
{lib_cli_exit_tools-1.3.1 → lib_cli_exit_tools-1.5.0}/docs/system-design/module_reference.md
RENAMED
|
@@ -10,6 +10,10 @@ Complete
|
|
|
10
10
|
**Related Files:**
|
|
11
11
|
|
|
12
12
|
* `src/lib_cli_exit_tools/lib_cli_exit_tools.py`
|
|
13
|
+
* `src/lib_cli_exit_tools/core/configuration.py`
|
|
14
|
+
* `src/lib_cli_exit_tools/core/exit_codes.py`
|
|
15
|
+
* `src/lib_cli_exit_tools/application/runner.py`
|
|
16
|
+
* `src/lib_cli_exit_tools/adapters/signals.py`
|
|
13
17
|
* `src/lib_cli_exit_tools/cli.py`
|
|
14
18
|
* `src/lib_cli_exit_tools/__init__conf__.py`
|
|
15
19
|
* `src/lib_cli_exit_tools/__init__.py`
|
|
@@ -42,8 +46,8 @@ Automations and downstream CLIs rely on `lib_cli_exit_tools` for deterministic e
|
|
|
42
46
|
1. Console script (or `python -m lib_cli_exit_tools`) resolves to `lib_cli_exit_tools.cli.main`.
|
|
43
47
|
2. The Click group stores global flags and mutates `lib_cli_exit_tools.config`.
|
|
44
48
|
3. `run_cli` optionally installs signal handlers, executes the requested Click command, and funnels exceptions into `handle_cli_exception`.
|
|
45
|
-
4. `handle_cli_exception` maps signals and errors to exit codes using `default_signal_specs
|
|
46
|
-
5. `print_exception_message` and `_print_output` render diagnostics when tracebacks are suppressed.
|
|
49
|
+
4. `handle_cli_exception` maps signals and errors to exit codes using `default_signal_specs` and `get_system_exit_code`.
|
|
50
|
+
5. `print_exception_message` and `_print_output` (within `application.runner`) render diagnostics when tracebacks are suppressed.
|
|
47
51
|
6. Packaging metadata from `__init__conf__` feeds CLI help/version output so docs and runtime stay synchronized.
|
|
48
52
|
|
|
49
53
|
**System Dependencies:** Standard library (`signal`, `subprocess`, `sys`, `importlib.metadata`) plus `click` and `rich-click` for CLI/TUI behavior.
|
|
@@ -53,80 +57,63 @@ Automations and downstream CLIs rely on `lib_cli_exit_tools` for deterministic e
|
|
|
53
57
|
## Core Components
|
|
54
58
|
|
|
55
59
|
### Module: lib_cli_exit_tools/lib_cli_exit_tools.py
|
|
56
|
-
* **Purpose:**
|
|
60
|
+
* **Purpose:** Provide a façade that re-exports configuration, signal helpers, and orchestration utilities so existing imports stay valid after the refactor.
|
|
57
61
|
* **Location:** `src/lib_cli_exit_tools/lib_cli_exit_tools.py`
|
|
62
|
+
* **Notes:** Aggregates symbols from the layered modules to minimise breaking changes and exposes `i_should_fail()` as a deterministic failure helper for exercising error-handling paths.
|
|
63
|
+
|
|
64
|
+
### Module: lib_cli_exit_tools/core/configuration.py
|
|
65
|
+
* **Purpose:** Own the mutable runtime configuration shared across CLI executions.
|
|
66
|
+
* **Location:** `src/lib_cli_exit_tools/core/configuration.py`
|
|
58
67
|
|
|
59
68
|
#### Dataclass: `_Config`
|
|
60
|
-
* **
|
|
61
|
-
* **
|
|
62
|
-
* `traceback` (bool) — emit full tracebacks when `True`.
|
|
63
|
-
* `exit_code_style` (`"errno" | "sysexits"`) — choose mapping strategy.
|
|
64
|
-
* `broken_pipe_exit_code` (int) — exit status for `BrokenPipeError`.
|
|
65
|
-
* `traceback_force_color` (bool) — opt-in flag to force ANSI-coloured Rich tracebacks on non-TTY streams.
|
|
66
|
-
* **Notes:** Mutations apply process-wide; callers should restore defaults in tests.
|
|
69
|
+
* **Role:** Captures traceback, exit-code style, broken-pipe handling, and Rich colouring toggles.
|
|
70
|
+
* **Notes:** Mutations apply process-wide; tests must restore defaults to avoid leakage.
|
|
67
71
|
|
|
68
72
|
#### Constant: `config`
|
|
69
|
-
* **
|
|
70
|
-
* **Interactions:** Mutated by CLI
|
|
71
|
-
|
|
72
|
-
#### Exception Hierarchy: `CliSignalError`, `SigIntInterrupt`, `SigTermInterrupt`, `SigBreakInterrupt`
|
|
73
|
-
* **Purpose:** Represent signal-triggered interruptions so exit handlers can differentiate them from generic errors.
|
|
74
|
-
* **Notes:** Raised by generated signal handlers; mapped to exit codes 130 (SIGINT), 143 (SIGTERM), 149 (SIGBREAK).
|
|
75
|
-
|
|
76
|
-
#### Dataclass: `SignalSpec`
|
|
77
|
-
* **Purpose:** Describe how to translate a signal into an exception, stderr message, and exit code.
|
|
78
|
-
* **Key Fields:** `signum`, `exception`, `message`, `exit_code`.
|
|
79
|
-
* **Usage:** Consumed by `install_signal_handlers`, `handle_cli_exception`.
|
|
80
|
-
|
|
81
|
-
#### Protocol: `_Echo`
|
|
82
|
-
* **Purpose:** Structural type for echo-like callables (defaulting to `click.echo`).
|
|
83
|
-
* **Usage:** Enables dependency injection/testing of output behavior.
|
|
84
|
-
|
|
85
|
-
#### Function: `_default_echo(message: str, *, err: bool = True) -> None`
|
|
86
|
-
* **Purpose:** Bridge to `click.echo` when no custom echo is provided.
|
|
87
|
-
* **Side Effects:** Writes text to stdout/stderr via Click.
|
|
73
|
+
* **Role:** Singleton instance consumed by adapters and orchestration code.
|
|
74
|
+
* **Interactions:** Mutated by the CLI (`--traceback`) and inspected by error handlers and exit-code mappers.
|
|
88
75
|
|
|
89
|
-
|
|
90
|
-
* **Purpose:**
|
|
91
|
-
* **
|
|
76
|
+
### Module: lib_cli_exit_tools/core/exit_codes.py
|
|
77
|
+
* **Purpose:** Convert exceptions into deterministic OS exit statuses.
|
|
78
|
+
* **Location:** `src/lib_cli_exit_tools/core/exit_codes.py`
|
|
92
79
|
|
|
93
|
-
#### Function: `
|
|
94
|
-
* **
|
|
95
|
-
* **
|
|
80
|
+
#### Function: `get_system_exit_code(exc: BaseException) -> int`
|
|
81
|
+
* **Role:** Mirrors platform-specific errno/winerror semantics or BSD sysexits based on `config.exit_code_style`.
|
|
82
|
+
* **Notes:** Handles `CalledProcessError`, `SystemExit`, and `BrokenPipeError` explicitly before falling back to errno tables.
|
|
96
83
|
|
|
97
|
-
|
|
98
|
-
* **Purpose:**
|
|
99
|
-
* **
|
|
84
|
+
### Module: lib_cli_exit_tools/adapters/signals.py
|
|
85
|
+
* **Purpose:** Translate operating-system signals into structured exceptions and reversible handlers.
|
|
86
|
+
* **Location:** `src/lib_cli_exit_tools/adapters/signals.py`
|
|
100
87
|
|
|
101
|
-
####
|
|
102
|
-
* **
|
|
103
|
-
* **Behavior:** Detects signal exceptions, `BrokenPipeError`, `click.ClickException`, and `SystemExit`; otherwise defers to `print_exception_message` and `get_system_exit_code`.
|
|
88
|
+
#### Exceptions: `CliSignalError`, `SigIntInterrupt`, `SigTermInterrupt`, `SigBreakInterrupt`
|
|
89
|
+
* **Role:** Represent distinct signal pathways so exit handling can map them to stable codes (130/143/149).
|
|
104
90
|
|
|
105
|
-
####
|
|
106
|
-
* **
|
|
107
|
-
* **Behavior:** Optionally installs handlers, invokes `cli.main(...)`, funnels exceptions to `handle_cli_exception`, and restores handlers.
|
|
91
|
+
#### Dataclass: `SignalSpec`
|
|
92
|
+
* **Role:** Describe signal metadata (signum, exception, message, exit code) used by installers and handlers.
|
|
108
93
|
|
|
109
|
-
#### Function: `
|
|
110
|
-
* **
|
|
111
|
-
* **Behavior:** Supports subprocess return codes, `SystemExit`, `KeyboardInterrupt`, `BrokenPipeError`, and default fallbacks.
|
|
94
|
+
#### Function: `default_signal_specs(extra: Iterable[SignalSpec] | None = None) -> list[SignalSpec]`
|
|
95
|
+
* **Role:** Provide platform-aware defaults (always SIGINT; conditional SIGTERM/SIGBREAK) with optional extension points.
|
|
112
96
|
|
|
113
|
-
#### Function: `
|
|
114
|
-
* **
|
|
97
|
+
#### Function: `install_signal_handlers(specs: Sequence[SignalSpec] | None = None) -> Callable[[], None]`
|
|
98
|
+
* **Role:** Register handlers that raise the specified exceptions and return a restoration callback for clean-up.
|
|
115
99
|
|
|
116
|
-
|
|
117
|
-
* **Purpose:**
|
|
118
|
-
* **
|
|
100
|
+
### Module: lib_cli_exit_tools/application/runner.py
|
|
101
|
+
* **Purpose:** Orchestrate Click command execution with shared signal wiring, exception translation, and Rich-based diagnostics.
|
|
102
|
+
* **Location:** `src/lib_cli_exit_tools/application/runner.py`
|
|
119
103
|
|
|
120
|
-
####
|
|
121
|
-
* **
|
|
122
|
-
* **Behavior:** Flushes streams, surfaces captured subprocess output, renders highlighted tracebacks when enabled.
|
|
104
|
+
#### Protocol: `_Echo`
|
|
105
|
+
* **Role:** Structural type enabling dependency injection for stderr writers in tests.
|
|
123
106
|
|
|
124
|
-
####
|
|
125
|
-
* **
|
|
107
|
+
#### Utilities: `flush_streams`, `_build_console`, `_print_output`, `print_exception_message`
|
|
108
|
+
* **Role:** Manage stream flushing and Rich rendering when tracebacks are suppressed or forced.
|
|
126
109
|
|
|
127
|
-
#### Function: `
|
|
128
|
-
* **
|
|
110
|
+
#### Function: `handle_cli_exception(exc, *, signal_specs=None, echo=None) -> int`
|
|
111
|
+
* **Role:** Map exceptions to exit codes, emit signal messages, honour `config.traceback`, and delegate to `get_system_exit_code` when needed.
|
|
112
|
+
* **Notes:** Raises the original exception when traceback mode is enabled; otherwise trims output and prints captured subprocess streams.
|
|
129
113
|
|
|
114
|
+
#### Function: `run_cli(cli, argv=None, *, prog_name=None, signal_specs=None, install_signals=True, exception_handler=None, signal_installer=None) -> int`
|
|
115
|
+
* **Role:** Install signal handlers (unless disabled), execute the passed Click command, and funnel exceptions through an injectable handler before flushing streams.
|
|
116
|
+
* **Notes:** New `exception_handler` and `signal_installer` hooks support advanced embedding and unit testing scenarios.
|
|
130
117
|
### Module: lib_cli_exit_tools/cli.py
|
|
131
118
|
* **Purpose:** Provide the Click command group and subcommands that surface the exit tooling.
|
|
132
119
|
* **Location:** `src/lib_cli_exit_tools/cli.py`
|
|
@@ -144,6 +131,10 @@ Automations and downstream CLIs rely on `lib_cli_exit_tools` for deterministic e
|
|
|
144
131
|
#### Function: `cli_info() -> None`
|
|
145
132
|
* **Purpose:** Emit project metadata by delegating to `__init__conf__.print_info()`.
|
|
146
133
|
|
|
134
|
+
#### Function: `cli_fail() -> None`
|
|
135
|
+
* **Purpose:** Invoke `lib_cli_exit_tools.i_should_fail()` so operators can validate error-path handling from the packaged CLI without crafting bespoke failing commands.
|
|
136
|
+
* **Notes:** Surfaces the stable `RuntimeError('i should fail')` message, making it safe for scripted assertions and support playbooks.
|
|
137
|
+
|
|
147
138
|
#### Function: `main(argv=None) -> int`
|
|
148
139
|
* **Purpose:** Compose the CLI invocation by delegating to `lib_cli_exit_tools.run_cli`, returning exit codes instead of exiting directly.
|
|
149
140
|
|
|
@@ -187,6 +178,10 @@ Automations and downstream CLIs rely on `lib_cli_exit_tools` for deterministic e
|
|
|
187
178
|
* `install_signal_handlers` returns a restoration callback; callers must execute it (preferably in `finally`) to restore original handlers.
|
|
188
179
|
* SIGTERM and SIGBREAK specs are conditionally added based on platform capabilities.
|
|
189
180
|
|
|
181
|
+
**Extensibility:**
|
|
182
|
+
|
|
183
|
+
* `run_cli` exposes `exception_handler` and `signal_installer` hooks so embedders and unit tests can replace the default wiring without patching globals.
|
|
184
|
+
|
|
190
185
|
---
|
|
191
186
|
|
|
192
187
|
## Testing Approach
|
|
@@ -191,6 +191,78 @@
|
|
|
191
191
|
"except Exception:\n",
|
|
192
192
|
" lib_cli_exit_tools.print_exception_message(trace_back=True)"
|
|
193
193
|
]
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"cell_type": "markdown",
|
|
197
|
+
"id": "d56cb190",
|
|
198
|
+
"metadata": {},
|
|
199
|
+
"source": [
|
|
200
|
+
"## 7) Registered Command Fail"
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"cell_type": "code",
|
|
205
|
+
"execution_count": null,
|
|
206
|
+
"id": "b2eb015b",
|
|
207
|
+
"metadata": {},
|
|
208
|
+
"outputs": [],
|
|
209
|
+
"source": [
|
|
210
|
+
"!lib_cli_exit_tools fail"
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"cell_type": "markdown",
|
|
215
|
+
"id": "6c546140",
|
|
216
|
+
"metadata": {},
|
|
217
|
+
"source": [
|
|
218
|
+
"## 8) Registered Command Fail with Traceback"
|
|
219
|
+
]
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"cell_type": "code",
|
|
223
|
+
"execution_count": null,
|
|
224
|
+
"id": "db445316",
|
|
225
|
+
"metadata": {},
|
|
226
|
+
"outputs": [],
|
|
227
|
+
"source": [
|
|
228
|
+
"!lib_cli_exit_tools --traceback fail"
|
|
229
|
+
]
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"cell_type": "markdown",
|
|
233
|
+
"id": "24c157fa",
|
|
234
|
+
"metadata": {},
|
|
235
|
+
"source": [
|
|
236
|
+
"## 9) Script Command Fail"
|
|
237
|
+
]
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"cell_type": "code",
|
|
241
|
+
"execution_count": null,
|
|
242
|
+
"id": "81a4fa19",
|
|
243
|
+
"metadata": {},
|
|
244
|
+
"outputs": [],
|
|
245
|
+
"source": [
|
|
246
|
+
"!{sys.executable} -m lib_cli_exit_tools fail"
|
|
247
|
+
]
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"cell_type": "markdown",
|
|
251
|
+
"id": "ab2685a2",
|
|
252
|
+
"metadata": {},
|
|
253
|
+
"source": [
|
|
254
|
+
"## 10) Script Command Fail with Traceback"
|
|
255
|
+
]
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"cell_type": "code",
|
|
259
|
+
"execution_count": null,
|
|
260
|
+
"id": "ea02859a",
|
|
261
|
+
"metadata": {},
|
|
262
|
+
"outputs": [],
|
|
263
|
+
"source": [
|
|
264
|
+
"!{sys.executable} -m lib_cli_exit_tools --traceback fail"
|
|
265
|
+
]
|
|
194
266
|
}
|
|
195
267
|
],
|
|
196
268
|
"metadata": {
|
|
@@ -206,4 +278,4 @@
|
|
|
206
278
|
},
|
|
207
279
|
"nbformat": 4,
|
|
208
280
|
"nbformat_minor": 5
|
|
209
|
-
}
|
|
281
|
+
}
|