Bystroushaak's blog / English section / Programming / Python / Installation of pip packages on offline computer

Installation of pip packages on offline computer

I had to install some software on old firewalled machine, running Centos 6 and python3.3. Machine was in a network, that allowed only ssh connection and nothing else.

Firewalled computer didn't even have pip, so I had to install it.

Setuptools and PIP

First, I installed setuptools. I had to manually download last working version of the setuptools supporting python3.3, which is 39.2.0. I've uploaded unpacked directory to the firewalled computer and run following commands:

[root@computer offline_pip_repo]# cd setuptools-39.2.0/
[root@computer setuptools-39.2.0]# ls
bootstrap.py  docs             CHANGES.rst  LICENSE      msvc-build-launcher.cmd  PKG-INFO       pytest.ini  setup.cfg  setuptools           tests                   tox.ini
conftest.py   easy_install.py  launcher.c   MANIFEST.in  pavement.py              pkg_resources  README.rst  setup.py   setuptools.egg-info  towncrier_template.rst
[root@computer setuptools-39.2.0]# python3 setup.py install
running install
running bdist_egg
...
... several hundred lines of text
...
Adding setuptools 39.2.0 to easy-install.pth file
Installing easy_install-3.3 script to /usr/bin
Installing easy_install script to /usr/bin

Installed /usr/lib/python3.3/site-packages/setuptools-39.2.0-py3.3.egg
Processing dependencies for setuptools==39.2.0
Finished processing dependencies for setuptools==39.2.0

Then I had to download pip that supports python3.3. Changelog told me that it was version 10.0.1. Again, I uploaded the unpacked archive to the firewalled computer and run manually python3 setup.py install:

[root@computer offline_pip_repo]# ls
setuptools-39.2.0  pip-10.0.1
[root@computer offline_pip_repo]# cd pip-10.0.1/
[root@computer pip-10.0.1]# ls
AUTHORS.txt  docs  LICENSE.txt  MANIFEST.in  NEWS.rst  PKG-INFO  pyproject.toml  README.rst  setup.cfg  setup.py  src
[root@computer pip-10.0.1]# python3 setup.py install
running install
running bdist_egg
running egg_info
...
... several thousand lines of text
...
Installing pip script to /usr/bin
Installing pip3.3 script to /usr/bin
Installing pip3 script to /usr/bin

Installed /usr/lib/python3.3/site-packages/pip-10.0.1-py3.3.egg
Processing dependencies for pip==10.0.1
Finished processing dependencies for pip==10.0.1

Then I've verified that pip was really installed correctly and it works:

[root@computer pip-10.0.1]# pip

Usage:   
  pip <command> [options]

Commands:
  install                     Install packages.
  download                    Download packages.
  uninstall                   Uninstall packages.
  freeze                      Output installed packages in requirements format.
  list                        List installed packages.
  show                        Show information about installed packages.
  check                       Verify installed packages have compatible dependencies.
  config                      Manage local and global configuration.
  search                      Search PyPI for packages.
  wheel                       Build wheels from your requirements.
  hash                        Compute hashes of package archives.
  completion                  A helper command used for command completion.
  help                        Show help for commands.

General Options:
  -h, --help                  Show help.
  --isolated                  Run pip in an isolated mode, ignoring environment variables and user configuration.
  -v, --verbose               Give more output. Option is additive, and can be used up to 3 times.
  -V, --version               Show version and exit.
  -q, --quiet                 Give less output. Option is additive, and can be used up to 3 times (corresponding to WARNING, ERROR, and CRITICAL logging levels).
  --log <path>                Path to a verbose appending log.
  --proxy <proxy>             Specify a proxy in the form [user:passwd@]proxy.server:port.
  --retries <retries>         Maximum number of retries each connection should attempt (default 5 times).
  --timeout <sec>             Set the socket timeout (default 15 seconds).
  --exists-action <action>    Default action when a path already exists: (s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort).
  --trusted-host <hostname>   Mark this host as trusted, even though it does not have valid or any HTTPS.
  --cert <path>               Path to alternate CA bundle.
  --client-cert <path>        Path to SSL client certificate, a single file containing the private key and the certificate in PEM format.
  --cache-dir <dir>           Store the cache data in <dir>.
  --no-cache-dir              Disable the cache.
  --disable-pip-version-check
                              Don't periodically check PyPI to determine whether a new version of pip is available for download. Implied with --no-index.
  --no-color                  Suppress colored output

