Different kinds of Import Errors

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Dec 8 21:53:25 EST 2007


On Sun, 09 Dec 2007 00:25:53 +0000, Jeremy C B Nicoll wrote:

> >       for app_name in settings.INSTALLED_APPS:
> >           try:
> >               __import__(app_name + '.management', {}, {}, [''])
> >           except ImportError, exc:
> >               if exc.args[0]!='No module named management':
> >                   raise
...
> I want to ask a possibly related question.  My impression is
> that while writing and testing something like the above code one has
> somehow to know that "ImportError" can be raised, so one can explicitly
> define how it is to be treated.  How does one find that out?

Reading the docs. Trial and error. Background knowledge about what the 
function is doing. There's no perfect solution; unfortunately many 
functions fail to document what exceptions they can be expected to raise.

In principle, any exception that isn't documented is a bug. You can't be 
expected to recover from bugs, all you can do is report it to the 
function author.


> While in this case, one might hope that an import action could only fail
> with ImportError, isn't it possible that - say - one might get an
> IOError because of a problem on the module search path ... and maybe
> there are lots of other less obvious exceptions that could be raised?

The author of a function has a choice to make: 

(1) expose any exceptions that are raised by his code to the caller; or

(2) swallow those exceptions and raise one or two known exceptions.

Neither is the "right" answer in all circumstances. Sometimes you might 
want to just propagate exceptions, especially if the caller is in a 
position to do something about them. Sometimes the right solution is to 
hide those exceptions, and just expose a single MyModuleError exception 
to callers.

Sometimes neither is ideal.


> How does one write a try/except piece of code that works (ie traps
> whatever exception occurs, though obviously it can't necessarily fix an
> arbitrary exception) for any exception, even those not known of in
> advance by the author?

Generally, you don't. If you can't recover from an exception, there's 
little point in trapping it. Exceptions are:

(1) You're writing some sort of library function and you want to hide the 
internal errors that occur, so you might write:

def function():
    try:
        processing()
    except (IndexError, NameError):
        raise MyModuleError("bad things happened")
    except (IOError, MemoryError):
        raise MyModuleError("your computer is broken")


(But notice how much potentially useful information you've thrown away by 
doing this. Are you sure you want to hide that?)


(2) At the very top level of your application, where you might do 
something like this:

# Untested
if __name__ == '__main__':
    try:
        main()
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception, e:
        log_exception(e)
        print >>sys.stderr, "Die die die!!!"
        sys.exit(45)
    except: # Catch things that don't inherit from exceptions
        print >>sys.stderr, "This should never happen"
        sys.exit(46)



Hope that helps.


-- 
Steven.




More information about the Python-list mailing list