| Name | wheel-getter JSON |
| Version |
0.4.4
JSON |
| download |
| home_page | None |
| Summary | Get or build wheels for isolated installation of a Python package |
| upload_time | 2025-09-10 11:19:34 |
| maintainer | None |
| docs_url | None |
| author | Detlef Lannert |
| requires_python | >=3.12 |
| license | None |
| keywords |
wheel
installation
package
uv
|
| VCS |
 |
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
No coveralls.
|
# wheel-getter
## What's the problem?
I want to install (locally authored) Python packages on servers that (for
security and other reasons) can't retrieve packages from PyPI or that (for
security reasons) don't have compilers and other development tools
installed. And I want to be sure that the same packages are installed as in
my development or staging environment, identified by a hash checksum.
My workflows are based on uv, which is fast and has other advantages in
comparison to pip, pip-tools and other “legacy” tools. Unfortunately uv
doesn't (yet?) offer an export of wheels (like `pip wheel`) that were
downloaded or locally built. AFAICT uv doesn't even cache downloaded wheel
but just their contents (which makes copying / hardlinking them into venv's
faster).
## How can wheel-getter help?
This tool reads uv's lockfile and downloads the same wheels that uv has used
for the current project. The lockfile contains checksums for these wheels;
they are checked against the downloaded files.
For locally built wheels the lockfile has “sdist” information with URLs and
checksums for the source archives. The wheel-getter tool retrieves these
archives, invokes `uv build` and grabs the resulting wheels.
For these freshly made wheels some metadata is added to the wheel directory,
containing file size and checksum so that the wheels can be verified.
## Can wheel-getter guarantee workflow security?
No. Use it at your own risk.
## How can I install this tool?
The easiest way is `uv tool install wheel-getter`; there are plenty of
alternatives, of course.
## How should I use wheel-getter?
It is recommended to cd into the base directory of your project where your
`pyproject.toml` file lives, after having locked and synced (and tested) the
project. Then invoke wheel-getter, specifying the Python version unless it's
the one that executes wheel-getter itself:
```
wheel-getter --python=3.11
```
If all is well, all required wheels should be collected in the `wheels`
subdirectory (or the output directory specified by `--wheelhouse`).
Please note that no wheels are built for packages installed as editable; you
should build them as usual and copy them to the “wheelhouse” yourself.
Since this tool has only been tested and used under Linux, there can (and
will) be problems with other OSes.
## Example
Let's assume you have a development installation of a Python project with
a `pyproject.toml` file, managed with uv.
### Step 1: Preparation
Build a wheel from your project: `uv build` (after having incremented the
version number, e.g. with `uv version --bump minor` or the like).
### Step 2: Collect wheels
Invoke wheel-getter; check the contents of the `wheels` directory.
### Step 3: Create temporary staging installation
Create a directory for a temporary staging installation. It should be
outside your development tree (so that neither uv nor git will regard it as
belonging to the project) but on the same filesystem (so that uv can create
hardlinks ad lib). Copy or, better, symlink the `wheels` directory and
initialize a bare Python project like this:
```
cd staging_base
ln -s ~/projects/my_proj/wheels .
uv init --bare stage313
cd stage313
uv python pin 3.13
uv add --no-index --find-links ../wheels my-proj
```
You should now have a uv lockfile referencing your project and all packages
it depends on as installed from `../wheels`, and if all was well, the
project dependencies were satisfied from this “wheelhouse”.
The pinned Python version should be the same that wheel-getter was running
for in the previous step. Otherwise it would not match version-dependent
wheels.
### Step 4: Deployment on the target host
We will assume that the target host runs the same (or a sufficiently
compatible) OS, has a working uv installation and allows key-based SSH
access from your local user. The following steps could as well be performed
by tools like ansible, pyinfra or whatever you prefer.
```
ssh target "mkdir -p /home/myuser/myproj/wheels /home/myuser/myproj/run"
rsync -avxc --exclude .venv ./ target:/home/myuser/myproj/run/
rsync -avxc ../wheels/ target:/home/myuser/myproj/wheels/
ssh target "cd /home/myuser/myproj/run && uv sync --no-index -f ../wheels"
```
If everything was fine, ssh into the target host and verify that your new
installation works as intended, for instance executing a project script or a
Django management command:
```
ssh target "cd /home/myuser/myproj/run && uv run my-proj --help"
```
### Steps 5 and onwards: Repeat for updates
For updates with new versions of your project and/or its dependencies, you
can repeat this process. In order to save time and bandwidth you can recycle
the wheels directories on the local and on the target host; wheel-getter
won't download the same wheels again if they are already present and have
the correct checksum. When rsyncing the wheels to the target host you might
want to add the `--delete` option unless you plan to create another
installation with previously used wheels. Running installations won't need
the wheels in the “wheelhouse” any more.
## If you find a bug or want to improve this tool …
… you are welcome to write a bug report or, preferably, supply a PR. Please
be aware, though, that I may be slow (but willing) to respond; my primary
concern is that this tool works for me, and I probably haven't run into lots
of edge and corner cases.
Raw data
{
"_id": null,
"home_page": null,
"name": "wheel-getter",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": null,
"keywords": "wheel, installation, package, uv",
"author": "Detlef Lannert",
"author_email": "Detlef Lannert <detlef@lannert.de>",
"download_url": "https://files.pythonhosted.org/packages/f0/22/8c607a6851d5dcaf74d5b23d181e366282b66528acf6829f6176af7aaea3/wheel_getter-0.4.4.tar.gz",
"platform": null,
"description": "# wheel-getter\n\n## What's the problem?\n\nI want to install (locally authored) Python packages on servers that (for\nsecurity and other reasons) can't retrieve packages from PyPI or that (for\nsecurity reasons) don't have compilers and other development tools\ninstalled. And I want to be sure that the same packages are installed as in\nmy development or staging environment, identified by a hash checksum.\n\nMy workflows are based on uv, which is fast and has other advantages in\ncomparison to pip, pip-tools and other \u201clegacy\u201d tools. Unfortunately uv\ndoesn't (yet?) offer an export of wheels (like `pip wheel`) that were\ndownloaded or locally built. AFAICT uv doesn't even cache downloaded wheel\nbut just their contents (which makes copying / hardlinking them into venv's\nfaster).\n\n## How can wheel-getter help?\n\nThis tool reads uv's lockfile and downloads the same wheels that uv has used\nfor the current project. The lockfile contains checksums for these wheels;\nthey are checked against the downloaded files.\n\nFor locally built wheels the lockfile has \u201csdist\u201d information with URLs and\nchecksums for the source archives. The wheel-getter tool retrieves these\narchives, invokes `uv build` and grabs the resulting wheels.\n\nFor these freshly made wheels some metadata is added to the wheel directory,\ncontaining file size and checksum so that the wheels can be verified.\n\n## Can wheel-getter guarantee workflow security?\n\nNo. Use it at your own risk.\n\n## How can I install this tool?\n\nThe easiest way is `uv tool install wheel-getter`; there are plenty of\nalternatives, of course.\n\n## How should I use wheel-getter?\n\nIt is recommended to cd into the base directory of your project where your\n`pyproject.toml` file lives, after having locked and synced (and tested) the\nproject. Then invoke wheel-getter, specifying the Python version unless it's\nthe one that executes wheel-getter itself:\n\n```\nwheel-getter --python=3.11\n```\n\nIf all is well, all required wheels should be collected in the `wheels`\nsubdirectory (or the output directory specified by `--wheelhouse`).\n\nPlease note that no wheels are built for packages installed as editable; you\nshould build them as usual and copy them to the \u201cwheelhouse\u201d yourself.\n\nSince this tool has only been tested and used under Linux, there can (and\nwill) be problems with other OSes.\n\n## Example\n\nLet's assume you have a development installation of a Python project with\na `pyproject.toml` file, managed with uv.\n\n### Step 1: Preparation\n\nBuild a wheel from your project: `uv build` (after having incremented the\nversion number, e.g. with `uv version --bump minor` or the like).\n\n### Step 2: Collect wheels\n\nInvoke wheel-getter; check the contents of the `wheels` directory.\n\n### Step 3: Create temporary staging installation\n\nCreate a directory for a temporary staging installation. It should be\noutside your development tree (so that neither uv nor git will regard it as\nbelonging to the project) but on the same filesystem (so that uv can create\nhardlinks ad lib). Copy or, better, symlink the `wheels` directory and\ninitialize a bare Python project like this:\n\n```\ncd staging_base\nln -s ~/projects/my_proj/wheels .\nuv init --bare stage313\ncd stage313\nuv python pin 3.13\nuv add --no-index --find-links ../wheels my-proj\n```\n\nYou should now have a uv lockfile referencing your project and all packages\nit depends on as installed from `../wheels`, and if all was well, the\nproject dependencies were satisfied from this \u201cwheelhouse\u201d.\n\nThe pinned Python version should be the same that wheel-getter was running\nfor in the previous step. Otherwise it would not match version-dependent\nwheels.\n\n### Step 4: Deployment on the target host\n\nWe will assume that the target host runs the same (or a sufficiently\ncompatible) OS, has a working uv installation and allows key-based SSH\naccess from your local user. The following steps could as well be performed\nby tools like ansible, pyinfra or whatever you prefer.\n\n```\nssh target \"mkdir -p /home/myuser/myproj/wheels /home/myuser/myproj/run\"\nrsync -avxc --exclude .venv ./ target:/home/myuser/myproj/run/\nrsync -avxc ../wheels/ target:/home/myuser/myproj/wheels/\nssh target \"cd /home/myuser/myproj/run && uv sync --no-index -f ../wheels\"\n```\n\nIf everything was fine, ssh into the target host and verify that your new\ninstallation works as intended, for instance executing a project script or a\nDjango management command:\n\n```\nssh target \"cd /home/myuser/myproj/run && uv run my-proj --help\"\n```\n\n### Steps 5 and onwards: Repeat for updates\n\nFor updates with new versions of your project and/or its dependencies, you\ncan repeat this process. In order to save time and bandwidth you can recycle\nthe wheels directories on the local and on the target host; wheel-getter\nwon't download the same wheels again if they are already present and have\nthe correct checksum. When rsyncing the wheels to the target host you might\nwant to add the `--delete` option unless you plan to create another\ninstallation with previously used wheels. Running installations won't need\nthe wheels in the \u201cwheelhouse\u201d any more.\n\n## If you find a bug or want to improve this tool \u2026\n\n\u2026 you are welcome to write a bug report or, preferably, supply a PR. Please\nbe aware, though, that I may be slow (but willing) to respond; my primary\nconcern is that this tool works for me, and I probably haven't run into lots\nof edge and corner cases.\n",
"bugtrack_url": null,
"license": null,
"summary": "Get or build wheels for isolated installation of a Python package",
"version": "0.4.4",
"project_urls": {
"Changelog": "https://github.com/detlefla/wheel-getter/blob/master/CHANGELOG.md",
"Homepage": "https://github.com/detlefla/wheel-getter",
"Issues": "https://github.com/detlefla/wheel-getter/issues",
"Repository": "https://github.com/detlefla/wheel-getter.git"
},
"split_keywords": [
"wheel",
" installation",
" package",
" uv"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "7fa2393bbb76a78f27956fb07b3a12a07cd13b4a0eb91ca5a24a53e0844f6977",
"md5": "fe81ec6def0d8304b151edb83f511f64",
"sha256": "9b77daa8725a28819ba89f4419506d6396d697275c47ffa2b0512c4fee5bebb5"
},
"downloads": -1,
"filename": "wheel_getter-0.4.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "fe81ec6def0d8304b151edb83f511f64",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 22831,
"upload_time": "2025-09-10T11:19:32",
"upload_time_iso_8601": "2025-09-10T11:19:32.911741Z",
"url": "https://files.pythonhosted.org/packages/7f/a2/393bbb76a78f27956fb07b3a12a07cd13b4a0eb91ca5a24a53e0844f6977/wheel_getter-0.4.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "f0228c607a6851d5dcaf74d5b23d181e366282b66528acf6829f6176af7aaea3",
"md5": "cc0265c9adf02fbeb996c8cb1ee8593c",
"sha256": "8de81db2c1e68138ed9429eb351159dfe3b306587335596a28fa6d58407708cb"
},
"downloads": -1,
"filename": "wheel_getter-0.4.4.tar.gz",
"has_sig": false,
"md5_digest": "cc0265c9adf02fbeb996c8cb1ee8593c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 22758,
"upload_time": "2025-09-10T11:19:34",
"upload_time_iso_8601": "2025-09-10T11:19:34.034835Z",
"url": "https://files.pythonhosted.org/packages/f0/22/8c607a6851d5dcaf74d5b23d181e366282b66528acf6829f6176af7aaea3/wheel_getter-0.4.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-10 11:19:34",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "detlefla",
"github_project": "wheel-getter",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "wheel-getter"
}