4

Here is the code:

def make_dir(dir_name):
 if os.path.exists(dir_name):
  shutil.rmtree(dir_name)
 try:
  os.makedirs(dir_name)
 except OSError, e:
  print "ErrorNo: %s (%s)" % (e.errno, errno.errorcode[e.errno])
  raise

IFF the directory already exists, I get the following:

ErrorNo: 13 (EACCES)
Traceback (most recent call last):
  File "run_pnoise.py", line 167, in <module>
    make_dir("prep_dat")
  File "run_pnoise.py", line 88, in make_dir
    os.makedirs(dir_name)
  File "c:\Program Files (x86)\Python27\lib\os.py", line 157, in makedirs
    mkdir(name, mode)
WindowsError: [Error 5] Access is denied: 'prep_dat'

If I run the program again, it works, indicating that the program indeed does have access to the directory(s), since the shutil.rmtree call is obviously working. I have come up with a workaround which I will post. However, is there a better explanation and/or workaround?

My assumption is that the shutil.rmtree call is returning before the OS is totally done deleting all of the files and subdirectories. Also, since the shutil.rmtree call is not throwing an exception, any EACCESS (13) error on the makedirs call is likely bogus. My attempt (as modified after Apalala's comment):

def make_dir(dir_name):
    retry = True
    if os.path.exists(dir_name):
        shutil.rmtree(dir_name)
    while retry:
        try:
            # per Apalala, sleeping before the makedirs() eliminates the exception!
            time.sleep(0.001)
            os.makedirs(dir_name)
        except OSError, e:
            #time.sleep(0.001) # moved to before the makedirs() call 
            #print "ErrorNo: %s (%s)" % (e.errno, errno.errorcode[e.errno])
            if e.errno != 13: # eaccess
                raise
        else:
            retry = False

This seems to work reliably. There is the race condition problem mentioned in other posts, however that seems unlikely, and would probably result in a different exception.

David Rogers
  • 4,010
  • 3
  • 29
  • 28
  • 1
    I would expect that if the call to `sleep()` is made before the call to `makedirs()` the no exceptions should be raised. For debugging's sake, you could add a `while os.path.isdir(dir_name): print 'still there'` before the call to `makedirs()`. – Apalala Jan 06 '11 at 17:00
  • Your assumption is correct. Win API `DeleteFile` only marks the directory for deletion, so when the call returns, the directory still exists. So you have a race condition with the following makedirs call. On unix the unlink would simply remove the name, so the collision doesn't happen. – schlenk Dec 23 '14 at 19:06

3 Answers3

0

I had the same problem, and this looks similar to my solution, except I was sleeping (0.1).

jgritty
  • 11,660
  • 3
  • 38
  • 60
0

Can't you simply use an «except» statement ?

def make_dir(dir_name):
    retry = True
    if os.path.exists(dir_name):
        shutil.rmtree(dir_name)
    while retry:
        try:
            os.makedirs(dir_name)
        except OSError, e:
            time.sleep(0.001)
            if e.errno != 13: # eaccess
                raise
        except WindowsError:
#           (do some stuff)
        else:
            retry = False

It should work, no ?!

  • I don't understand how this is materially different from what I proposed. What am I missing? – David Rogers Jan 12 '11 at 01:22
  • 1
    The `except WindowsError` will never happen as WindowsError is a subclass of OSError, so the previous `except OSError' will be triggered instead. – Ethan Furman Jul 27 '11 at 19:49
0

In your previous post, you said the program raised a «WindowsError» exception:

WindowsError: [Error 5] Access is denied: 'prep_dat'

Your code can handle «OSError» exceptions using the «except» statement, but it cannot handle «WindowsError» exceptions... if you want to handle «WindowsError» exceptions, you must use the «except» statement like this:

        except WindowsError:
#           (do some stuff)

Note that you can handle any exception like this:

except Exception, e:
    # this code will catch all raised exceptions. The variable «e» contains an instance of the raised exception.