Offline repository

I could install all dependencies by manually downloading packages and running setup.py, but I didn't want to spend so much time with it, so I've created offline repository with pip2pi.

pip2pi can be installed using pip on my computer:

$ pip install --user pip2pi

I've then told it to download package pytest and py in specific versions (last working versions with python3.3) into directory called repository:

$ pip2tgz repository pytest==3.2.0 py==1.4.33
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Collecting pytest==3.2.0
  Using cached pytest-3.2.0-py2.py3-none-any.whl (186 kB)
  Saved ./repository/pytest-3.2.0-py2.py3-none-any.whl
Collecting py==1.4.33
  Using cached py-1.4.33-py2.py3-none-any.whl (83 kB)
  Saved ./repository/py-1.4.33-py2.py3-none-any.whl
Collecting setuptools
  Using cached setuptools-45.2.0-py3-none-any.whl (584 kB)
  Saved ./repository/setuptools-45.2.0-py3-none-any.whl
Successfully downloaded pytest py setuptools

Done. 3 new archives currently saved in 'repository'.

I verified that requirements were downloaded:

$ tree repository/
repository/
├── pytest-3.2.0-py2.py3-none-any.whl
├── py-1.4.33-py2.py3-none-any.whl
└── setuptools-45.2.0-py3-none-any.whl

0 directories, 3 files

Then, it was necessary to create symlinks, so that whole repository could be used with pip:

$ dir2pi repository/

Here is what the structure looked after this command:

$ tree repository/
repository/
├── simple
│   ├── py
│   │   ├── index.html
│   │   └── py-1.4.33-py2.py3-none-any.whl -> ../../py-1.4.33-py2.py3-none-any.whl
│   ├── pytest
│   │   ├── index.html
│   │   └── pytest-3.2.0-py2.py3-none-any.whl -> ../../pytest-3.2.0-py2.py3-none-any.whl
│   ├── setuptools
│   │   ├── index.html
│   │   └── setuptools-45.2.0-py3-none-any.whl -> ../../setuptools-45.2.0-py3-none-any.whl
│   └── index.html
├── pytest-3.2.0-py2.py3-none-any.whl
├── py-1.4.33-py2.py3-none-any.whl
└── setuptools-45.2.0-py3-none-any.whl

4 directories, 10 files

Then I've copied repository directory via ssh to firewalled machine and run install from local repository directory:

[root@computer offline_pip_repo]# pip install --no-index --find-links=file:repository pytest
DEPRECATION: Python 3.3 supported has been deprecated and support for it will be dropped in the future. Please upgrade your Python.
Looking in links: file:repository
Collecting pytest
Collecting py>=1.4.33 (from pytest)
Requirement already satisfied: setuptools in /usr/lib/python3.3/site-packages (from pytest) (0.6rc11)
Installing collected packages: py, pytest
Successfully installed py-1.4.33 pytest-3.2.0

And thats it.

Edit

There is one special case; for most packages, this will download wheel format of the package. If you need to install the packages to system with older pip, which doesn't know wheels, you can use following command to download old .tar.gz format of packages:

pip2pi -s offline_pip_repo --no-binary=:all: <package_names>

Important parameter is --no-binary=:all:. The documentation says that it should be possible to use --no-use-wheel, but that doesn't work anymore with newer pip.

Become a Patron