Package for listing version of packages used in a Jupyter notebook

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())

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))

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

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.