ZetCode

Python os.removedirs Function

Last modified April 11, 2025

This comprehensive guide explores Python's os.removedirs function, which recursively removes empty directories. We'll cover usage patterns, error handling, and practical directory cleanup examples.

Basic Definitions

The os.removedirs function removes directories recursively. It works from the leaf directory up to the root, removing empty parents.

Key behavior: removes leaf directory first, then empty parents up the path. Raises OSError if any directory in path is not empty or removal fails.

Removing a Single Empty Directory

The simplest use of os.removedirs removes one empty directory. This behaves like os.rmdir but with the same error conditions.

remove_single_dir.py
import os

# Create a test directory
test_dir = "temp_dir"
os.makedirs(test_dir, exist_ok=True)

# Remove the directory
try:
    os.removedirs(test_dir)
    print(f"Successfully removed {test_dir}")
except OSError as e:
    print(f"Error removing {test_dir}: {e}")

# Verify removal
if not os.path.exists(test_dir):
    print(f"{test_dir} no longer exists")

This example creates a temporary directory, removes it, and verifies success. The exist_ok=True prevents errors if the directory already exists.

Note that os.removedirs will fail if the directory contains files or subdirectories, unlike shutil.rmtree which forces deletion.

Removing Nested Empty Directories

os.removedirs shines when removing nested empty directory trees. It automatically removes parent directories if they become empty.

remove_nested_dirs.py
import os

# Create nested directory structure
base_dir = "parent/child/grandchild"
os.makedirs(base_dir)

# Remove the leaf directory and empty parents
try:
    os.removedirs(base_dir)
    print(f"Removed directory tree up from {base_dir}")
except OSError as e:
    print(f"Error removing directories: {e}")

# Check which directories remain
for dirpath in ["parent", "parent/child", base_dir]:
    exists = os.path.exists(dirpath)
    print(f"{dirpath} exists: {exists}")

This creates a three-level directory structure, then removes it completely. The function works from the grandchild up, removing each empty parent.

If any directory in the path contains other files, removal stops at that level. Only empty directories above the specified path will be removed.

Handling Non-Empty Directories

When encountering non-empty directories, os.removedirs raises OSError. This example demonstrates proper error handling for such cases.

handle_non_empty.py
import os

# Create directory with a file
dir_path = "test_dir"
os.makedirs(dir_path, exist_ok=True)
with open(os.path.join(dir_path, "file.txt"), "w") as f:
    f.write("test")

# Attempt removal
try:
    os.removedirs(dir_path)
except OSError as e:
    print(f"Failed to remove {dir_path}: {e}")
    print("Directory is not empty")

# Cleanup alternative
import shutil
shutil.rmtree(dir_path)
print(f"Forcefully removed {dir_path} with shutil.rmtree")

The first attempt fails because the directory contains a file. The example then shows using shutil.rmtree for forceful directory removal.

Always handle OSError when using os.removedirs as directory contents may change between checking and removal attempts.

Removing Relative Path Directories

os.removedirs works with relative paths, removing directories relative to the current working directory. This example demonstrates this.

relative_paths.py
import os

# Create relative directory structure
os.makedirs("./relative/path/to/dir", exist_ok=True)

# Store original working directory
original_dir = os.getcwd()

# Change to intermediate directory
os.chdir("./relative/path")

# Remove using relative path
try:
    os.removedirs("to/dir")
    print("Removed relative path directories")
except OSError as e:
    print(f"Error: {e}")

# Return to original directory
os.chdir(original_dir)

# Verify removal
print(f"Path exists: {os.path.exists('relative/path/to/dir')}")

This shows how relative paths are interpreted based on current working directory. The function removes directories relative to the current path when called.

Be cautious with relative paths - the removal scope depends on current directory. Absolute paths are generally safer for predictable behavior.

Preserving Non-Empty Parent Directories

os.removedirs stops removal when encountering a non-empty directory. This example shows how it preserves directories containing other files.

preserve_parents.py
import os

# Create test structure
base_path = "preserve_test/a/b/c"
os.makedirs(base_path)

# Add file to intermediate directory
with open("preserve_test/a/important.txt", "w") as f:
    f.write("don't delete me")

# Attempt removal
try:
    os.removedirs(base_path)
    print("Full path removed")
except OSError as e:
    print(f"Partial removal: {e}")

# Check what remains
for dirpath in ["preserve_test", "preserve_test/a", base_path]:
    exists = os.path.exists(dirpath)
    print(f"{dirpath} exists: {exists}")

The file in the 'a' directory prevents removal of that directory and its parents. Only the 'b' and 'c' directories (which become empty) are successfully removed.

This behavior makes os.removedirs safe for cleaning up empty directory trees without risking deletion of directories containing other files.

Comparing with os.rmdir and shutil.rmtree

This example contrasts os.removedirs with similar directory removal functions, showing their different behaviors and use cases.

compare_removal.py
import os
import shutil

# Setup test directories
os.makedirs("compare_test/a/b/c", exist_ok=True)

print("Using os.rmdir (single directory):")
try:
    os.rmdir("compare_test/a/b/c")
    print("Successfully removed leaf directory")
except OSError as e:
    print(f"Error: {e}")

print("\nUsing os.removedirs (recursive empty directories):")
try:
    os.removedirs("compare_test/a/b")
    print("Successfully removed empty tree")
except OSError as e:
    print(f"Error: {e}")

# Recreate structure with a file
os.makedirs("compare_test2/a/b/c")
with open("compare_test2/a/file.txt", "w") as f:
    f.write("test")

print("\nUsing shutil.rmtree (forceful removal):")
try:
    shutil.rmtree("compare_test2")
    print("Forcefully removed entire tree")
except OSError as e:
    print(f"Error: {e}")

os.rmdir removes only the specified directory. os.removedirs removes empty parents. shutil.rmtree removes everything forcefully.

Choose the appropriate function based on whether you need safety, recursion, or unconditional removal in your specific use case.

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.