Python import helper

Wednesday 18 June 2008

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 = ""
            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 = ""
            import numpy
        except ImportError:
            raise Exception("Need numpy, from " + url)
        return numpy
    elif name == 'Image':
        url = ""
            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.

tagged: » 3 reactions


k3rni 11:21 AM on 18 Jun 2008

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.

Ned Batchelder 11:50 AM on 18 Jun 2008

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.

toidinamai 2:04 AM on 21 Jun 2008

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:
not displayed and no spam.
Leave this empty:
not searched.
Name and either email or www are required.
Don't put anything here:
Leave this empty:
URLs auto-link and some tags are allowed: <a><b><i><p><br><pre>.