What would be the best way in Python to determine whether a directory is writeable for the user executing the script? Since this will likely involve using the os module I should mention I'm running it under a *nix environment.
12 Answers
Although what Christophe suggested is a more Pythonic solution, the os module does have the os.access function to check access:
os.access('/path/to/folder', os.W_OK)
# W_OK is for writing, R_OK for reading, etc.

- 939
- 1
- 14
- 25

- 37,799
- 10
- 82
- 91
-
6Depending on the situation, the "easier to ask for forgiveness" is not the best way, even in Python. It is sometimes advisable to "ask permission" as with the os.access() method mentioned, for example when the probability of having to catch an error is high. – mjv Feb 06 '10 at 19:32
-
66Testing a directory for just the write bit isn't enough if you want to write files to the directory. You will need to test for the execute bit as well if you want to write into the directory. os.access('/path/to/folder', os.W_OK | os.X_OK) With os.W_OK by itself you can only delete the directory (and only if that directory is empty) – fthinker Mar 23 '12 at 17:13
-
6Another gotcha of `os.access()` is it checks using the *real* UID and GID, not the *effective* ones. This could cause weirdness in SUID/SGID environments. (‘but the script runs setuid root, why can't it write to the file?’) – Alexios May 13 '16 at 08:37
-
I will look it up, but it would be useful to see what os.access() returns here in the solution. I presume it's a boolean. – Ray Salemi Oct 11 '16 at 14:31
-
10Maybe a program just wants to know without having the need to actually write. It might just want to change the look and/or behaviour of a GUI according to the property. In that case I would not consider it pythonic to write and delete a file just as a test. – Bachsau Apr 20 '18 at 17:43
-
5Just tested on a Windows network share. `os.access(dirpath, os.W_OK | os.X_OK)` returns True even if i have no write access. – iamanigeeit Oct 09 '18 at 08:50
-
3As already said, this give wrong results on Windows... Please add a comment in your answer, then I will remove the downvote. – schlamar Jan 10 '19 at 14:28
-
This solution does not work in case of network mapped drive! – nphaibk Aug 03 '23 at 22:07
It may seem strange to suggest this, but a common Python idiom is
It's easier to ask for forgiveness than for permission
Following that idiom, one might say:
Try writing to the directory in question, and catch the error if you don't have the permission to do so.

- 2,021
- 1
- 13
- 33

- 112,638
- 29
- 165
- 179
-
9+1 Python or not, this is really the most reliable way to test for access. – John Knoeller Jan 21 '10 at 22:32
-
8This also takes care of other errors that can happen when writing to the disk - no diskspace left for example. That's the power of trying .. you dont need to remember everything that can go wrong ;-) – Jochen Ritzel Jan 21 '10 at 23:37
-
4Thanks guys. Decided to go with os.access as speed is an important factor in what I'm doing here although I can certainly understand the merits in "it's easier to ask for forgiveness than for permission." ;) – illuminatedtiger Jan 22 '10 at 01:04
-
2@illuminatedtiger: that's perfectfly fine, just be aware of the notes in the documentation (http://docs.python.org/library/os.html#os.access) – ChristopheD Jan 22 '10 at 07:00
-
4It's a great IDIO...m - especially when coupled with another idiom `except: pass` - this way you can always be optimistic and think highly of yourself. /sarcasm off. Now why would I want to, e.g. try to write something into every directory in my filesystem, to produce a list of writable locations? – Tomasz Gandor Apr 05 '16 at 08:20
-
2@Tomasz Gandor: I don't think `except: pass` is a generally accepted idiom :-) (in any language). That being said, compiling a list of writable locations on your filesystem is doomed to be out of date from the moment you create it. What use case does this have? Even checking if you *can* write to a directory just one line before you try to write (in code) is not a guarantee of any sorts (since it is not an atomic operation). Just "trying" is still what you'll need to do anyway. – ChristopheD Apr 06 '16 at 00:07
-
2I agree. The right approach depends on a situation - if you want to write to the directory anyway - just go for it, and catch errors (EAFP). But, if you need to write to directories A, B, and C - and you only find out that C fails down the road - you may have wasted (computation) time and... money (think - cloud computing). Or you need to be able to clean up after such failed "transaction". Well, the last one you may need anyway; you may still loose permissions in TOCTOU. – Tomasz Gandor Apr 06 '16 at 07:41
-
10Maybe a program just wants to know without having the need to actually write. It might just want to change the look and/or behaviour of a GUI according to the property. In that case I would not consider it pythonic to write and delete a file just as a test. – Bachsau Apr 20 '18 at 17:44
-
1
-
An issue with this is you don't always get a 'Python' error that you can easily catch, per se. I mean, if you're doing such as `subprocess.run(...)` then Python won't throw permission errors for those subprocess calls. – Brōtsyorfuzthrāx Sep 02 '21 at 10:59
My solution using the tempfile
module:
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
Update:
After testing the code again on Windows I see that there is indeed an issue when using tempfile there, see issue22107: tempfile module misinterprets access denied error on Windows.
In the case of a non-writable directory, the code hangs for several seconds and finally throws an IOError: [Errno 17] No usable temporary file name found
. Maybe this is what user2171842 was observing?
Unfortunately the issue is not resolved for now so to handle this, the error needs to be caught as well:
except (OSError, IOError) as e:
if e.errno == errno.EACCES or e.errno == errno.EEXIST: # 13, 17
The delay is of course still present in these cases then.
-
1I think the one using tempfile is the cleaner because it for sure doesnt leave residuals. – grasshopper Dec 31 '14 at 00:59
-
4this method is not working using `tempfile`. it only works when there is no `OSError` meaning it has permission to write/delete. otherwise it will not `return False` because no error is returned, and the script won't continue to execute or exit. nothing is returned. it's just stuck at that line. however, creating a non-temporary file such as khattam's answer does work both when permission is allowed or denied. help? – May 06 '16 at 18:24
-
-
On Windows, with a non-writable directory the delays is NOT several seconds. I waited 30 minutes for this to return, before giving up and interrupting the code. Tested on Windows 11 with Python 3.10 and it still appears, after all these years, to be an [open bug](https://github.com/python/cpython/issues/66305). The workaround is to use a fixed filename like say 'write_text.txt' in place of a system generated temp filename, then when you execute 'open(filename,"w")' it throws error '[Errno 13] Permission denied:' – nwsmith Aug 25 '23 at 10:35
Check the mode bits:
import os, stat
def isWritable(dirname):
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)
)

