DerWeh
DerWeh

Reputation: 1829

Pythonic exception handling: only catching specific errno

I often read that in python "it is easier to ask for forgiveness then for permission", so it is sometimes considered better to use try except instead of if.

I often have statements like

if (not os.path.isdir(dir)):
    os.mkdir(dir).

The likely replacement would be

try:
    os.mkdir(dir)
except OSError:
    pass.

However I would like to be more specific and only ignore the errno.EEXIST, as this is the only error that is expected to happen and I have no idea what could happen.

try:
    os.mkdir(dir)
except OSError:
    if(OSError.errno != errno.EEXIST):
        raise
    else:
        pass.

Seems to do the trick. But this is really bulky and will 'pollute' my code and reduce readability if I need plenty of these code-blocks. Is there a pythonic way to do this in Python 2.X? What is the standard procedure to handle such cases?

edits:

Upvotes: 4

Views: 1471

Answers (3)

Anurag Sinha
Anurag Sinha

Reputation: 197

This example is for exception OSError : 17, 'File exists'

import sys
try:
    value = os.mkdir("dir")
except:
    e = sys.exc_info()[:2]
    e = str(e)
    if "17" in e:
        raise OSError #Perform Action
    else:
        pass   

Just change the number 17 to your exception number. You can get a better explanation at this link.

Upvotes: 0

DerWeh
DerWeh

Reputation: 1829

I just stumbled across the probably most elegant solution: creating the ignored context manager:

import errno
from contextlib import contextmanager

@contextmanager
def ignorednr(exception, *errornrs):
    try:
        yield
    except exception as e:
        if e.errno not in errornrs:
            raise
        pass


with ignorednr(OSError, errno.EEXIST):
     os.mkdir(dir)

This way I just have the ugly job of creating the context manager once, from then on the syntax is quite nice and readable.

The solution is taken from https://www.youtube.com/watch?v=OSGv2VnC0go.

Upvotes: 1

Padraic Cunningham
Padraic Cunningham

Reputation: 180550

If you are calling it multiple times with different args, put it in a function:

def catch(d, err):
    try:
        os.mkdir(d)
    except OSError as e:
        if e.errno != err:
            raise

Then call the function passing in whatever args:

 catch(, "foo", errno.EEXIST)

You could also allow the option of passing passing multiple errno's if you wanted more:

def catch(d, *errs):
    try:
        os.mkdir(d)
    except OSError as e:
        if e.errno not in errs:
            raise

catch("foo", errno.EEXIST, errno.EPERM)

Upvotes: 0

Related Questions