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

74,080

Solution 1

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

Solution 2

I'd say implement your own rmtree with os.walk that ensures access by using os.chmod on each file before trying to delete it.

Something like this (untested):

import os
import stat

def rmtree(top):
    for root, dirs, files in os.walk(top, topdown=False):
        for name in files:
            filename = os.path.join(root, name)
            os.chmod(filename, stat.S_IWUSR)
            os.remove(filename)
        for name in dirs:
            os.rmdir(os.path.join(root, name))
    os.rmdir(top)      

Solution 3

Well, the marked solution did not work for me... did this instead:

os.system('rmdir /S /Q "{}"'.format(directory))

Solution 4

shutil.rmtree(path,ignore_errors=False,onerror=errorRemoveReadonly) 
def errorRemoveReadonly(func, path, exc):
    excvalue = exc[1]
    if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
        # change the file to be readable,writable,executable: 0777
        os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  
        # retry
        func(path)
    else:
        raiseenter code here

If ignore_errors is set, errors are ignored; otherwise, if onerror is set, it is called to handle the error with arguments (func, path, exc_info) where func is os.listdir, os.remove, or os.rmdir; path is the argument to that function that caused it to fail; and exc_info is a tuple returned by sys.exc_info(). If ignore_errors is false and onerror is None, an exception is raised.enter code here

Share:
74,080

Related videos on Youtube

Sridhar Ratnakumar
Author by

Sridhar Ratnakumar

Updated on July 05, 2022

Comments

  • Sridhar Ratnakumar
    Sridhar Ratnakumar almost 2 years

    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)

    • jfs
      jfs about 14 years
      shutil.rmtree uses os.remove to remove files. os.remove removes read-only files just fine (at least on Unix). os.remove can't remove file on Windows if it is in use.
    • Stevoisiak
      Stevoisiak about 6 years
    • Ali_Sh
      Ali_Sh over 2 years
      As I experienced, perhaps, this error will be appeared if the directory is open and you run the the code and is related to removing process, not the creation step.
  • Daniel G
    Daniel G about 14 years
    This is nearly right - Windows only supports stat.S_IWRITE (which is what you want anyway) - docs.python.org/library/os.html#os.chmod
  • Sridhar Ratnakumar
    Sridhar Ratnakumar about 14 years
    Heh. I just discovered the onerror handler at voidspace.org.uk/downloads/pathutils.py
  • Sridhar Ratnakumar
    Sridhar Ratnakumar about 14 years
  • Epcylon
    Epcylon about 14 years
    I did test that os.chmod(filename, stat.S_IWUSR) removed the read-only flag, so it does work on WinXP. And considering this is what the docs say about stat.S_IWRITE: "Unix V7 synonym for S_IWUSR" (docs.python.org/library/stat.html#stat.S_IWRITE), I'm thinking my code is right anyway.
  • Pakman
    Pakman over 10 years
    Even though the comments for this answer state 'change the file/folder to not be read-only', I still received access denied on read-only folders. This implementation worked, though.
  • Adam
    Adam almost 10 years
    A word of warning to those copy-pasting this function as is, move the import stat out of the function. I was receiving RuntimeError: sys.meta_path must be a list of import hooks when I'd left the import within the function AND the function was within the __del__ method of a class.
  • Anthony
    Anthony about 9 years
    Great, with file paths that are too long this seems like the only way. A recommendation to commit to or change shutil.rmtree perhaps.
  • GDICommander
    GDICommander almost 9 years
    The "else raise" part of the solution will not raise the exception. Coming from the Python documentation: "Exceptions raised by onerror will not be caught." docs.python.org/2/library/shutil.html#shutil.rmtree
  • omerfarukdogan
    omerfarukdogan over 5 years
    Calling rm -rf on Windows? I don't think so.
  • Dustin Michels
    Dustin Michels over 5 years
    Very strange. I use a unix-like console emulator for Windows (cmder). The subprocess.call approach works when I run the script from that console, but not if I run it from the default "Command Prompt"
  • besil
    besil over 5 years
    Have you tried before downvoting? I confirm it works under Windows
  • omerfarukdogan
    omerfarukdogan over 5 years
    @besil, yes, call('rm -rf "C:\\Temp\\tmp7cm15k\\"', shell=True) results in 'rm' is not recognized as an internal or external command, operable program or batch file.
  • besil
    besil over 5 years
    mh, I think it works for me because I use Cygwin as terminal emulator instead of command prompt
  • Richard Jessop
    Richard Jessop about 5 years
    @besil: qualify your suggestion to running under cygwin or some other windows-ported unix shell.
  • besil
    besil about 5 years
    @RichardJessop just use Cygwin instead of Windows Command Prompt for launching your python script. Cygwin has 'rm' and other unix utilities in the path, so when the py script do 'call system rm', rm is effectively found
  • Helping Hands
    Helping Hands over 4 years
    This removed the directory itself. Can you please tell how to remove all dir and files inside a directory? For example if I give path : myproject/dir1/ then it removes dir1 but I want to delete everything which is under dir1.
  • Alper
    Alper over 3 years
    This works with stat.S_IWRITE in python 2.7 in windows 10 for read-only files.
  • Mario Orlandi
    Mario Orlandi over 3 years
    Nice, but fails in presence of nested subfolders ... unless you recourse deletion by replacing "os.rmdir(os.path.join(root, name))" with "rmtree(os.path.join(root, name))"
  • Epcylon
    Epcylon over 3 years
    Have you tried it and gotten an error? The code walks the tree from the bottom up, so all directories are empty by the time we run os.rmdir on them, assuming everything else works.
  • Maryam Bahrami
    Maryam Bahrami about 3 years
    Be very careful using this function. This function goes to every subfolder and delete the files in there.
  • Epcylon
    Epcylon about 3 years
    Maryam Bahrami: Yes, that is the purpose of the rmtree function. If this is not what you want, why are you using it?
  • Mawg says reinstate Monica
    Mawg says reinstate Monica about 2 years
    Personally, I find it easier just to delete the directory and recreate it (although you do lose the timestamp that way)