- 21,897
- 23
- 83
- 145

- 25,416
- 6
- 48
- 54
Stumbled across this thread searching for examples for someone. First result on Google, congrats!
People talk about the Pythonic way of doing it in this thread, but no simple code examples? Here you go, for anyone else who stumbles in:
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")
This attempts to open a filehandle for writing, and exits with an error if the file specified cannot be written to: This is far easier to read, and is a much better way of doing it rather than doing prechecks on the file path or the directory, as it avoids race conditions; cases where the file becomes unwriteable between the time you run the precheck, and when you actually attempt to write to the file.

- 1,886
- 1
- 15
- 22
-
4This applies to a file, not directory which is what the OP asked. You can have a file in a directory and have the directory not be writable but the file itself is, should the file already exist. This may be important in systems administration where you're eg creating log files that you want to already exist but don't want people using a log directory for temp space. – Mike S Apr 11 '17 at 18:41
-
...and actually I voted it down, which I now think was a mistake. There are issues, as Rohaq mentioned, with race conditions. There are other issues on various platforms where you may test the directory, and it looks writable, but it actually isn't. Performing cross-platform directory writable checks is harder than it looks. So as long as you're aware of the issues, this may be a fine technique. I was looking at it from a too UNIX-y perspective, which is my mistake. Someone edit this answer so I can remove my -1. – Mike S Apr 12 '17 at 15:29
-
I've edited it, in case you want to remove the -1 :) And yes, cross-platform directory checks can get more complicated, but generally you're looking to create/write to a file in that directory - in which case the example I've given should still apply. If some directory permission related issue comes up, it should still throw an IOError when attempting to open the filehandle. – Rohaq Apr 22 '17 at 04:13
-
1I removed my downvote. Sorry about that, and thanks for your contribution. – Mike S Apr 24 '17 at 16:01
-
1
If you only care about the file perms, os.access(path, os.W_OK)
should do what you ask for. If you instead want to know whether you can write to the directory, open()
a test file for writing (it shouldn't exist beforehand), catch and examine any IOError
, and clean up the test file afterwards.
More generally, to avoid TOCTOU attacks (only a problem if your script runs with elevated privileges -- suid or cgi or so), you shouldn't really trust these ahead-of-time tests, but drop privs, do the open()
, and expect the IOError
.

- 491
- 2
- 6
Here is something I created based on ChristopheD's answer:
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"

- 1,164
- 1
- 8
- 14
if os.access(path_to_folder, os.W_OK) is not True:
print("Folder not writable")
else :
print("Folder writable")
more info about access can be find it here

- 1,658
- 20
- 20
-
5This is basically a copy of Max Shawabkeh's answer with a little wrapper around it. Makes it a quick copy paste but a better idea would be to have added it to the original post of Max. – Jorrick Sleijster Aug 20 '17 at 18:21
-
1This does not work on Windows. I set 'Deny Write' on the folder, but the above code still says it's writable! – nwsmith Aug 25 '23 at 09:43
I ran into this same need while adding an argument via argparse. The built in type=FileType('w')
wouldn't work for me as I was looking for a directory. I ended up writing my own method to solve my problem. Here is the result with argparse snippet.
#! /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()
That results in the following:
$ 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 ~
I went back and added print opts.dir to the end, and everything appears to be functioning as desired.

- 4,950
- 3
- 27
- 36

- 21
- 2
If you need to check the permission of another user (yes, I realize this contradicts the question, but may come in handy for someone), you can do it through the pwd
module, and the directory's mode bits.
Disclaimer - does not work on Windows, as it doesn't use the POSIX permissions model (and the pwd
module is not available there), e.g. - solution only for *nix systems.
Note that a directory has to have all the 3 bits set - Read, Write and eXecute.
Ok, R is not an absolute must, but w/o it you cannot list the entries in the directory (so you have to know their names). Execute on the other hand is absolutely needed - w/o it the user cannot read the file's inodes; so even having W, without X files cannot be created or modified. More detailed explanation at this link.
Finally, the modes are available in the stat
module, their descriptions are in inode(7) man.
Sample code how to check:
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

- 19,097
- 3
- 55
- 60
check if a stat object is readable or writable
useful to check if a pipe is readable or writable
import os, stat
def check_access(s, check="r"):
"check if s=os.stat(path) is readable or writable"
u = os.geteuid(); g = os.getegid(); m = s.st_mode
if check == "r":
return (
((s[stat.ST_UID] == u) and (m & stat.S_IRUSR)) or
((s[stat.ST_GID] == g) and (m & stat.S_IRGRP)) or
(m & stat.S_IROTH)
) != 0
if check == "w":
return (
((s[stat.ST_UID] == u) and (m & stat.S_IWUSR)) or
((s[stat.ST_GID] == g) and (m & stat.S_IWGRP)) or
(m & stat.S_IWOTH)
) != 0
s = os.stat(0) # fd 0 == stdin
print(f"fd 0 is readable?", check_access(s, "r"))
s = os.stat(1) # fd 1 == stdout
print(f"fd 1 is writable?", check_access(s, "w"))
os.write(1, b"hello\n")
based on the answer by Joe Koberg
see also: same thing in javascript
probably breaks on windows

- 2,447
- 1
- 18
- 25