Make a Python-native .chub installer from wheels and their dependencies.
Project description
pychub
Table of Contents
- Overview
- The Name
- Why pychub?
- Why not just use insert favorite tool name here?
- How it works
- CLI Parameters
- The
.chubconfigmetadata file - Roadmap
- License
Overview
pychub is a Python packaging tool that bundles your wheel and all of its
dependencies into a single self-extracting .chub file.
The .chub file can be executed directly with any compatible Python interpreter
(system Python, virtual environment, conda env, etc.) to install the package and
its dependencies into the current environment.
Optionally, it can run a specified entrypoint after installation, and this can be done via an ephemeral venv.
The Name
As you might guess, pychub is a combination of python and chubby. While the standard wheels are quite a bit leaner, consisting of your application and the metadata required to install it, pychub bundles all of your dependencies into a single file. This results in a "thicker" file and, thus, the pychub name was born.
Sometimes software developers like to have a little fun with naming, since deadlines and testing and debugging are often fairly serious matters.
Why pychub?
Most Python packaging tools fall into one of two extremes:
- Frozen binaries (PyInstaller, PyOxidizer, etc.) - lock you to a specific platform, bundle the Python runtime, and create large artifacts.
- Wheel distribution only - require manual
pip installcommands, assume users know how to manage dependencies.
pychub lives in between: it avoids runtime bloat by using the host Python interpreter, but also keeps the experience smooth by shipping all dependencies pre-downloaded and ready to install.
This makes it:
- Build-tool agnostic - Poetry, setuptools, Hatch, Flit, pygradle... if it spits out a wheel, pychub can package it.
- Environment agnostic - works in any Python environment that meets your
Requires-Pythonspec. - Simple -
python yourpackage.chubinstalls everything; optionally runs your tool.
Why Not Just Use [insert favorite tool name here]?
Well, you might be right! This is not a simple question, and I will not presume that I can make that determination for you. You have the best knowledge of your use case, and that means that you are in the best position to make that decision.
There are several really great packaging tools available for python. Many of them share a few overlapping capabilities, and they all have their own unique features that help with the use cases that they were designed to solve. Pychub is no exception. It shares some features with other tools, but it was designed with a slightly different perspective to address particular use cases.
Here is a table that might help users decide which tool is the best fit for their use case. (Hint: it might, or might not, be pychub!)
Feature Comparison
| Feature/Need | pychub | pex | shiv | zipapp | PyInstaller / PyOxidizer |
|---|---|---|---|---|---|
| Single-file distribution | Yes (.chub) |
Yes (.pex, or native executables with --scie) |
Yes (.pyz) |
Yes (.pyz) |
Yes (binary) |
| Includes Python interpreter | No - uses current environment | Optional - --scie mode bundles an interpreter |
No - uses host interpreter | No - uses host interpreter | Yes - frozen binary |
| Reproducible install | Yes - exact wheel copies | Yes - PEX-locked deps, hermetic builds | Installs into its own venv on run | Sometimes - zip structure | No - binary blob |
| Works in venv/conda/sys env | Yes - pip into any target | Yes - any compatible interpreter; venv integration strong | Yes - wheels embedded in zip | Yes - but ephemeral venv | Yes - embedded runtime |
| Create a new venv | Yes - ephemeral or persistent | Yes - can build/run in ephemeral or existing venvs | No - installs into current venv | Yes - ephemeral only | No - uses frozen runtime |
| Lifecycle script hooks | Yes - user scripts at install | No (limited setup only) | No | No | Build-time hooks only |
| Runtime execution | Optional via entrypoint | Yes - run apps or REPL directly | Yes - runs entrypoints | Yes - run modules from archive | Yes - runs binary |
| Cross-platform artifact | Limited - wheels must be xplat | Yes - multi-platform PEX or scie supports platform targeting | Yes - pure-Python only | Limited - depends on wheels | No - per-platform build |
| Network-free install | Yes - offline ready | Yes - offline ready | No - pulls from PyPI if needed | Sometimes - depends on config | Yes - all-in-one binary |
| Target audience | Devs needing flexible installs | Devs needing sealed, reproducible apps | Devs wanting simple .pyz bundling | Devs shipping portable scripts | End-user binary delivery |
The table below shows how various packaging tools align with common deployment needs. Rather than list features, it focuses on use cases so that you can choose the tool that best fits your project’s real-world requirements. Each column reflects how well a given tool supports that scenario, whether it’s a perfect match, a partial fit, or better suited elsewhere.
Use Case Alignment
| Use Case / Scenario | pychub | pex | shiv | zipapp | PyInstaller / PyOxidizer |
|---|---|---|---|---|---|
| Distribute a CLI/lib in one file | best fit | best fit | works | works | overkill |
| Ship sealed GUI/CLI to users w/o Python | n/a | works (esp. with --scie) |
n/a | n/a | best fit |
| Run directly from compressed archive | yes⁷ | best fit | best fit | best fit | n/a |
| Reproducible install without network | best fit | best fit | no - pulls from PyPI if required | possible¹ | works |
| Install into any Python env | best fit | yes (any compatible interpreter) | yes - installs wheels into venv | best fit | n/a |
| Include Python interpreter in artifact | n/a | yes (--scie eager/lazy) |
no | n/a | yes |
| Use lifecycle (pre/post) scripts | runtime³ | n/a | n/a | n/a | build-time⁴ |
| Install from wheels using pip | yes | yes | yes | optional | no |
| Build Docker containers with no runtime pip⁶ | best fit | works | works | works | works |
| Bundle for ephemeral one-off jobs | yes | best fit | best fit | best fit | overkill |
| Deploy without re-downloading deps | best fit | best fit | partial | partial | yes |
| Target cross-platform deployment | limited² | yes - multi-platform support built | limited - pure-Python only | limited | no |
| Package with Conda dependencies | roadmap⁵ | n/a | n/a | n/a | n/a |
| Support compile-time customization or setup | limited³ | n/a | n/a | n/a | yes (scriptable) |
Notes:
¹ Zipapps can embed dependencies, but behavior varies depending on how you construct the archive.
² pychub is only cross-platform if bundled wheels themselves are portable.
³ Only pychub supports runtime post-install user scripts.
⁴ PyOxidizer allows scripted setup at build time, not runtime.
⁵ Conda support is exploratory/on the roadmap for pychub.
⁶ Multi-stage Docker: install with pychub in a builder stage (e.g., in a venv) and copy only
the venv/app into the runtime image; the final image contains no pip and performs no install.
⁷ Running a .chub with --exec uses an ephemeral venv and requires pip.
So the point isn’t that any of these are "best" or "wrong" tools. They’re all excellent for the jobs they were built for. Pychub simply covers a different slice of the space: inherently reproducible, single-file, wheel-based bundles that install into the current Python environment without pulling from the network.
How It Works
NOTE: The target environment must be Python 3.9+ and it must have pip installed.
When the .chub file is created, its name is derived from the main wheel, if
the user does not provide a name with the --chub option. The name is derived
from the wheel metadata, and it is formatted as <Name>-<Version>.chub.
While it has been mentioned that pychub creates reproducible installs, it
should be understood that this is not making claims about the target host state.
This is about the bundled wheels that are installed into the target environment.
When you run pychub, it creates a structure like this:
libs/ # your main wheel and all dependency wheels
scripts/ # lifecycle scripts parent directory
pre/ # pre-install scripts
post/ # post-install scripts
includes/ # additional files to include in the bundle
runtime/ # bootstrap installer
.chubconfig # metadata: ID, version, entrypoint, post-install
__main__.py # entry that bootstraps the runtime
This happens through the following steps:
- Copy your wheel into
libs/. - Resolve and download dependencies using pip (also into
libs/). - Copy additional wheels into
libs/. - Resolve and download dependencies for each wheel using pip (also into
libs/). - Copy any additional user-specified files to
includes/(with relative paths). - Copy any pre- and post-install scripts to
scripts/pre/andscripts/post/. - Inject the pychub runtime and include
__main__.pyto enable the runtime CLI and its operations. - Update the
.chubconfigwith these details, including a metadata entry for themain_wheel. - Package everything into a
.chubfile usingzip. - Append wheels and their dependencies to an existing
.chub:- Using a single
--add-wheeloption and a comma-delimited list:--add-wheel dir/second.whl,dir2/third.whl --chub existing.chub - Using repeated
--add-wheeloptions:--add-wheel dir1/second.whl --add-wheel dir2/third.whl --chub existing.chub
- Using a single
CLI Parameters
This section describes the CLI commands available in pychub for building,
and then operating, a .chub file.
Building a Chub
The pychub build CLI packages your Python project’s wheel and its
dependencies into a single .chub file.
usage: pychub <wheel> [build options]
| Option | Short Form | Description | Repeatable |
|---|---|---|---|
<wheel> |
N/A | Path to the main wheel file to process | no |
--add-wheel |
-a |
Optional path to a wheel to add (plus deps) | yes |
--chub |
-c |
Optional path to the output .chub file |
no |
--chubproject |
N/A | Optional path to chubproject.toml as build config source |
no |
--chubproject-save |
N/A | Optional path to write build config to chubproject.toml |
no |
--entrypoint |
-e |
Optional entrypoint to run after install | no |
--include |
-i |
Optional list of files to include | yes |
--metadata-entry |
-m |
Optional metadata to include in .chubconfig |
yes |
--post-script |
-o |
Optional path to post-install script(s) to include | yes |
--pre-script |
-p |
Optional path to pre-install script(s) to include | yes |
--verbose |
-v |
Optionally show more information when building | no |
--version |
N/A | Show version info and exit | no |
Notes:
<wheel>:- Mandatory argument (except with
--add-wheel,--chubconfig, or--version). - Accepts an argument of any legal path to a wheel file.
- Mandatory argument (except with
--add-wheel:- Optional for single invocation, but required when appending wheels to an
existing
.chub.
- Optional for single invocation, but required when appending wheels to an
existing
--chub:- Optional for single invocation, but required when appending wheels to an
existing
.chub. - Defaults to
<Name>-<Version>.chubderived from wheel metadata.
- Optional for single invocation, but required when appending wheels to an
existing
--chubproject:- Optional.
- Requires an argument specifying the path to a
chubproject.tomlfile. - If specified, matching file entries are overridden by the corresponding values on the command line.
--chubproject-save:- Optional.
- Requires an argument specifying the path to the destination
chubproject.tomlfile. - Can be specified along with
--chubprojectto preserve changes if you include additional CLI options and arguments.
--entrypoint:- Optional.
- The value is a single string, and quoted if it contains spaces.
- May be overridden during runtime invocation.
- Pychub does not parse or validate the inner arguments; they are stored
and passed verbatim to the child process when
--runor--execis used at runtime. - Formats:
- entrypoint target:
module:function [args](optional arguments supported).
- console script entrypoint (PEP 621):
console-script-name [args](optional arguments supported).
- entrypoint target:
--include:- Optional.
- Repeatable option to supply multiple files.
- Any legal path to a file.
- May specify a destination relative to the installation directory.
- Formats:
- Single option with single file:
--include /path/to/file[::dest] - Single option with multiple files:
--include /path/to/file1[::dest] /path/to/file2[::dest] /path/to/fileN[::dest] - Multiple options for multiple files:
--include /path/to/file1[::dest] --include /path/to/file2[::dest] --include /path/to/fileN[::dest]
- Single option with single file:
--metadata-entry:- Optional.
- Repeatable option to supply multiple key-value pairs.
- Values can be single items or space‑separated lists.
- Lists are parsed as YAML arrays in the
.chubconfigfile. - Formats:
- Single option with a single key-value pair:
--metadata-entry key=value - Single option with multiple key-value pairs:
--metadata-entry key1=value1 key2=value2 keyN=valueN - Multiple options for multiple key-value pairs:
--metadata-entry key1=value1 --metadata-entry key2=value2 --metadata-entry keyN=valueN
- Single option with a single key-value pair:
--post-script:- Optional.
- Runs after the installation, but before the entrypoint.
- Repeatable option to supply multiple post-install scripts.
- Any legal path to a script file.
- Formats:
- Single option with a single script:
--post-script /path/to/script.sh - Single option with multiple scripts:
--post-script /path/to/script1.sh,/path/to/script2.sh,/path/to/scriptN.sh - Multiple options for multiple scripts:
--post-script /path/to/script1.sh --post-script /path/to/script2.sh --post-script /path/to/scriptN.sh
- Single option with a single script:
--pre-script:- Optional.
- Runs before installation.
- Repeatable option to supply multiple pre-install scripts.
- Any legal path to a script file.
- Formats:
- Single option with a single script:
--pre-script /path/to/script.sh - Single option with multiple scripts:
--pre-script /path/to/script1.sh,/path/to/script2.sh,/path/to/scriptN.sh - Multiple options for multiple scripts:
--pre-script /path/to/script1.sh --pre-script /path/to/script2.sh --pre-script /path/to/scriptN.sh
- Single option with a single script:
Example Usage (build)
The usage of pychub should be fairly straightforward and intuitive, as you
can see in the following examples:
-
Basic build
pychub dist/mypackage-1.0.0-py3-none-any.whl -
Custom output file
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --chub dist/app.chub
-
Simple callable spec (no args, and no spaces, so no quotes necessary)
pychub dist/app.whl \ --entrypoint mypkg.cli:main
-
Callable spec with arguments (quotes are required because of spaces)
pychub dist/app.whl \ --entrypoint "mypkg.cli:main --mode train --limit 100"
-
Console script with arguments (quotes are required because of spaces)
pychub dist/app.whl \ --entrypoint "mypackage-cli --verbose --config conf.yml"
-
Include a single file
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --include ./extra.cfg
-
Include with destination path relative to install dir
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --include README.md::docs
-
Multiple includes (comma-separated in a single flag)
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --include a.txt::conf,b.json::data,c.ini
-
Multiple includes (repeat the flag)
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --include a.txt \ --include b.json::data \ --include c.ini
-
Add pre-install scripts
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --pre-script ./scripts/check_env.sh
-
Add post-install scripts (multiple via comma-separated list)
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --post-script init.sh,finish.sh
-
Combine pre/post scripts with includes and entrypoint
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --pre-script pre.sh \ --post-script post.sh \ --include config.toml::conf \ --entrypoint mypackage.cli:main
-
Add metadata entries (single)
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --metadata-entry maintainer:me@example.com
-
Add metadata entries (list value and multiple pairs in one flag)
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --metadata-entry tags:http,client,cli,priority \ --metadata-entry team:platform
-
Verbose build
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --verbose
-
Append an additional wheel to an existing .chub (repeatable flag)
pychub --chub dist/app.chub \ --add-wheel dist/extras/tool-2.0.0-py3-none-any.whl \ --add-wheel dist/extras/helper-1.2.3-py3-none-any.whl
-
Append additional wheels via a single comma-separated flag
pychub --chub dist/app.chub \ --add-wheel dist/extras/tool-2.0.0-py3-none-any.whl,dist/extras/helper-1.2.3-py3-none-any.whl
-
Show version and exit
pychub --version -
“Everything together” example
pychub dist/mypackage-1.0.0-py3-none-any.whl \ --chub dist/multi.chub \ --entrypoint mypackage.cli:main \ --include config.toml::conf,README.md::docs \ --pre-script pre.sh \ --post-script post.sh \ --metadata-entry maintainer:me@example.com,tags:http,client \ --verbose
Configuring a Chub Build With chubproject.toml
It may be more convenient to configure a build with a chubproject.toml file.
As you may have guessed, its name is similar to pyproject.toml, and it follows
a format that is identical to what you would use in the tool namespace of a
pyproject.toml file.
Here is an example chubproject.toml file that includes all possible options,
and it is a bit similar to the "Everything Together" example above:
[package]
chub = "dist/mybundle.chub"
wheel = "dist/app-1.2.3.whl"
entrypoint = "pkg.cli:main"
add_wheels = ["dist/addon.whl"]
includes = [
"docs/README.md", # Copies to includes/README.md
"docs/README.md::manuals/", # Copies to includes/manuals/README.md
"docs/README.md::manuals/guide.md" # Copies to includes/manuals/guide.md
]
[scripts]
pre = ["scripts/pre_check.sh"]
post = ["scripts/post_install.sh"]
[metadata]
maintainer = "you@example.com"
tags = ["http", "client"]
Notes:
- This example uses the "table" format. TOML syntax also accepts the "inline"
format, which is a bit more compact. While this is valid and acceptable, we
recommend using the "table" format for clarity. In "inline" format, the previous
example would be written as:
[package] chub = "dist/mybundle.chub" wheel = "dist/app-1.2.3.whl" entrypoint = "pkg.cli:main" add_wheels = ["dist/addon.whl"] includes = ["README.md::docs", "config/extra.cfg::conf"] scripts = {pre = ["scripts/pre_check.sh"], post = ["scripts/post_install.sh"]} metadata = {maintainer = "you@example.com", tags = ["http", "client"]}
- The
packagenamespace is optional. Not only is it optional, but namespaces liketool.pychub.packageare also permissible. If you do include a namespace it must bepackage,pychub.package, or it must end with.pychub.package(e.g.,tool.pychub.package). - Using a
chubproject.tomlfile implies that the.chubbuild is one-shot. While you can append additional wheels to an existing.chubfile, the file entries can only include items at initial build time. If you specify an existing.chubfile in thechubproject.tomlfile, pychub will exit with an error.
Operating a Chub
When you run a .chub file directly with Python, it operates in
runtime mode and installs its bundled wheels into the current
Python environment (system Python, venv, conda env, etc.).
usage: python /path/to/some.chub [runtime options] [-- [entrypoint-args...]]
The -- token is the POSIX end‑of‑options marker. Everything after -- is
not parsed by pychub and is forwarded unchanged to the entrypoint process
selected by --run (or the baked‑in entrypoint if none is provided).
| Option | Short Form | Description |
|---|---|---|
--dry-run |
-d |
Show actions without performing them |
--exec |
-e |
Run entrypoint in a temporary venv (deleted after) |
--help |
-h |
Show help and exit |
--info |
-i |
Display .chub info and exit |
--list |
-l |
List bundled wheels and exit |
--no-post-scripts |
Skip post install scripts | |
--no-pre-scripts |
Skip pre install scripts | |
--no-scripts |
Skip pre/post install scripts | |
--quiet |
-q |
Suppress output wherever possible |
--run [ENTRYPOINT] |
-r |
Run the baked-in or specified ENTRYPOINT |
--show-scripts |
-s |
Show the pre/post install scripts and exit |
--unpack [DIR] |
-u |
Extract .chubconfig and all wheel-related files |
--venv DIR |
Create a venv and install wheels into it | |
--version |
Show version info and exit | |
--verbose |
-v |
Extra logs wherever possible |
Notes:
--dry-run:- Prevents any changes from being made to the environment.
--exec:- Runs as an ephemeral venv installation that is wiped after execution.
- Runs in a strictly temporary venv.
- Implies a no-arg
--rununless explicitly provided. - State is not preserved between runs.
- Since no state is preserved, this option implies
--no-scripts(i.e.,--no-pre-scriptsand--no-post-scripts)
--help:- Shows help and exit.
--info:- Shows
.chubconfigmetadata. - When used with
--verbose:- shows pre/post install scripts (like with
--show-scripts). - includes
--versioninformation.
- shows pre/post install scripts (like with
- Shows
--list:- Lists bundled wheels and exit.
- Wheels are listed in the order they were added to the
.chubfile. - Included dependency wheels are shown under the dependent wheel:
included-wheel.whl: - dep1.whl - dep2.whl - depN.whl
--no-post-scripts:- Skips post-install scripts.
--no-pre-scripts:- Skips pre-install scripts.
--no-scripts:- Implies
--no-post-scriptsand--no-pre-scripts.
- Implies
-q,--quiet:- Overrides
--verbose. - Compatible with any other option, though results may vary.
- Overrides
--run [ENTRYPOINT]:- If provided,
ENTRYPOINToverrides the baked‑in default. - If omitted, it uses the baked‑in entrypoint (if present).
- If omitted and no baked‑in entrypoint exists, warns and exits with code 0.
ENTRYPOINTformat:module:functionconsole-script-name
- To pass arguments to the entrypoint, place them after
--so pychub does not interpret them. - Virtual environment option compatibility:
--exec(for ephemeral venv)--venv(for persistent venv)
- If provided,
--show-scripts:- Allows verification of arbitrary pre/post install script content.
--unpack [DIR]:- Wheels, scripts, includes, and the
.chubconfigare extracted. - Specify a directory as
DIRto extract to the specified directory. - If no directory is specified, the current working directory is used, and
a directory derived from the
.chubfile name is created.
- Wheels, scripts, includes, and the
--version:- Shows version information, regardless of verbosity, (then exits) for:
- current environment's Python interpreter
- pychub
- bundled wheels
- Shows version information, regardless of verbosity, (then exits) for:
--venv DIR:- Creates a virtual environment at path
DIRand installs wheels into it.
- Creates a virtual environment at path
--verbose:- Ignored if
--quietis used. - Compatible with any other option, though results may vary.
- Ignored if
Runtime Options Compatibility Matrix
This table is a helpful compatibility matrix for runtime options.
dry-run |
exec |
help |
info |
list |
no-post-scripts |
no-pre-scripts |
no-scripts |
quiet |
run |
show-scripts |
unpack |
venv |
version |
verbose |
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
dry-run |
— | Yes | No | No | No | Yes | Yes | Yes | Yes | Yes | No | Yes | Yes | No | Yes |
exec |
Yes | — | No | No | No | Yes | Yes | Yes | Yes | Yes | No | No | No | No | Yes |
help |
No | No | — | No | No | No | No | No | No | No | No | No | No | No | No |
info |
No | No | No | — | Yes | No | No | No | Yes | No | No | No | No | No | Yes |
list |
No | No | No | Yes | — | No | No | No | Yes | No | No | No | No | No | Yes |
no-post-scripts |
Yes | Yes | No | No | No | — | Yes | Yes | Yes | Yes | No | No | Yes | No | Yes |
no-pre-scripts |
Yes | Yes | No | No | No | Yes | — | Yes | Yes | Yes | No | No | Yes | No | Yes |
no-scripts |
Yes | Yes | No | No | No | Yes | Yes | — | Yes | Yes | No | No | Yes | No | Yes |
quiet |
Yes | Yes | No | Yes | Yes | Yes | Yes | Yes | — | Yes | No | Yes | Yes | Yes | Yes |
run |
Yes | Yes | No | No | No | Yes | Yes | Yes | Yes | — | No | No | Yes | No | Yes |
show-scripts |
No | No | No | No | No | No | No | No | No | No | — | No | No | No | No |
unpack |
Yes | No | No | No | No | No | No | No | Yes | No | No | — | No | No | Yes |
venv |
Yes | Yes | No | No | No | Yes | Yes | Yes | Yes | Yes | No | No | — | No | Yes |
version |
No | No | No | No | No | No | No | No | Yes | No | No | No | No | — | Yes |
verbose |
Yes | Yes | No | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | Yes | Yes | Yes | — |
Example Usage (runtime)
Unpacking and operating a .chub file has a significant number of CLI features
when compared to building a .chub file, but the usage should still be fairly
straightforward and intuitive. We think that it provides a lot of flexibility
without sacrificing ease of use. The list of examples, below, is fairly
comprehensive, although you can still come up with more combinations for your
own use cases.
-
Install everything to the current environment
python mypackage.chub -
Dry-run install (no changes)
python mypackage.chub --dry-run
-
Dry-run install with all pre- and post-scripts skipped
python mypackage.chub \ --dry-run \ --no-scripts
-
Install into a new virtual environment
python mypackage.chub --venv ./myenv
-
Create a venv and skip pre- and post-scripts
python mypackage.chub \ --venv ./myenv \ --no-scripts
-
Create a venv and run the baked-in entrypoint
python mypackage.chub \ --venv ./myenv \ --run
-
Create a venv and run a different entrypoint (module:function)
python mypackage.chub \ --venv ./myenv \ --run othermodule.cli:main
-
Create a venv and run a different entrypoint (console script)
python mypackage.chub \ --venv ./myenv \ --run other-cli
-
Dry-run venv creation and entrypoint run (plan only)
python mypackage.chub \ --dry-run \ --venv ./planned-env \ --run
-
Invoke the baked-in entrypoint with arguments
python mypackage.chub --run -- --mode train --limit 100
-
Run a different entrypoint (module:function) with arguments
python mypackage.chub \ --run othermodule.cli:main \ -- --mode train --limit 100
-
Run a different entrypoint (console script) with arguments
python mypackage.chub \ --run other-cli \ -- --mode train --limit 100
-
Execute the baked-in entrypoint via ephemeral install
python mypackage.chub --exec
-
Execute the baked-in entrypoint with arguments via ephemeral install
python mypackage.chub --exec -- --mode train --limit 100
-
Execute a custom entrypoint via ephemeral install
python mypackage.chub \ --exec \ --run othermodule.cli:main
-
Execute a custom entrypoint with arguments via ephemeral install
python mypackage.chub \ --exec \ --run othermodule.cli:main \ -- --mode train --limit 100
-
List bundled wheels (names)
python mypackage.chub --list
-
List bundled wheels quietly
python mypackage.chub \ --list \ --quiet
-
Unpack all contents to a directory
python mypackage.chub --unpack ./tmp
-
Dry-run unpack (see what would be extracted)
python mypackage.chub \ --dry-run \ --unpack ./tmp
-
Show chub info (metadata)
python mypackage.chub --info
-
Show chub info with extra details (scripts and versions)
python mypackage.chub \ --info \ --verbose
-
Show pre/post install scripts without running anything
python mypackage.chub --show-scripts
-
Install and run baked entrypoint with verbose logs
python mypackage.chub \ --run \ --verbose
-
Quiet install (minimal output)
python mypackage.chub --quiet
-
Show full version info and exit
python mypackage.chub --version
-
Help message
python mypackage.chub --help
Pre-install and Post-install Scripts
NOTE: Pre-install and post-install scripts pose a security risk!
Someone could include malicious actions when they include these scripts,
and if you run the .chub file with elevated privileges, they could cause
damage to your system. Either ensure that you completely trust the vendor
that provided the .chub file, or verify the script contents before you
execute/install the .chub file.
When pychub runs your pre- and post-install scripts, it does so as simply and predictably as possible. Pre-install scripts run first, in the order you list them. Post-install scripts run afterward, also in order. If any script fails (returns a non‑zero exit code), pychub immediately stops and reports which script has failed. Missing scripts won’t blow up the run. They’re skipped with a warning so that you don’t get stuck on a typo.
Scripts are launched via the system shell. On POSIX, we use /bin/sh to launch
the script. On Windows, it’s cmd.exe. If you’re on Linux or macOS, and your
file contains a shebang (like #!/usr/bin/env bash or #!/usr/bin/env python3),
that shebang will control which interpreter actually runs it. On Windows, .sh
files won’t magically work unless you’ve got a POSIX-like shell (e.g., Git Bash
or WSL2) on your PATH. If you want a pain-free cross‑platform story, prefer
.cmd/.bat/.ps1 on Windows and shell/Python scripts on POSIX, or just write
Python scripts and run them with python.
Please be aware that pychub behavior on Windows is untested. The recommended
approach for Windows users, at this time, is to use WSL2, or another POSIX-like
shell. If native Windows support is important to you, please file an issue, and
reach out to collaborate, if possible.
Finally, a word about runtime flags: --no-scripts disables both phases, and
--no-pre-scripts and --no-post-scripts let you skip just one side or the
other.
The .chubconfig Metadata File
The .chubconfig file is a YAML text file that contains metadata about the
bundled wheels. It is used by the runtime CLI to determine what to extract,
and how to handle certain operations. Note that the metadata contains a key
of main_wheel that indicates the main wheel.
Here is an example .chubconfig file:
---
name: my-app
version: 1.2.3
entrypoint: myapp.cli:main
scripts:
pre:
- install_cert.sh
post:
- cleanup.sh
includes:
- extra.cfg
- config.json::conf
wheels:
myapp-1.2.3-py3-none-any.whl:
- requests-2.31.0-py3-none-any.whl
- requests_toolbelt-0.9.1-py3-none-any.whl
mylib-0.4.2-py3-none-any.whl:
- somedep-3.2.1-py3-none-any.whl
- someotherdep-2.3.4-py3-none-any.whl
otherlib-1.26.4-py3-none-any.whl: []
metadata:
main_wheel: myapp-1.2.3-py3-none-any.whl
tags: [http, client]
maintainer: someone@example.com
Roadmap
| Status | Feature | Notes |
|---|---|---|
| In Progress | Support TOML for options | Read/Write TOML files for options. |
| Planned | Build tool support | Support integration with pyproject.toml. |
| Planned | Quick-start guide | Convenience for getting started quickly. |
| Planned | Handle dependency conflicts | Provide multiple-version/duplicate-wheel dependency strategies. |
| Exploring | c/native support | Explore facilitating c/native support (maybe with conda). |
| Exploring | Wheel extras support | Explore handling extras for wheels (w/Requires-Dist). |
| Exploring | Conda support | Evaluate creating/targeting conda environments. |
| Future | Digital signature support | Explore signing chub files for verification. |
License
The MIT License (MIT) Copyright © 2025 Steve Storck steve973@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pychub-1.0.0.tar.gz.
File metadata
- Download URL: pychub-1.0.0.tar.gz
- Upload date:
- Size: 45.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90661ae5dab38f536be3a324f2a016a34c8746bdae476f7b7ab45deb24877572
|
|
| MD5 |
e745690d965caf324adca3bea97f390b
|
|
| BLAKE2b-256 |
140d022b1ed9f231a250ff53e2745a4cf5d109c893271d36d4a359164f80912b
|
File details
Details for the file pychub-1.0.0-py3-none-any.whl.
File metadata
- Download URL: pychub-1.0.0-py3-none-any.whl
- Upload date:
- Size: 44.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da2204c07938c472bc9eccffd042c6d2334e0e1d982a672da3f5426b42890888
|
|
| MD5 |
76937d82415ff691f2b6f6f8c0e8ea19
|
|
| BLAKE2b-256 |
71c79c40a054ffe9f8160498ecb823c8a5ac95701ce78e52ab4d6ec0a917640b
|