Archive for April 2012

django-sphinxdoc 1.1

Most Python projects use Sphinx for their documentation. And many (most?) Python powered websites use Django as framework.

So there might be some people who use both Sphinx and Django. If you belong to this group and want to integrate the documentation of your projects into your Django powered website, django-sphinxdoc might be the app you’re searching for.

Django-sphinxdoc can build and import your Sphinxdocumentation and provides views for browsing and searching it. You can see django-sphinxdoc in action be reading its documentation.

What’s new in this version?

  • [NEW] Support static and download files.
  • [NEW] Additional context to search view so that project information is available in the template.
  • [CHANGE] Updated some templates
  • [FIX] Fixed a bug with the updatedoc command and ~ in paths.
  • [FIX] Include all module index files.
  • [FIX] Improved indexing behaviour
  • [FIX] Improved behaviour when building the docs.

You can find django-sphinxdoc in the Cheese Shop or at Bitbucket.

Check Python site-packages for Updates

A while ago, I found a nice little script called check_for_updates.py 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.

"""
try:
    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 = ['http://pypi.python.org/pypi']
    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*.

    """
    try:
        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
    curses.setupterm()
    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:]
    else:
        indexes = ['http://pypi.python.org/pypi']
    print(CLEAR_SCREEN + BOLD + 'Packages with newer versions:' + NORMAL)
    print('')

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

        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 check_for_updates.py 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.