Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Exception Safe Pickle Use

Background

I've inherited a code base with a lot of try ... except: clauses. Most of them are way too broad, and make it a pain to debug. I've been going through and changing each to the most reasonable form, which usually involves removing it or specifying the exception(s).

Problem

But I'm a little stumped by this one:

try:
    with open(self.session_filename, "rb") as f:
        data = cPickle.loads(zlib.decompress(f.read()))
except:
    # we didn't need your file anyway!
    return

I want to handle the exceptions specifically, but the Python docs on Pickle say:

exception pickle.UnpicklingError

This exception is raised when there is a problem unpickling an object. Note that other exceptions may also be raised during unpickling, including (but not necessarily limited to) AttributeError, EOFError, ImportError, and IndexError.

Translation: The method might throw anything!

So apparently it can raise arbitrary exceptions, which makes it hard to handle them specifically.

How can I most reasonably deal with this situation, keeping the following goals in mind:

  1. I want to catch all exceptions resulting from a bad filename or other OS issues, or a bad format.
  2. I don't want to be overly broad and thus hide other issues.
  3. I'd prefer not to read the implementation and try to parse out all the different potential exceptions. That would be implementation-dependent, possibly fail with updates, and take a lot of time.

It may be that not all can be fulfilled.

like image 200
jtpereyda Avatar asked Oct 23 '15 16:10

jtpereyda


2 Answers

Breaking up the exceptions into several handlers may be what you want, with a catchall if you need it.

try:
    with open(self.session_filename, "rb") as f:
         data = cPickle.loads(zlib.decompress(f.read()))
except pickle.UnpicklingError as e:
    # normal, somewhat expected
    continue
except (AttributeError,  EOFError, ImportError, IndexError) as e:
    # secondary errors
    print(traceback.format_exc(e))
    continue
except Exception as e:
    # everything else, possibly fatal
    print(traceback.format_exc(e))
    return
like image 157
opticaliqlusion Avatar answered Oct 24 '22 16:10

opticaliqlusion


Generally I would try to handle only specific exceptions which is not really possible in this case: Who knows what exceptions could cPickle.loads throw in the future.

Where it is no possible to be more specific in the type of the exceptions I'd try to be more specific on the code block that I wrap in try ... except. For this example this could be like this:

with open(self.session_filename, "rb") as f:
    uncompressed_data = zlib.decompress(f.read())

try:
    data = cPickle.loads(uncompressed_data)
except cPickle.UnpicklingError:
    raise
except Exception as e:
    # Unpickling failed
    raise cPickle.UnpicklingError(repr(e))
like image 39
Bluehorn Avatar answered Oct 24 '22 18:10

Bluehorn