The function takes a list of paths to all folders and checks if it is empty. If empty, it deletes. But after she deleted the folder, the error
FileNotFoundError: [WinError 3] The system cannot find the path specified: '\\Projects\\Example\\New folder' appears. I do not fully understand why it is looking for it after deletion. And one more problem. If there is another empty folder inside an empty folder, only the nested one will be deleted. How to fix it?
def delete_empy_folders(paths_to_folders): for folder_path in paths_to_folders: if not os.listdir(folder_path) and split(folder_path)[-1] not in ignore_list: os.rmdir(folder_path)
The problem is that you don’t check whether the path even exists, and you cannot list contents of non-existent folders.
>>> import os >>> os.listdir("aaa") Traceback (most recent call last): File "<stdin>", line 1, in <module> FileNotFoundError: [Errno 2] No such file or directory: 'aaa'
You can use os.path.isdir to check if given path exists and is a directory:
>>> os.path.isdir("/tmp") True >>> os.path.isdir("aaa") False
(Don’t confuse with os.path.isfile – you want directories here, ans isfile checks for non-dir files!)
So your code will look like:
def delete_empy_folders(paths_to_folders): for folder_path in paths_to_folders: if os.path.isdir(folder_path) and not os.listdir(folder_path) and split(folder_path)[-1] not in ignore_list: os.rmdir(folder_path)
Python also has a nice lib to deal with paths, called
pathlib. Quick demonstration of methods that might be useful if you decide to switch:
from pathlib import Path p = Path("/tmp") p.is_dir() # just like os.path.isdir p.name # to get only the last name from path, no matter how complex it is, your split(p)[-1] p.parts # for your own split - for absolute paths first element will be "/", the rest are just stuff between '/'s p.rmdir() # will only work if empty, just like os.rmdir
In neither os/os.path nor pathlib there is a ready method to check for files inside of directory. You used os.listdir, for pathlib.Path objects we have iterdir which is a generator (lazy, perfect for directories) – but to have exact same behaviour, we can map it to a list:
list(p.iterdir()) # works like os.listdir(p) but returns a list of pathlib.Path objects instead of a list of str
But we only need to know if there’s at least one element, so let’s use
next to get one value from generator – and we’ll use second argument to provide the default so we don’t get an exception:
None is falsy (its
if check behaves like False/bool(None) is False), so we either get a Path (truthy) or None (falsy).
All in all,
def delete_empy_folders(paths_to_folders): for folder_path in paths_to_folders: folder_path = Path(folder_path) # if we get strings, but it would be the best to receive Path objects already if folder_path.is_dir() and not next(folder_path.iterdir(), None) and p.name not in ignore_list: folder_path.rmdir()