Introduction

Managing multiple Python projects into different Python versions is not an easy task. This is where your current project will either make or break due to unsatisfy project requirements.

What is pyenv?

pyenv is a Python version management tool. pyenv were build from source which means it doesn’t depend on Python that installed by default into your current operating system. It enables you to install multiple Python versions and allows swithing between version that you had installed.

Here is the official page for pyenv

Why pyenv?

pyenv let’s you install multiple Python versions and switching between version easily either for global or local. This will helps you to manage multiple versions without the need to uninstall other version, mess up or conflict with your current system setup. Which means that you can have multiple projects and each project can have different versions installed.

Projects Directory structure

Let’s get started!

In this tutorial, there are 5 different projects that has some Python versions requirements.

  • Project A – Python 3.9.13
  • Project B – Python 2.4.5
  • Project C – Python 2.7.15 and Python 3.9.13
  • Project D – Python 2.7.15 and Python 3.9.13
  • Project E – Python 3.5.10 and 3.12-dev

To have better view on this it is wisely to put it into tabular data and populate it into a table below named as Python Version Project Management

Python Version Python 2.4.5 Python 2.7.15 Python 3.5.10 Python 3.9.13 3.12-dev
Project A No No No Yes No
Project B Yes No No No No
Project C No Yes No Yes No
Project D No Yes No Yes No
Project E No No Yes No Yes

Python Version Project Management table

As we look at above Python Version Project Management

  • There are five different versions which is
    • Python 2.4.5
    • Python 2.7.15
    • Python 3.5.10
    • Python 3.9.13
    • Python 3.12-dev
  • Few projects share the same Python version except Python 2.4.5,Python 3.5.10 and Python 3.12-dev
    • Python 2.7.15 – share with Project C and Project D
    • Python 3.9.13 – share with Project A, Project C and Project D

Now, lets create our projects:

    main
    ├── project_a
    ├── project_b
    ├── project_c
    ├── project_d
    └── project_e

Here we talk about the details:

  • We create a main folder as index folder that consists five different projects. We call our main directory as root folder/directory
  • Inside our root directory has five projects consisting of project_a, project_b , project_c, project_d and project_e.
A guide using command on how to create directory main and all subfolders project_a, project_b and project_c. However you can skip this part of tutorial if you don’t need to.

“`
$ mkdir main && cd main & mkdir project_a project_b project_c project_d project_e
“`

This will bring you into main directory/folder. Also it’s called as root folder. If you browse through we created three different projects names project_a, project_b and project_c

We have all together five different versions that need to be installed in our pyenv.

  • Python 2.4.5
  • Python 2.7.15
  • Python 3.5.10
  • Python 3.9.13
  • Python 3.12-dev

pyenv installation

Before we proceed to install pyenv lets check it out our pre-installed Python packages version available into our system. As my Linux machine is Debian that came with pre-installed Python packages.

In the system got both versions Python2 and Python3. If I run both at my terminal this will display as below.

$ python -V

This the output shows for Python2 the legacy version

Python 2.7.16

while check for python3

$ python3 -V

This is the output for Python3

Python 3.7.3

We need to install pip before we proceed to install pyenv. Mine I had pip3 installed.

To proceed with pyenv installation we need to get it’s dependencies

sudo apt install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev \
libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl \
git

After that, clone it from github

$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv

Once done with cloning, add this commands to your .bashrc via terminal

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc)

Now, we are ready to go with pyenv. Once you installed pyenv you can check the version as below:

$ pyenv -v

Next, let’s take a look at pyenv documentation here:

$ man pyenv

This will display all the output from your terminal screen.

pyenv-man-page

List of Python version

$ pyenv install -list

This will bring you to a long list Python version for selection

pyenv-list

install Python version using pyenv

We need to install each version accordingly starts from Python 2.4.5 … until 3.12-dev. Here is the list.

To install Python version here is the syntax

pyenv install <python-version>

Replace the <python-version> accordingly with the pyenv list

Here is our first Python version 2.4.5

$ pyenv install 2.4.5

To ensure whether Python version 2.4.5 had installed let’s run command pyenv versions

root@pythonhat:/home/el/main# pyenv versions
* system
  2.4.5

Proceed to finish other version as well. Once you have done with all the versions installed let’s check it out by running pyenv versions again.

root@pythonhat:/home/el/main# pyenv versions
* system (set by /root/.pyenv/version)
  2.4.5
  2.7.15
  3.5.10
  3.9.13
  3.12-dev

pyenv global

