next up previous contents
Next: Writing Modules Up: Exceptions Previous: The Exception Hierarchy   Contents

Raising Exceptions

In addition to responding to exceptions in other programs, you can raise exceptions in your own programs.

You can raise any of the existing exceptions, or you can create new ones of your own. Figure 9.1 lists all the built-in exceptions; you can also find their names by examining the directory of the __builtins__ object; all the exceptions contain the string ``Error'' or ``Exit''.

You can create your own exceptions as subclasses of the built in Exception class. (Creating and working with classes is described in detail in Chapter 10.4.) To create a new exception called MyError, the following code can be used:

class MyError(Exception):
   pass
The pass statement serves as a placeholder in situations when Python expects a statement, but you don't need to do anything. No further details are needed to create a usable exception.

After creating an exception, you can use the raise statement to activate it. Suppose we are writing a function which will create an archive of files on a 100Mb zip disk. Before writing the archive, we will check to make sure that all the files will fit on the disk; if they will not, we'll raise a SizeError exception. In this way, the calling program can decide on what action is appropriate. Here is the code to define the exception and create the archive:

import shutil,os

class SizeError(Exception):
    pass

def mkarchive(dir,capacity=100*1024*1024):
 
    files = os.listdir(dir)
    totalsize = 0 
    for f in files:
        totalsize = totalsize + os.getsize(os.path.join(dir,f))
        if totalsize > capacity:
            raise SizeError(dir)

    for f in files:
        shutil.copy(os.path.join(dir,f),os.path.join('/zip',f))
Note that the copy function may very well raise exceptions of its own; however, since we've defined our own SizeError exception, we'll be able to distinguish between the two types of error.

Now consider how we might use this function. Suppose that we're going to create several archives, with a program that will prompt us to change disks between each archive. The following program would repeatedly call the mkarchive function, printing appropriate status messages after each call:

dirs = ['/home/joe/papers','/home/sue/backup','/home/fred/save']
for d in dirs:
    print 'Insert zip disk and hit return ',
    sys.stdin.readline()

    try:
        mkarchive(dir)
        print 'Archived %s to zip disk' % dir
    except SizeError,msg:
        print 'Directory %s too large for zip disk' % msg
    except IOError,msg:
        print 'Error archiving directory %s : %s' % (dir,msg)
Notice that the print statement after the call to mkarchive will only be executed if no exception was encountered in the function call.

While it's natural to think of raising exceptions when an error is detected, exceptions can be used in other situations as well. Recall the walk function introduced in Section 8.6. This function will traverse a directory, calling a user-written function each time a new directory is encountered. Suppose we wish to write a program to search for a file with a particular name, but we'd like the program to stop searching as soon as it finds such a file. While we could exit the program entirely (by calling sys.exit), there's no way to simply return from the walk function until all the directories have been traversed without exceptions. We could create an exception, raise that exception once the filename has been found, and put the call to walk inside a try/except loop. The following program implements that strategy.

import os
class FoundException(Exception):
    pass

def chkname(name,dir,files):
    if name in files:
        raise FoundException(os.path.join(dir,name))

name = 'errno.h'
startdir = '/usr/include'
try:
    os.path.walk(startdir,chkname,name)
    print '%s not found starting at %s' % (name,startdir)
except FoundException,pathname:
    print '%s found: %s' % (name,pathname)
A similar strategy can be employed to make a ``panic'' exit from inside of deeply-nested loops.
next up previous contents
Next: Writing Modules Up: Exceptions Previous: The Exception Hierarchy   Contents
Phil Spector 2003-11-12