Search code examples
pythonwindowsfile-permissionsshutil

shutil.rmtree fails on Windows with 'Access is denied'


In Python, when running shutil.rmtree over a folder that contains a read-only file, the following exception is printed:

 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 221, in rmtree
   onerror(os.remove, fullname, sys.exc_info())
 File "C:\Python26\lib\shutil.py", line 219, in rmtree
   os.remove(fullname)
WindowsError: [Error 5] Access is denied: 'build\\tcl\\tcl8.5\\msgs\\af.msg'

Looking in File Properties dialog I noticed that af.msg file is set to be read-only.

So the question is: what is the simplest workaround/fix to get around this problem - given that my intention is to do an equivalent of rm -rf build/ but on Windows? (without having to use third-party tools like unxutils or cygwin - as this code is targeted to be run on a bare Windows install with Python 2.6 w/ PyWin32 installed)


Solution

  • Check this question out: What user do python scripts run as in windows?

    Apparently the answer is to change the file/folder to not be read-only and then remove it.

    Here's onerror() handler from pathutils.py mentioned by @Sridhar Ratnakumar in comments:

    def onerror(func, path, exc_info):
        """
        Error handler for ``shutil.rmtree``.
    
        If the error is due to an access error (read only file)
        it attempts to add write permission and then retries.
    
        If the error is for another reason it re-raises the error.
        
        Usage : ``shutil.rmtree(path, onerror=onerror)``
        """
        import stat
        # Is the error an access error?
        if not os.access(path, os.W_OK):
            os.chmod(path, stat.S_IWUSR)
            func(path)
        else:
            raise