lib-cli-exit-tools 1.1.1__tar.gz → 1.3.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.1.1 → lib_cli_exit_tools-1.3.0}/.env.example +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/.github/workflows/ci.yml +1 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/.github/workflows/codeql.yml +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/.github/workflows/release.yml +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/.gitignore +1 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/AGENTS.md +10 -14
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/CHANGELOG.md +8 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/CONTRIBUTING.md +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/DEVELOPMENT.md +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/LICENSE +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/Makefile +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/PKG-INFO +2 -2
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/README.md +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/codecov.yml +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/docs/system-design/reference.md +9 -2
- lib_cli_exit_tools-1.3.0/notebooks/Quickstart.ipynb +209 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/packaging/README.md +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/packaging/brew/Formula/lib-cli-exit-tools.rb +7 -2
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/packaging/conda/recipe/meta.yaml +2 -2
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/packaging/nix/flake.nix +20 -22
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/pyproject.toml +2 -2
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/qlty.toml +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/__init__.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/_utils.py +131 -0
- lib_cli_exit_tools-1.3.0/scripts/build.py +66 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/bump.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/bump_major.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/bump_minor.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/bump_patch.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/bump_version.py +121 -15
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/clean.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/dev.py +0 -0
- lib_cli_exit_tools-1.3.0/scripts/generate_nix_flake.py +191 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/install.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/menu.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/push.py +3 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/release.py +3 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/run_cli.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/test.py +144 -73
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/scripts/version_current.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/src/lib_cli_exit_tools/__init__.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/src/lib_cli_exit_tools/__init__conf__.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/src/lib_cli_exit_tools/__main__.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/src/lib_cli_exit_tools/cli.py +49 -1
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/src/lib_cli_exit_tools/lib_cli_exit_tools.py +59 -17
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/src/lib_cli_exit_tools/py.typed +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/tests/test_cli.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/tests/test_cli_extra.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/tests/test_exit_tools.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/tests/test_extend_cli.py +0 -0
- {lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/tests/test_lib_extra.py +1 -1
- lib_cli_exit_tools-1.1.1/notebooks/Quickstart.ipynb +0 -121
- lib_cli_exit_tools-1.1.1/scripts/build.py +0 -45
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -2,20 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## On session start
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- Read following files and keep their guidance in working memory:
|
|
7
|
-
- core_programming_solid.md
|
|
8
|
-
- bash_clean_architecture.md
|
|
9
|
-
- bash_clean_code.md
|
|
10
|
-
- bash_small_functions.md
|
|
11
|
-
- python_solid_architecture_enforcer.md
|
|
12
|
-
- python_clean_architecture.md/media/srv-main-softdev/projects/libs/bitranox_template_py_cli
|
|
13
|
-
- python_clean_code.md
|
|
14
|
-
- python_small_functions_style.md
|
|
15
|
-
- python_libraries_to_use.md
|
|
16
|
-
- python_structure_template.md
|
|
17
|
-
- self_documenting.md
|
|
5
|
+
Review the system prompt files in `/media/srv-main/softdev/*/projects/softwarestack/systemprompts` and keep their guidance in working memory:
|
|
18
6
|
|
|
7
|
+
- core_programming_solid.md
|
|
8
|
+
- python_solid_architecture_enforcer.md
|
|
9
|
+
- python_clean_architecture.md
|
|
10
|
+
- python_clean_code.md
|
|
11
|
+
- python_small_functions_style.md
|
|
12
|
+
- python_libraries_to_use.md
|
|
13
|
+
- python_structure_template.md
|
|
14
|
+
- self_documenting.md
|
|
15
|
+
- self_documenting_template.md
|
|
19
16
|
|
|
20
17
|
always apply those Rules :
|
|
21
18
|
|
|
@@ -37,7 +34,6 @@ when writing or refracturing Python scripts, apply those Rules :
|
|
|
37
34
|
- python_libraries_to_use.md
|
|
38
35
|
- python_lib_structure_template.md
|
|
39
36
|
|
|
40
|
-
|
|
41
37
|
## Project Structure & Module Organization
|
|
42
38
|
|
|
43
39
|
- `src/lib_cli_exit_tools/`: Python package.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lib_cli_exit_tools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.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
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
17
|
Classifier: Typing :: Typed
|
|
18
18
|
Requires-Python: >=3.10
|
|
19
|
-
Requires-Dist: click>=
|
|
19
|
+
Requires-Dist: rich-click>=1.9.1
|
|
20
20
|
Provides-Extra: dev
|
|
21
21
|
Requires-Dist: build>=1.2; extra == 'dev'
|
|
22
22
|
Requires-Dist: codecov>=2.1.13; extra == 'dev'
|
|
File without changes
|
|
File without changes
|
|
@@ -138,9 +138,9 @@ The package is the core runtime library for handling CLI exits within the broade
|
|
|
138
138
|
**Location:** `lib_cli_exit_tools/lib_cli_exit_tools.py`
|
|
139
139
|
|
|
140
140
|
#### Function: print_exception_message
|
|
141
|
-
**Purpose:** Display the current exception message (and optional traceback) with output truncation safeguards.
|
|
141
|
+
**Purpose:** Display the current exception message (and optional rich-formatted traceback) with output truncation safeguards.
|
|
142
142
|
**Input:** `trace_back`, `length_limit`, optional `stream`.
|
|
143
|
-
**Output:** Writes formatted error details to the target stream
|
|
143
|
+
**Output:** Writes formatted error details to the target stream using a `rich` console and flushes stdout/stderr.
|
|
144
144
|
**Location:** `lib_cli_exit_tools/lib_cli_exit_tools.py`
|
|
145
145
|
|
|
146
146
|
#### Function: _print_output
|
|
@@ -167,6 +167,13 @@ The package is the core runtime library for handling CLI exits within the broade
|
|
|
167
167
|
**Output:** Dict passed to Click context settings.
|
|
168
168
|
**Location:** `lib_cli_exit_tools/cli.py`
|
|
169
169
|
|
|
170
|
+
#### Function: _configure_rich_click_output
|
|
171
|
+
**Purpose:** Neutralise rich-click styling when stdout is a pipe or uses non-UTF encodings so help text stays ASCII-safe on Windows CI.
|
|
172
|
+
**Input:** None; inspects the active stdout stream via `click.get_text_stream`.
|
|
173
|
+
**Output:** Adjusts rich-click globals (forced terminal flag, colour system, panel boxes) to avoid emitting characters that legacy encodings cannot represent.
|
|
174
|
+
**Location:** `lib_cli_exit_tools/cli.py`
|
|
175
|
+
|
|
176
|
+
|
|
170
177
|
#### Function: cli
|
|
171
178
|
**Purpose:** Root Click group that stores global options (currently `--traceback`) and updates library configuration.
|
|
172
179
|
**Input:** Click `Context`, boolean `traceback` option.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"id": "7fb27b941602401d91542211134fc71a",
|
|
6
|
+
"metadata": {},
|
|
7
|
+
"source": [
|
|
8
|
+
"# lib_cli_exit_tools Quickstart\n",
|
|
9
|
+
"\n",
|
|
10
|
+
"Use this notebook to install the package, explore the CLI, and observe how rich-formatted tracebacks behave when you enable debugging output.\n"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"cell_type": "markdown",
|
|
15
|
+
"id": "acae54e37e7d407bbb7b55eff062a284",
|
|
16
|
+
"metadata": {},
|
|
17
|
+
"source": [
|
|
18
|
+
"## 1) Install latest from GitHub (default)\n"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"cell_type": "code",
|
|
23
|
+
"execution_count": null,
|
|
24
|
+
"id": "9a63283cbaf04dbcab1f6479b197f3a8",
|
|
25
|
+
"metadata": {},
|
|
26
|
+
"outputs": [],
|
|
27
|
+
"source": [
|
|
28
|
+
"# update pip and setuptools\n",
|
|
29
|
+
"import sys\n",
|
|
30
|
+
"\n",
|
|
31
|
+
"!{sys.executable} -m pip install --upgrade pip\n",
|
|
32
|
+
"!{sys.executable} -m pip install --upgrade setuptools\n",
|
|
33
|
+
"\n",
|
|
34
|
+
"# install lib_cli_exit_tools from GitHub (default)\n",
|
|
35
|
+
"!{sys.executable} -m pip install --upgrade git+https://github.com/bitranox/lib_cli_exit_tools.git"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"cell_type": "markdown",
|
|
40
|
+
"id": "8dd0d8092fe74a7c96281538738b07e2",
|
|
41
|
+
"metadata": {},
|
|
42
|
+
"source": [
|
|
43
|
+
"## Or: Install from PyPI (alternative)\n",
|
|
44
|
+
"Uncomment and run the cell below if you prefer the PyPI release.\n"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"cell_type": "code",
|
|
49
|
+
"execution_count": null,
|
|
50
|
+
"id": "72eea5119410473aa328ad9291626812",
|
|
51
|
+
"metadata": {},
|
|
52
|
+
"outputs": [],
|
|
53
|
+
"source": [
|
|
54
|
+
"# !{sys.executable} -m pip install --upgrade lib_cli_exit_tools\n"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"cell_type": "markdown",
|
|
59
|
+
"id": "8edb47106e1a46a883d545849b8ab81b",
|
|
60
|
+
"metadata": {},
|
|
61
|
+
"source": [
|
|
62
|
+
"## 2) CLI: version and help\n"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"cell_type": "code",
|
|
67
|
+
"execution_count": null,
|
|
68
|
+
"id": "10185d26023b46108eb7d9f57d49d2b3",
|
|
69
|
+
"metadata": {},
|
|
70
|
+
"outputs": [],
|
|
71
|
+
"source": [
|
|
72
|
+
"!lib_cli_exit_tools --version\n",
|
|
73
|
+
"!lib_cli_exit_tools --help\n",
|
|
74
|
+
"!lib_cli_exit_tools info"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"cell_type": "markdown",
|
|
79
|
+
"id": "8763a12b2bbd4a93a75aff182afb95dc",
|
|
80
|
+
"metadata": {},
|
|
81
|
+
"source": [
|
|
82
|
+
"## 3) Demo command for failure handling\n",
|
|
83
|
+
"The helper below builds a tiny Click command that purposely raises an error so you can compare short messages with rich tracebacks.\n"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"cell_type": "code",
|
|
88
|
+
"execution_count": null,
|
|
89
|
+
"id": "7623eae2785240b9bd12b16a66d81610",
|
|
90
|
+
"metadata": {},
|
|
91
|
+
"outputs": [],
|
|
92
|
+
"source": [
|
|
93
|
+
"import click\n",
|
|
94
|
+
"from lib_cli_exit_tools.lib_cli_exit_tools import config, run_cli\n",
|
|
95
|
+
"\n",
|
|
96
|
+
"\n",
|
|
97
|
+
"@click.command()\n",
|
|
98
|
+
"def quickstart_fail() -> None:\n",
|
|
99
|
+
" \"\"\"Raise a demo error to exercise lib_cli_exit_tools.\"\"\"\n",
|
|
100
|
+
" raise RuntimeError(\"demo failure from Quickstart\")\n",
|
|
101
|
+
"\n",
|
|
102
|
+
"\n",
|
|
103
|
+
"def run_quickstart_demo(traceback_enabled: bool) -> int:\n",
|
|
104
|
+
" \"\"\"Execute the demo command with the desired traceback mode.\n",
|
|
105
|
+
"\n",
|
|
106
|
+
" The helper keeps tests deterministic by disabling signal handlers\n",
|
|
107
|
+
" in notebook contexts and resets global flags after execution.\n",
|
|
108
|
+
" \"\"\"\n",
|
|
109
|
+
"\n",
|
|
110
|
+
" original_flag = config.traceback\n",
|
|
111
|
+
" config.traceback = traceback_enabled\n",
|
|
112
|
+
" try:\n",
|
|
113
|
+
" return run_cli(quickstart_fail, argv=[], install_signals=False)\n",
|
|
114
|
+
" finally:\n",
|
|
115
|
+
" config.traceback = original_flag"
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"cell_type": "markdown",
|
|
120
|
+
"id": "7cdc8c89c7104fffa095e18ddfef8986",
|
|
121
|
+
"metadata": {},
|
|
122
|
+
"source": [
|
|
123
|
+
"## 4) CLI failure with short message (default)\n",
|
|
124
|
+
"Tracebacks are suppressed by default; the CLI emits a concise summary and returns a deterministic exit code.\n"
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"cell_type": "code",
|
|
129
|
+
"execution_count": null,
|
|
130
|
+
"id": "b118ea5561624da68c537baed56e602f",
|
|
131
|
+
"metadata": {},
|
|
132
|
+
"outputs": [],
|
|
133
|
+
"source": [
|
|
134
|
+
"exit_code = run_quickstart_demo(False)\n",
|
|
135
|
+
"print(f\"Exit code: {exit_code}\")"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"cell_type": "markdown",
|
|
140
|
+
"id": "938c804e27f84196a10c8828c723f798",
|
|
141
|
+
"metadata": {},
|
|
142
|
+
"source": [
|
|
143
|
+
"## 5) CLI failure with rich traceback\n",
|
|
144
|
+
"Enable tracebacks to surface a full Rich-formatted stack trace for debugging.\n"
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"cell_type": "code",
|
|
149
|
+
"execution_count": null,
|
|
150
|
+
"id": "504fb2a444614c0babb325280ed9130a",
|
|
151
|
+
"metadata": {},
|
|
152
|
+
"outputs": [],
|
|
153
|
+
"source": [
|
|
154
|
+
"import lib_cli_exit_tools\n",
|
|
155
|
+
"\n",
|
|
156
|
+
"try:\n",
|
|
157
|
+
" run_quickstart_demo(True)\n",
|
|
158
|
+
"except RuntimeError:\n",
|
|
159
|
+
" lib_cli_exit_tools.print_exception_message(trace_back=True)"
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"cell_type": "markdown",
|
|
164
|
+
"id": "59bbdb311c014d738909a11f9e486628",
|
|
165
|
+
"metadata": {},
|
|
166
|
+
"source": [
|
|
167
|
+
"## 6) Library usage: exit codes and traceback formatting\n",
|
|
168
|
+
"Use the functional API to translate exceptions into exit codes and to opt in to rich tracebacks programmatically.\n"
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"cell_type": "code",
|
|
173
|
+
"execution_count": null,
|
|
174
|
+
"id": "b43b363d81ae4b689946ece5c682cd59",
|
|
175
|
+
"metadata": {},
|
|
176
|
+
"outputs": [],
|
|
177
|
+
"source": [
|
|
178
|
+
"import lib_cli_exit_tools\n",
|
|
179
|
+
"\n",
|
|
180
|
+
"# Short message (default)\n",
|
|
181
|
+
"try:\n",
|
|
182
|
+
" raise FileNotFoundError(\"missing.txt\")\n",
|
|
183
|
+
"except Exception as exc:\n",
|
|
184
|
+
" exit_code = lib_cli_exit_tools.get_system_exit_code(exc)\n",
|
|
185
|
+
" lib_cli_exit_tools.print_exception_message(trace_back=False)\n",
|
|
186
|
+
" print(f\"Exit code would be: {exit_code}\")\n",
|
|
187
|
+
"\n",
|
|
188
|
+
"# Rich traceback\n",
|
|
189
|
+
"try:\n",
|
|
190
|
+
" raise ValueError(\"boom\")\n",
|
|
191
|
+
"except Exception:\n",
|
|
192
|
+
" lib_cli_exit_tools.print_exception_message(trace_back=True)"
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
],
|
|
196
|
+
"metadata": {
|
|
197
|
+
"kernelspec": {
|
|
198
|
+
"display_name": "Python 3",
|
|
199
|
+
"language": "python",
|
|
200
|
+
"name": "python3"
|
|
201
|
+
},
|
|
202
|
+
"language_info": {
|
|
203
|
+
"name": "python",
|
|
204
|
+
"version": "3"
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"nbformat": 4,
|
|
208
|
+
"nbformat_minor": 5
|
|
209
|
+
}
|
|
File without changes
|
{lib_cli_exit_tools-1.1.1 → lib_cli_exit_tools-1.3.0}/packaging/brew/Formula/lib-cli-exit-tools.rb
RENAMED
|
@@ -3,7 +3,7 @@ class LibCliExitTools < Formula
|
|
|
3
3
|
|
|
4
4
|
desc "CLI exit handling helpers: clean signals, exit codes, and error printing"
|
|
5
5
|
homepage "https://github.com/bitranox/lib_cli_exit_tools"
|
|
6
|
-
url "https://github.com/bitranox/lib_cli_exit_tools/archive/refs/tags/v1.
|
|
6
|
+
url "https://github.com/bitranox/lib_cli_exit_tools/archive/refs/tags/v1.3.0.tar.gz"
|
|
7
7
|
k3cc316e7d0b09dd79e617cb3e91b14ee414b7e6695b108a326d9d3ccd08dd9"
|
|
8
8
|
license "MIT"
|
|
9
9
|
|
|
@@ -11,10 +11,15 @@ k3cc316e7d0b09dd79e617cb3e91b14ee414b7e6695b108a326d9d3ccd08dd9"
|
|
|
11
11
|
|
|
12
12
|
# Vendor Python deps (fill versions/sha256 for an actual formula)
|
|
13
13
|
resource "click" do
|
|
14
|
-
url "https://files.pythonhosted.org/packages/
|
|
14
|
+
url "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz"
|
|
15
15
|
k3cc316e7d0b09dd79e617cb3e91b14ee414b7e6695b108a326d9d3ccd08dd9"
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
resource "rich-click" do
|
|
19
|
+
url "https://files.pythonhosted.org/packages/29/c2/f08b5e7c1a33af8a115be640aa0796ba01c4732696da6d2254391376b314/rich_click-1.9.1.tar.gz"
|
|
20
|
+
ab87be0f5a4c171b43778922b5ed1f99611a0db5a4bf4d0f36770c18ef848d4"
|
|
21
|
+
end
|
|
22
|
+
|
|
18
23
|
def install
|
|
19
24
|
virtualenv_install_with_resources
|
|
20
25
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{% set name = "lib_cli_exit_tools" %}
|
|
2
|
-
{% set version = "1.
|
|
2
|
+
{% set version = "1.3.0" %}
|
|
3
3
|
|
|
4
4
|
package:
|
|
5
5
|
name: {{ name|lower }}
|
|
@@ -28,7 +28,7 @@ requirements:
|
|
|
28
28
|
- hatchling >=1.25
|
|
29
29
|
run:
|
|
30
30
|
- python >=3.10
|
|
31
|
-
- click >=
|
|
31
|
+
- rich-click >=1.9.1
|
|
32
32
|
|
|
33
33
|
test:
|
|
34
34
|
commands:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
description = "
|
|
2
|
+
description = "bitranox_template_py_cli Nix flake";
|
|
3
3
|
|
|
4
4
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
|
5
5
|
inputs.flake-utils.url = "github:numtide/flake-utils";
|
|
@@ -11,15 +11,13 @@
|
|
|
11
11
|
lib = pkgs.lib;
|
|
12
12
|
pypkgs = pkgs.python310Packages;
|
|
13
13
|
|
|
14
|
-
# Vendor hatchling>=1.25 from PyPI (wheel) to satisfy PEP 517 build
|
|
15
14
|
hatchlingVendor = pypkgs.buildPythonPackage rec {
|
|
16
15
|
pname = "hatchling";
|
|
17
16
|
version = "1.25.0";
|
|
18
|
-
format = "wheel";
|
|
19
|
-
# Use explicit URL for py3 wheel; nixpkgs 24.05 fetchPypi may choose a py2.py3 path.
|
|
17
|
+
format = "wheel";
|
|
20
18
|
src = pkgs.fetchurl {
|
|
21
|
-
url = "https://files.pythonhosted.org/packages/py3/h/hatchling
|
|
22
|
-
hash = "sha256-tHlI5F1NlzA0WE3UyznBS2pwInzyh6t+wK15g0CKiCw
|
|
19
|
+
url = "https://files.pythonhosted.org/packages/py3/h/hatchling/hatchling-1.25.0-py3-none-any.whl";
|
|
20
|
+
hash = "sha256-tHlI5F1NlzA0WE3UyznBS2pwInzyh6t+wK15g0CKiCw";
|
|
23
21
|
};
|
|
24
22
|
propagatedBuildInputs = [
|
|
25
23
|
pypkgs.packaging
|
|
@@ -31,30 +29,30 @@
|
|
|
31
29
|
];
|
|
32
30
|
doCheck = false;
|
|
33
31
|
};
|
|
32
|
+
richClickVendor = pypkgs.buildPythonPackage rec {
|
|
33
|
+
pname = "rich-click";
|
|
34
|
+
version = "1.9.1";
|
|
35
|
+
format = "wheel";
|
|
36
|
+
src = pkgs.fetchurl {
|
|
37
|
+
url = "https://files.pythonhosted.org/packages/a8/77/e9144dcf68a0b3f3f4386986f97255c3d9f7c659be58bb7a5fe8f26f3efa/rich_click-1.9.1-py3-none-any.whl";
|
|
38
|
+
sha256 = "sha256-6mEUqeCBt9aMwHsxUHA5j4BvAbsODEnaVvEp5nKHeBc=";
|
|
39
|
+
};
|
|
40
|
+
doCheck = false;
|
|
41
|
+
};
|
|
42
|
+
|
|
34
43
|
in
|
|
35
44
|
{
|
|
36
45
|
packages.default = pypkgs.buildPythonPackage {
|
|
37
46
|
pname = "lib_cli_exit_tools";
|
|
38
|
-
version = "1.
|
|
47
|
+
version = "1.3.0";
|
|
39
48
|
pyproject = true;
|
|
40
|
-
# Build from the repository root (two levels up from packaging/nix)
|
|
41
49
|
src = ../..;
|
|
42
|
-
# For pinned releases, swap src for fetchFromGitHub with a rev/sha256.
|
|
43
|
-
# src = pkgs.fetchFromGitHub {
|
|
44
|
-
# owner = "bitranox";
|
|
45
|
-
# repo = "lib_cli_exit_tools";
|
|
46
|
-
# rev = "v1.1.1";
|
|
47
|
-
# sha256 = "<fill-me>";
|
|
48
|
-
# };
|
|
49
|
-
|
|
50
|
-
# Ensure PEP 517 backend is available at required version
|
|
51
|
-
# Ensure PEP 517 backend available at required version (>=1.25)
|
|
52
50
|
nativeBuildInputs = [ hatchlingVendor ];
|
|
53
|
-
propagatedBuildInputs = [
|
|
51
|
+
propagatedBuildInputs = [ richClickVendor ];
|
|
54
52
|
|
|
55
53
|
meta = with pkgs.lib; {
|
|
56
|
-
description = "
|
|
57
|
-
homepage = "https://github.com/bitranox/
|
|
54
|
+
description = "Rich-powered logging helpers for colorful terminal output";
|
|
55
|
+
homepage = "https://github.com/bitranox/bitranox_template_py_cli";
|
|
58
56
|
license = licenses.mit;
|
|
59
57
|
maintainers = [];
|
|
60
58
|
platforms = platforms.unix ++ platforms.darwin;
|
|
@@ -65,7 +63,7 @@
|
|
|
65
63
|
packages = [
|
|
66
64
|
pkgs.python310
|
|
67
65
|
hatchlingVendor
|
|
68
|
-
|
|
66
|
+
richClickVendor
|
|
69
67
|
pypkgs.pytest
|
|
70
68
|
pkgs.ruff
|
|
71
69
|
pkgs.nodejs
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "lib_cli_exit_tools"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.3.0"
|
|
4
4
|
description = "CLI exit handling helpers: clean signals, exit codes, and error printing"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
7
|
-
dependencies = ["click>=
|
|
7
|
+
dependencies = ["rich-click>=1.9.1"]
|
|
8
8
|
license = { text = "MIT" }
|
|
9
9
|
authors = [{ name = "bitranox", email = "bitranox@gmail.com" }]
|
|
10
10
|
keywords = ["cli", "exit", "signals", "errors", "click"]
|
|
File without changes
|
|
File without changes
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
3
5
|
import re
|
|
4
6
|
import shlex
|
|
5
7
|
import subprocess
|
|
6
8
|
import sys
|
|
9
|
+
import tempfile
|
|
10
|
+
import hashlib
|
|
11
|
+
import json
|
|
12
|
+
from urllib.request import urlopen
|
|
7
13
|
from dataclasses import dataclass
|
|
8
14
|
from pathlib import Path
|
|
9
15
|
from subprocess import CompletedProcess
|
|
@@ -194,6 +200,95 @@ def read_version_from_pyproject(pyproject: Path = Path("pyproject.toml")) -> str
|
|
|
194
200
|
return match.group(1) if match else ""
|
|
195
201
|
|
|
196
202
|
|
|
203
|
+
def ensure_conda(auto_install: bool = True) -> bool:
|
|
204
|
+
"""Ensure the `conda` CLI is available, optionally bootstrapping Miniforge."""
|
|
205
|
+
|
|
206
|
+
if cmd_exists("conda"):
|
|
207
|
+
return True
|
|
208
|
+
|
|
209
|
+
if not auto_install:
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
system = platform.system().lower()
|
|
213
|
+
machine = platform.machine().lower()
|
|
214
|
+
|
|
215
|
+
if system.startswith("linux"):
|
|
216
|
+
os_name = "Linux"
|
|
217
|
+
elif system == "darwin":
|
|
218
|
+
os_name = "MacOSX"
|
|
219
|
+
else:
|
|
220
|
+
return False
|
|
221
|
+
|
|
222
|
+
if machine in {"x86_64", "amd64"}:
|
|
223
|
+
arch = "x86_64"
|
|
224
|
+
elif machine in {"aarch64", "arm64"}:
|
|
225
|
+
arch = "aarch64" if os_name == "Linux" else "arm64"
|
|
226
|
+
else:
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
filename = f"Miniforge3-{os_name}-{arch}.sh"
|
|
230
|
+
base = "https://github.com/conda-forge/miniforge/releases/latest/download/"
|
|
231
|
+
asset_url = base + filename
|
|
232
|
+
sums_url = base + "SHA256SUMS"
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
with urlopen("https://api.github.com/repos/conda-forge/miniforge/releases/latest", timeout=10) as resp:
|
|
236
|
+
release = json.loads(resp.read().decode("utf-8"))
|
|
237
|
+
for asset in release.get("assets", []):
|
|
238
|
+
name = asset.get("name")
|
|
239
|
+
if name == filename:
|
|
240
|
+
asset_url = asset.get("browser_download_url", asset_url)
|
|
241
|
+
elif name == "SHA256SUMS":
|
|
242
|
+
sums_url = asset.get("browser_download_url", sums_url)
|
|
243
|
+
except Exception:
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
conda_root = Path.home() / "miniforge3"
|
|
247
|
+
|
|
248
|
+
if not conda_root.exists():
|
|
249
|
+
attempts = 3
|
|
250
|
+
for _ in range(attempts):
|
|
251
|
+
try:
|
|
252
|
+
installer_bytes = urlopen(asset_url, timeout=30).read()
|
|
253
|
+
sums_text = urlopen(sums_url, timeout=30).read().decode("utf-8")
|
|
254
|
+
except Exception:
|
|
255
|
+
continue
|
|
256
|
+
|
|
257
|
+
expected_hash = None
|
|
258
|
+
for line in sums_text.splitlines():
|
|
259
|
+
line = line.strip()
|
|
260
|
+
if line.endswith(f" {filename}"):
|
|
261
|
+
parts = line.split()
|
|
262
|
+
if parts:
|
|
263
|
+
expected_hash = parts[0]
|
|
264
|
+
break
|
|
265
|
+
|
|
266
|
+
if not expected_hash:
|
|
267
|
+
continue
|
|
268
|
+
|
|
269
|
+
actual_hash = hashlib.sha256(installer_bytes).hexdigest()
|
|
270
|
+
if actual_hash != expected_hash:
|
|
271
|
+
continue
|
|
272
|
+
|
|
273
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
274
|
+
installer = Path(tmp) / filename
|
|
275
|
+
installer.write_bytes(installer_bytes)
|
|
276
|
+
installer.chmod(0o755)
|
|
277
|
+
install = run(["bash", str(installer), "-b"], check=False, capture=False)
|
|
278
|
+
if install.code == 0:
|
|
279
|
+
break
|
|
280
|
+
else:
|
|
281
|
+
return False
|
|
282
|
+
candidates = [conda_root / "condabin", conda_root / "bin"]
|
|
283
|
+
|
|
284
|
+
existing = os.environ.get("PATH", "").split(os.pathsep)
|
|
285
|
+
new_entries = [str(p) for p in candidates if p.exists()]
|
|
286
|
+
if new_entries:
|
|
287
|
+
os.environ["PATH"] = os.pathsep.join(new_entries + [p for p in existing if p])
|
|
288
|
+
|
|
289
|
+
return cmd_exists("conda")
|
|
290
|
+
|
|
291
|
+
|
|
197
292
|
def ensure_clean_git_tree() -> None:
|
|
198
293
|
dirty = subprocess.call(["bash", "-lc", "! git diff --quiet || ! git diff --cached --quiet"], stdout=subprocess.DEVNULL)
|
|
199
294
|
if dirty == 0:
|
|
@@ -241,6 +336,7 @@ def gh_release_edit(tag: str, title: str, body: str) -> None:
|
|
|
241
336
|
|
|
242
337
|
def sync_packaging() -> None:
|
|
243
338
|
run([sys.executable, "scripts/bump_version.py", "--sync-packaging"], check=False)
|
|
339
|
+
run([sys.executable, "scripts/generate_nix_flake.py"], check=False)
|
|
244
340
|
|
|
245
341
|
|
|
246
342
|
def bootstrap_dev() -> None:
|
|
@@ -253,3 +349,38 @@ def bootstrap_dev() -> None:
|
|
|
253
349
|
import_module("sqlite3")
|
|
254
350
|
except Exception:
|
|
255
351
|
run([sys.executable, "-m", "pip", "install", "pysqlite3-binary"], check=False)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def ensure_nix(auto_install: bool = True) -> bool:
|
|
355
|
+
"""Ensure the `nix` command is available, optionally bootstrapping it."""
|
|
356
|
+
|
|
357
|
+
if cmd_exists("nix"):
|
|
358
|
+
return True
|
|
359
|
+
|
|
360
|
+
if not auto_install:
|
|
361
|
+
return False
|
|
362
|
+
|
|
363
|
+
import os
|
|
364
|
+
import sys
|
|
365
|
+
|
|
366
|
+
platform = sys.platform
|
|
367
|
+
if not (platform.startswith("linux") or platform == "darwin"):
|
|
368
|
+
return False
|
|
369
|
+
|
|
370
|
+
# Install single-user Nix (no-daemon) for non-root environments.
|
|
371
|
+
install_cmd = "curl -L https://nixos.org/nix/install | sh -s -- --no-daemon"
|
|
372
|
+
run(["bash", "-lc", install_cmd], check=False, capture=False)
|
|
373
|
+
|
|
374
|
+
profile_dir = Path.home() / ".nix-profile"
|
|
375
|
+
profile_env = profile_dir / "etc" / "profile.d" / "nix.sh"
|
|
376
|
+
bin_dir = profile_dir / "bin"
|
|
377
|
+
|
|
378
|
+
if bin_dir.exists():
|
|
379
|
+
path_entries = os.environ.get("PATH", "").split(os.pathsep)
|
|
380
|
+
if str(bin_dir) not in path_entries:
|
|
381
|
+
os.environ["PATH"] = os.pathsep.join([str(bin_dir)] + [p for p in path_entries if p])
|
|
382
|
+
|
|
383
|
+
if profile_env.exists():
|
|
384
|
+
run(["bash", "-lc", f". {profile_env} >/dev/null 2>&1 && nix --version"], check=False, capture=False)
|
|
385
|
+
|
|
386
|
+
return cmd_exists("nix")
|