WizardKit/scripts/wk/io.py

95 lines
2.2 KiB
Python

"""WizardKit: I/O Functions"""
# vim: sts=2 sw=2 ts=2
import logging
import os
import pathlib
import shutil
# STATIC VARIABLES
LOG = logging.getLogger(__name__)
# Functions
def delete_empty_folders(path):
"""Recursively delete all empty folders in path."""
LOG.debug('path: %s', path)
# Delete empty subfolders first
for item in os.scandir(path):
if item.is_dir():
delete_empty_folders(item.path)
# Attempt to remove (top) path
try:
delete_folder(path, force=False)
except OSError:
# Assuming it's not empty
pass
def delete_folder(path, force=False, ignore_errors=False):
"""Delete folder if empty or if forced.
NOTE: Exceptions are not caught by this function,
ignore_errors is passed to shutil.rmtree to allow partial deletions.
"""
LOG.debug(
'path: %s, force: %s, ignore_errors: %s',
path, force, ignore_errors,
)
if force:
shutil.rmtree(path, ignore_errors=ignore_errors)
else:
os.rmdir(path)
def delete_item(path, force=False, ignore_errors=False):
"""Delete file or folder, optionally recursively.
NOTE: Exceptions are not caught by this function,
ignore_errors is passed to delete_folder to allow partial deletions.
"""
LOG.debug(
'path: %s, force: %s, ignore_errors: %s',
path, force, ignore_errors,
)
path = pathlib.Path(path)
if path.is_dir():
delete_folder(path, force=force, ignore_errors=ignore_errors)
else:
os.remove(path)
def non_clobber_path(path):
"""Update path as needed to non-existing path, returns pathlib.Path."""
LOG.debug('path: %s', path)
path = pathlib.Path(path)
name = path.name
new_path = None
suffix = ''.join(path.suffixes)
name = name.replace(suffix, '')
# Bail early
if not path.exists():
return path
# Find non-existant path
for _i in range(1000):
new_path = path.with_name(f'{name}_{_i}').with_suffix(suffix)
if not new_path.exists():
break
# Raise error if viable path not found
if not new_path:
raise FileExistsError(new_path)
# Done
LOG.debug('new path: %s', new_path)
return new_path
if __name__ == '__main__':
print("This file is not meant to be called directly.")