35

I seem to remember there is a package that printed the versions and relevant information about Python packages used in a Jupyter notebook so the results in it were reproducible. But I cannot remember the name of the package. Can any of you point me in the right direction?

Thanks in advance!

msx
  • 555
  • 1
  • 5
  • 11

9 Answers9

34

I've cobbled this answer by combining the two solutions already provided. I ultimately wanted to generate a requirements.txt type file, for easy use with the awesome Binder website. Obviously, I don't want to pip freeze my whole system but I also don't want to create separate virtual environments for every notebook (which is ultimately where my problem stems from).

This outputs a nicely formatted requirements.txt type string and handles some of the intricacies involved when you use import from rather than just import.

Get locally imported modules from current notebook

import pkg_resources
import types
def get_imports():
    for name, val in globals().items():
        if isinstance(val, types.ModuleType):
            # Split ensures you get root package, 
            # not just imported function
            name = val.__name__.split(".")[0]

        elif isinstance(val, type):
            name = val.__module__.split(".")[0]
            
        # Some packages are weird and have different
        # imported names vs. system/pip names. Unfortunately,
        # there is no systematic way to get pip names from
        # a package's imported name. You'll have to add
        # exceptions to this list manually!
        poorly_named_packages = {
            "PIL": "Pillow",
            "sklearn": "scikit-learn"
        }
        if name in poorly_named_packages.keys():
            name = poorly_named_packages[name]
            
        yield name
imports = list(set(get_imports()))

# The only way I found to get the version of the root package
# from only the name of the package is to cross-check the names 
# of installed packages vs. imported packages
requirements = []
for m in pkg_resources.working_set:
    if m.project_name in imports and m.project_name!="pip":
        requirements.append((m.project_name, m.version))

for r in requirements:
    print("{}=={}".format(*r))

Sample output:

scipy==0.19.0
requests==2.18.1
Pillow==5.0.0
numpy==1.13.0
matplotlib==2.0.2

EDITED 2018-04-21: pip version 10 stopped supporting the .get_installed_distributions() method. Using pkg_resources.working_set instead.

petezurich
  • 9,280
  • 9
  • 43
  • 57
Alex P. Miller
  • 2,128
  • 1
  • 23
  • 20
  • 3
    This answer is nice because it determines the version of a package even if you import only a subpackage (e.g., the version of `scipy` if you import `scipy.integrate`). Thanks! – millikan Oct 30 '18 at 15:15
31

This gets all the installed packages

import pip #needed to use the pip functions
for i in pip.get_installed_distributions(local_only=True):
    print(i)

To get the list of packages from current notebook

import types
def imports():
    for name, val in globals().items():
        if isinstance(val, types.ModuleType):
            yield val.__name__
list(imports())
Vivek Srinivasan
  • 2,687
  • 3
  • 17
  • 17
  • 2
    Thanks for your reply, but I am looking for a package that only lists the packages used in the notebook in question. – msx Nov 04 '16 at 18:09
  • possible duplicate of this question – Vivek Srinivasan Nov 04 '16 at 18:27
  • http://stackoverflow.com/questions/4858100/how-to-list-imported-modules – Vivek Srinivasan Nov 04 '16 at 18:28
  • +1 for the answer using `globals` and `types.ModuleType` as it answer the OP question and it is more reliable than other solutions from the aforementioned post (some of theses answers using `sys.modules` will skip modules imported like `import numpy as np`). – mgc Nov 04 '16 at 19:26
  • For convenience it can be useful to sort the package by name. It can be simply achieved by sorting the list like this: `sorted(pip.get_installed_distributions(local_only=True), key=lambda x: x.project_name.lower())`. – Romain Dec 11 '17 at 10:43
  • 8
    I get an error running the first code block: `AttributeError: module 'pip' has no attribute 'get_installed_distributions'` `pip.__version__ == '19.2.3'` – Bill Nov 27 '19 at 05:25
27

One-liner:

# In[1]:
import pandas as pd
import numpy as np
import tensorflow as tf

print('\n'.join(f'{m.__name__}=={m.__version__}' for m in globals().values() if getattr(m, '__version__', None)))

Output:

pandas==1.1.1
numpy==1.19.1
tensorflow==2.2.0
  • 2
    add a == to the print function to make it similar to the requirements format – msarafzadeh May 05 '21 at 11:06
  • one liner should not exists in my opinion. I know it is a cool trend, but, in my opinion it is one of the most unreadable thing a programmer can do to another programmer :D – Valentin_Ștefan Feb 10 '23 at 17:47
5

I made some improvements to @Alex P. Miller's answer so that (sorry I don't have enough reps to "comment" directly on his answer)

  1. Automatically works with module names where case sensitivity was causing problems
  2. Also lists modules without version numbers as "unknown" to make it clear it couldn't find a match.
  3. also lists built in modules if it can detect it.
