How To Delete Non-Empty Folder In Python rmdir

Deleting a folder in Python is easy if the folder is empty. You can simply use the os.rmdir() method. However, this will raise an error if the folder contains any files or subfolders.

To delete a non-empty folder recursively in Python, you need to use the shutil module. The shutil.rmtree() method will delete the entire folder tree including all subfolders and files.

In this comprehensive guide, we will cover the following topics in detail:

Overview of Deleting Folders in Python

  • os.rmdir() to delete an empty folder
  • shutil.rmtree() to delete a non-empty folder
  • Handling errors and exceptions
  • Deleting read-only files
  • Concurrent file additions
  • Cross-platform support

When to Use os.rmdir() vs shutil.rmtree()

  • Use os.rmdir() only when the folder is guaranteed to be empty
  • Use shutil.rmtree() when the folder may contain files/subfolders
  • rmtree() is recursive, deleting the entire folder tree

shutil.rmtree() Usage and Examples

  • Import the shutil module
  • Call shutil.rmtree(path) to delete folder at path
  • Set ignore_errors parameter to handle exceptions
  • Use onerror callback to delete read-only files

Handling Errors and Exceptions

  • Catch PermissionError or OSError exceptions
  • Understand error cases like read-only files
  • Set ignore_errors=True to delete other content
  • Implement onerror callback to clear file permissions

Deleting Folders with Read-Only Files

  • Read-only files prevent folder deletion
  • ignore_errors=True deletes all except read-only files
  • Implement onerror callback to modify permissions
  • Examples for deleting folders with read-only files

Avoiding Race Conditions with Concurrent Writes

  • Concurrent file additions can cause rmtree() to fail
  • Use retries and delay to handle race conditions
  • Example implementation for safe deletion with retries

Cross-Platform Support for Windows, Linux, macOS

  • Use forward vs back slashes properly in file paths
  • Handle drive letters and root folders for Windows
  • Permissions issues on Linux and macOS
  • Examples covering all major operating systems

By the end, you will have in-depth knowledge of how to robustly and safely delete folders in Python on any operating system. Let’s get started!\

Overview of Deleting Folders in Python

Before we dive into the details, let’s understand the key concepts and approaches for deleting folders in Python:

os.rmdir() to Delete an Empty Folder

The os module provides the os.rmdir(path) method to delete a folder (directory) by path.

However, rmdir() has a key limitation – it will only work if the folder is empty. If the folder contains any files or subfolders, rmdir() will raise an OSError.

Here is an example:

import os

folder = '/path/to/myfolder'

os.rmdir(folder) # Works if folder is empty
JavaScript

So os.rmdir() is only useful when you can guarantee the folder does not contain anything.

shutil.rmtree() to Delete a Non-Empty Folder

To delete a folder that contains files or other folders, we need to use the shutil module instead.

The shutil.rmtree(path) method will delete a folder and all its contents recursively. It is equivalent to a rm -rf path in Linux and Unix.

Here is an example of using shutil.rmtree():

import shutil

folder = '/path/to/myfolder' 

shutil.rmtree(folder) # Deletes folder and all contents
JavaScript

As you can see, rmtree() allows deleting the entire folder tree in one shot.

Handling Errors and Exceptions

However, deleting folders can lead to errors in certain cases:

  • Folder contains read-only files
  • Current user lacks permissions
  • Folder contains files open by other processes
  • Race conditions with concurrent file additions

To handle such errors, rmtree() provides some options:

  • Set ignore_errors=True to proceed deleting other contents
  • Provide an onerror callback to handle errors gracefully

We will cover these in detail later.

Deleting Read-Only Files

On Windows, read-only files will prevent deleting the parent folder. To handle this, we need to clear the read-only flag first.

The onerror callback provides a way to modify file permissions before retrying deletion.

Avoiding Race Conditions

If concurrent processes are adding files to the folder, rmtree() may fail.

To avoid this race condition, use the retries and delay arguments to retry deletions.

Now that we understand the key concepts, let’s look at the options in more depth.

When to Use os.rmdir() vs shutil.rmtree()

