135 votes

Détermination si un répertoire est inscriptible

Quel serait le meilleur moyen en Python de déterminer si un répertoire est accessible en écriture pour l'utilisateur exécutant le script ? Puisque cela impliquera probablement l'utilisation du module os, je devrais mentionner que je l'exécute sous un environnement *nix.

241voto

Max Shawabkeh Points 19030

Bien que la solution proposée par Christophe soit plus Pythonique, le module os possède tout de même la fonction os.access pour vérifier l'accès :

os.access('/chemin/vers/dossier', os.W_OK) # W_OK pour l'écriture, R_OK pour la lecture, etc.

6 votes

Selon la situation, il n'est pas toujours préférable de "demander pardon" par facilité, même en Python. Il est parfois conseillé de "demander la permission" comme avec la méthode os.access() mentionnée, par exemple lorsque la probabilité de devoir attraper une erreur est élevée.

70 votes

Tester un répertoire pour savoir uniquement s'il a le droit d'écriture ne suffit pas si vous voulez écrire des fichiers dans le répertoire. Vous devrez également tester le bit d'exécution si vous voulez écrire dans le répertoire. os.access('/chemin/vers/dossier', os.W_OK | os.X_OK) Avec os.W_OK seul, vous ne pouvez que supprimer le répertoire (et seulement s'il est vide)

6 votes

Une autre difficulté de os.access() est qu'elle vérifie en utilisant l'UID et le GID réels, et non pas les effectifs. Cela pourrait causer des bizarreries dans des environnements SUID/SGID. ('mais le script s'exécute en tant que root setuid, pourquoi ne peut-il pas écrire dans le fichier ?')

86voto

ChristopheD Points 38217

Il peut sembler étrange de suggérer cela, mais un idiome Python courant est

Il est plus facile de demander pardon que la permission

En suivant cet idiome, on pourrait dire :

Essayez d'écrire dans le répertoire en question, et capturez l'erreur si vous n'avez pas la permission de le faire.

9 votes

+1 Python ou non, c'est vraiment le moyen le plus fiable de tester l'accès.

9 votes

Cela prend également en charge d'autres erreurs qui peuvent survenir lors de l'écriture sur le disque - pas d'espace disque par exemple. C'est la puissance d'essayer .. vous n'avez pas besoin de tout retenir ce qui pourrait mal se passer ;-)

4 votes

Merci les gars. J'ai décidé d'utiliser os.access car la vitesse est un facteur important dans ce que je fais ici, bien que je puisse certainement comprendre les mérites de "il est plus facile de demander pardon que la permission". ;)

28voto

zak Points 1

Ma solution utilisant le module tempfile :

import tempfile
import errno

def isWritable(path):
    try:
        testfile = tempfile.TemporaryFile(dir = path)
        testfile.close()
    except OSError as e:
        if e.errno == errno.EACCES:  # 13
            return False
        e.filename = path
        raise
    return True

Mise à jour : Après avoir testé à nouveau le code sur Windows, je vois qu'il y a effectivement un problème lors de l'utilisation de tempfile là-bas, voir issue22107 : le module tempfile interprète mal l'erreur d'accès refusé sur Windows. Dans le cas d'un répertoire non inscriptible, le code se bloque pendant plusieurs secondes et lance enfin une IOError : [Errno 17] No usable temporary file name found. Peut-être que c'est ce que l'utilisateur2171842 observait ? Malheureusement, le problème n'est pas résolu pour le moment, afin de gérer cela, l'erreur doit également être capturée :

    except (OSError, IOError) as e:
        if e.errno == errno.EACCES or e.errno == errno.EEXIST:  # 13, 17

Le délai est bien sûr toujours présent dans ces cas-là.

1 votes

Je pense que celui qui utilise tempfile est le plus propre car il ne laisse certainement pas de résidus.

4 votes

