Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: programmatically running "pip list"

Tags:

python

pip

I'm writing a bit of code that will report and reconcile differences between two pip-managed python installations.

How can I programmatically get the information provided by pip list without making a subprogram invocation of pip?

like image 556
Mark Harrison Avatar asked Jan 31 '16 23:01

Mark Harrison


2 Answers

The top answers as of 2/1/2019 are outdated and no longer work with newer versions of pip.

But no worries - it's still possible to get a list of packages programmatically:

Options:

A. _internal.main

from pip import _internal
_internal.main(['list'])

This will print out three columns with Package. Version, and Location

Note that usage of pip's internal api is not recommended.

B. pkg_resources

import pkg_resources
print([p.project_name for p in pkg_resources.working_set])
# note that this is same as calling pip._vendor.pkg_resources.working_set

C. iter_modules

Takes a long time to execute (~300ms on computer w/ I5 CPU, SSD, & 8 gigs ram). The benefit is that it will have a far more extensive list of modules and it will output importable names.

Ex: python-dateutil is imported as dateutil, but iter_modules will give you the importable name: dateutil

from pkgutil import iter_modules
print([p.name for p in iter_modules()])

D. Call pip in command line via subprocess

The solution to this is trivial and I'll leave this as an exercise to the reader

aka I'm too lazy to do this, good luck! :D

like image 82
Almenon Avatar answered Oct 11 '22 16:10

Almenon


Update for Python 3.6 and Pip 19.0.1

> from pip._internal.utils.misc import get_installed_distributions
> p = get_installed_distributions()
> pprint.pprint(p)

[wheel 0.32.3 (/usr/local/lib/python3.7/site-packages),
 wcwidth 0.1.7 (/usr/local/lib/python3.7/site-packages),
 virtualenv 16.0.0 (/usr/local/lib/python3.7/site-packages),
 virtualenv-clone 0.3.0 (/usr/local/lib/python3.7/site-packages),
 urllib3 1.24.1 (/usr/local/lib/python3.7/site-packages),
 typing 3.6.6 (/usr/local/lib/python3.7/site-packages),
 terminaltables 3.1.0 (/usr/local/lib/python3.7/site-packages),
 ...

Original Answer

Pip is just python module, so just import it and call list:

import pip

pip.main(['list'])

# you can get details on package using show:

pip.main(['show', 'wheel'])

Ok so there is better way:

pip.utils.get_installed_distributions()

returns you list of packages installed.

packages = pip.utils.get_installed_distributions()

p = packages[0]

p.project_name 
p.version
p.egg_name
p.location

You can see what pip list is doing from the source code here

Also get_installed_distributions accept whole bunch of parameters to return only local packages (from current virtualenv) etc. Please see help here.

There is also underlying low level command from _vendor module:

[p for p in pip._vendor.pkg_resources.working_set]

However get_installed_distributions provide simplier api.

like image 18
vittore Avatar answered Oct 11 '22 17:10

vittore