Poetry: Offline installation of packages
All notes in this series:
- Poetry: Fixing dubious ownership error
- Poetry: build.py example
- Poetry: Automatically generate package version from git commit
- Poetry: Fix warning about sources
- Poetry: Running Black and isort with pre-commit hooks
- Poetry: Fixing permission error when upgrading dulwich
- NiceGUI with Click, Poetry, auto-reload and classes
- Poetry: Offline installation of packages
- Run Poetry command as systemd service
- GitLab CI and poetry-dynamic-versioning
- Poetry: install alpha builds
- Upgrade version of pkginfo used by Poetry
These notes are about how to perform an offline installation of a Python application using poetry install
, not about how to install Poetry itself offline.
Currently, Poetry does not support offline installation of packages. As a work-around, you can run a local PyPI server on your offline machine, then configure poetry install
to use the local PyPI server. First though, you need to gather all the packages your application needs. The following notes cover all these steps.
Perform offline package installation with Poetry §
The initial setup §
In my case, my Python application has a pyproject.toml
with both public and private dependencies. These are available via two Poetry sources: one is an internal mirror of the public PyPI (pypi_mirror
), and the other is an internal private PyPI repository (pypi_private
):
I have two computers: an online machine which has Internet access, and can reach both sources; and an offline machine, which is effectively air-gapped.
Download packages §
First, we need to download all the packages necessary for the Python application using the online machine.
Poetry does not provide a way to just download packages, but you can get the same effect by combining Poetry and Pip as follows1:
This will leave you with a packages
directory that includes all the packages, from both the public and private sources.
How this method works §
The --with-credentials
option is crucial for this method to work with the private PyPI server. This ensures that the requirements.txt
includes the credentials required for the pip download
command to fetch the private packages. The resulting requirements.txt
will look something like:
If you omit --with-credentials
, then the pip download
command will work until it hits a package in your private PyPI server (assuming it requires authentication), at which point it will error.
Install the local PyPI server §
On the offline machine, install pypiserver2. It is a single Python wheel with no dependencies, so it is easy to bootstrap if necessary. Copy across the pypiserver
wheel, then from the same directory run:
Run the local PyPI server §
Then copy across the packages
directory which was created earlier, and within that directory run:
This will start to serve up the packages at http://localhost:8080/simple/
. You can visit in your browser to confirm.
Modify your pyproject.toml
§
In order to use the local PyPI server on the offline machine, the pyproject.toml
sources need editing. Since we now have one PyPI server that provides both the public and private packages, we can change both sources to point at it3:
Perform the offline install §
Perform the offline install by running:
This will install your application on the offline machine, fetching all the packages from your local PyPI server.
That’s it! 🎉
A note on the warning §
When running poetry install
you will get the following warning:
In this case, it is safe to ignore the warning. It occurs because the poetry.lock
file contains a hash of the pyproject.toml
file which is updated when you run poetry lock
. We modified pyproject.toml
without running poetry lock
, so the hash has been broken, but the only change has been to point at our local PyPI server which is serving up the same packages.
Future work §
Read on if you’d like to contribute to a (potentially) better solution.
Buried within this very relevant Poetry issue is this nugget of a WIP PR4 which adds a poetry download
command. If this command works it would simplify the download steps listed above. Unfortunately it was never merged and has not been updated in two years. Regardless, I tried to give it a go. To install it into C:\poetry\poetry-dl-fork
(to avoid clobbering my main Poetry installation), I ran:
However, when I tried to run poetry download
I got this error:
I’ve not dug into it much, but I presume this error happened because poetry-core
has moved on a lot since this MR.
I attempted to rebase this branch against master
in case it was a trivial patch, but there were a lot of conflicts, and it looks like files have moved around a bit since the MR was made. It may be possible to resurrect this branch without too much work, though I’m not familiar enough with the Poetry source to know.
Backlinks §
- I’ve linked to this page from this GitHub comment.
Thanks to this answer, this answer and this answer which provided a good starting point, but were missing the
--with-credentials
required for private repositories. ↩︎Instead, the local PyPI server could be installed on a separate machine so long as the offline machine has network access to it, but then you will need to update the hostname/IP in the
pyproject.toml
file accordingly in the “Modify yourpyproject.toml
” section. ↩︎Ideally I’d like to find a way to do this without editing the
pyproject.toml
. This could be done by messing around with the hosts file, but that doesn’t seem ideal. ↩︎Thanks to nikolaikopernik for beginning to tackle this issue, even though ultimately it was not merged. ↩︎
All notes in this series:
- Poetry: Fixing dubious ownership error
- Poetry: build.py example
- Poetry: Automatically generate package version from git commit
- Poetry: Fix warning about sources
- Poetry: Running Black and isort with pre-commit hooks
- Poetry: Fixing permission error when upgrading dulwich
- NiceGUI with Click, Poetry, auto-reload and classes
- Poetry: Offline installation of packages
- Run Poetry command as systemd service
- GitLab CI and poetry-dynamic-versioning
- Poetry: install alpha builds
- Upgrade version of pkginfo used by Poetry