Cette méthode ne fonctionne pas en utilisant tempfile. cela ne fonctionne que s'il n'y a pas d'OSError, ce qui signifie qu'il a l'autorisation d'écrire/supprimer. sinon, il ne va pas return False parce qu'aucune erreur n'est renvoyée, et le script ne continuera pas à s'exécuter ou à sortir. rien n'est renvoyé. il reste juste bloqué à cette ligne. cependant, la création d'un fichier non temporaire comme la réponse de khattam fonctionne que la permission soit autorisée ou refusée. aidez-moi?

0 votes

Cela peut également provoquer OSError: [Errno 30] système de fichiers en lecture seule

10voto

sverkerw Points 441

Si vous vous souciez uniquement des autorisations sur le fichier, os.access(chemin, os.W_OK) devrait faire ce que vous demandez. Si vous voulez plutôt savoir si vous pouvez écrire dans le répertoire, open() un fichier de test en écriture (il ne devrait pas exister auparavant), attrapez et examinez toute IOError, puis nettoyez le fichier de test après.

Plus généralement, pour éviter les attaques TOCTOU (seulement un problème si votre script s'exécute avec des privilèges élevés -- suid ou cgi ou autre), vous ne devriez pas vraiment faire confiance à ces tests effectués à l'avance, mais baisser les privilèges, faire le open(), et attendre l' IOError.

10voto

Rohaq Points 568

Tombé sur ce fil en cherchant des exemples pour quelqu'un. Premier résultat sur Google, félicitations!

Les gens parlent de la façon pythonique de le faire dans ce fil, mais pas d'exemples de code simples? Le voici, pour quiconque tomberait dessus :

import sys

chemin_du_fichier = 'C:\\chemin\\vers\\votre\\fichier.txt'

try:
    handlefichier = open( chemin_du_fichier, 'w' )
except IOError:
    sys.exit( 'Impossible d'écrire dans le fichier ' + chemin_du_fichier )

handlefichier.write("J'écris ce texte dans le fichier\n")

Cela tente d'ouvrir un handlefichier pour l'écriture, et quitte avec une erreur si le fichier spécifié ne peut pas être écrit: C'est bien plus facile à lire, et c'est une bien meilleure façon de le faire plutôt que de faire des prévérifications sur le chemin du fichier ou le répertoire, car cela évite les conditions de course; des cas où le fichier devient inécrivable entre le moment où vous exécutez la prévérification, et lorsque vous tentez réellement d'écrire dans le fichier.

4 votes

Cela s'applique à un fichier, et non à un répertoire, ce qui est ce que l'OP a demandé. Vous pouvez avoir un fichier dans un répertoire et le répertoire n'est pas inscriptible, mais le fichier lui-même l'est, s'il existe déjà. Cela peut être important dans l'administration des systèmes lorsque, par exemple, vous créez des fichiers journaux qui doivent déjà exister mais que vous ne voulez pas que les gens utilisent un répertoire de journaux pour stocker des fichiers temporaires.

0 votes

...et en fait j'ai voté contre, ce que je pense maintenant être une erreur. Il y a des problèmes, comme l'a mentionné Rohaq, avec les conditions de course. Il y a d'autres problèmes sur diverses plates-formes où vous pouvez tester le répertoire, et il semble qu'il soit inscriptible, mais en réalité ce n'est pas le cas. Effectuer des vérifications d'écriture de répertoire interplateformes est plus difficile qu'il n'y paraît. Donc tant que vous êtes conscient des problèmes, cette technique peut être valable. Je l'ai examiné d'un point de vue trop UNIX-y, ce qui est mon erreur. Quelqu'un modifie cette réponse pour que je puisse retirer mon -1.

0 votes

J'ai modifié cela, au cas où vous voudriez supprimer le -1 :) Et oui, les vérifications de répertoires multiplateformes peuvent devenir plus compliquées, mais en général, vous cherchez à créer/écrire dans un fichier dans ce répertoire - auquel cas l'exemple que j'ai donné devrait toujours s'appliquer. Si un problème lié aux autorisations du répertoire se présente, il devrait toujours générer une IOError lors de la tentative d'ouverture du handle de fichier.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X