# show versions of packages
# adopted from https://stackoverflow.com/questions/40428931/package-for-listing-version-of-packages-used-in-a-jupyter-notebook

    def get_imports():
        for name, val in globals().items():
            if isinstance(val, types.ModuleType):
                # Split ensures you get root package, 
                # not just imported function
                name = val.__name__.split(".")[0]
            elif isinstance(val, type):
                name = val.__module__.split(".")[0]
            # Some packages are weird and have different
            # imported names vs. system/pip names. Unfortunately,
            # there is no systematic way to get pip names from
            # a package's imported name. You'll have to add
            # exceptions to this list manually!
            poorly_named_packages = {
                "sklearn": "scikit-learn"
            }
            if name in poorly_named_packages.keys():
                name = poorly_named_packages[name]
            yield name.lower()
    imports = list(set(get_imports()))

    # The only way I found to get the version of the root package
    # from only the name of the package is to cross-check the names 
    # of installed packages vs. imported packages
    modules = []
    for m in sys.builtin_module_names:
        if m.lower() in imports and m !='builtins':
            modules.append((m,'Python BuiltIn'))
            imports.remove(m.lower())

    for m in pkg_resources.working_set:
        if m.project_name.lower() in imports and m.project_name!="pip":
            modules.append((m.project_name, m.version))
            imports.remove(m.project_name.lower())

    for m in sys.modules:
        if m.lower() in imports and m !='builtins':
            modules.append((m,'unknown'))

    # print('System=='+platform.system()+' '+platform.release()+'; Version=='+platform.version())
    for r in modules:
        print("{}=={}".format(*r))
gafortiby
  • 61
  • 1
  • 4
3

Adapted from gafortiby's answer: a shorter version to list only explicit list of packages. I found this suitable to memorize versions of the most important packages used in a jupyter notebook (for other readers or future use):

import pkg_resources
# list packages to be checked
root_packages = [
    'geoviews', 'geopandas', 'pandas', 'numpy', 
    'matplotlib', 'shapely', 'cartopy', 'holoviews',
    'mapclassify', 'fiona', 'bokeh']
# print versions, but check if package is imported first
for m in pkg_resources.working_set:
    if m.project_name.lower() in root_packages:
        print(f"{m.project_name}=={m.version}")

Output:

Shapely==1.7.0
pandas==1.0.1
numpy==1.18.1
matplotlib==3.1.3
mapclassify==2.2.0
holoviews==1.12.7
geoviews==1.6.6
geopandas==0.6.3
Fiona==1.8.13
Cartopy==0.17.0
bokeh==1.4.0

Enhanced version with nicer display:

import pkg_resources
from IPython.display import display
import pandas as pd

root_packages = [
    'geoviews', 'geopandas', 'pandas', 'numpy', 'cloudpickle',
    'matplotlib', 'shapely', 'cartopy', 'holoviews',
    'mapclassify', 'fiona', 'bokeh', 'pyproj', 'ipython',
    'jupyterlab']
root_packages.sort(reverse=True)
root_packages_list = []

for m in pkg_resources.working_set:
    if m.project_name.lower() in root_packages:
        root_packages_list.append([m.project_name, m.version])

display(pd.DataFrame(
            root_packages_list,
            columns=["package", "version"]
        ).set_index("package").transpose())

Output: Example output package versions

Alex
  • 2,784
  • 2
  • 32
  • 46
2

Another solution (based on Vivek's answer):

import types

def imports():
    for name, val in globals().items():
        if isinstance(val, types.ModuleType):
            yield val.__name__

excludes = ['builtins', 'types', 'sys']

imported_modules = [module for module in imports() if module not in excludes]

clean_modules = []

for module in imported_modules:

    sep = '.'  # to handle 'matplotlib.pyplot' cases
    rest = module.split(sep, 1)[0]
    clean_modules.append(rest)

changed_imported_modules = list(set(clean_modules))  # drop duplicates

pip_modules = !pip freeze  # you could also use `!conda list` with anaconda

for module in pip_modules:
    name, version = module.split('==')
    if name in changed_imported_modules:
        print(name + '\t' + version)

Sample output:

astropy 3.2.1
matplotlib  3.1.0
numpy   1.16.4
pandas  0.25.0
0

I think the pip based approaches are superior in terms of functionality, but it may be possible the OP was trying to recall the name of the version_information extension for Jupyter: https://pypi.org/project/version_information/

chepyle
  • 976
  • 1
  • 9
  • 16
  • 1
    version_information seems not being maintained anymore and does not work with python3.8, but here there is a pull request https://github.com/jrjohansson/version_information/pull/16 and fork that works https://github.com/ahmedsalhin/version_information. It can be installed with `pipenv install git+https://github.com/ahmedsalhin/version_information#egg=version_information` – Pablo Marin-Garcia Jan 25 '21 at 00:22
0

Since these answers are a bit dated, the simpler solutions didn't work for me and it took some stumbling to find an easy, working solution elsewhere online:

from sinfo import sinfo
sinfo()
scideas
  • 3
  • 1
0

I had some problems just doing writing in an empty cell pip list But once I ran it in a whole new file, I had no problems at all, and got all the libraries installed in the notebook!

Adan Mori
  • 1
  • 1