Stefan Scherfke

Check Python site-packages for Updates

A while ago, I found a nice little script called which uses PIP to check your installed Python packages for updates. However, it didn’t work under Python 3, so I ported it myself:

Use pip to get a list of local packages to check against one or more package
indexes for updated versions.

    from cStringIO import StringIO
    import xmlrpclib
except ImportError:
    from io import StringIO
    import xmlrpc.client as xmlrpclib

from distutils.version import StrictVersion, LooseVersion
import sys

import pip

def get_local_packages():
    Call pip's freeze -l

    returns a list of package_name, version tuples

    sys.stdout = mystdout = StringIO()
    pip.main(['freeze', '-l'])
    sys.stdout = sys.__stdout__

    pkgs = mystdout.getvalue().split('\n')
    return [p.split('==') for p in pkgs]

def find_current_version(package, index_urls=None):
    Using the XMLRPC method available for PyPI, get the most recent version
    of <package> from each of the index_urls and figure out which one (if any)
    is higher

    Returns a tuple of the index with the higher version and the version it has

    if index_urls is None:
        index_urls = ['']
    cur_version = '0'
    cur_index = ''
    for index_url in index_urls:
        pypi = xmlrpclib.ServerProxy(index_url, xmlrpclib.Transport())
        pypi_hits = pypi.package_releases(package)
        if len(pypi_hits) > 0:
            if compare_versions(pypi_hits[0], cur_version):
                cur_version = pypi_hits[0]
                cur_index = index_url

    return cur_index, cur_version

def compare_versions(version1, version2):
    Compare 2 versions, starting with StrictVersion, and falling back on
    LooseVersion. Returns ``True`` if *version1* is greater than *version2*.

        return StrictVersion(version1) > StrictVersion(version2)
    # in case of abnormal version number, fall back to LooseVersion
    except ValueError:
        return LooseVersion(version1) > LooseVersion(version2)

def output_line(pkg_name, new_version, old_version, index_url):
    """Output the line showing the formatted information."""
    msg = '%(bd)s%(pkg_name)s%(nm)s (%(new)s) via %(index)s. Currently %(old)s.'
    params = {
        'bd': BOLD,
        'nm': NORMAL,
        'pkg_name': pkg_name,
        'new': new_version,
        'old': old_version,
        'index': index_url,
    print(msg % params)

NEWER = lambda x, y: compare_versions(str(x), y) == 1

if __name__ == '__main__':
    import curses
    CLEAR_SCREEN = curses.tigetstr('clear').decode('utf-8')
    BOLD = curses.tigetstr('bold').decode('utf-8')
    NORMAL = curses.tigetstr('sgr0').decode('utf-8')

    if len(sys.argv) > 1:
        indexes = sys.argv[1:]
        indexes = ['']
    print(CLEAR_SCREEN + BOLD + 'Packages with newer versions:' + NORMAL)

    for pkg in get_local_packages():
        # pip outputs a single 0 at the end of the list. Ignore it.
        if len(pkg) < 2:

        index, current_version = find_current_version(pkg[0], index_urls=indexes)
        if current_version and NEWER(str(current_version), pkg[1]):
            output_line(pkg[0], current_version, pkg[1], index)

Just execute it from anywhere using a Python interpreter whose packages you’d like to check (e.g., python3 or from within a virtualenv). You can then uses pip install -U <packagename> (or pip-3.2 for Python 3) to update the packages.

Update: The yolk package does the same via yolk -U. It doesn’t support Python 3, though. I wonder when PIP will get that functionality.