Search code examples
pythonexceptionioerror

Why do I get inconsistent exceptions on Python?


I encountered a very strange behavior in Python, a behavior that is not consistent.

...
except IOError as msg:
    sys.exit("###ERROR IOError: %s" % (msg))

Usually this would get me a message like:

###ERROR IOError: [Errno 13] Permission denied: 'filename'

In same cases the above code is giving me a tuple instead of a proper error message.

###ERROR IOError: (13, 'Permission denied')

This is very strange because in all case the exception come from the same python method, codecs.open(...)

What makes me wonder more about this is that if I remove the handling the exception will reach upper levels with the right text (full error message), always!

except IOError as msg:
    print(msg)
    raise msg

The above example will always print a complete message, like IOError: [Errno 13] Permission denied: u'filename'.

Why is this happening and how do I prevent this, I don't want to give incomplete error messages to the users.

I wanted to reproduce this behavior in a test file, but I was not able to reproduce this outside the project.

I suspect that is has something to do with the usage of sys.exit() because print(msg) will give good result but sys.exit not.


Solution

  • First, when reraising an exception, never do except Exc as e: raise e. It is always just plain raise with no arguments. This will preserve the traceback.

    No, this has nothing to do with sys.exit and everything to do with how the exception was instantiated. You are always getting an exception; just sometimes its string representation will resemble that of a tuple.

    >>> print IOError(13, 'Permission denied')
    [Errno 13] Permission denied
    >>> print IOError((13, 'Permission denied'))
    (13, 'Permission denied')
    

    Without showing the full traceback, there's no way to tell what exactly is raising the error in this way. Also, without properly reraising like I pointed out, you won't be getting the full traceback.