Advanced python CoP

Table of contents:

  • Managing multiple python versions
  • pip common issues
  • virtualenv and its many wrappers
In [94]:
%%HTML
<blockquote class="reddit-card" data-card-created="1582892002"><a href="https://www.reddit.com/r/ProgrammerHumor/comments/at77za/new_python_projects/">New Python projects</a> from <a href="http://www.reddit.com/r/ProgrammerHumor">r/ProgrammerHumor</a></blockquote>
<script async src="//embed.redditmedia.com/widgets/platform.js" charset="UTF-8"></script>

Multiple python versions on ubuntu

Up to ubuntu 19, ubuntu comes with 2 versions of python python2.x and python3.x. For ubuntu 18.04 it's python2.7 and python3.6.

In [11]:
! python2 --version
Python 2.7.17
In [22]:
! python3 --version
Python 3.6.9

python3 / python2 are just symlinks to the default python2.x and python 3.x versions

In [23]:
! ls -l $(which python3)
lrwxrwxrwx 1 root root 9 gru  3 11:20 /usr/bin/python3 -> python3.6

How to install some other version?

In [42]:
! python3.9 --version
Python 3.9.0a4

If the version is not there, you still can build python binary from sources.

In [43]:
# git clone https://github.com/python/cpython.git
# git checkout v1.0.1
# ./configure && make && ./python --version

Never remove python from debian-based distros

$ grep -rni /usr/bin/python3 /usr/ --exclude="*.py"
sbin/aptd:1:#! /usr/bin/python3
bin/keyring:1:#!/usr/bin/python3
bin/gnome-terminal:1:#!/usr/bin/python3
...

Some cli tools installed with pip create an entry script. So, which python version does my python tool use?

In [2]:
! black --version
black, version 19.10b0
In [4]:
! which black
/home/gjklv8/.local/bin/black
In [37]:
! head -n1 $(which black)
#!/usr/bin/python3.8

Run the tool with different python version

In [38]:
! python3.6 -m black --version
black.py, version 19.10b0

Of course i had installed black for python3.6, but not for python3.7:

In [41]:
! python3.7 -m black --version
/usr/bin/python3.7: No module named black

So how do you install pip package for a specific python version?

But first, install pip. The official way: https://pip.pypa.io/en/stable/installing/

System wide:

In [50]:
# sudo python3.6 get-pip.py
In [53]:
! which pip3.6
/usr/local/bin/pip3.6

Just for the current user:

In [ ]:
# python3.8 get-pip.py --user
In [52]:
! which pip3.8
/home/gjklv8/.local/bin/pip3.8

/home/gjklv8/.local/bin needs to be added to $PATH for this to work. Same goes for all scripts installed with pip install --user

get-pip script will create a pipX script depending on the X python version used to run get-pip.py

You can also use linux package manager to install pip

In [55]:
# sudo apt install python3-pip

But this option has some issues:

  • you can't choose python version other than python2 and python3
  • you get old pip version
  • pip will tell you that "you should upgrade with pip install -U pip" which will break pip :D https://github.com/pypa/pip/issues/5599

Pip is just a python module, so you can always use -m

In [57]:
# python3.7 -m pip install black --user

I have 2 scripts / projects. Both use the same python version, both use the same python module, but the first one works only with 1.1 version and the second only with 1.2.

Virtualenv - separate python environment for each project

virtualenv vs venv

In [95]:
%%HTML
<blockquote class="reddit-card" data-card-created="1582892091"><a href="https://www.reddit.com/r/ProgrammerHumor/comments/91vtas/python_27/">Python 2.7</a> from <a href="http://www.reddit.com/r/ProgrammerHumor">r/ProgrammerHumor</a></blockquote>
<script async src="//embed.redditmedia.com/widgets/platform.js" charset="UTF-8"></script>

Virtualenv is a community maintained package, which was added to python standard library in python 3.3. Virtualenv is actually quite popular, because it has some extra features and works for both python2 and python3.

In [58]:
! python3.8 -m venv venv_dir
The virtual environment was not created successfully because ensurepip is not
available.  On Debian/Ubuntu systems, you need to install the python3-venv
package using the following command.

    apt-get install python3-venv

You may need to use sudo with that command.  After installing the python3-venv
package, recreate your virtual environment.

Failing command: ['/home/gjklv8/repos/advanced-python-course/venv_dir/bin/python3.8', '-Im', 'ensurepip', '--upgrade', '--default-pip']

The apt package python3.8 by default doesn't include venv :(

In [59]:
# sudo apt install python3.8-venv
In [87]:
! python3.8 -m venv venv_dir
In [73]:
! tree -L 4 venv_dir/
venv_dir/
├── bin
│   ├── activate
│   ├── activate.csh
│   ├── activate.fish
│   ├── Activate.ps1
│   ├── easy_install
│   ├── easy_install-3.8
│   ├── pip
│   ├── pip3
│   ├── pip3.8
│   ├── python -> python3.8
│   ├── python3 -> python3.8
│   └── python3.8 -> /usr/bin/python3.8
├── include
├── lib
│   └── python3.8
│       └── site-packages
│           ├── easy_install.py
│           ├── pip
│           ├── pip-19.2.3.dist-info
│           ├── pkg_resources
│           ├── __pycache__
│           ├── setuptools
│           └── setuptools-41.2.0.dist-info
├── lib64 -> lib
└── pyvenv.cfg

12 directories, 14 files

Activate the virtual enviroment with venv_dir/bin/activate. deactivate will be available in PATH to exit venv. And that's it. (can't do that in ipython)

In [83]:
# source ./venv_dir/bin/activate
# pip install pyjokes
# python -c "import pyjokes; print(pyjokes.get_joke())"
# "An SQL query goes into a bar, walks up to two tables and asks, 'Can I join you?'"
In [78]:
# deactivate
In [85]:
# python -c "import pyjokes; print(pyjokes.get_joke())"
# Traceback (most recent call last):
#  File "<string>", line 1, in <module>
# ImportError: No module named pyjokes
In [81]:
! tree -L 4 venv_dir/
venv_dir/
├── bin
│   ├── activate
│   ├── activate.csh
│   ├── activate.fish
│   ├── Activate.ps1
│   ├── easy_install
│   ├── easy_install-3.8
│   ├── pip
│   ├── pip3
│   ├── pip3.8
│   ├── pyjoke
│   ├── pyjokes
│   ├── python -> python3.8
│   ├── python3 -> python3.8
│   └── python3.8 -> /usr/bin/python3.8
├── include
├── lib
│   └── python3.8
│       └── site-packages
│           ├── easy_install.py
│           ├── pip
│           ├── pip-19.2.3.dist-info
│           ├── pkg_resources
│           ├── __pycache__
│           ├── pyjokes
│           ├── pyjokes-0.6.0.dist-info
│           ├── pyjokescli
│           ├── setuptools
│           └── setuptools-41.2.0.dist-info
├── lib64 -> lib
└── pyvenv.cfg

15 directories, 16 files
In [92]:
%%HTML
<a href="https://imgflip.com/i/3qokvk"><img src="https://i.imgflip.com/3qokvk.jpg" title="made at imgflip.com"/></a>

Python looks for site-packages relative to its path. Activate just inserts venv directory to PATH and prepares deactivete command.

Pycharm does the same thing when you create new project with new virtualenv interpreter.

That's actually all you need to know about virtual environments, but there's also a lot of wrappers that provide additional functionality:

  • combining python version management with venv
  • listing all created venvs
  • activating venv by name
  • pythonversion + venv + external dependencies