Skip to main content

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

  1. Flushes host stdio, so the native side's direct fd-1/fd-2 writes can't land ahead of earlier buffered Python output.
  2. Imports the native module and looks up run_cli (helpful BinShimError if the wheel for this platform is missing).
  3. Calls run_cli(argv) (default sys.argv[1:]), passing argv through byte-faithfully — no shell interpretation.
  4. Translates the returned code into process semantics:
    • ordinary codes are returned for you to sys.exit with;
    • 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 — 130 exits plainly as 130;
    • a KeyboardInterrupt escaping the native call is treated as the SIGINT-shutdown path, and no traceback ever reaches the user.

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 (the 128 + N POSIX 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:

  1. run_cli(argv) -> int always returns; it never terminates the process.
  2. 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.
  3. 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

bin_shim-0.1.1.tar.gz (10.4 kB view details)

Uploaded Source

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

Hashes for bin_shim-0.1.1.tar.gz
Algorithm Hash digest
SHA256 9972911c22754a5370f666245cbe5d9d9aa04d9f7289d166142c9c3c6ee3b8c3
MD5 3e1cfb6ff5245992facb5bc8fb2269d9
BLAKE2b-256 6afc2e09f2de12c0937834fc3f2bacde597f6e25499b0bf4b3d71292b7dbf822

See more details on using hashes here.

Provenance

The following attestation bundles were made for bin_shim-0.1.1.tar.gz:

Publisher: release.yml on thekevinscott/bin-shim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.1 This release

1 file

0.1.0

1 file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page