Translator

Human → Computer

Do not catch import errors, use pkg_resources

written by Patrick Gerken on 2010-08-20

After debugging a funny problem in tests which came from Circular Imports that got eaten, let me show you how you can test, if some package is available, and how you can test, if that package is new enough:

So, this is a common snippet:

try:
    import Products.LinguaPlone
except ImportError:
    HAS_LINGUA_PLONE = False
else:
    HAS_LINGUA_PLONE = True

That might trigger circular import exceptions. It will not always fail, depending on what gets imported first. The circular import gets caught by the "except ImportError:" line. So you will not see an exception here, but in some other funny place. Good luck debugging that.

Another thing that I see sometimes is a check to implement backward compatibility

try:
    from foo import new_thing
except ImportError:
    OLD_FOO = True
else:
    OLD_FOO = False

if OLD_FOO:
    def new_thing(something):
    return something + 'cool'

This can sometimes trigger ImportErrors and it does not show its intention like it could.

pkg_resources has an API which can help you to clarify things:

import pkg_resources
try:
    pkg_resources.get_distribution('Products.LinguaPlone>=4.0.0')
except pkg_resources.DistributionNotFound:
    HAS_LINGUA_PLONE = False
    HAS_CURRENT_LINGUA_PLONE = False
except pkg_resources.VersionConflict:
    HAS_LINGUA_PLONE = True
    HAS_CURRENT_LINGUA_PLONE = False
else:
    HAS_LINGUA_PLONE = True
    HAS_CURRENT_LINGUA_PLONE = True
`

Now, that is a bit more verbose, but

xxx