1113

Using pip, is it possible to figure out which version of a package is currently installed?

I know about pip install XYZ --upgrade but I am wondering if there is anything like pip info XYZ. If not what would be the best way to tell what version I am currently using.

Alexis
  • 23,545
  • 19
  • 104
  • 143

16 Answers16

1570

As of pip 1.3, there is a pip show command.

$ pip show Jinja2
---
Name: Jinja2
Version: 2.7.3
Location: /path/to/virtualenv/lib/python2.7/site-packages
Requires: markupsafe

In older versions, pip freeze and grep should do the job nicely.

$ pip freeze | grep Jinja2
Jinja2==2.7.3
AdamKG
  • 13,678
  • 3
  • 38
  • 46
  • 8
    @techtonik: It's for [freezing current modules](http://www.pip-installer.org/en/1.1/requirements.html) to a requirements.txt. – Hugo Feb 15 '14 at 10:59
  • 6
    The naming of 'freeze' is historical - it dates back to [at least 2008](https://github.com/pypa/pip/commit/97c152c463713bdaa0c1531a910eeae681035489#diff-65959455a7706e04f0827533ac39563bL133). At the time, many people were already familiar with "freezing" ruby gems, so pip borrowed the then-widely-used name. – AdamKG Feb 17 '14 at 21:54
  • 2
    this was not obvious nor documented, but you can type ```pip show pip``` to get pip's version info, rather than ```pip --version``` as I would've expected. – Marc Maxmeister Jan 11 '16 at 18:55
  • `pip freeze` has the advantage that it shows editable VCS checkout versions correctly, while `pip show` does not. – spookylukey Jul 28 '16 at 06:38
  • Wish they gave this an intuitive name like `pip info`. Is there any way to alias commands in pip? – Noldorin Mar 02 '21 at 01:51
  • 1
    I would suggest calling with -i flag as you sometimes do not know which ones are capital letters and which ones are not: `pip freeze | grep -i xyz` – Vitali Avagyan Jan 24 '22 at 11:27
87

I just sent a pull request in pip with the enhancement Hugo Tavares said:

(specloud as example)

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio
Bengineer
  • 7,264
  • 7
  • 27
  • 28
60

Pip 1.3 now also has a list command:

$ pip list
argparse (1.2.1)
pip (1.5.1)
setuptools (2.1)
wsgiref (0.1.2)
RickyA
  • 15,465
  • 5
  • 71
  • 95
  • Say package name is X. To find the version - What is the difference between using pip list and doing import X and then X.__version__? Are both the package versions? – variable Oct 13 '19 at 04:27
  • both are valid, but `pip list` is generic, and `__version__` is not. I have also seen `version()` and `get_version()` for the imported one. – RickyA Oct 14 '19 at 08:35
45

and with --outdated as an extra argument, you will get the Current and Latest versions of the packages you are using :

$ pip list --outdated
distribute (Current: 0.6.34 Latest: 0.7.3)
django-bootstrap3 (Current: 1.1.0 Latest: 4.3.0)
Django (Current: 1.5.4 Latest: 1.6.4)
Jinja2 (Current: 2.6 Latest: 2.8)

So combining with AdamKG 's answer :

$ pip list --outdated | grep Jinja2
Jinja2 (Current: 2.6 Latest: 2.8)

Check pip-tools too : https://github.com/nvie/pip-tools

KevinS
  • 8,087
  • 2
  • 17
  • 9
25

The python function returning just the package version in a machine-readable format:

from importlib.metadata import version 
version('numpy')

Prior to python 3.8:

pip install importlib-metadata 
from importlib_metadata import version
version('numpy')

The bash equivalent (here also invoked from python) would be much more complex (but more robust - see caution below):

import subprocess
def get_installed_ver(pkg_name):
    bash_str="pip freeze | grep -w %s= | awk -F '==' {'print $2'} | tr -d '\n'" %(pkg_name)
    return(subprocess.check_output(bash_str, shell=True).decode())

Sample usage:

# pkg_name="xgboost"
# pkg_name="Flask"
# pkg_name="Flask-Caching"
pkg_name="scikit-learn"

print(get_installed_ver(pkg_name))
>>> 0.22

Note that in both cases pkg_name parameter should contain package name in the format as returned by pip freeze and not as used during import, e.g. scikit-learn not sklearn or Flask-Caching, not flask_caching.

Note that while invoking pip freeze in bash version may seem inefficient, only this method proves to be sufficiently robust to package naming peculiarities and inconsistencies (e.g. underscores vs dashes, small vs large caps, and abbreviations such as sklearn vs scikit-learn).

Caution: in complex environments both variants can return surprise version numbers, inconsistent with what you can actually get during import.

One such problem arises when there are other versions of the package hidden in a user site-packages subfolder. As an illustration of the perils of using version() here's a situation I encountered:

$ pip freeze | grep lightgbm
lightgbm==2.3.1

and

$ python -c "import lightgbm; print(lightgbm.__version__)"
2.3.1

vs.

$ python -c "from importlib_metadata import version; print(version(\"lightgbm\"))"
2.2.3

until you delete the subfolder with the old version (here 2.2.3) from the user folder (only one would normally be preserved by `pip` - the one installed as last with the `--user` switch):

$ ls /home/jovyan/.local/lib/python3.7/site-packages/lightgbm*
/home/jovyan/.local/lib/python3.7/site-packages/lightgbm-2.2.3.dist-info
/home/jovyan/.local/lib/python3.7/site-packages/lightgbm-2.3.1.dist-info

Another problem is having some conda-installed packages in the same environment. If they share dependencies with your pip-installed packages, and versions of these dependencies differ, you may get downgrades of your pip-installed dependencies.

To illustrate, the latest version of numpy available in PyPI on 04-01-2020 was 1.18.0, while at the same time Anaconda's conda-forge channel had only 1.17.3 version on numpy as their latest. So when you installed a basemap package with conda (as second), your previously pip-installed numpy would get downgraded by conda to 1.17.3, and version 1.18.0 would become unavailable to the import function. In this case version() would be right, and pip freeze/conda list wrong:

$ python -c "from importlib_metadata import version; print(version(\"numpy\"))"
1.17.3

$ python -c "import numpy; print(numpy.__version__)"
1.17.3

$ pip freeze | grep numpy
numpy==1.18.0

$ conda list | grep numpy
numpy                     1.18.0                   pypi_0    pypi
Asclepius
  • 57,944
  • 17
  • 167
  • 143
mirekphd
  • 4,799
  • 3
  • 38
  • 59
  • 1
    Why not use `importlib.metadata.version('NameOfProject')`? https://docs.python.org/3/library/importlib.metadata.html#distribution-versions – sinoroc Dec 30 '19 at 15:32
  • 1
    Great find @sinoroc! I think you should post it as an answer, and I will delete my rather overengineered one:) Sample PoC: `from importlib_metadata import version; version('Flask-Caching')` – mirekphd Dec 30 '19 at 15:41
  • 1
    I'll let you go for it – sinoroc Dec 30 '19 at 15:43
  • Your newest edits surprise me. Could you try `python -c "import pkg_resources; print(pkg_resources.get_distribution('lightgbm').version)"`? – sinoroc Jan 05 '20 at 17:38
  • That one gives you the correct answer - the latest version installed (2.3.1), when `version()` still returns the earliest (oldest) one (2.2.3). You can replicate this result by installing both versions with the `--user` switch, but preserving manually the `lightgbm-2.2.3.dist-info` folder, to have both of them together, as listed above (pip would *normally* remove it - until it doesn't). – mirekphd Jan 06 '20 at 10:41
  • You seem to have an unusual environment... Nonetheless, it might be worth reporting your findings on the [`importlib-metadata` issue tracker](https://gitlab.com/python-devs/importlib_metadata/issues). Might be something that is fixable (I would assume the version that gets imported by default should be the same found by `importlib.metadata.version`), or maybe the maintainers would explain why it works this way. – sinoroc Jan 06 '20 at 11:02
  • OK, I reported the issue, will move the discussion further. I preserved the containers that have this problem, and think I can replicate it, so hopefully will the devs. The multiple subfolders with lightgbm package most likely resulted from sharing the same `.local` folder by two different containers... possible not only under docker, but even under Openshift, which would not prevent the same user from installing multiple versions of the package to the same `.local` folder mapped to the local / network storage. It's enough to have 2 containers running in the same namespace... – mirekphd Jan 06 '20 at 11:24
  • The import_lib mechanism does not work if you package an app with py2app; This is as of py2app 0.23 – hasii Mar 09 '21 at 17:19
17

You can also install yolk and then run yolk -l which also gives some nice output. Here is what I get for my little virtualenv:

(venv)CWD> /space/vhosts/pyramid.xcode.com/venv/build/unittest 
project@pyramid 43> yolk -l
Chameleon       - 2.8.2        - active 
Jinja2          - 2.6          - active 
Mako            - 0.7.0        - active 
MarkupSafe      - 0.15         - active 
PasteDeploy     - 1.5.0        - active 
Pygments        - 1.5          - active 
Python          - 2.7.3        - active development (/usr/lib/python2.7/lib-dynload)
SQLAlchemy      - 0.7.6        - active 
WebOb           - 1.2b3        - active 
account         - 0.0          - active development (/space/vhosts/pyramid.xcode.com/project/account)
distribute      - 0.6.19       - active 
egenix-mx-base  - 3.2.3        - active 
ipython         - 0.12         - active 
logilab-astng   - 0.23.1       - active 
logilab-common  - 0.57.1       - active 
nose            - 1.1.2        - active 
pbkdf2          - 1.3          - active 
pip             - 1.0.2        - active 
pyScss          - 1.1.3        - active 
pycrypto        - 2.5          - active 
pylint          - 0.25.1       - active 
pyramid-debugtoolbar - 1.0.1        - active 
pyramid-tm      - 0.4          - active 
pyramid         - 1.3          - active 
repoze.lru      - 0.5          - active 
simplejson      - 2.5.0        - active 
transaction     - 1.2.0        - active 
translationstring - 1.1          - active 
venusian        - 1.0a3        - active 
waitress        - 0.8.1        - active 
wsgiref         - 0.1.2        - active development (/usr/lib/python2.7)
yolk            - 0.4.3        - active 
zope.deprecation - 3.5.1        - active 
zope.interface  - 3.8.0        - active 
zope.sqlalchemy - 0.7          - active 
Gustavo
  • 179
  • 3
17

You can use the grep command to find out.

pip show <package_name>|grep Version

Example:

pip show urllib3|grep Version

will show only the versions.

Metadata-Version: 2.0
Version: 1.12

Rajiv
  • 582
  • 2
  • 8
  • 18
  • `grep` is for Unix, the Windows equivalent is `findstr` [(See @Quinn's answer)](https://stackoverflow.com/a/48959839/3936044) – Mandera Oct 20 '20 at 11:10
15

pip show works in python 3.7:

pip show selenium
Name: selenium
Version: 4.0.0a3
Summary: Python bindings for Selenium
Home-page: https://github.com/SeleniumHQ/selenium/
Author: UNKNOWN
Author-email: UNKNOWN
License: Apache 2.0
Location: c:\python3.7\lib\site-packages\selenium-4.0.0a3-py3.7.egg
Requires: urllib3
Required-by:
sinoroc
  • 18,409
  • 2
  • 39
  • 70
Superstone
  • 151
  • 1
  • 3
10

There's also a tool called pip-check which gives you a quick overview of all installed packages and their update status:

enter image description here

Haven't used it myself; just stumbled upon it and this SO question in quick succession, and since it wasn't mentioned...

Ola Tuvesson
  • 5,062
  • 2
  • 28
  • 37
10

pip list can also be told to format its output as json. It could be a safer approach to parse the version.

pip list --no-index --format=json | \
  jq -r '.[] | select(.name=="Jinja2").version'
# 2.10.1
Romain
  • 19,910
  • 6
  • 56
  • 65
8

The easiest way is this:

import jinja2
print jinja2.__version__
HamZa
  • 14,671
  • 11
  • 54
  • 75
user5730083
  • 105
  • 1
  • 2
  • 9
    This only works for packages that have defined `__version__` in their source code. Many packages do not. – spookylukey Jul 28 '16 at 06:37
  • Is it good practice to include this version while packaging or it is good practice to only have the version in the setup.py file version parameter? – variable Oct 13 '19 at 04:31
  • 1
    This method is also not robust to package naming inconsistencies (there are at least 3 types) between the expected input of `import` and the output of `pip freeze`. – mirekphd Dec 30 '19 at 15:30
7

On windows, you can issue command such as:

pip show setuptools | findstr "Version"

Output:

Version: 34.1.1
Quinn
  • 4,394
  • 2
  • 21
  • 19
7

To do this using Python code:

Using importlib.metadata.version

Python ≥3.8

import importlib.metadata
importlib.metadata.version('beautifulsoup4')
'4.9.1'

Python ≤3.7

(using importlib_metadata.version)

!pip install importlib-metadata

import importlib_metadata
importlib_metadata.version('beautifulsoup4')
'4.9.1'

Using pkg_resources.Distribution

import pkg_resources
pkg_resources.get_distribution('beautifulsoup4').version
'4.9.1'
pkg_resources.get_distribution('beautifulsoup4').parsed_version
<Version('4.9.1')>

Credited to comments by sinoroc and mirekphd.

Asclepius
  • 57,944
  • 17
  • 167
  • 143
1

For Windows you can

  1. open cmd and type python, press enter.

  2. type the import and press enter.

  3. type ._version__ and press enter.

As you can see in screen shot here I am using this method for checking the version of serial module.

Image


4b0
  • 21,981
  • 30
  • 95
  • 142
DRPandya
  • 113
  • 3
  • 14
0

In question, it is not mentioned which OS user is using (Windows/Linux/Mac)

As there are couple of answers which will work flawlessly on Mac and Linux.

Below command can be used in case the user is trying to find the version of a python package on windows.

In PowerShell use below command :

pip list | findstr <PackageName>

Example:- pip list | findstr requests

Output : requests 2.18.4

Ashwani Singh
  • 876
  • 11
  • 10
0
import pkg_resources
packages = [dist.project_name for dist in pkg_resources.working_set]
try:
   for count, item in enumerate(packages):
      print(item, pkg_resources.get_distribution(item).version)
except:
    pass here

The indentations might not be perfect. The reason I am using a Try- Except block is that few library names will throw errors because of parsing the library names to process the versions. even though packages variable will contain all the libraries install in your environment.

Syenix
  • 208
  • 2
  • 9