
## Overview
This tool runs a Python application using the UV binary. It extracts your application, optionally reads configuration from pycrucible.toml or pyproject.toml, and uses uv to execute it in an ephemeral environment.
## What does this mean?
You get a single self-contained binary that can be distributed across machines running the same platform. No Python installation is required - just an internet connection. Run the executable, and it takes care of the rest.
> [!NOTE]
> This readme is for version v0.3.x. A few important changes has been made, but mostly to the better use of tool.
>
> You can see all the changes in [CHANGELOG FILE](https://github.com/razorblade23/PyCrucible/blob/main/CHANGELOG.md).
## Documentation
Documentation can be found at [PyCrucible docs](https://pycrucible.razorblade23.dev).
## Documentation
Better documentation can be found at [docs](https://pycrucible.razorblade23.dev).
## How to get `PyCrucible`
There are a couple of ways to get PyCrucible.
### Using `PyPI`
PyCrucible is published to `PyPI` for every release. All you need to do is:
```bash
pip install pycrucible
```
### Using `Github Releases`
You can download pre-made binaries for your system from [Github Releases](https://github.com/razorblade23/PyCrucible/releases/latest) page
### Downloading and building from source code
1. Ensure you have [Rust](https://www.rust-lang.org/) installed.
2. Clone the repository
```git clone https://github.com/razorblade23/PyCrucible```
3. Change directory to be inside of a project
```cd PyCrucible```
4. Build Runner
```cargo build -p pycrucible_runner --release```
5. Build Pycrucible
```cargo build -p pycrucible --release```
> [!NOTE]
> The resulting binary will be in `target/release/pycrucible`.
## How to use `PyCrucible`
All you need for starting is a single `main.py` file with some code.
If you installed it using `pip` you can just run it with:
```bash
pycrucible -e .
```
This will embed your project and produce a new binary which is by default called `launcher` (or `launcher.exe` on Windows).
> [!TIP]
> To configure the output path and name of your binary, use `-o` or `--output` flag.
>
> Example: `pycrucible -e . -o ./myapp` (or `pycrucible -e . -o ./myapp.exe`)
This is now all you need to distribute your python project to other people.
No python required on their end. Just this single binary.
Running `pycrucible --help` reveals more options:
```bash
$ pycrucible --help
Tool to generate python executable by melding UV and python source code in crucible of one binary
Usage: pycrucible [OPTIONS]
Options:
-e, --embed <EMBED>
Directory containing Python project to embed. When specified, creates a new binary with the embedded project
-o, --output <OUTPUT>
Output path for the new binary when using --embed
--uv-path <UV_PATH>
Path to `uv` executable. If not found, it will be downloaded automatically [default: `.`]
--debug
Enable debug output
-h, --help
Print help
-V, --version
Print version
```
## How to configure `PyCrucible`
Configuration can be set in two files:
- `pycrucible.toml`
- `pyproject.toml`
> [!NOTE]
> When both `pycrucible.toml` and `pyproject.toml` are discovered, configuration from `pycrucible.toml` will take effect.
> [!IMPORTANT]
> When using any configuration, only `entrypoint` is required. Other options are optional.
> [!TIP]
> In both `pycrucible.toml` and `pyproject.toml` directive `entrypoint` can also be replaced by just `entry`.
Both of these files have exact same configuration options. You can find example file for `pycrucible.toml` [here](https://raw.githubusercontent.com/razorblade23/PyCrucible/refs/heads/main/pycrucible.toml.example)
In `pycrucible.toml` you would define configuration like this:
```toml
entrypoint = "src/main.py"
# or
entry = "src/main.py"
[options]
debug = false
extract_to_temp = false
delete_after_run = false
[package.patterns]
include = [
"**/*.py",
]
exclude = [
"**/__pycache__/**",
]
[env]
FOO = "foo"
BAR = "bar"
[hooks]
pre_run = "some_script.py"
post_run = "some_other_script.py"
```
In `pyproject.toml` you would define configuration like this:
```toml
[tool.pycrucible]
entrypoint = "src/main.py"
# or
entry = "src/main.py"
[tool.pycrucible.options]
debug = false
extract_to_temp = false
delete_after_run = false
offline_mode = false
[tool.pycrucible.patterns]
include = [
"**/*.py",
]
exclude = [
"**/__pycache__/**",
]
[tool.pycrucible.env]
FOO = "foo"
BAR = "bar"
[tool.pycrucible.hooks]
pre_run = "some_script.py"
post_run = "some_other_script.py"
```
### Update your project from GitHub
In configuration file its possible to set your GitHub repository, so the resulting binary will always check for update before running the application.
In `pycrucible.toml` it would look like this:
```toml
[source]
repository = "https://github.com/username/repo"
branch = "main"
update_strategy = "pull"
```
In `pyproject.toml` it would look like this-
```toml
[tool.pycrucible.source]
repository = "https://github.com/username/repo"
branch = "main"
update_strategy = "pull"
```
#### Default configuration
```python
entrypoint = "main.py"
# Options
debug = false
extract_to_temp = false
delete_after_run = false
# Patterns
patterns.include = [
"**/*.py",
]
patterns.exclude = [
".venv/**/*",
"**/__pycache__/**",
".git/**/*",
"**/*.pyc",
"**/*.pyo",
"**/*.pyd"
]
# Source repository (GitHub)
source = None
# Enviroment variables
env = None
# Pre and post run hooks
hooks = None
```
If any of these configuration options is not used, it will be replaced with default value.
#### NOTE - `entrypoint` directive is required when using any configuration options.
## Features
- **Cross-Platform**:
- [x] Windows support
- [x] macOS support (testing)
- [x] Linux support
- **Small overhead**:
- [x] Runner binary that embeds your project is **just 2 MB**. This ofcourse grows with embedding `uv` and your project.
- **Configurable**:
- [ ] Use `pycrucible.toml` or `pyproject.toml` to customize embedding details
- [x] entrypoint
- [x] include/exlude files
- [x] arguments to `uv`
- [x] env variables
- [x] update source code from github
- [x] pre and post run hooks (python scripts)
- [ ] offline mode
- [x] extract to temporary directory (removes temporary directory after running automaticly)
- [x] remove extracted files after running
- [x] Support for multiple ways of defining requirements
- [x] `uv` initialized `pyproject.toml` (This is preffered !)
- [x] `requirements.txt`
- [x] `pylock.toml`
- [x] `setup.py`
- [x] `setup.cfg`
- [x] Load the project as a directory
- **Tests**:
- [x] Unit tests covering as much as i can make it
## Thanks to
The idea is inspired by [Packaged](https://packaged.live/).
Thanks to all the briliant developers at `Astral`.
They did awesome job with [uv](https://astral.sh/blog/uv).
Raw data
{
"_id": null,
"home_page": null,
"name": "pycrucible",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": null,
"keywords": "install, python installer, install python, python packaging, python build tool, pycrucible, pyinstaller, py2exe, python wrapper, python cli tool",
"author": null,
"author_email": "razorblade23 <contact@razorblade23.dev>",
"download_url": null,
"platform": null,
"description": "\n\n## Overview\nThis tool runs a Python application using the UV binary. It extracts your application, optionally reads configuration from pycrucible.toml or pyproject.toml, and uses uv to execute it in an ephemeral environment.\n\n## What does this mean?\nYou get a single self-contained binary that can be distributed across machines running the same platform. No Python installation is required - just an internet connection. Run the executable, and it takes care of the rest.\n\n> [!NOTE]\n> This readme is for version v0.3.x. A few important changes has been made, but mostly to the better use of tool.\n>\n> You can see all the changes in [CHANGELOG FILE](https://github.com/razorblade23/PyCrucible/blob/main/CHANGELOG.md).\n\n## Documentation\nDocumentation can be found at [PyCrucible docs](https://pycrucible.razorblade23.dev).\n\n## Documentation\nBetter documentation can be found at [docs](https://pycrucible.razorblade23.dev).\n\n## How to get `PyCrucible`\nThere are a couple of ways to get PyCrucible.\n\n### Using `PyPI`\nPyCrucible is published to `PyPI` for every release. All you need to do is:\n```bash\npip install pycrucible\n```\n\n### Using `Github Releases`\nYou can download pre-made binaries for your system from [Github Releases](https://github.com/razorblade23/PyCrucible/releases/latest) page\n\n### Downloading and building from source code\n1. Ensure you have [Rust](https://www.rust-lang.org/) installed.\n\n2. Clone the repository\n```git clone https://github.com/razorblade23/PyCrucible```\n\n3. Change directory to be inside of a project\n```cd PyCrucible```\n\n4. Build Runner\n```cargo build -p pycrucible_runner --release```\n\n5. Build Pycrucible\n```cargo build -p pycrucible --release```\n\n> [!NOTE]\n> The resulting binary will be in `target/release/pycrucible`.\n\n## How to use `PyCrucible`\nAll you need for starting is a single `main.py` file with some code.\n\nIf you installed it using `pip` you can just run it with:\n```bash\npycrucible -e .\n```\n\nThis will embed your project and produce a new binary which is by default called `launcher` (or `launcher.exe` on Windows).\n> [!TIP]\n> To configure the output path and name of your binary, use `-o` or `--output` flag.\n>\n> Example: `pycrucible -e . -o ./myapp` (or `pycrucible -e . -o ./myapp.exe`)\n\nThis is now all you need to distribute your python project to other people.\n\nNo python required on their end. Just this single binary.\n\nRunning `pycrucible --help` reveals more options:\n```bash\n$ pycrucible --help\nTool to generate python executable by melding UV and python source code in crucible of one binary\n\nUsage: pycrucible [OPTIONS]\n\nOptions:\n -e, --embed <EMBED>\n Directory containing Python project to embed. When specified, creates a new binary with the embedded project\n -o, --output <OUTPUT>\n Output path for the new binary when using --embed\n --uv-path <UV_PATH>\n Path to `uv` executable. If not found, it will be downloaded automatically [default: `.`]\n --debug\n Enable debug output\n -h, --help\n Print help\n -V, --version\n Print version\n```\n\n\n## How to configure `PyCrucible`\nConfiguration can be set in two files:\n- `pycrucible.toml`\n- `pyproject.toml`\n\n> [!NOTE]\n> When both `pycrucible.toml` and `pyproject.toml` are discovered, configuration from `pycrucible.toml` will take effect.\n\n> [!IMPORTANT]\n> When using any configuration, only `entrypoint` is required. Other options are optional.\n\n> [!TIP]\n> In both `pycrucible.toml` and `pyproject.toml` directive `entrypoint` can also be replaced by just `entry`.\n\nBoth of these files have exact same configuration options. You can find example file for `pycrucible.toml` [here](https://raw.githubusercontent.com/razorblade23/PyCrucible/refs/heads/main/pycrucible.toml.example)\n\nIn `pycrucible.toml` you would define configuration like this:\n```toml\nentrypoint = \"src/main.py\"\n# or\nentry = \"src/main.py\"\n\n[options]\ndebug = false\nextract_to_temp = false\ndelete_after_run = false\n\n[package.patterns]\ninclude = [\n \"**/*.py\",\n]\nexclude = [\n \"**/__pycache__/**\",\n]\n\n[env]\nFOO = \"foo\"\nBAR = \"bar\"\n\n[hooks]\npre_run = \"some_script.py\"\npost_run = \"some_other_script.py\"\n```\n\nIn `pyproject.toml` you would define configuration like this:\n```toml\n[tool.pycrucible]\nentrypoint = \"src/main.py\"\n# or\nentry = \"src/main.py\"\n\n[tool.pycrucible.options]\ndebug = false\nextract_to_temp = false\ndelete_after_run = false\noffline_mode = false\n\n[tool.pycrucible.patterns]\ninclude = [\n \"**/*.py\",\n]\nexclude = [\n \"**/__pycache__/**\",\n]\n\n[tool.pycrucible.env]\nFOO = \"foo\"\nBAR = \"bar\"\n\n[tool.pycrucible.hooks]\npre_run = \"some_script.py\"\npost_run = \"some_other_script.py\"\n```\n\n### Update your project from GitHub\nIn configuration file its possible to set your GitHub repository, so the resulting binary will always check for update before running the application.\n\nIn `pycrucible.toml` it would look like this:\n```toml\n[source]\nrepository = \"https://github.com/username/repo\"\nbranch = \"main\"\nupdate_strategy = \"pull\"\n```\n\n\nIn `pyproject.toml` it would look like this-\n```toml\n[tool.pycrucible.source]\nrepository = \"https://github.com/username/repo\"\nbranch = \"main\"\nupdate_strategy = \"pull\"\n```\n\n#### Default configuration\n```python\nentrypoint = \"main.py\"\n\n# Options\ndebug = false\nextract_to_temp = false\ndelete_after_run = false\n\n# Patterns\npatterns.include = [\n \"**/*.py\",\n]\npatterns.exclude = [\n \".venv/**/*\",\n \"**/__pycache__/**\",\n \".git/**/*\",\n \"**/*.pyc\",\n \"**/*.pyo\",\n \"**/*.pyd\"\n]\n\n# Source repository (GitHub)\nsource = None\n\n# Enviroment variables\nenv = None\n\n# Pre and post run hooks\nhooks = None\n```\nIf any of these configuration options is not used, it will be replaced with default value.\n#### NOTE - `entrypoint` directive is required when using any configuration options.\n\n## Features\n- **Cross-Platform**: \n - [x] Windows support\n - [x] macOS support (testing)\n - [x] Linux support\n- **Small overhead**:\n - [x] Runner binary that embeds your project is **just 2 MB**. This ofcourse grows with embedding `uv` and your project.\n- **Configurable**: \n - [ ] Use `pycrucible.toml` or `pyproject.toml` to customize embedding details\n - [x] entrypoint\n - [x] include/exlude files\n - [x] arguments to `uv`\n - [x] env variables\n - [x] update source code from github\n - [x] pre and post run hooks (python scripts)\n - [ ] offline mode\n - [x] extract to temporary directory (removes temporary directory after running automaticly)\n - [x] remove extracted files after running\n - [x] Support for multiple ways of defining requirements\n - [x] `uv` initialized `pyproject.toml` (This is preffered !)\n - [x] `requirements.txt`\n - [x] `pylock.toml`\n - [x] `setup.py`\n - [x] `setup.cfg`\n - [x] Load the project as a directory\n- **Tests**:\n - [x] Unit tests covering as much as i can make it\n\n## Thanks to\nThe idea is inspired by [Packaged](https://packaged.live/).\n\nThanks to all the briliant developers at `Astral`.\nThey did awesome job with [uv](https://astral.sh/blog/uv).\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python wrapper for the PyCrucible CLI tool",
"version": "0.3.0",
"project_urls": {
"Homepage": "https://github.com/razorblade23/PyCrucible",
"Issues": "https://github.com/razorblade23/PyCrucible/issues",
"Repository": "https://github.com/razorblade23/PyCrucible.git"
},
"split_keywords": [
"install",
" python installer",
" install python",
" python packaging",
" python build tool",
" pycrucible",
" pyinstaller",
" py2exe",
" python wrapper",
" python cli tool"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "1d6582b6a3e3d892ee821df3d5f252714589e61acdbfd21f16c76e4a88e6bedb",
"md5": "26605fee402a79bf302becbbe17cbf62",
"sha256": "31ebe993145bff3f4d99db4542a1546f90b4f3579793321b7ab936c6a62078e4"
},
"downloads": -1,
"filename": "pycrucible-0.3.0-py3-none-macosx_10_12_x86_64.whl",
"has_sig": false,
"md5_digest": "26605fee402a79bf302becbbe17cbf62",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 2416443,
"upload_time": "2025-07-26T07:32:42",
"upload_time_iso_8601": "2025-07-26T07:32:42.536949Z",
"url": "https://files.pythonhosted.org/packages/1d/65/82b6a3e3d892ee821df3d5f252714589e61acdbfd21f16c76e4a88e6bedb/pycrucible-0.3.0-py3-none-macosx_10_12_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "ae3a2b019100acce54149a2fa296de91930dd9e6af3c373f9cecc3555fb5a812",
"md5": "0bb7ca3728534e224ac9a2b3a5eefb2a",
"sha256": "14c4ddd1df7872af55e50bb1411c0323f6f4d61600f118378723a5e1adabaa1e"
},
"downloads": -1,
"filename": "pycrucible-0.3.0-py3-none-manylinux_2_39_x86_64.whl",
"has_sig": false,
"md5_digest": "0bb7ca3728534e224ac9a2b3a5eefb2a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 2706557,
"upload_time": "2025-07-26T07:32:44",
"upload_time_iso_8601": "2025-07-26T07:32:44.768178Z",
"url": "https://files.pythonhosted.org/packages/ae/3a/2b019100acce54149a2fa296de91930dd9e6af3c373f9cecc3555fb5a812/pycrucible-0.3.0-py3-none-manylinux_2_39_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "f711b567431241933968076126590df1f9458b9ae751d011bf7746b209965a58",
"md5": "921e045a0ac049512aac12420a5a3134",
"sha256": "700830b0619e34482e7179e905fc92ec22af92ea97ee5d438cc276705f4bfc35"
},
"downloads": -1,
"filename": "pycrucible-0.3.0-py3-none-win_amd64.whl",
"has_sig": false,
"md5_digest": "921e045a0ac049512aac12420a5a3134",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 2596143,
"upload_time": "2025-07-26T07:32:46",
"upload_time_iso_8601": "2025-07-26T07:32:46.346780Z",
"url": "https://files.pythonhosted.org/packages/f7/11/b567431241933968076126590df1f9458b9ae751d011bf7746b209965a58/pycrucible-0.3.0-py3-none-win_amd64.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-26 07:32:42",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "razorblade23",
"github_project": "PyCrucible",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "pycrucible"
}