Каким будет лучший способ в Python определить, является ли каталог доступным для пользователя, выполняющего script? Поскольку это, скорее всего, связано с использованием модуля os, я должен упомянуть, что я запускаю его в среде * nix.
Определение того, является ли каталог доступным для записи
Ответ 1
Хотя то, что предложил Кристоф, является более Pythonic решением, модуль os имеет функцию os.access для проверки доступа:
os.access('/path/to/folder', os.W_OK)
# W_OK для записи, R_OK для чтения и т.д.
Ответ 2
Может показаться странным предположить это, но общая идиома Python -
Проще просить прощения чем для разрешения
Следуя этой идиоме, можно сказать:
Попробуйте записать в соответствующий каталог и поймайте ошибку, если у вас нет разрешения на это.
Ответ 3
Мое решение с использованием модуля 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
Обновление: после повторного тестирования кода в Windows я вижу, что действительно существует проблема при использовании там временного файла, см. Проблему 22107: модуль временного файла неверно интерпретирует ошибку "отказ в доступе" в Windows. В случае IOError: [Errno 17] No usable temporary file name found
для записи директории код зависает на несколько секунд и, наконец, выдает IOError: [Errno 17] No usable temporary file name found
. Может быть, это то, что наблюдал пользователь 2171842? К сожалению, проблема пока не решена, поэтому для решения этой проблемы также необходимо отследить ошибку:
except (OSError, IOError) as e:
if e.errno == errno.EACCES or e.errno == errno.EEXIST: # 13, 17
Задержка, конечно, все еще присутствует в этих случаях.
Ответ 4
Наткнулся на этот поток, ища примеры для кого-то. Первый результат в Google, поздравляю!
Люди говорят о питоническом способе делать это в этой теме, но нет простых примеров кода? Здесь вы идете, для всех, кто спотыкается:
import sys
filepath = 'C:\\path\\to\\your\\file.txt'
try:
filehandle = open( filepath, 'w' )
except IOError:
sys.exit( 'Unable to write to file ' + filepath )
filehandle.write("I am writing this text to the file\n")
Это попытка открыть дескриптор файла для записи и выйти с ошибкой, если указанный файл не может быть записан: Это намного проще читать, и это гораздо лучший способ сделать это, а не делать предварительные проверки на пути к файлу или каталог, поскольку он позволяет избежать условий гонки; случаи, когда файл становится невосприимчивым между моментом запуска предварительной проверки и когда вы пытаетесь записать файл.
Ответ 5
Если вы только заботитесь о файлах perms, os.access(path, os.W_OK)
должен делать то, о чем вы просите. Если вы хотите узнать, можете ли вы умеете записывать в каталог, open()
тестовый файл для записи (он не должен существовать заранее), поймайте и изучите любой IOError
, и очистите затем файл теста.
В более общем плане, чтобы избежать TOCTOU атак (только проблема, если ваш script работает с повышенными привилегиями - suid или cgi или так что), вы не должны действительно доверять этим проверкам времени, но откажитесь от утилов, сделайте open()
и ожидайте IOError
.
Ответ 6
Проверьте бит режима:
def isWritable(name):
uid = os.geteuid()
gid = os.getegid()
s = os.stat(dirname)
mode = s[stat.ST_MODE]
return (
((s[stat.ST_UID] == uid) and (mode & stat.S_IWUSR)) or
((s[stat.ST_GID] == gid) and (mode & stat.S_IWGRP)) or
(mode & stat.S_IWOTH)
)
Ответ 7
Вот что я создал на основе ответа ChristopheD:
import os
def isWritable(directory):
try:
tmp_prefix = "write_tester";
count = 0
filename = os.path.join(directory, tmp_prefix)
while(os.path.exists(filename)):
filename = "{}.{}".format(os.path.join(directory, tmp_prefix),count)
count = count + 1
f = open(filename,"w")
f.close()
os.remove(filename)
return True
except Exception as e:
#print "{}".format(e)
return False
directory = "c:\\"
if (isWritable(directory)):
print "directory is writable"
else:
print "directory is not writable"
Ответ 8
if os.access(path_to_folder, os.W_OK) is not True:
print("Folder not writable")
else :
print("Folder writable")
больше информации о доступе можно найти здесь
Ответ 9
Я столкнулся с этой же необходимостью при добавлении аргумента через argparse. Встроенный type=FileType('w')
не будет работать для меня, так как я искал каталог. Я закончил писать свой собственный метод, чтобы решить мою проблему. Вот результат с фрагментом argparse.
#! /usr/bin/env python
import os
import argparse
def writable_dir(dir):
if os.access(dir, os.W_OK) and os.path.isdir(dir):
return os.path.abspath(dir)
else:
raise argparse.ArgumentTypeError(dir + " is not writable or does not exist.")
parser = argparse.ArgumentParser()
parser.add_argument("-d","--dir", type=writable_dir(), default='/tmp/',
help="Directory to use. Default: /tmp")
opts = parser.parse_args()
Это приводит к следующему:
$ python dir-test.py -h
usage: dir-test.py [-h] [-d DIR]
optional arguments:
-h, --help show this help message and exit
-d DIR, --dir DIR Directory to use. Default: /tmp
$ python dir-test.py -d /not/real
usage: dir-test.py [-h] [-d DIR]
dir-test.py: error: argument -d/--dir: /not/real is not writable or does not exist.
$ python dir-test.py -d ~
Я вернулся и добавил print opts.dir до конца, и все, кажется, функционирует так, как нужно.
Ответ 10
Если вам нужно проверить разрешение другого пользователя (да, я понимаю, что это противоречит вопросу, но может пригодиться кому-то), вы можете сделать это через модуль pwd
и биты режима каталога.
Отказ от ответственности - не работает в Windows, так как он не использует модель разрешений POSIX (а модуль pwd
там недоступен), например. - решение только для систем * nix.
Обратите внимание, что в каталоге должны быть установлены все 3 бита - Чтение, Запись и eXecute.
Хорошо, R не является абсолютным обязательным, но без него вы не можете перечислить записи в каталоге (чтобы вы знали их имена). Выполнение с другой стороны абсолютно необходимо - без него пользователь не может прочитать файл inodes; поэтому даже наличие W без X файлов не может быть создано или изменено. Более подробное объяснение по этой ссылке.
Наконец, режимы доступны в модуле stat
, их описания находятся в файле inode (7).
Пример кода, как проверить:
import pwd
import stat
import os
def check_user_dir(user, directory):
dir_stat = os.stat(directory)
user_id, group_id = pwd.getpwnam(user).pw_uid, pwd.getpwnam(user).pw_gid
directory_mode = dir_stat[stat.ST_MODE]
# use directory_mode as mask
if user_id == dir_stat[stat.ST_UID] and stat.S_IRWXU & directory_mode == stat.S_IRWXU: # owner and has RWX
return True
elif group_id == dir_stat[stat.ST_GID] and stat.S_IRWXG & directory_mode == stat.S_IRWXG: # in group & it has RWX
return True
elif stat.S_IRWXO & directory_mode == stat.S_IRWXO: # everyone has RWX
return True
# no permissions
return False