ZetCode

Python os.access Function

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.

Basic Definitions

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.

Checking File Existence

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

# Check if file exists
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")

# Create file if it doesn't 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.

Testing Read Permissions

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"

# Check read permission
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}")

# Alternative approach using try/except
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.

Testing Write Permissions

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"

# Check file write permission
if os.access(file_path, os.W_OK):
    print(f"Can write to {file_path}")
else:
    print(f"Cannot write to {file_path}")

# Check directory write permission
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.

Testing Execute Permissions

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"

# Check file execute permission
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}")

# Check directory search permission
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.

Combining Permission Flags

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"

# Check read and write permissions
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}")

# Check all permissions
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.

Real vs Effective IDs

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)}")

# Temporarily drop privileges
os.seteuid(os.getuid())

print("\nAfter privilege drop:")
show_ids()
print(f"Accessible: {os.access(file_path, os.R_OK)}")

# Restore privileges
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.

Security Considerations

Best Practices

Source References

Author

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.