views:

148

answers:

1

I've moved IOError handling to a separate function to avoid boilerplate when opening files for reading.

But what if IOError fires when the file is being read? If sshfs disconnects, or file is deleted by root, etc.?

def safe_open(*args):
    try:
        return open(*args)
    except IOError:
        quit('Error when opening file \'{0}\'. Error #{1[0]}: {1[1]}'.format(\
        args[0], sys.exc_info()[1].args))

...

with safe_open(myfile, 'r') as f:
    for i in f:
        print i

with safe_open(anotherfile, 'r') as f:
    try:
        conf = ''.join(f).format(**args)
    except KeyError:
        quit('\nOops, your template \'{0}\' has placeholders for' + \
        'parameters\nthat were not supplied in the command line: - {1}\n' +
        '\nCan\'t proceed. Ending. Nothing has been changed yet.'.format( \
        args['host_template'], '\n - '.join(sys.exc_info()[1].args)), 1)

File is read in different ways, so I don't see a way to put it into the function and pass the changing part as arguments.

[Added: thought of this solution, but it makes a generator that can't be closed. If a loop is stopped, the file is left open.]

def reader(*args):
    try:
        with safe_open(*args) as f:
            for i in f:
                yield i
    except IOError:
        print('IOError when trying to read \'{0}\''.format(args[0]))

for i in reader(myfile, 'r'):
    pass # do some job
+5  A: 

I would probably try move the file operations into separate functions and wrap those in a try... except

actually I just got an even better idea... put the error handling into a decorator and apply the decorator to each of the functions that does file operations

def catch_io_errors(fn):
    def decorator(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except IOError:
            quit('whatever error text')
    return decorator

then you can put all file ops into their own functions and apply the decorator

@catch_io_errors
def read_file():
    with safe_open(myfile, 'r') as f:
        for i in f:
            print i

or if you need compatibility with python 2.3:

def read_file():
    with safe_open(myfile, 'r') as f:
        for i in f:
            print i

read_file = catch_io_errors(read_file)
Jiaaro
Good idea with decorators! Didn't think of it.
culebrón
Nice use of decorators. Always looking for good example to sell them :-)
e-satis
For actual feature parity with 2.3, you'd have to get rid of the use of "with" as well. :)
jamessan
@jamessan oh yeah... I just copy/pasted that part hehe :P
Jiaaro