web-dev-qa-db-fra.com

shutil.rmtree échoue sous Windows avec 'Accès refusé'

En Python, lors de l'exécution de shutil.rmtree sur un dossier contenant un fichier en lecture seule, l'exception suivante est imprimée:

 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'

Recherche dans la boîte de dialogue Propriétés du fichier J'ai remarqué que le fichier af.msg est configuré pour être en lecture seule. 

La question est donc la suivante: quel est le le plus simple solution de contournement/correctif pour contourner ce problème - étant donné que mon intention est de créer un équivalent de rm -rf build/ mais sous Windows? (sans avoir à utiliser d'outils tiers tels que unxutils ou cygwin, car ce code est destiné à être exécuté sur une installation Windows nue avec Python 2.6 avec PyWin32 installé)

57
Sridhar Ratnakumar

Vérifiez cette question:

Quel utilisateur les scripts python s'exécutent-ils comme dans windows?

Apparemment, la solution consiste à modifier le fichier/dossier pour qu'il ne soit pas en lecture seule, puis à le supprimer.

Voici le gestionnaire onerror() de pathutils.py mentionné par @Sridhar Ratnakumar dans les commentaires:

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
    if not os.access(path, os.W_OK):
        # Is the error an access error ?
        os.chmod(path, stat.S_IWUSR)
        func(path)
    else:
        raise
71
Justin Peel

Je dirais que vous devez implémenter votre propre répertoire avec os.walk qui garantit l’accès en utilisant os.chmod sur chaque fichier avant de tenter de le supprimer.

Quelque chose comme ça (non testé):

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)      
22
Epcylon

Eh bien, la solution marquée ne fonctionnait pas pour moi ... a fait ceci à la place:

os.system('rmdir /S /Q "{}"'.format(directory))
9
AlexeiOst
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

Si ignore_errors est défini, les erreurs sont ignorées. sinon, en cas d'erreur est défini, il est appelé pour traiter l'erreur avec des arguments (func, path, exc_info) où func est os.listdir, os.remove ou os.rmdir; chemin est l'argument de cette fonction qui a provoqué son échec; et exc_info est un tuple renvoyé par sys.exc_info (). Si ignore_errors est false et onerror est None, une exception est levée.entrez le code ici

0
RongyanZheng