Now we are going to select our Python 3.9.13 as our global that enable across the wide system.

You can simply copy and paste which version as according to your project specification. It start with version number or a specific Python distribution like minicondas, jython and so on.

$ pyenv global 3.9.13

Why install 3.9.13 as global due to that three projects share the common Python version which is project_a, project_c and project_d.

pyenv versions switching using global command from system to 3.9.13

Run this in our terminal:

$ pyenv versions

This will displays a list of Python versions we had installed before this.

root@pythonhat:/home/el/main# pyenv versions
  system
  2.4.5
  2.7.15
  3.5.10
* 3.9.13 (set by /root/.pyenv/version)
  3.12-dev

If you notice that * asterik sign shifted from sytem via pyenv global command to 3.9.13 and it indicates the directory (set by /root/.pyenv/version).

As we had initialize our Python version 3.9.13 as global but we need to test it to make sure it works well with our specification.

Thus, below a script named checkversion.py into our root directory/folder that print statements:

  • greet Hello, World!
  • current path or working directory
  • Python version
# checkversion.py

import sys
import os

# get the current working directory
cwd = os.getcwd()

print("Hello, World!")
print("from folder path: " + cwd)
print("Here is the Python version: " + sys.version)

checkversion.py

Let’s run checkversion.py and see if it’s working.

$ python checkversion.py

Let’s see the output.

Hello, World!
Printing folder path: /home/el/main
Here is the Python version: 3.9.13 (main, Aug 13 2022, 20:45:03)
[GCC 8.3.0]

As you can see pyenv assign command python to 3.9.13 version. Next, let’s browse through pyenv versions and let’s copy and paste script checkversion.py to each of the projects folder.

    main
    ├── checkversion.py
    ├── project_a
    │   └── checkversion.py
    ├── project_b
    │   └── checkversion.py
    ├── project_c
    │   └── checkversion.py
    ├── project_d
    │   └── checkversion.py
    └── project_e
        └── checkversion.py
  • check_version.py script will be copied to each of project folders which is project_a, project_b, project_c, project_d and project_e
$ pyenv versions

Now let’s run our Python script checkversion.py

$ python checkversion.py

pyenv local

pyenv local is where current Python global version will be overrides. If you look at our table we decided to use global Python version 3.9.13 for project_a, project_c and project_d. However for project_b our specific version is 2.7.15. This is where pyenv local command will come useful.

Let’s do it step by step.

1st browse into the current folder which is project_b

2nd type command as below.

Identify

$ pyenv local 2.4.5

Next, run checkversion.py script.

$ python checkversion.py

Output from running the checkversion.py shown as below.

root@pythonhat:/home/el/main/project_b# pyenv versions
  system
* 2.4.5  (set by /home/el/main/project_b/.python-version)
  2.7.15
  3.5.10
  3.9.13
  3.12-dev

As you can notice we are in project_b directory and * or asteriks is at level 2.7.15 and set direct into project_b directory instead for project_a that were set into root or system folder.

Multiple versions global or local pyenv

We can setup either multiple versions pyenv global or pyenv local with pyenv. Likewise for Debian can have both Python2.x and Python3.x installed into the wide system. pyenv can have more versions than enough for you to install.

The sequence starts from the left and followed by the next. Here is the illustration.

Project E:

  • make sure you are in the current project_e directory
  • install with precedence from left to right – 3.9.13, and 2.7.15
$ pyenv local 3.5.10 3.12-dev

Next run with python script

$ python checkversion.py

Let’s run python command in terminal it will start from the left version which is 3.5.10

Conclusion

pyenv allows you to maintain multiple projects with breeze. However to make sure you be efficient in managing projects if not thousand but maybe at least hundreds:

  • Have a structured list of projects that splitted by project name and Python versions for each
  • Identify if it shares a common Python version. If more projects share a common Python version then that Python version should be treated as pyenv global.
  • pyenv local can be used if it doesn’t have any common Python version amongst other project. Run command pyenv local only into that particular project directory.
  • Setup multiple versions for a project either pyenv global or pyenv local with precedence starting from left to right and python command will enable it precedence left version as it main or default pyenv version. Set it according to it’s priority will helps to manage better, saves time and less trouble.

Challenge: Multiple versions for project_c and project_d

If you realized that both project_c and project_d share the same versions which is 2.7.15 and 3.9.13. While it also has the same version 3.9.13 with project_a our current pyenv global. Let’s solve this together if we should initialized both project into multiple pyenv global or pyenv local? Choose either one and why?

Look forward to your suggestion. Happy coding and have fun!