ZetCode

Python os.symlink Function

Last modified April 11, 2025

This comprehensive guide explores Python's os.symlink function, which creates symbolic links (symlinks) between files. We'll cover link types, cross-platform behavior, and practical file system linking examples.

Basic Definitions

The os.symlink function creates a symbolic link pointing to a target file or directory. Symlinks are references that act like the target.

Key parameters: src (target path), dst (link path), target_is_directory (Windows-specific flag). Requires appropriate permissions on both paths.

Creating a Basic File Symlink

The simplest use of os.symlink creates a symbolic link to a file. This example shows basic link creation and verification.

basic_symlink.py
import os

# Create target file
target = "original.txt"
with open(target, "w") as f:
    f.write("This is the original file")

# Create symbolic link
link = "link_to_original.txt"
os.symlink(target, link)

# Verify link
if os.path.islink(link):
    print(f"{link} is a symlink pointing to {os.readlink(link)}")
    with open(link) as f:
        print(f"Content: {f.read()}")
else:
    print("Symlink creation failed")

This creates a target file, then a symlink pointing to it. The code verifies the link and reads through it. Symlinks behave like the target file.

Note that symlinks can become broken if the target is moved or deleted.

Creating a Directory Symlink

Symlinks can also point to directories. This example demonstrates directory symlink creation and traversal.

dir_symlink.py
import os

# Create target directory
target_dir = "original_dir"
os.makedirs(target_dir, exist_ok=True)

# Create file in target
with open(os.path.join(target_dir, "file.txt"), "w") as f:
    f.write("File in original directory")

# Create directory symlink
link_dir = "link_to_dir"
os.symlink(target_dir, link_dir, target_is_directory=True)

# Verify and use directory symlink
if os.path.islink(link_dir):
    print(f"{link_dir} links to {os.readlink(link_dir)}")
    print("Contents:", os.listdir(link_dir))
    with open(os.path.join(link_dir, "file.txt")) as f:
        print(f.read())
else:
    print("Directory symlink creation failed")

This creates a directory, adds a file to it, then makes a symlink to the directory. The code verifies the link and accesses files through it.

On Windows, target_is_directory=True is required for directory symlinks.

Relative vs Absolute Symlinks

Symlinks can use either relative or absolute paths. This affects behavior when files are moved. This example shows both approaches.

relative_absolute.py
import os

# Setup directories
os.makedirs("data/files", exist_ok=True)
with open("data/files/target.txt", "w") as f:
    f.write("Target file content")

# Create relative symlink
os.symlink("files/target.txt", "data/relative_link.txt")

# Create absolute symlink
abs_path = os.path.abspath("data/files/target.txt")
os.symlink(abs_path, "data/absolute_link.txt")

# Verify links
print("Relative link points to:", os.readlink("data/relative_link.txt"))
print("Absolute link points to:", os.readlink("data/absolute_link.txt"))

# Change working directory and test
os.chdir("data")
print("\nAfter changing directory:")
print("Relative still works:", open("relative_link.txt").read())
print("Absolute still works:", open("absolute_link.txt").read())

Relative links maintain their relationship when the containing directory moves. Absolute links break if the target moves but work from any location.

Choose relative links for portable directory structures, absolute for fixed locations.

Handling Symlink Existence

Attempting to create a symlink where one exists raises FileExistsError. This example shows proper handling of existing symlinks.

existing_symlinks.py
import os
import errno

target = "target_file.txt"
link = "existing_link.txt"

# Create initial file and link
with open(target, "w") as f:
    f.write("Original content")
os.symlink(target, link)

# Safe symlink creation function
def create_symlink(src, dst):
    try:
        os.symlink(src, dst)
    except FileExistsError:
        if os.path.islink(dst):
            print(f"Symlink {dst} already exists")
            # Optionally update existing symlink
            os.remove(dst)
            os.symlink(src, dst)
            print(f"Updated {dst} to point to {src}")
        else:
            print(f"{dst} exists but isn't a symlink")

