cornsnake.util_dir
Working with directories, files, and file paths.
1""" 2Working with directories, files, and file paths. 3 4[Documentation](http://docs.mrseanryan.cornsnake.s3-website-eu-west-1.amazonaws.com/cornsnake/util_dir.html) 5""" 6 7import os 8from glob import glob 9import re 10import shutil 11from pathlib import Path 12 13from . import util_os 14from . import util_robust_delete 15 16TOTAL_BYTES_IN_GIGABYTE = 1000000000 17 18delete_dirs = util_robust_delete.delete_dirs # allow access via this file 19 20 21def copy_directory(from_path: str, to_path: str) -> None: 22 """ 23 Copy a directory from one location to another. 24 25 Args: 26 from_path (str): The path of the directory to copy from. 27 to_path (str): The path of the directory to copy to. 28 """ 29 shutil.copytree(from_path, to_path) 30 31 32def ensure_dir_exists(target_dir: str) -> None: 33 """ 34 Ensure that a directory exists, creating it if necessary. 35 36 Args: 37 target_dir (str): The path of the directory to ensure existence of. 38 """ 39 if not os.path.exists(target_dir): 40 os.makedirs(target_dir) 41 42 43def find_files_by_extension(dir_path: str, extension: str) -> list[str]: 44 """ 45 Find files in a directory by a specific file extension. 46 47 Args: 48 dir_path (str): The path of the directory to search for files. 49 extension (str): The file extension to search for. 50 51 Example: ('c:\\temp\\x', '.json') -> ['c:\\temp\\x\\1.json', 'c:\\temp\\x\\2.json'] 52 53 Returns: 54 list: A list of file paths with the specified extension. 55 """ 56 found_files = [] 57 contents = os.listdir(dir_path) 58 for content in contents: 59 path_to_sub = os.path.join(dir_path, content) 60 if os.path.isfile(path_to_sub) and path_to_sub.endswith(extension): 61 found_files.append(path_to_sub) 62 return found_files 63 64 65def find_files(dir_path: str) -> list[str]: 66 """Find all files in the given directory.""" 67 found_files = [] 68 contents = os.listdir(dir_path) 69 for content in contents: 70 path_to_sub = os.path.join(dir_path, content) 71 if os.path.isfile(path_to_sub): 72 found_files.append(path_to_sub) 73 return found_files 74 75 76def find_files_recursively(dir_path: str, extension: str = ".*") -> list[str]: 77 result = [ 78 y for x in os.walk(dir_path) for y in glob(os.path.join(x[0], f"*{extension}")) 79 ] 80 return result 81 82 83def get_dir_parts(path_to_file: str) -> list[str]: 84 """ 85 Get the directory components of the given file path. 86 87 Example: 'c:\\temp\\x\\my-file.txt' -> ['c','temp','x'] 88 """ 89 path_to_dir = os.path.dirname(path_to_file) 90 path = os.path.normpath(path_to_dir) 91 return path.split(os.sep) 92 93 94def get_directory_of_this_script(____file__: str) -> str: 95 """ 96 Get the directory that contains this script. 97 98 Args: 99 __file__ (str): The path to this Python script file. 100 Returns: 101 The absolute path to directory containing your Python script file. 102 """ 103 return os.path.dirname(os.path.realpath(____file__)) 104 105 106def get_parent_dir(my_path: str) -> str: 107 """Get the absolute path of the parent directory of the given directory.""" 108 return str(Path(my_path).parent.absolute()) 109 110 111def get_total_dir_size_in_bytes(start_path: str) -> int: 112 total_size = 0 113 for dirpath, _dirnames, filenames in os.walk(start_path): 114 for f in filenames: 115 fp = os.path.join(dirpath, f) 116 # skip if it is symbolic link 117 if not os.path.islink(fp): 118 fp_allow_long_path = "\\\\?\\" + fp if util_os.is_windows() else fp 119 total_size += os.path.getsize(fp_allow_long_path) 120 121 return total_size 122 123 124def get_total_dir_size_in_gigabytes(start_path: str) -> float: 125 """Calculate the total size of a directory in gigabytes. 126 Args: 127 start_path (str): The path of the directory to calculate size of. 128 Returns: 129 float: The total size of the directory in gigabytes.""" 130 return get_total_dir_size_in_bytes(start_path) / TOTAL_BYTES_IN_GIGABYTE 131 132 133def get_unique_dirpath(path_to_dir: str) -> str: 134 """ 135 Get a unique directory path similar to the given path. 136 """ 137 138 def _ends_with_hyphen_number(path: str) -> bool: 139 m = re.search(r"-\d+$", path) 140 return m is not None 141 142 # Avoid appending like x-01-02-03 143 if _ends_with_hyphen_number(path_to_dir): 144 path_to_dir = path_to_dir[:-3] 145 146 suffix = 2 147 path_to_dir_new = path_to_dir 148 while os.path.exists(path_to_dir_new): 149 path_to_dir_new = f"{path_to_dir}-{suffix:02}" 150 suffix += 1 151 return path_to_dir_new 152 153 154def is_empty_directory(path_to_file: str) -> bool: 155 """Check if a directory is empty. 156 Args: 157 path_to_file (str): The path of the directory to check. 158 Returns: 159 bool: True if the directory is empty, False otherwise.""" 160 if os.path.isfile(path_to_file): 161 return False 162 contents = os.listdir(path_to_file) 163 return len(contents) == 0 164 165 166def is_empty_directory_only_subdirectories(path_to_file: str) -> bool: 167 """Check if a directory is empty by inspecting subdirectories. 168 Args: 169 path_to_file (str): The path of the directory to check. 170 Returns: 171 bool: True if the directory is empty or only contains empty subdirectories, False otherwise. 172 """ 173 if os.path.isfile(path_to_file): 174 return False 175 contents = os.listdir(path_to_file) 176 for content in contents: 177 path_to_sub = os.path.join(path_to_file, content) 178 if os.path.isfile(path_to_sub): 179 return False 180 if not os.path.isfile(path_to_sub): 181 is_empty = is_empty_directory_only_subdirectories(path_to_sub) 182 if not is_empty: 183 return False 184 return True 185 186 187def move_directory(path_to_dir: str, path_to_dir_renamed: str) -> None: 188 shutil.move(path_to_dir, path_to_dir_renamed)
74def delete_dirs(temp_dirs_to_delete: str) -> None: 75 """ 76 Delete directories and their contents. 77 - Python holds on to some paths - so delete as much as we can 78 79 Args: 80 temp_dirs_to_delete (list): A list of directory paths to be deleted. 81 """ 82 dirs_with_locked_items = [] 83 # faster delete: 84 for temp_dir in temp_dirs_to_delete: 85 try: 86 _rmrf(temp_dir) 87 except FileNotFoundError: 88 dirs_with_locked_items.append(temp_dir) 89 # Intentionally NOT passing exception onwards 90 except PermissionError: 91 dirs_with_locked_items.append(temp_dir) 92 # Intentionally NOT passing exception onwards 93 94 # slower, more robust delete: 95 for temp_dir in dirs_with_locked_items: 96 _delete_dir_contents(temp_dir)
Delete directories and their contents.
- Python holds on to some paths - so delete as much as we can
Args: temp_dirs_to_delete (list): A list of directory paths to be deleted.
22def copy_directory(from_path: str, to_path: str) -> None: 23 """ 24 Copy a directory from one location to another. 25 26 Args: 27 from_path (str): The path of the directory to copy from. 28 to_path (str): The path of the directory to copy to. 29 """ 30 shutil.copytree(from_path, to_path)
Copy a directory from one location to another.
Args: from_path (str): The path of the directory to copy from. to_path (str): The path of the directory to copy to.
33def ensure_dir_exists(target_dir: str) -> None: 34 """ 35 Ensure that a directory exists, creating it if necessary. 36 37 Args: 38 target_dir (str): The path of the directory to ensure existence of. 39 """ 40 if not os.path.exists(target_dir): 41 os.makedirs(target_dir)
Ensure that a directory exists, creating it if necessary.
Args: target_dir (str): The path of the directory to ensure existence of.
44def find_files_by_extension(dir_path: str, extension: str) -> list[str]: 45 """ 46 Find files in a directory by a specific file extension. 47 48 Args: 49 dir_path (str): The path of the directory to search for files. 50 extension (str): The file extension to search for. 51 52 Example: ('c:\\temp\\x', '.json') -> ['c:\\temp\\x\\1.json', 'c:\\temp\\x\\2.json'] 53 54 Returns: 55 list: A list of file paths with the specified extension. 56 """ 57 found_files = [] 58 contents = os.listdir(dir_path) 59 for content in contents: 60 path_to_sub = os.path.join(dir_path, content) 61 if os.path.isfile(path_to_sub) and path_to_sub.endswith(extension): 62 found_files.append(path_to_sub) 63 return found_files
Find files in a directory by a specific file extension.
Args: dir_path (str): The path of the directory to search for files. extension (str): The file extension to search for.
Example: ('c:\temp\x', '.json') -> ['c:\temp\x\1.json', 'c:\temp\x\2.json']
Returns: list: A list of file paths with the specified extension.
66def find_files(dir_path: str) -> list[str]: 67 """Find all files in the given directory.""" 68 found_files = [] 69 contents = os.listdir(dir_path) 70 for content in contents: 71 path_to_sub = os.path.join(dir_path, content) 72 if os.path.isfile(path_to_sub): 73 found_files.append(path_to_sub) 74 return found_files
Find all files in the given directory.
84def get_dir_parts(path_to_file: str) -> list[str]: 85 """ 86 Get the directory components of the given file path. 87 88 Example: 'c:\\temp\\x\\my-file.txt' -> ['c','temp','x'] 89 """ 90 path_to_dir = os.path.dirname(path_to_file) 91 path = os.path.normpath(path_to_dir) 92 return path.split(os.sep)
Get the directory components of the given file path.
Example: 'c:\temp\x\my-file.txt' -> ['c','temp','x']
95def get_directory_of_this_script(____file__: str) -> str: 96 """ 97 Get the directory that contains this script. 98 99 Args: 100 __file__ (str): The path to this Python script file. 101 Returns: 102 The absolute path to directory containing your Python script file. 103 """ 104 return os.path.dirname(os.path.realpath(____file__))
Get the directory that contains this script.
Args: __file__ (str): The path to this Python script file. Returns: The absolute path to directory containing your Python script file.
107def get_parent_dir(my_path: str) -> str: 108 """Get the absolute path of the parent directory of the given directory.""" 109 return str(Path(my_path).parent.absolute())
Get the absolute path of the parent directory of the given directory.
112def get_total_dir_size_in_bytes(start_path: str) -> int: 113 total_size = 0 114 for dirpath, _dirnames, filenames in os.walk(start_path): 115 for f in filenames: 116 fp = os.path.join(dirpath, f) 117 # skip if it is symbolic link 118 if not os.path.islink(fp): 119 fp_allow_long_path = "\\\\?\\" + fp if util_os.is_windows() else fp 120 total_size += os.path.getsize(fp_allow_long_path) 121 122 return total_size
125def get_total_dir_size_in_gigabytes(start_path: str) -> float: 126 """Calculate the total size of a directory in gigabytes. 127 Args: 128 start_path (str): The path of the directory to calculate size of. 129 Returns: 130 float: The total size of the directory in gigabytes.""" 131 return get_total_dir_size_in_bytes(start_path) / TOTAL_BYTES_IN_GIGABYTE
Calculate the total size of a directory in gigabytes. Args: start_path (str): The path of the directory to calculate size of. Returns: float: The total size of the directory in gigabytes.
134def get_unique_dirpath(path_to_dir: str) -> str: 135 """ 136 Get a unique directory path similar to the given path. 137 """ 138 139 def _ends_with_hyphen_number(path: str) -> bool: 140 m = re.search(r"-\d+$", path) 141 return m is not None 142 143 # Avoid appending like x-01-02-03 144 if _ends_with_hyphen_number(path_to_dir): 145 path_to_dir = path_to_dir[:-3] 146 147 suffix = 2 148 path_to_dir_new = path_to_dir 149 while os.path.exists(path_to_dir_new): 150 path_to_dir_new = f"{path_to_dir}-{suffix:02}" 151 suffix += 1 152 return path_to_dir_new
Get a unique directory path similar to the given path.
155def is_empty_directory(path_to_file: str) -> bool: 156 """Check if a directory is empty. 157 Args: 158 path_to_file (str): The path of the directory to check. 159 Returns: 160 bool: True if the directory is empty, False otherwise.""" 161 if os.path.isfile(path_to_file): 162 return False 163 contents = os.listdir(path_to_file) 164 return len(contents) == 0
Check if a directory is empty. Args: path_to_file (str): The path of the directory to check. Returns: bool: True if the directory is empty, False otherwise.
167def is_empty_directory_only_subdirectories(path_to_file: str) -> bool: 168 """Check if a directory is empty by inspecting subdirectories. 169 Args: 170 path_to_file (str): The path of the directory to check. 171 Returns: 172 bool: True if the directory is empty or only contains empty subdirectories, False otherwise. 173 """ 174 if os.path.isfile(path_to_file): 175 return False 176 contents = os.listdir(path_to_file) 177 for content in contents: 178 path_to_sub = os.path.join(path_to_file, content) 179 if os.path.isfile(path_to_sub): 180 return False 181 if not os.path.isfile(path_to_sub): 182 is_empty = is_empty_directory_only_subdirectories(path_to_sub) 183 if not is_empty: 184 return False 185 return True
Check if a directory is empty by inspecting subdirectories. Args: path_to_file (str): The path of the directory to check. Returns: bool: True if the directory is empty or only contains empty subdirectories, False otherwise.