HelloGoodbye
HelloGoodbye

Reputation: 3902

How to safely determine the cause of an exception that is caught?

In Python, there are a number of built-in exceptions that can be thrown by various standard library functions (and of course by other code). A certain exception can potentially be thrown for many reasons, and you may want to find out whether it was thrown for a specific reason.

For example, in Windows, if you try to move a file when it is locked by another process, you are likely to get a PermissionError:

PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Path\\to\\the\\file'

In my case, I want to determine whether the the reason a PermissionError exception is thrown is because a file I try to move is locked, and I currently do that by looking at the error message in the exception that I catch:

try:
    # Move file
    os.rename(source_path, dest_path)

except PermissionError as e:
    if str(e).find('The process cannot access the file because it is being used by another process') != -1:
        # File not unlocked yet; do something, e.g. wait a moment and try again
    else:
        # Exception thrown for some other reason; do something else

However, to check whether str(e) contains a specific error message as a substring doesn't feel completely safe, as I haven't seen any specification of what message will be assigned to the exception thrown by os.rename when the source file is locked, or what type of exception should be thrown or even if an exception should be thrown at all. So this behavior could change in a future version of Python, or vary between different Python implementations.

So, how can I safely determine whether a PermissionError exception was thrown because of the fact that I tried to access a locked file, if we may assume that a PermissionError exception will be thrown? Or if we may not assume that, how can I safely achieve the same thing that my application currently achieves?

Upvotes: 4

Views: 167

Answers (3)

Dimitris Fasarakis Hilliard
Dimitris Fasarakis Hilliard

Reputation: 160367

Lærne is correct, all you need to do to correctly determine the cause of an error is check against it's errno attribute.

The list of available error symbols is located in the errno module which you can import and use by check against the symbols defined in it. A trivial example:

import os, errno

try:
    os.remove(filename)
except OSError as e:
    if e.errno != errno.ENOENT:
        raise

which re-raises the exception if no such file/directory exists.

Upvotes: 1

Lærne
Lærne

Reputation: 3142

Standard python exception uses the C errno code, you can access with e.errno.

On mac/linux, you can see the list of posix errno values.

On windows, you can access an additional error code, provided by the window OS, using e.winerror. You can then look for the correct code to check with the documentation from microsoft.

Upvotes: 5

Lazik
Lazik

Reputation: 2520

On Windows it will be safe to use the exception string It will always be 'The process cannot access the file because it is being used by another process'

You can always do

if "The process cannot access the file because it is being used by another process" in str(e):
    #file is locked
    pass

Upvotes: 1

Related Questions