The os and shutil modules provide different approaches for deleting folders in Python. To recap:

  • Use os.rmdir(path) to delete an empty folder at path
  • Use shutil.rmtree(path) to delete a folder and all its contents

os.rmdir() Only for Empty Folders

The os.rmdir() method will delete a folder only if it is guaranteed empty.

For example, when deleting a temp folder that your script created and populated earlier:

import os
import tempfile

# Create temp folder
temp_dir = tempfile.mkdtemp() 

# Do some processing...

# Delete temp folder 
os.rmdir(temp_dir)
JavaScript

Here you know the temp folder cannot have any content left over. So os.rmdir() is safe to use.

But if there is any chance your folder contains files or subfolders, os.rmdir() will fail with:

OSError: [Errno 39] Directory not empty: 'folder' 
JavaScript

So only use os.rmdir() when you are 100% sure the folder is empty.

shutil.rmtree() For Deleting Folder Trees

For all other cases, use shutil.rmtree(path) to delete a folder and all its contents recursively.

Some examples where rmtree() is required:

  • Deleting user-specified folders which may have arbitrary content
  • Deleting temp folders your script did not create
  • Cleaning up nested subfolders and files
  • Resetting test folders between runs

The key advantage of rmtree() is it will recursively descend into subfolders and delete the entire tree. Much more powerful than rmdir().

Now let’s look at rmtree() usage in more depth.

shutil.rmtree() Usage and Examples

The shutil module provides the rmtree() function to delete an entire folder tree recursively. Here is the signature:

shutil.rmtree(path, ignore_errors=False, onerror=None)
JavaScript

It accepts the following parameters:

  • path – Path of the folder to delete (required)
  • ignore_errors – If True, errors are ignored and deletion proceeds
  • onerror – Callback function called on error

Let’s see some examples of using rmtree() to delete folders in Python.

Import shutil Module

To use rmtree(), you need to import the shutil module first:

import shutil
JavaScript

Delete Folder at Given Path

To delete a folder at a given path:

folder = '/path/to/myfolder'

shutil.rmtree(folder)
JavaScript

This will recursively delete myfolder and all its contents.

Set ignore_errors to True

If you want deletion to proceed even if there are errors:

shutil.rmtree(folder, ignore_errors=True) 
JavaScript

This will ignore PermissionErrors and continue deleting the rest of the folder tree.

More on handling errors later.

Provide onerror Callback

To provide a callback function to handle errors:

def handle_error(func, path, exc_info):
  # Check for read-only files, etc
  pass

shutil.rmtree(folder, onerror=handle_error)
JavaScript

Now that we’ve covered the basics, let’s look at handling errors.

Handling Errors and Exceptions

Deleting folders in Python using shutil.rmtree() may lead to errors in certain cases:

  • Folder contains read-only files
  • Insufficient permissions to delete files or folders
  • Folder contains files open in another process
  • Race conditions when files are modified concurrently

Thankfully, rmtree() provides some mechanisms to handle such errors gracefully:

  • The ignore_errors parameter
  • Custom onerror callback function

Let’s see how to use them when deleting folders.

Catching PermissionError and OSError

First, you can catch PermissionError and OSError exceptions directly when calling rmtree():

import shutil

try:
  shutil.rmtree(folder)
except OSError as e:
  print("Error: %s - %s." % (e.filename, e.strerror))
except PermissionError as e: 
  print("Permissions error: %s" % e.filename)  
JavaScript

This will handle cases where the current user does not have sufficient permissions to delete the files.

Set ignore_errors=True

To make rmtree() ignore certain errors and proceed with deleting the rest of the files in a folder:

shutil.rmtree(folder, ignore_errors=True)
JavaScript

This will ignore PermissionErrors and delete as much content as possible.

Implement onerror Callback

However, ignore_errors will not help with all error cases like read-only files.

To handle these, you need to implement an onerror callback function:

def handle_error(func, path, exc_info):
  # Check for read-only files, etc
  pass

shutil.rmtree(folder, onerror=handle_error)
JavaScript

When rmtree() encounters an error, it will call this function, allowing you to implement custom error handling like modifying file permissions.

