Why do we version packages?
When you have previously worked on text documents you might have found yourself naming files as myfile.doc
, myfilev2.doc
, myfilev3.doc
, etc., so that you can keep track of which version is which. Alternatively, you might use a file name based on the date: myfile22062020.doc
, myfile23062020.doc
, myfile27062020.doc
.
Similar to text documents, Python packages are "versioned" so that we can easily keep track of what is in each version. Python packages, however, are versioned according to a strict format:
major.minor.patch
...where major, minor, and patch are all integer numbers. For example, at the time of writing the latest version of the requests
package is 2.24.0
.
Whenever a change is made to a Python package, the version number is changed (regardless of how small the change is). The changes are split according to three different categories:
If the change is a backwards compatible bug fix, the
patch
is increased.If the change is a backwards compatible piece of new functionality, the
minor
version is increased.If the change is not backwards compatible (so it is a "breaking change"), the
major
version is increased.
In this course so far we have installed Python packages using the command pip install <package>
, where <package>
is the name of the Python package that you want to install. When we run this command there is no mention of any sort of package version. However, you might notice that the output of the command does include a reference to a particular package version. For example, if I run the following command:
→ pip install requests Collecting requests Using cached https://files.pythonhosted.org/packages/45/1e/0c169c6a5381e241ba7404532c16a21d86ab872c9bed8bdcd4c423954103/requests-2.24.0-py2.py3-none-any.whl Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in ./anaconda3/lib/python3.7/site-packages (from requests) (1.24.1) Requirement already satisfied: certifi>=2017.4.17 in ./anaconda3/lib/python3.7/site-packages (from requests) (2019.6.16) Requirement already satisfied: chardet<4,>=3.0.2 in ./anaconda3/lib/python3.7/site-packages (from requests) (3.0.4) Requirement already satisfied: idna<3,>=2.5 in ./anaconda3/lib/python3.7/site-packages (from requests) (2.8) Installing collected packages: requests Successfully installed requests-2.24.0 ~ →
Note that my command pip install requests
doesn’t mention a specific version of the package, but that the last line of the output Successfully installed requests-2.24.0
shows that we have installed a specific version: 2.24.0
. This version, at the time of writing, is the latest version of the requests
package available. So, if you don’t specify a package version, pip
installs the latest requests package available.
Get to grips with package versioning
The simplest way to install a particular Python package version is to use the ==
operator. For example, pip install requests==2.1.0
will, as you would expect, install version 2.1.0
. There are, however, a number of different ways in which to specify the package version. For example:
pip install requests~=2.2
will install the highest version available above2.2
, but not3.0
or higher.pip install requests~=2.1.0
will install the highest version available above2.1.0
, but not2.2.0
or higher.pip install requests>2.5.0
will install the highest version available above2.5.0
.pip install “requests>2.4.0,<2.6.0”
will install the highest version available above2.4.0
, but lower than2.6.0
.
Let’s give some of these commands a go together. Each time we install the requests
package we will uninstall it using the pip uninstall <package>
command. Let’s start by uninstalling requests
:
~ → pip uninstall requests Uninstalling requests-2.5.3: Would remove: /Users/george/anaconda3/lib/python3.7/site-packages/requests-2.5.3.dist-info/* /Users/george/anaconda3/lib/python3.7/site-packages/requests/* Proceed (y/n)? y Successfully uninstalled requests-2.5.3 ~ →
Now let’s run pip install requests~=2.2
:
~ → pip install requests~=2.2 Collecting requests~=2.2 Using cached https://files.pythonhosted.org/packages/45/1e/0c169c6a5381e241ba7404532c16a21d86ab872c9bed8bdcd4c423954103/requests-2.24.0-py2.py3-none-any.whl Requirement already satisfied: idna<3,>=2.5 in ./anaconda3/lib/python3.7/site-packages(fromrequests~=2.2)(2.8) Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in ./anaconda3/lib/python3.7/site-packages(fromrequests~=2.2)(1.24.1) Requirement already satisfied: certifi>=2017.4.17 in ./anaconda3/lib/python3.7/site-packages(fromrequests~=2.2)(2019.6.16) Requirement already satisfied: chardet<4,>=3.0.2 in ./anaconda3/lib/python3.7/site-packages(fromrequests~=2.2)(3.0.4) Installing collected packages: requests Successfully installed requests-2.24.0 ~ →
As expected, this installs version 2.24.0
, the highest version of requests
available below 3.0
(which doesn’t actually exist yet) at the time of writing. Let’s uninstall again and then run pip install requests~=2.1.0
:
→ pip uninstall requests Uninstalling requests-2.24.0: Would remove: /Users/george/anaconda3/lib/python3.7/site-packages/requests-2.24.0.dist-info/* /Users/george/anaconda3/lib/python3.7/site-packages/requests/* Proceed (y/n)? y Successfully uninstalled requests-2.24.0 ~ → pip install requests~=2.1.0 Collecting requests~=2.1.0 Using cached https://files.pythonhosted.org/packages/1e/97/f0a8e5e71c75a2abf5ec91438b84ec1a40a5e1b5f985c06721a3ebe57c0a/requests-2.1.0-py2.py3-none-any.whl conda 4.7.5 has requirement requests>=2.12.4, but you'll have requests2.1.0 which is incompatible. anaconda-client1.7.2 has requirement requests>=2.9.1, but you'll have requests 2.1.0 which is incompatible. Installing collected packages: requests Successfully installed requests-2.1.0 ~ →
This installs version 2.1.0
, the highest version of requests
available in the 2.1.x
range. Let’s uninstall requests
again and try our last installation command, pip install “requests>2.4.0,<2.6.0”
:
~ → pip uninstall requests Uninstalling requests-2.1.0: Would remove: /Users/george/anaconda3/lib/python3.7/site-packages/requests-2.1.0.dist-info/* /Users/george/anaconda3/lib/python3.7/site-packages/requests/* Proceed (y/n)? y Successfully uninstalled requests-2.1.0 ~ →pip install “requests>2.4.0,<2.6.0” -bash: 2.6.0”: No such file or directory ~ →pip install "requests>2.4.0,<2.6.0" Collecting requests<2.6.0,>2.4.0 Using cached https://files.pythonhosted.org/packages/95/54/44dc83b5f11c6da06bf9abd18c8a0905e0e297e0a9c3bfbc0c6ee4bdd33d/requests-2.5.3-py2.py3-none-any.whl conda 4.7.5 has requirement requests>=2.12.4, but you'll have requests 2.5.3 which is incompatible. anaconda-client1.7.2 has requirement requests>=2.9.1, but you'll have requests 2.5.3 which is incompatible. Installing collected packages: requests Successfully installed requests-2.5.3 ~ →
This installs requests 2.5.3
, the highest version of requests
available above 2.4.0
but below 2.6.0
.
To watch me installing different versions of requests
check out the following screencast:
Exercise
Your manager has been doing some analysis using Python. They have written a script which makes use of two Python packages: matplotlib
version 3.2.2
and numpy
version 1.19.0
.
First install the script: p1c4s2_exercise_script.py
Then install the two particular package versions needed and run the script.
Let’s Recap!
Python packages are versioned so that we can keep track of what code is in each version.
Python packages have a new version number each and every time a change to the package is made.
You can use
pip
to install your desired version of a Python package.
Now that you are up to speed with Python package versioning, let’s check your understanding of Pip with a short quiz. Then we’ll look at setting up a Python virtual environment, one way of using different Python package versions across different projects.