4

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:

  • use raise instead raise OSerror as pointed out by @Francisco Couzo
  • I use Python 2.7
DerWeh
  • 1,721
  • 1
  • 15
  • 26

3 Answers3

1

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.

DerWeh
  • 1,721
  • 1
  • 15
  • 26
0

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.

CarenRose
  • 1,266
  • 1
  • 12
  • 24
Anurag Sinha
  • 187
  • 4
  • 15
  • 2
    I think my question already provides a better answer, it is shorter and doesn't use the explicit number. I read the numbers might differ depending on the system so `errno.EEXIST` is better and also more readable. – DerWeh Oct 24 '16 at 20:55
0

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)
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321