Don't mix yum/dnf and pip for installation of system-wide Python packages
Posted on Fri 13 January 2017 in Python
Update (January 25, 2017): Updated instructions on preparing the Python virtual environment to work with setuptools 34+ on CentOS/RHEL 7. Also updated the Ansible playbook to skip seperately updating pip and setuptools upon creation of a new virtual environment on Fedora.
Too many times I've seen people using a mix of yum/ dnf and pip for installation of system-wide Python packages This causes all sorts of problems .
TL; DR Install system-wide Python packages with yum/dnf and only use pip inside a virtual environment. For an example, see my Ansible snippet below .
Note
I'll use CentOS 7 for the examples, but the concepts apply to all current Fedora and CentOS/RHEL distributions.
Problems with mixing yum/dnf and pip
People usually install the python2-pip
package to boot-strap installation of
pip on their systems:
sudo yum -y install epel-release
sudo yum -y install python2-pip
At the time of writing, this will install pip 8.1.2 on the system, while the
latest pip version is 9.0.1.
A user will soon notice that on each run of the pip
command the following
message is shown:
You are using pip version 8.1.2, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Naively, he will upgrade pip with:
sudo pip install --upgrade pip
which will replace the previous pip installation in system locations (e.g.
/usr/bin
, /usr/lib/python2.7/site-packages/pip
, ...) with the new pip
version.
The problem is that this will leave RPM with no clue as to
what is going on. If you run rpm --verify python2-pip
it will show that
everything is broken:
S.5....T. /usr/bin/pip
S.5....T. /usr/bin/pip2
S.5....T. /usr/bin/pip2.7
missing /usr/lib/python2.7/site-packages/pip-8.1.2-py2.7.egg-info
missing /usr/lib/python2.7/site-packages/pip-8.1.2-py2.7.egg-info/PKG-INFO
missing /usr/lib/python2.7/site-packages/pip-8.1.2-py2.7.egg-info/SOURCES.txt
missing /usr/lib/python2.7/site-packages/pip-8.1.2-py2.7.egg-info/dependency_links.txt
missing /usr/lib/python2.7/site-packages/pip-8.1.2-py2.7.egg-info/entry_points.txt
missing /usr/lib/python2.7/site-packages/pip-8.1.2-py2.7.egg-info/not-zip-safe
missing /usr/lib/python2.7/site-packages/pip-8.1.2-py2.7.egg-info/requires.txt
missing /usr/lib/python2.7/site-packages/pip-8.1.2-py2.7.egg-info/top_level.txt
S.5....T. /usr/lib/python2.7/site-packages/pip/__init__.py
S.5....T. /usr/lib/python2.7/site-packages/pip/__init__.pyc
missing /usr/lib/python2.7/site-packages/pip/__init__.pyo
.......T. /usr/lib/python2.7/site-packages/pip/__main__.py
S.5....T. /usr/lib/python2.7/site-packages/pip/__main__.pyc
missing /usr/lib/python2.7/site-packages/pip/__main__.pyo
[ ... output trimmed ... ]
S.5....T. /usr/lib/python2.7/site-packages/pip/vcs/subversion.py
S.5....T. /usr/lib/python2.7/site-packages/pip/vcs/subversion.pyc
missing /usr/lib/python2.7/site-packages/pip/vcs/subversion.pyo
S.5....T. /usr/lib/python2.7/site-packages/pip/wheel.py
S.5....T. /usr/lib/python2.7/site-packages/pip/wheel.pyc
missing /usr/lib/python2.7/site-packages/pip/wheel.pyo
Furthermore, when a new version of the python2-pip
becomes available, yum
upgrade will complain about not being able to find some files and directories.
For example, on upgrade from python-pip-7.1.0-1.el7
to
python2-pip-8.1.2-5.el7
when pip was upgraded with pip in-between, yum
upgrade gives the following warnings:
warning: file /usr/lib/python2.7/site-packages/pip/_vendor/_markerlib/markers.pyo: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip/_vendor/_markerlib/markers.pyc: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip/_vendor/_markerlib/markers.py: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip/_vendor/_markerlib/__init__.pyo: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip/_vendor/_markerlib/__init__.pyc: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip/_vendor/_markerlib/__init__.py: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip/_vendor/_markerlib: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg-info/top_level.txt: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg-info/requires.txt: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg-info/pbr.json: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg-info/not-zip-safe: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg-info/entry_points.txt: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg-info/dependency_links.txt: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg-info/SOURCES.txt: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg-info/PKG-INFO: remove failed: No such file or directory
warning: file /usr/lib/python2.7/site-packages/pip-7.1.0-py2.7.egg-info: remove failed: No such file or directory
Proper way to to use pip without mixing it with yum/dnf
The solution is to limit pip's use to installation of Python packages inside a Python virtual environment.
First install the python-virtualenv
package with yum/dnf:
sudo yum -y install python-virtualenv
Then use it to create and activate a new virtual environment:
virtualenv myvenv
source myvenv/bin/activate
Note
At the time of writing, CentOS/RHEL 7's system-installed virtualenv package is very old (1.10.1) and creates a virtual environment with very old pip (1.4.1) and setuptools (0.9.8) packages. Hence, it is recommended to update them separately, before installation of other things in the virtual environment.
Since setuptools version 34, setuptools package no longer bundles its requirements and relies on installing whell distributions of its requirements. To install these wheels, it needs a newer version pip, hence pip needs to be updated separately before setuptools:
pip install -U pip
pip install -U setuptools
A complete Ansible playbook for proper creation of a Python virtual environment is provided later.
Then install whichever Python package you want inside the Python virtual environment.
Tip: Don't install the system pip package
To avoid mistakenly using pip outside a virtual environment, don't install
the pip system package (e.g. python2-pip
).
This way, pip
executable will only be available after you activate the chosen
virtual environment, which limits mistakes with using the system-wide pip to
the minimum.
Ansible playbook for installation of packages inside a virtual environment
If you need to automate installation of python-virtualenv
system package and
creation of a Python virtual environment for installation of project's
requirements inside this virtual environment, you can use the following
Ansible playbook:
- name: Playbook for installation of packages inside a virtual environment
hosts: all
become: true
vars:
# adjust these variables to your project's needs
venv_path: /opt/myvenv/
requirements:
- requests
- simplejson
- six
tasks:
- name: Install python-virtualenv package
package: name=python-virtualenv state=installed
- block:
- name: Create virtual environment with up-to-date pip
pip:
virtualenv: "{{ venv_path }}"
name: pip
state: latest
- name: Update virtual environment's setuptools
pip:
virtualenv: "{{ venv_path }}"
name: setuptools
state: latest
when:
- ansible_distribution in ["CentOS", "RedHat"]
- ansible_distribution_major_version | int == 7
- name: Install project's requirements in virtual environement
pip:
virtualenv: "{{ venv_path }}"
name: "{{ requirements }}"
state: latest
Note
Due to a bug in Ansible's pip
module which causes
Ansible to use system-installed pip2
executable and ignore the pip
executable installed inside the virtual environment, you must use at least
version 2.2.1 RC3 which
fixes the bug.
Note
Fedora comes with virtualenv 14.0.1+ which automatically downloads new releases of pip, setuptools, wheel and their requirements from PyPI, therefore there is no need to update them separately before installing project's requirements in virtual environment.
If your project's requirements are not pure Python packages, but also include
packages with C/C++ extensions, they'll need to be built as
part of the installation process. Therefore, you'll need to have at least gcc
and python-devel
packages installed. You can use the following Ansible task
to achieve that:
- name: Install project's building prerequisites
package: name={{ item }} state=installed
with_items:
- gcc
- python-devel
# add other packages required to build your project's requirements
Put it before the Install project's requirements in virtual environement task.