Пакет для листинга версий пакетов, используемых в ноутбуке Jupyter

Кажется, я помню, что есть пакет, в котором были напечатаны версии и соответствующая информация о пакетах Python, используемых в ноутбуке Jupyter, поэтому результаты в нем были воспроизводимыми. Но я не могу вспомнить имя пакета. Может ли кто-нибудь из вас указать мне в правильном направлении?

Спасибо заранее!

Ответ 1

Получает все установленные пакеты

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

Получить список пакетов из текущего ноутбука

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

Ответ 2

Я обдумал этот ответ, объединив два уже предоставленных решения. В конечном итоге я хотел создать файл типа require.txt, чтобы его можно было легко использовать на замечательном веб-сайте Binder. Очевидно, что я не хочу pip freeze всю систему целиком, но я также не хочу создавать отдельные виртуальные среды для каждого ноутбука (отсюда и моя проблема).

Это выводит красиво отформатированную строку типа require.txt и обрабатывает некоторые сложности, возникающие при использовании import from а не только import.

Получить локально импортированные модули из текущей записной книжки

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 imported name. You'll have to had
        # 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))

Пример вывода:

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

РЕДАКТИРОВАНИЕ 2018-04-21: версия 10 .get_installed_distributions() перестала поддерживать метод .get_installed_distributions(). pkg_resources.working_set этого используйте pkg_resources.working_set.

Ответ 3

Я сделал некоторые улучшения в ответе @Alex P. Miller, чтобы (извините, у меня недостаточно повторений, чтобы "прокомментировать" его ответ)

  1. Автоматически работает с именами модулей, где чувствительность к регистру вызывает проблемы
  2. Также перечисляет модули без номеров версий как "неизвестные", чтобы было ясно, что они не могут найти соответствие.
  3. также перечисляет встроенные модули, если он может обнаружить его.
# 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 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))

Ответ 4

Я думаю, что подходы, основанные на pip, превосходят с точки зрения функциональности, но, возможно, ОП пытался вспомнить название расширения version_information для Jupyter: https://pypi.org/project/version_information/

Ответ 5

Другое решение (на основе ответа Vaeka 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)

Пример вывода:

astropy 3.2.1
matplotlib  3.1.0
numpy   1.16.4
pandas  0.25.0