# Test the function
create_symlink(target, link)
create_symlink(target, "regular_file.txt")  # This would fail

The create_symlink function safely handles existing symlinks. It checks if the existing path is a symlink before attempting to overwrite it.

For non-symlink files, you might want different handling to avoid data loss.

Windows-Specific Behavior

Windows handles symlinks differently than Unix. This example shows Windows- specific considerations, including privilege requirements.

windows_symlinks.py
import os
import sys
import ctypes

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

if sys.platform == "win32":
    target = "C:\\Windows\\notepad.exe"
    link = "notepad_link.exe"
    
    if is_admin():
        try:
            # On Windows, need admin privileges or developer mode
            os.symlink(target, link, target_is_directory=False)
            print(f"Created symlink from {link} to {target}")
            
            # Verify
            if os.path.islink(link):
                print("Link verified")
                os.startfile(link)  # Try opening through symlink
        except OSError as e:
            print(f"Symlink creation failed: {e}")
    else:
        print("This script requires admin privileges on Windows")
else:
    print("This example is for Windows only")

Windows requires either admin privileges or developer mode enabled for symlink creation. The code checks for admin rights before attempting to create links.

The target_is_directory parameter is crucial on Windows for proper symlink type creation.

Checking and Reading Symlinks

Python provides functions to check for and read symlinks. This example demonstrates symlink detection and inspection.

inspect_symlinks.py
import os

# Setup test files
os.makedirs("test_dir", exist_ok=True)
with open("test_dir/original.txt", "w") as f:
    f.write("Original content")
os.symlink("original.txt", "test_dir/link.txt")

def inspect_path(path):
    print(f"\nInspecting {path}:")
    print(f"exists(): {os.path.exists(path)}")
    print(f"lexists(): {os.path.lexists(path)}")
    print(f"islink(): {os.path.islink(path)}")
    
    if os.path.islink(path):
        print(f"readlink(): {os.readlink(path)}")
        print(f"Actual content: {open(path).read()}")

# Test different paths
inspect_path("test_dir/original.txt")
inspect_path("test_dir/link.txt")
inspect_path("test_dir/nonexistent.txt")
inspect_path("test_dir/broken_link.txt")  # Create broken link
os.symlink("nonexistent.txt", "test_dir/broken_link.txt")
inspect_path("test_dir/broken_link.txt")

The inspect_path function shows various symlink inspection methods. os.path.exists follows symlinks, while os.path.lexists checks the link itself.

Broken links return True for lexists() and islink() but False for exists().

Cross-Platform Symlink Handling

This example demonstrates writing code that handles symlinks across different operating systems, accounting for platform differences.

cross_platform.py
import os
import sys
import platform

def create_symlink_crossplatform(src, dst):
    """Create symlink handling platform differences"""
    try:
        if sys.platform == "win32":
            # Windows requires directory flag
            is_dir = os.path.isdir(src)
            os.symlink(src, dst, target_is_directory=is_dir)
        else:
            os.symlink(src, dst)
        print(f"Created symlink from {dst} to {src}")
    except OSError as e:
        print(f"Failed to create symlink: {e}")
        if sys.platform == "win32" and e.winerror == 1314:
            print("On Windows, you need admin privileges or developer mode")

# Test the function
target_file = "data.txt"
target_dir = "docs"
link_file = "data_link.txt"
link_dir = "docs_link"

# Create targets
with open(target_file, "w") as f:
    f.write("Test data")
os.makedirs(target_dir, exist_ok=True)

# Create symlinks
create_symlink_crossplatform(target_file, link_file)
create_symlink_crossplatform(target_dir, link_dir)

# Verify
print("\nVerification:")
for link in [link_file, link_dir]:
    if os.path.lexists(link):
        print(f"{link} -> {os.readlink(link)}")
    else:
        print(f"{link} not created")

This function handles Windows' target_is_directory requirement automatically. It also provides helpful error messages for Windows privilege issues.

The verification step uses lexists() to check for both valid and broken links.

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.