bin-shim (Python)
Runtime shim for native CLIs exposed in-process as run_cli(argv) -> int.
The pattern: your Rust (or C, or Zig) CLI is compiled once as a library and
exposed through Python bindings (e.g. pyo3) as a function that takes argv and
returns an exit code. Your PyPI package's console script then needs to make
the process behave exactly as if the binary had been run directly — exit
codes, signals, stdio ordering. bin-shim owns those process semantics so
your launcher reduces to one line.
The npm sibling package (same repo) covers the spawn pattern for Node; both implementations execute the same process-semantics conformance spec.
Install
uv add bin-shim
Quickstart
Your package ships a native bindings module (say yourpkg._native) exposing
run_cli. Point a console script at a two-line entry:
# yourpkg/cli.py
import sys
from bin_shim import main
def entry() -> None:
sys.exit(main("yourpkg._native"))
# pyproject.toml
[project.scripts]
yourcli = "yourpkg.cli:entry"
What main does
- Flushes host stdio, so the native side's direct fd-1/fd-2 writes can't land ahead of earlier buffered Python output.
- Imports the native module and looks up
run_cli(helpfulBinShimErrorif the wheel for this platform is missing). - Calls
run_cli(argv)(defaultsys.argv[1:]), passing argv through byte-faithfully — no shell interpretation. - Translates the returned code into process semantics:
- ordinary codes are returned for you to
sys.exitwith; - on POSIX,
130/143(the core's graceful-shutdown codes for SIGINT/SIGTERM) restore the default handler and re-raise the signal, so the parent shell observes genuine signal death and job control works; - on Windows there is no re-raise —
130exits plainly as130; - a
KeyboardInterruptescaping the native call is treated as the SIGINT-shutdown path, and no traceback ever reaches the user.
- ordinary codes are returned for you to
API
main(module, argv=None, *, entry_point="run_cli", importer=None, run_cli=None, platform=None) -> int
Resolve and invoke the native entry point, apply exit semantics, and return
the code to pass to sys.exit. For the POSIX signal-shutdown codes it does
not return (the process dies by re-raised signal). importer and run_cli
are injectable seams for testing; platform defaults to sys.platform.
resolve_run_cli(module, *, entry_point="run_cli", importer=None) -> RunCli
Import module and return its entry_point callable, or raise
BinShimError with an installation hint.
apply_exit_semantics(code, *, platform=None) -> int
The translation step alone: passthrough for ordinary codes, signal re-raise
for 130/143 on POSIX, plain passthrough on Windows.
Constants and types
SIGINT_EXIT_CODE = 130,SIGTERM_EXIT_CODE = 143(the128 + NPOSIX convention)RunCli = Callable[[list[str]], int]Importer = Callable[[str], ModuleType]BinShimError— resolution failures and contract violations
The run_cli contract
What this library requires of the native side:
run_cli(argv) -> intalways returns; it never terminates the process.- It registers its own SIGINT/SIGTERM (POSIX) / ctrl-c (Windows) handling for the duration of the run; on receipt it performs graceful shutdown and returns 130/143. Shutdown logic lives in the core, once — launchers only translate.
- It writes only to file descriptors 1/2; it never touches host-language stdio objects.
What bin-shim does not do
- Build or package the native module. That's your build backend (maturin, setuptools-rust, …).
- Argv middleware. Preprocess argv yourself and pass the result to
main. - Spawn anything. This is the in-process strategy; nothing is executed as a child process.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file bin_shim-0.1.1.tar.gz.
File metadata
- Download URL: bin_shim-0.1.1.tar.gz
- Upload date:
- Size: 10.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9972911c22754a5370f666245cbe5d9d9aa04d9f7289d166142c9c3c6ee3b8c3
|
|
| MD5 |
3e1cfb6ff5245992facb5bc8fb2269d9
|
|
| BLAKE2b-256 |
6afc2e09f2de12c0937834fc3f2bacde597f6e25499b0bf4b3d71292b7dbf822
|
Provenance
The following attestation bundles were made for bin_shim-0.1.1.tar.gz:
Publisher:
release.yml on thekevinscott/bin-shim
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bin_shim-0.1.1.tar.gz -
Subject digest:
9972911c22754a5370f666245cbe5d9d9aa04d9f7289d166142c9c3c6ee3b8c3 - Sigstore transparency entry: 2538828452
- Sigstore integration time:
-
Permalink:
thekevinscott/bin-shim@f8ac06f1b3c1644a4df3666fcb8fc540bd1bbe7f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/thekevinscott
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f8ac06f1b3c1644a4df3666fcb8fc540bd1bbe7f -
Trigger Event:
push
-
Statement type: