lib-cli-exit-tools 2.3.2__tar.gz → 2.3.4__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-2.3.2 → lib_cli_exit_tools-2.3.4}/.codacy/cli-config.yaml +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.codacy/codacy.yaml +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.codacy/tools-configs/lizard.yaml +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.codacy/tools-configs/trivy.yaml +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.data_arch_violations.json +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.devcontainer/devcontainer.json +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.devcontainer/settings.json +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.env.example +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.github/actions/extract-metadata/action.yml +16 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.github/dependabot.yml +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.github/workflows/codeql.yml +1 -1
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.github/workflows/default_cicd_public.yml +63 -13
- lib_cli_exit_tools-2.3.4/.github/workflows/default_release_public.yml +95 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.gitignore +6 -1
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.qlty/qlty.toml +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.snyk +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/CHANGELOG.md +20 -2
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/CONTRIBUTING.md +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/DEVELOPMENT.md +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/INSTALL.md +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/LICENSE +0 -0
- lib_cli_exit_tools-2.3.4/Makefile +453 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/PKG-INFO +15 -14
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/README.md +5 -4
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/codecov.yml +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/docs/system-design/module_reference.md +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/notebooks/Quickstart.ipynb +5 -4
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/pyproject.toml +66 -12
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/__init__.py +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/__init__conf__.py +4 -2
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/__main__.py +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/adapters/__init__.py +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/adapters/signals.py +7 -7
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/application/__init__.py +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/application/runner.py +40 -23
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/cli/__init__.py +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/cli/commands.py +1 -2
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/cli/group.py +5 -3
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/cli/styling.py +4 -1
- lib_cli_exit_tools-2.3.4/src/lib_cli_exit_tools/cli/typed_click.py +51 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/core/__init__.py +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/core/configuration.py +8 -6
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/core/exit_codes.py +4 -4
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/lib_cli_exit_tools.py +12 -12
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/src/lib_cli_exit_tools/py.typed +0 -0
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/conftest.py +3 -1
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/test_adapters_signals.py +0 -1
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/test_application_runner.py +99 -4
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/test_behaviors.py +7 -6
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/test_cli.py +6 -5
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/test_core_configuration.py +7 -7
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/test_core_exit_codes.py +2 -2
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/test_metadata.py +18 -18
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/test_module_entry.py +4 -3
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/tests/test_signals_integration.py +6 -5
- lib_cli_exit_tools-2.3.2/.github/workflows/default_release_public.yml +0 -69
- lib_cli_exit_tools-2.3.2/Makefile +0 -260
- lib_cli_exit_tools-2.3.2/src/lib_cli_exit_tools/cli/typed_click.py +0 -29
- {lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.codacy/cli.sh +0 -0
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.github/actions/extract-metadata/action.yml
RENAMED
|
@@ -29,6 +29,11 @@ outputs:
|
|
|
29
29
|
BANDIT_SKIP_FLAG:
|
|
30
30
|
description: Bandit skip flag string (e.g. "-s B101,B601") or empty
|
|
31
31
|
value: ${{ steps.meta.outputs.BANDIT_SKIP_FLAG }}
|
|
32
|
+
PYTEST_MARKER_EXPR:
|
|
33
|
+
description: >-
|
|
34
|
+
Marker expression for the CI test run (e.g. "not local_only and not integration"),
|
|
35
|
+
built from tool.ci.pytest-exclude-markers
|
|
36
|
+
value: ${{ steps.meta.outputs.PYTEST_MARKER_EXPR }}
|
|
32
37
|
|
|
33
38
|
runs:
|
|
34
39
|
using: composite
|
|
@@ -69,6 +74,15 @@ runs:
|
|
|
69
74
|
bandit_skips = data.get('tool', {}).get('bandit', {}).get('skips', [])
|
|
70
75
|
bandit_skip_flag = f"-s {','.join(bandit_skips)}" if bandit_skips else ""
|
|
71
76
|
|
|
77
|
+
# --- [tool.ci] section ---
|
|
78
|
+
# CI always skips local_only (those tests need a dev box). A project whose
|
|
79
|
+
# suite also carries markers CI cannot satisfy - integration tests needing a
|
|
80
|
+
# container that a separate workflow starts - names them here, rather than
|
|
81
|
+
# every such repo forking this workflow to edit one -m expression.
|
|
82
|
+
ci_config = data.get('tool', {}).get('ci', {})
|
|
83
|
+
exclude_markers = ['local_only', *ci_config.get('pytest-exclude-markers', [])]
|
|
84
|
+
pytest_marker_expr = ' and '.join(f'not {m}' for m in exclude_markers)
|
|
85
|
+
|
|
72
86
|
# Write to GITHUB_OUTPUT for composite action outputs
|
|
73
87
|
with open(os.environ['GITHUB_OUTPUT'], 'a', encoding='utf-8') as out:
|
|
74
88
|
out.write(f"PROJECT_NAME={project}\n")
|
|
@@ -79,6 +93,7 @@ runs:
|
|
|
79
93
|
out.write(f"COV_REPORT_FILE={cov_report_file}\n")
|
|
80
94
|
out.write(f"COV_FAIL_UNDER={cov_fail_under}\n")
|
|
81
95
|
out.write(f"BANDIT_SKIP_FLAG={bandit_skip_flag}\n")
|
|
96
|
+
out.write(f"PYTEST_MARKER_EXPR={pytest_marker_expr}\n")
|
|
82
97
|
|
|
83
98
|
# Also write to GITHUB_ENV so subsequent steps can use ${{ env.VAR }}
|
|
84
99
|
with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
|
|
@@ -90,3 +105,4 @@ runs:
|
|
|
90
105
|
env.write(f"COV_REPORT_FILE={cov_report_file}\n")
|
|
91
106
|
env.write(f"COV_FAIL_UNDER={cov_fail_under}\n")
|
|
92
107
|
env.write(f"BANDIT_SKIP_FLAG={bandit_skip_flag}\n")
|
|
108
|
+
env.write(f"PYTEST_MARKER_EXPR={pytest_marker_expr}\n")
|
|
File without changes
|
{lib_cli_exit_tools-2.3.2 → lib_cli_exit_tools-2.3.4}/.github/workflows/default_cicd_public.yml
RENAMED
|
@@ -18,8 +18,8 @@ jobs:
|
|
|
18
18
|
python-latest: ${{ steps.metadata.outputs.python-latest }}
|
|
19
19
|
os-matrix: ${{ steps.metadata.outputs.os-matrix }}
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
22
|
-
- uses: actions/setup-python@
|
|
21
|
+
- uses: actions/checkout@v7
|
|
22
|
+
- uses: actions/setup-python@v7
|
|
23
23
|
with:
|
|
24
24
|
python-version: "3.x"
|
|
25
25
|
- name: Parse pyproject.toml for Python versions and OS matrix
|
|
@@ -66,8 +66,8 @@ jobs:
|
|
|
66
66
|
UV_LINK_MODE: "copy"
|
|
67
67
|
UV_BREAK_SYSTEM_PACKAGES: "1"
|
|
68
68
|
steps:
|
|
69
|
-
- uses: actions/checkout@
|
|
70
|
-
- uses: actions/setup-python@
|
|
69
|
+
- uses: actions/checkout@v7
|
|
70
|
+
- uses: actions/setup-python@v7
|
|
71
71
|
with:
|
|
72
72
|
python-version: ${{ matrix.python }}
|
|
73
73
|
- name: Install uv
|
|
@@ -169,7 +169,7 @@ jobs:
|
|
|
169
169
|
- name: Restore ruff cache
|
|
170
170
|
if: runner.environment == 'github-hosted'
|
|
171
171
|
id: ruff-cache
|
|
172
|
-
uses: actions/cache/restore@
|
|
172
|
+
uses: actions/cache/restore@v6
|
|
173
173
|
with:
|
|
174
174
|
path: .ruff_cache
|
|
175
175
|
key: ruff-${{ runner.os }}-py${{ matrix.python }}-${{ github.sha }}
|
|
@@ -201,7 +201,7 @@ jobs:
|
|
|
201
201
|
# and stale journal files cause "database is locked" errors.
|
|
202
202
|
COVERAGE_FILE: "${{ runner.temp }}/.coverage"
|
|
203
203
|
run: >-
|
|
204
|
-
pytest -m "
|
|
204
|
+
pytest -m "${{ env.PYTEST_MARKER_EXPR }}"
|
|
205
205
|
--cov=${{ env.SRC_PATH }}/${{ env.PACKAGE_MODULE }}
|
|
206
206
|
--cov-report=term-missing
|
|
207
207
|
--cov-report=xml:${{ env.COV_REPORT_FILE }}
|
|
@@ -236,12 +236,62 @@ jobs:
|
|
|
236
236
|
continue-on-error: true
|
|
237
237
|
shell: python
|
|
238
238
|
run: |
|
|
239
|
-
import subprocess, sys
|
|
239
|
+
import subprocess, sys, tempfile
|
|
240
240
|
import rtoml
|
|
241
241
|
from pathlib import Path
|
|
242
|
+
|
|
243
|
+
# Audit the project's OWN resolved dependency tree, not the ambient
|
|
244
|
+
# environment. "Install dev deps" uses --system, so the interpreter
|
|
245
|
+
# being audited is the runner image's, and that image ships packages
|
|
246
|
+
# this project neither declares nor distributes (setuptools, pip,
|
|
247
|
+
# wheel). Auditing those reported CVEs no consumer of this project is
|
|
248
|
+
# exposed to, and a scan that is permanently yellow is a scan everyone
|
|
249
|
+
# learns to ignore. Resolving pyproject.toml here keeps the result
|
|
250
|
+
# identical on every OS/python and dependent only on what we declare.
|
|
242
251
|
data = rtoml.load(Path("pyproject.toml"))
|
|
252
|
+
|
|
253
|
+
# Not every project declares dev dependencies, and those that do may use
|
|
254
|
+
# either an extra or a PEP 735 group. Asking uv for one that does not
|
|
255
|
+
# exist is a hard error ("Requested extra not found"), which would leave
|
|
256
|
+
# the audit permanently broken here rather than merely noisy, so select
|
|
257
|
+
# the flag from what this project actually declares.
|
|
258
|
+
selector = []
|
|
259
|
+
if "dev" in data.get("project", {}).get("optional-dependencies", {}):
|
|
260
|
+
selector = ["--extra", "dev"]
|
|
261
|
+
elif "dev" in data.get("dependency-groups", {}):
|
|
262
|
+
selector = ["--group", "dev"]
|
|
263
|
+
|
|
264
|
+
tmp = Path(tempfile.mkdtemp())
|
|
265
|
+
req = tmp / "compiled-requirements.txt"
|
|
266
|
+
subprocess.check_call(
|
|
267
|
+
["uv", "pip", "compile", *selector, "pyproject.toml", "-o", str(req), "--quiet"]
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
# Drop direct URL references ("pkg @ git+https://...") before auditing.
|
|
271
|
+
# pip-audit cannot audit those (they are not on PyPI) but, given a
|
|
272
|
+
# requirements file, first tries to `git clone` each one to resolve a
|
|
273
|
+
# version - a slow, credential-dependent fetch. No public project here
|
|
274
|
+
# uses one today, yet "allow-direct-references" is enabled, so this
|
|
275
|
+
# guards the day one appears and keeps this step identical to the
|
|
276
|
+
# default_cicd_private template's.
|
|
277
|
+
audit_req = tmp / "audit-requirements.txt"
|
|
278
|
+
kept, dropped = [], []
|
|
279
|
+
for line in req.read_text(encoding="utf-8").splitlines():
|
|
280
|
+
if " @ " in line and not line.lstrip().startswith("#"):
|
|
281
|
+
dropped.append(line.split(" @ ", 1)[0].strip())
|
|
282
|
+
else:
|
|
283
|
+
kept.append(line)
|
|
284
|
+
audit_req.write_text("\n".join(kept) + "\n", encoding="utf-8")
|
|
285
|
+
if dropped:
|
|
286
|
+
# Never drop coverage silently: name what is not being audited here.
|
|
287
|
+
print(f"::notice::pip-audit: not auditing {len(dropped)} direct-URL dependency/ies "
|
|
288
|
+
f"(audited in their own repo): {', '.join(sorted(dropped))}")
|
|
289
|
+
|
|
290
|
+
req = audit_req
|
|
243
291
|
vulns = data.get("tool", {}).get("pip-audit", {}).get("ignore-vulns", [])
|
|
244
|
-
|
|
292
|
+
# --no-deps: the compiled file is already a complete pinned resolution,
|
|
293
|
+
# so pip-audit must audit it verbatim rather than re-resolving it.
|
|
294
|
+
cmd = ["pip-audit", "--no-deps", "-r", str(req)]
|
|
245
295
|
for v in vulns:
|
|
246
296
|
cmd.extend(["--ignore-vuln", v])
|
|
247
297
|
sys.exit(subprocess.call(cmd))
|
|
@@ -293,7 +343,7 @@ jobs:
|
|
|
293
343
|
|
|
294
344
|
- name: Save ruff cache
|
|
295
345
|
if: always() && runner.environment == 'github-hosted' && steps.ruff-cache.outputs.cache-hit != 'true'
|
|
296
|
-
uses: actions/cache/save@
|
|
346
|
+
uses: actions/cache/save@v6
|
|
297
347
|
with:
|
|
298
348
|
path: .ruff_cache
|
|
299
349
|
key: ruff-${{ runner.os }}-py${{ matrix.python }}-${{ github.sha }}
|
|
@@ -302,8 +352,8 @@ jobs:
|
|
|
302
352
|
name: pipx/uv verification (ubuntu)
|
|
303
353
|
runs-on: ubuntu-latest
|
|
304
354
|
steps:
|
|
305
|
-
- uses: actions/checkout@
|
|
306
|
-
- uses: actions/setup-python@
|
|
355
|
+
- uses: actions/checkout@v7
|
|
356
|
+
- uses: actions/setup-python@v7
|
|
307
357
|
with:
|
|
308
358
|
python-version: "3.14"
|
|
309
359
|
|
|
@@ -341,8 +391,8 @@ jobs:
|
|
|
341
391
|
name: Execute notebooks (ubuntu, Python 3.14)
|
|
342
392
|
runs-on: ubuntu-latest
|
|
343
393
|
steps:
|
|
344
|
-
- uses: actions/checkout@
|
|
345
|
-
- uses: actions/setup-python@
|
|
394
|
+
- uses: actions/checkout@v7
|
|
395
|
+
- uses: actions/setup-python@v7
|
|
346
396
|
with:
|
|
347
397
|
python-version: "3.14"
|
|
348
398
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# The tag push is the only release event bmk guarantees: it runs
|
|
4
|
+
# `git push <remote> <tag>` unconditionally, whereas `gh release create` sits
|
|
5
|
+
# behind a gh-availability check and runs with check=False, so a missing or
|
|
6
|
+
# failing gh would leave nothing to publish. Listening for `release: published`
|
|
7
|
+
# as well fired a second, redundant run that raced the first to the upload and
|
|
8
|
+
# only ever logged "Skipping ... already exists".
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
tags:
|
|
12
|
+
- 'v*'
|
|
13
|
+
workflow_dispatch: {}
|
|
14
|
+
|
|
15
|
+
# One publish at a time per tag, so a workflow_dispatch re-run cannot overlap
|
|
16
|
+
# the run the tag push started.
|
|
17
|
+
concurrency:
|
|
18
|
+
group: release-${{ github.ref_name }}
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
build:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
env:
|
|
27
|
+
UV_LINK_MODE: "copy"
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v7
|
|
30
|
+
- uses: actions/setup-python@v7
|
|
31
|
+
with:
|
|
32
|
+
python-version: '3.14'
|
|
33
|
+
|
|
34
|
+
- name: Install uv
|
|
35
|
+
uses: astral-sh/setup-uv@v7
|
|
36
|
+
with:
|
|
37
|
+
enable-cache: true
|
|
38
|
+
prune-cache: false
|
|
39
|
+
|
|
40
|
+
- name: Build artifacts
|
|
41
|
+
run: uv build
|
|
42
|
+
|
|
43
|
+
- name: Upload artifacts
|
|
44
|
+
uses: actions/upload-artifact@v7
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/*
|
|
48
|
+
|
|
49
|
+
- name: Prune uv cache
|
|
50
|
+
continue-on-error: true
|
|
51
|
+
run: uv cache prune --ci
|
|
52
|
+
|
|
53
|
+
publish:
|
|
54
|
+
needs: build
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
environment: pypi
|
|
57
|
+
permissions:
|
|
58
|
+
contents: read
|
|
59
|
+
# id-token is required for OIDC / PyPI Trusted Publisher. It is harmless when
|
|
60
|
+
# a PYPI_API_TOKEN secret is configured, in which case the token path runs.
|
|
61
|
+
id-token: write
|
|
62
|
+
steps:
|
|
63
|
+
- name: Select PyPI auth method
|
|
64
|
+
id: auth
|
|
65
|
+
env:
|
|
66
|
+
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
67
|
+
run: |
|
|
68
|
+
if [ -n "$PYPI_API_TOKEN" ]; then
|
|
69
|
+
echo "PYPI_API_TOKEN is set; publishing with the API token."
|
|
70
|
+
echo "method=token" >> "$GITHUB_OUTPUT"
|
|
71
|
+
else
|
|
72
|
+
echo "No PYPI_API_TOKEN; publishing via OIDC Trusted Publisher."
|
|
73
|
+
echo "method=oidc" >> "$GITHUB_OUTPUT"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
- name: Download artifacts
|
|
77
|
+
uses: actions/download-artifact@v8
|
|
78
|
+
with:
|
|
79
|
+
name: dist
|
|
80
|
+
path: dist/
|
|
81
|
+
|
|
82
|
+
- name: Publish to PyPI (API token)
|
|
83
|
+
if: steps.auth.outputs.method == 'token'
|
|
84
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
85
|
+
with:
|
|
86
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
87
|
+
attestations: false
|
|
88
|
+
skip-existing: true
|
|
89
|
+
|
|
90
|
+
- name: Publish to PyPI (Trusted Publisher / OIDC)
|
|
91
|
+
if: steps.auth.outputs.method == 'oidc'
|
|
92
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
93
|
+
with:
|
|
94
|
+
attestations: true
|
|
95
|
+
skip-existing: true
|
|
File without changes
|
|
File without changes
|
|
@@ -4,10 +4,28 @@ All notable changes to this project are documented here. The format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.3.4] 2026-07-29 15:20:59
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- `run_cli()` now returns the exit code a command chose with `ctx.exit(...)` instead of always reporting `0` on the non-exception path. Click is invoked with `standalone_mode=False`, which makes it *return* that code rather than raising it, and `_run_command_with_handler` discarded the value before returning a hardcoded `0`. Only the exception path could therefore produce a non-zero status, so a command that completed normally while reporting a negative *answer* - a host that did not respond, a search that found nothing, anything distinguishing "ran fine, result is no" from "failed" - silently exited `0`. `ClickCommand.main` is annotated `-> object` to match what Click actually returns. A command that simply completes still yields `0`, since Click returns `None` there.
|
|
11
|
+
|
|
12
|
+
No released behaviour changes for existing users: a sweep of every project in this tree found no other consumer calling `ctx.exit()` with a non-zero code, no test pinned the previous behaviour, and the documented `run_cli` contract in the README already described executing the command with `standalone_mode=False` without mentioning that its result was dropped.
|
|
13
|
+
|
|
14
|
+
## [2.3.3] 2026-07-24 16:09:16
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- `print_info()` now writes via `sys.stdout.write()` instead of `print()`, and `print_exception_message()`'s `trace_back` / `length_limit` / `stream` parameters are keyword-only, along with several private `application/runner.py` helpers (`_resolve_traceback_choice`, `_render_exception_view`, `_session_config_manager`, `_install_signal_handlers_when_requested`) - closing the ruff PLR0917/FBT001 boolean-positional-argument findings that a newer ruff started reporting. All call sites (in this repo and downstream) already passed these by keyword, so this is not a breaking change.
|
|
18
|
+
- Replaced `typing.Callable`/`Iterable`/`Sequence`/`ContextManager` imports with their `collections.abc`/`contextlib` equivalents (ruff UP035), sorted `__all__` lists (RUF022), quoted `typing.cast()` type arguments (TC006), and moved a handful of type-checking-only imports behind `TYPE_CHECKING` (TC003) across `src` and `tests`.
|
|
19
|
+
- Replaced ambiguous en-dash characters in docstrings with ASCII hyphens (RUF002).
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Added an explicit, curated `[tool.ruff.lint].select` (the fleet-standard rule set) to `pyproject.toml` instead of relying on ruff's default rule set, which had grown to roughly 900 rules on the installed ruff release and was about to make CI red on unrelated, previously-unenforced rule families. Added matching `per-file-ignores` for tests, the CLI layer, `notebooks/Quickstart.ipynb`, and `application/runner.py`'s intentionally-wide dependency-injection seams (`PLR0913`).
|
|
23
|
+
- Documented the three narrow places where suppressing a lint finding is correct rather than fixing it: the `SigIntInterrupt`/`SigTermInterrupt`/`SigBreakInterrupt` exception names stay as-is (`# noqa: N818`) because renaming them would break every downstream `except Sig...Interrupt`; `getattr(signal, "SIGBREAK"/"CTRL_BREAK_EVENT")` and `getattr(exc, "winerror")` stay as `getattr()` (`# noqa: B009`) because typeshed only declares those attributes on Windows/`OSError`, so direct attribute access fails pyright strict on other platforms/types; and the `echo=lambda ...` test double stays a lambda (`# noqa: PLW0108`) because `messages.append` alone cannot accept the `err` keyword the echo protocol requires.
|
|
24
|
+
|
|
7
25
|
## [2.3.2] 2026-06-14
|
|
8
26
|
|
|
9
27
|
### Changed
|
|
10
|
-
- Added a `cli/typed_click.py` facade that wraps rich-click's `option` / `version_option` decorators behind explicit, fully-known signatures. This keeps the CLI layer clean under pyright 1.1.410 strict mode (which reports `reportUnknownMemberType` for rich-click's re-exported click decorators) without disabling the rule
|
|
28
|
+
- Added a `cli/typed_click.py` facade that wraps rich-click's `option` / `version_option` decorators behind explicit, fully-known signatures. This keeps the CLI layer clean under pyright 1.1.410 strict mode (which reports `reportUnknownMemberType` for rich-click's re-exported click decorators) without disabling the rule - the single `# pyright: ignore` is isolated to the facade boundary.
|
|
11
29
|
|
|
12
30
|
## [2.3.1] - 2026-04-24
|
|
13
31
|
|
|
@@ -157,7 +175,7 @@ All notable changes to this project are documented here. The format follows [Kee
|
|
|
157
175
|
### Changed
|
|
158
176
|
- Hardened `get_system_exit_code` handling for non-integer payloads and switched OS detection to `os.name`.
|
|
159
177
|
- Updated `_print_output` to decode both `bytes` and `str`, trimming assertions in favour of resilient diagnostics.
|
|
160
|
-
- Standardised signal messages (
|
|
178
|
+
- Standardised signal messages ("Aborted (SIGINT).", etc.) and cached metadata lookups in `__init__conf__`.
|
|
161
179
|
- Enforced an 85% coverage threshold (in line with `pyproject.toml` and Codecov settings) and removed spurious coverage pragmas to reflect the new test suite.
|
|
162
180
|
- Repartitioned the library into `core`, `adapters`, and `application` layers with `lib_cli_exit_tools` acting as the facade.
|
|
163
181
|
- `run_cli` now accepts injectable `exception_handler` and `signal_installer` hooks, and rich-click configuration is applied lazily from `main()`.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|