I tried to use shutil to delete a directory and all contained files, as follows:
import shutil
from os.path import exists
if exists(path_dir):
shutil.rmtree(path_dir)
Unfortunately, my solution does not work, throwing the following error:
FileNotFoundError: [Errno 2] No such file or directory: '._image1.jpg'
A quick search showed that I'm not alone in having this problem.
In my understanding, the rmtree function is equivalent to the rm -Rf $DIR shell command - but this doesn't seem to be the case.
p.s. for reconstruction purposes. Please create a symbolic link for example using ln -s /path/to/original /path/to/link
From How to remove a directory including all its files in python?
# function that deletes all files and then folder
import glob, os
def del_folder(dir_name):
dir_path = os.getcwd() + "\{}".format(dir_name)
try:
os.rmdir(dir_path) # remove the folder
except:
print("OSError") # couldn't remove the folder because we have files inside it
finally:
# now iterate through files in that folder and delete them one by one and delete the folder at the end
try:
for filepath in os.listdir(dir_path):
os.remove(dir_path + "\{}".format(filepath))
os.rmdir(dir_path)
print("folder is deleted")
except:
print("folder is not there")
You can also just use the ignore_errors flag with shutil.rmtree().
shutil.rmtree('/folder_name', ignore_errors=True)
That should remove a directory with file contents.
You are probably on Mac OSX and your directory is at least partially on a non-Mac filesystem (ie not HFS+). On those, Mac filesystem drivers automatically create binary companion files prefixed with ._ to record so-called extended attributes (explained in https://apple.stackexchange.com/questions/14980/why-are-dot-underscore-files-created-and-how-can-i-avoid-them, but also illustrated below).
rmtree on systems which do not support file descriptors in os.scandir (like Mac OSX) now unsafely creates a list of entries and then unlinks them one by one (creating a known race-condition: https://github.com/python/cpython/blob/908fd691f96403a3c30d85c17dd74ed1f26a60fd/Lib/shutil.py#L592-L621). Unfortunately two separate behaviours make this condition true every time:
test.txt) the meta file (._test.txt) is removed simultaneously.Thus, the extended attribute file will be missing when it is its turn and throw the FileNotFoundError you are experiencing.
I think this bug would be best addressed by cpython#14064, which aims at ignoring FileNotFoundErrors in rmtree generally.
In the mean time you could ignore unlinking errors on those meta files with onerror:
def ignore_extended_attributes(func, filename, exc_info):
is_meta_file = os.path.basename(filename).startswith("._")
if not (func is os.unlink and is_meta_file):
raise
shutil.rmtree(path_dir, onerror=ignore_extended_attributes)
To illustrate you can create a small ExFAT disk image and mount it to /Volumes/Untitled with the commands
hdiutil create -size 5m -fs exfat test.dmg
hdiutil attach test.dmg # mounts at /Volumes/Untitled
cd /Volumes/Untitled
mkdir test # create a directory to remove
cd test
touch test.txt
open test.txt # open the test.txt file in the standard editor
Just opening the file in the standard text editor creates an extended attributes file ._test.txt and records the last access time in it:
/Volumes/Untitled/test $ ls -a
. .. ._test.txt test.txt
/Volumes/Untitled/test $ xattr test.txt
com.apple.lastuseddate#PS
The problem is that unlinking the original file automatically also unlinks the companion file.
/Volumes/Untitled/test $ rm test.txt
/Volumes/Untitled/test $ ls -a
. ..