Complete guide to Python's os.access function covering file permission checks, path testing, and practical examples.
Last modified April 11, 2025
This comprehensive guide explores Python’s os.access function, which tests path accessibility and permissions. We’ll cover permission flags, effective vs real IDs, and practical file system testing examples.
The os.access function checks if the calling user has specified access rights to a path. It uses the real UID/GID rather than effective IDs.
Key parameters: path (file/directory to check), mode (permission flags: F_OK, R_OK, W_OK, X_OK). Returns True if access is allowed, False otherwise.
The simplest use of os.access verifies if a file exists using the F_OK mode flag. This is similar to os.path.exists but with different underlying implementation.
file_exists.py
import os
file_path = “example.txt” if os.access(file_path, os.F_OK): print(f"{file_path} exists") else: print(f"{file_path} does not exist")
if not os.access(file_path, os.F_OK): with open(file_path, “w”) as f: f.write(“Hello World”) print(f"Created {file_path}")
This example first checks for file existence, then creates the file if missing. Note that between the check and creation, the file state could change (TOCTOU).
For most cases, directly attempting the operation (like open) and handling exceptions is preferred over this two-step approach.
The R_OK mode tests if the file is readable by the current user. This checks both file permissions and parent directory traversal permissions.
read_permission.py
import os
file_path = “data.txt”
if os.access(file_path, os.R_OK): print(f"Can read {file_path}") with open(file_path) as f: print(f.read()) else: print(f"Cannot read {file_path}")
try: with open(file_path) as f: print(f.read()) except PermissionError: print(f"Permission denied for {file_path}") except FileNotFoundError: print(f"{file_path} not found")
The first approach uses os.access to check permissions before reading. The second shows the EAFP (Easier to Ask for Forgiveness than Permission) style.
The EAFP approach is generally preferred in Python as it avoids race conditions between check and operation.
The W_OK mode verifies if the file is writable. For directories, it checks if files can be created. This example demonstrates both cases.
write_permission.py
import os
file_path = “output.log” dir_path = “logs”
if os.access(file_path, os.W_OK): print(f"Can write to {file_path}") else: print(f"Cannot write to {file_path}")
if os.access(dir_path, os.W_OK): print(f"Can create files in {dir_path}") new_file = os.path.join(dir_path, “new.log”) with open(new_file, “w”) as f: f.write(“Log entry”) else: print(f"Cannot create files in {dir_path}")
This checks write permissions for both a file and directory. For directories, W_OK means new files can be created, not that existing files can be modified.
Remember that permission checks can become invalid between the check and actual write operation due to system changes.
The X_OK mode checks execute/search permissions. For files, this means executable binaries. For directories, it means traversal/search permission.
execute_permission.py
import os
script_path = “myscript.sh” dir_path = “/usr/local/bin”
if os.access(script_path, os.X_OK): print(f"Can execute {script_path}") os.system(f"./{script_path}") else: print(f"Cannot execute {script_path}")
if os.access(dir_path, os.X_OK): print(f"Can access {dir_path}") print(os.listdir(dir_path)) else: print(f"Cannot access {dir_path}")
The first part checks if a script is executable. The second verifies directory traversal permission, which is needed to list directory contents.
Execute permission on directories is separate from read permission - you need both to list and access contents.
Multiple permission flags can be combined using bitwise OR (|) to test several permissions at once. This is more efficient than multiple separate calls.
combined_permissions.py
import os
file_path = “config.json”
if os.access(file_path, os.R_OK | os.W_OK): print(f"Can read and write {file_path}") with open(file_path, “r+”) as f: data = f.read() f.seek(0) f.write(data.upper()) else: print(f"Missing required permissions for {file_path}")
all_perms = os.F_OK | os.R_OK | os.W_OK | os.X_OK if os.access(file_path, all_perms): print(f"Has full access to {file_path}") else: print(f"Doesn’t have full access to {file_path}")
The first check combines read and write permissions. The second demonstrates checking all possible permissions at once using bitwise OR operations.
Combining flags reduces system calls and potential race conditions between separate permission checks.
os.access uses real UID/GID rather than effective IDs. This example demonstrates the difference by temporarily dropping privileges.
real_vs_effective.py
import os import pwd
def show_ids(): print(f"Real UID: {os.getuid()}, Effective UID: {os.geteuid()}") print(f"Real GID: {os.getgid()}, Effective GID: {os.getegid()}")
file_path = “/root/.bashrc”
print(“Before privilege drop:”) show_ids() print(f"Accessible: {os.access(file_path, os.R_OK)}")
os.seteuid(os.getuid())
print("\nAfter privilege drop:") show_ids() print(f"Accessible: {os.access(file_path, os.R_OK)}")
os.seteuid(0)
This script shows how os.access behaves differently than actual operations when effective UID changes. It requires root privileges to demonstrate fully.
The key takeaway is that os.access checks based on real user, while actual file operations use effective user privileges.
TOCTOU risks: File state can change between check and use
Real vs effective: os.access uses real UID/GID, not effective
Prefer EAFP: Direct operations with exception handling are safer
Limited use cases: Mainly for user feedback, not security
Cross-platform: Behavior may vary between Unix and Windows
Use sparingly: Prefer direct operations with try/except
Combine flags: Test multiple permissions in one call
Document assumptions: Clearly note permission requirements
Consider alternatives: For security checks, use os.geteuid
Handle edge cases: Account for symlinks and special files
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.