Shutil rmtree – Python : How to delete a directory recursively using shutil.rmtree()

How to delete a directory recursively using shutil.rmtree() in Python ?

Shutil rmtree: In this article, we will discuss about how we can delete an empty directory and also all contents of a directory including sub directories using shutil.rmtree().

Delete an empty directory using os.rmdir() :

Python delete directory recursively: The os module of python provide a function i.e. os.rmdir(pathOfDir) which can delete an empty directory. It can also give rise to certain errors in some scenarios like:

  • When directory is not empty : OSError: [WinError 145] The directory is not empty:
  • When the given path not pointing to any of the directory : NotADirectoryError: [WinError 267] The directory name is invalid:
  • When the given path has no directory : FileNotFoundError: [WinError 2] The system cannot find the file specified:
#Program :

import os

# Deleting a empty directory using function os.rmdir() and handle the exceptions
try:
 os.rmdir('/somedirec/log2')

except:
 print('Not found directory')
Output :
Not found directory

Delete all files in a directory & sub-directories recursively using shutil.rmtree() :

Python delete directory recursively: The shutil module of python provides a function i.e. shutil.rmtree() to delete all the contents present in a directory.

 Syntax : shutil.rmtree(path, ignore_errors=False, onerror=None)
import shutil

dirPath = '/somedirec/logs5/';

# trying to delete all contents of a directory and handle exceptions
try:
 shutil.rmtree(dirPath)

except:
 print('Not found directory')
Output :
Not found directory

Here in this case if found, all contents of directory '/somedir/logs/' will be deleted. If any of the files in directory has read only attributes then user can’t delete the file and exception i.e. PermissionError will be raised therefore we can’t delete any remaining required files.

shutil.rmtree() & ignore_errors :

Shutil delete file: In previous scenario if we failed to delete any file, then we can’t delete further required files in the directory. Now, we can ignore the errors by passing ignore_errors=True in shutil.rmtree().

It will skip the file which raised the exception and then going forward it can delete all of the remaining files.

Let there be a scenario where we can’t delete a file in log directory, then we can use the following syntax so that this exception can be ignored:

shutil.rmtree(dirPath, ignore_errors=True)

Passing callbacks in shutil.rmtree() with onerror :

Shutil delete file: Instead of ignoring errors, there may be a case where we have to handle the errors.

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

In onerror parameter, callback function can be called to handle the errors

shutil.rmtree(dirPath, onerror=handleError)

The callable function passed must be callable like:

def handleError(func, path, exc_info):
   pass

where,

  • function : It is the function which raised exception.
  • path : The path that passed which raises the exception while removal.
  • excinfo : The exception information is returned

Now, if any exception is raised while deleting a file, then callback will handle the error. Then, shutil.rmtree() can continue deleting remaining files.

Now let a case where we want to delete all the contents of a directory '/somediec/logs', and there is somewhere a file in logs directory which shows permission issues, and we can’t delete all. So callback will be passed in oneerror parameter of that file.

In the callback if it accesses issue, then we will change the file permission and then call calling function i.e. rmtree() with path of file. Then the file will be deleted and rmtree() will further delete remaining contents in the directory.

import os
import shutil
import stat

#Error handling function will try to change permission and call calling function again

def handleError(func, path, exc_info):
 print('Handling Error for file ' , path)
 print(exc_info)

# check that if the file is accessing the issue
if not os.access(path, os.W_OK):
 print('helloWorld')
 # trying to change the permission of file
 os.chmod(path, stat.S_IWUSR)
 # Tring to call the calling function again
 func(path)