Now let’s look specifically at deleting folders containing read-only files.

Deleting Folders with Read-Only Files

On Windows, folders containing read-only files cannot be deleted normally. The rmtree() function will fail with a PermissionError.

For example:

PermissionError: [WinError 5] Access is denied: 'readonly_file.txt' 
JavaScript

To delete folders containing read-only files, we need to:

  1. Set ignore_errors=True to delete other contents
  2. Implement onerror callback to modify file permissions

Let’s see examples of both approaches.

ignore_errors Deletes All Except Read-only Files

Setting ignore_errors=True allows rmtree() to proceed despite errors:

shutil.rmtree(folder, ignore_errors=True)
JavaScript

However, it will not delete the read-only files themselves. The folder will still remain, just containing only those read-only files.

So ignore_errors allows deleting all except the read-only files.

onerror Callback to Modify Permissions

To fully delete the entire folder tree including read-only files, we need to handle the PermissionError in the onerror callback.

Here is an example:

import os, stat

def remove_readonly(func, path, excinfo):
  os.chmod(path, stat.S_IWRITE)
  func(path)

shutil.rmtree(folder, onerror=remove_readonly)
JavaScript

This implements a callback that:

  1. Changes the file permissions to writable
  2. Retries deletion on that file

Now rmtree() will be able to delete folders even with read-only files!

Avoiding Race Conditions with Concurrent Writes

One potential issue when deleting folders is race conditions if files are being added concurrently.

For example, consider this scenario:

  1. Python script calls rmtree('/folder')
  2. Meanwhile, another process adds a file to /folder
  3. Deletion fails since folder contents changed

To avoid such race conditions, rmtree() provides two parameters:

  • retries – Number of retries if errors are encountered
  • delay – Delay (in seconds) between retries

Here is an example usage:

shutil.rmtree(
  folder, 
  ignore_errors=True,
  retries=3,
  delay=1
)
JavaScript

This will retry the entire folder deletion up to 3 times, with a 1 second delay between each attempt.

This provides tolerance for concurrent write operations.

Cross-platform support for Windows, Linux, macOS

When developing cross-platform Python code for deleting folders, you need to watch out for OS-specific quirks.

Here are some tips for POSIX vs Windows systems:

Use Forward vs Backward Slashes

On Windows, use backward slashes or raw strings for paths:

folder = r'C:\path\to\folder'
JavaScript

On POSIX systems like Linux/macOS, use forward slashes:

folder = '/home/user/folder' 
JavaScript

Or better, use OS-agnostic paths with os.path:

import os
folder = os.path.join('root','subfolder')
JavaScript

Check for Drive Letters on Windows

On Windows, joining paths naively can strip the drive letter:

os.path.join('C:\\', 'folder') # Bad, gives \folder
JavaScript

So always include the drive when constructing Windows paths:

python drive = 'C:' path = os.path.join(drive, 'folder') # Good

Beware of Root Folder Deletion

Deleting folders like '/' or 'C:\\' at the root can be dangerous. Make sure to validate paths to avoid data loss.

Handle Permissions Issues on Linux/macOS

On Linux/macOS you may need sudo privileges to delete folders in restricted locations like /usr/, /System/ etc.

Handle PermissionErrors and provide instructions if admin access is required.

Summary

To summarize, deleting folders in Python requires using shutil.rmtree() for non-empty folders, along with proper error handling:

  • Use os.rmdir() only for guaranteed empty folders
  • shutil.rmtree() deletes folder trees recursively
  • Set ignore_errors=True to proceed on errors
  • Implement onerror callback to handle errors like read-only files
  • Retry deletions to avoid race conditions from concurrent writes
  • Watch out for OS-specific path issues

Following these best practices will help you robustly delete folders across platforms and avoid data loss issues.

The shutil module is quite powerful, providing many other useful file operations like copying, archiving, moving etc. I encourage you to check out the official shutil documentation further.

I hope this guide was useful in helping you master deleting folders in Python. Please feel free to provide any feedback or suggestions for improvement.

Leave a Comment