Python import helper

Wednesday 18 June 2008This is over 16 years old. Be careful.

Aptus has dependencies on three large packages, wxPython, Numpy, and PIL. The simple thing to do would be to import the modules and use the methods I need. But if the module is missing, an unhelpful ImportError message is all you get. And if the module is present, but isn’t recent enough, then the method call may fail with a missing name.

To solve these problems, I use this helper function instead:

def importer(name):
    """ Import modules in a helpful way, raising detailed exceptions
        if the module can't be found or isn't the proper version.
    """
    if name == 'wx':
        url = "http://wxpython.org/"
        try:
            import wx
        except ImportError:
            raise Exception("Need wxPython, from " + url)
        if not hasattr(wx, 'BitmapFromBuffer'):
            raise Exception("Need wxPython 2.8 or greater, from " + url)
        return wx
    
    elif name == 'numpy':
        url = "http://numpy.scipy.org/"
        try:
            import numpy
        except ImportError:
            raise Exception("Need numpy, from " + url)
        return numpy
    
    elif name == 'Image':
        url = "http://pythonware.com/products/pil/"
        try:
            import Image
        except ImportError:
            raise Exception("Need PIL, from " + url)
        if not hasattr(Image, 'fromarray'):
            raise Exception("Need PIL 1.1.6 or greater, from " + url)
        return Image

Then, instead of “import wx”, I use:

wx = importer("wx")

and if anything goes wrong, the exception includes helpful details.

This technique still suffers from the problem of detecting that the module is actually missing. Because of Python’s impoverished exceptions, catching ImportError doesn’t necessarily mean that the module was missing, although that’s the most likely reason.

Comments

[gravatar]
This seems somewhat crude. Isn't pkg_resources meant for exactly that purpose? It can even use a callback to install the missing package at the right version, IIUC.
[gravatar]
As I was writing this up, I knew that eggs provided infrastructure that would do much of this. But I'm still not that fluent with eggs, it may well be a much better solution.
[gravatar]
You could also have a look at PEP 302. Putting a marker at the end of sys.path and an importer that looks for this marker into sys.path_hooks you could get the above functionality with (probably) less code and you don't have to change your import statements.

Add a comment:

Ignore this:
Leave this empty:
Name is required. Either email or web are required. Email won't be displayed and I won't spam you. Your web site won't be indexed by search engines.
Don't put anything here:
Leave this empty:
Comment text is Markdown.