|
import os |
|
import warnings |
|
from enum import Enum |
|
from pathlib import Path |
|
from typing import List, Union |
|
|
|
try: |
|
from typing import Literal |
|
except ImportError: |
|
from typing_extensions import Literal |
|
|
|
|
|
def check_path_suffix(path_str: str, |
|
allowed_suffix: Union[str, List[str]] = '') -> bool: |
|
"""Check whether the suffix of the path is allowed. |
|
|
|
Args: |
|
path_str (str): |
|
Path to check. |
|
allowed_suffix (List[str], optional): |
|
What extension names are allowed. |
|
Offer a list like ['.jpg', ',jpeg']. |
|
When it's [], all will be received. |
|
Use [''] then directory is allowed. |
|
Defaults to []. |
|
|
|
Returns: |
|
bool: |
|
True: suffix test passed |
|
False: suffix test failed |
|
""" |
|
if isinstance(allowed_suffix, str): |
|
allowed_suffix = [allowed_suffix] |
|
pathinfo = Path(path_str) |
|
suffix = pathinfo.suffix.lower() |
|
if len(allowed_suffix) == 0: |
|
return True |
|
if pathinfo.is_dir(): |
|
if '' in allowed_suffix: |
|
return True |
|
else: |
|
return False |
|
else: |
|
for index, tmp_suffix in enumerate(allowed_suffix): |
|
if not tmp_suffix.startswith('.'): |
|
tmp_suffix = '.' + tmp_suffix |
|
allowed_suffix[index] = tmp_suffix.lower() |
|
if suffix in allowed_suffix: |
|
return True |
|
else: |
|
return False |
|
|
|
|
|
class Existence(Enum): |
|
"""State of file existence.""" |
|
FileExist = 0 |
|
DirectoryExistEmpty = 1 |
|
DirectoryExistNotEmpty = 2 |
|
MissingParent = 3 |
|
DirectoryNotExist = 4 |
|
FileNotExist = 5 |
|
|
|
|
|
def check_path_existence( |
|
path_str: str, |
|
path_type: Literal['file', 'dir', 'auto'] = 'auto', |
|
) -> Existence: |
|
"""Check whether a file or a directory exists at the expected path. |
|
|
|
Args: |
|
path_str (str): |
|
Path to check. |
|
path_type (Literal[, optional): |
|
What kind of file do we expect at the path. |
|
Choose among `file`, `dir`, `auto`. |
|
Defaults to 'auto'. path_type = path_type.lower() |
|
|
|
Raises: |
|
KeyError: if `path_type` conflicts with `path_str` |
|
|
|
Returns: |
|
Existence: |
|
0. FileExist: file at path_str exists. |
|
1. DirectoryExistEmpty: folder at path exists and. |
|
2. DirectoryExistNotEmpty: folder at path_str exists and not empty. |
|
3. MissingParent: its parent doesn't exist. |
|
4. DirectoryNotExist: expect a folder at path_str, but not found. |
|
5. FileNotExist: expect a file at path_str, but not found. |
|
""" |
|
path_type = path_type.lower() |
|
assert path_type in {'file', 'dir', 'auto'} |
|
pathinfo = Path(path_str) |
|
if not pathinfo.parent.is_dir(): |
|
return Existence.MissingParent |
|
suffix = pathinfo.suffix.lower() |
|
if path_type == 'dir' or\ |
|
path_type == 'auto' and suffix == '': |
|
if pathinfo.is_dir(): |
|
if len(os.listdir(path_str)) == 0: |
|
return Existence.DirectoryExistEmpty |
|
else: |
|
return Existence.DirectoryExistNotEmpty |
|
else: |
|
return Existence.DirectoryNotExist |
|
elif path_type == 'file' or\ |
|
path_type == 'auto' and suffix != '': |
|
if pathinfo.is_file(): |
|
return Existence.FileExist |
|
elif pathinfo.is_dir(): |
|
if len(os.listdir(path_str)) == 0: |
|
return Existence.DirectoryExistEmpty |
|
else: |
|
return Existence.DirectoryExistNotEmpty |
|
if path_str.endswith('/'): |
|
return Existence.DirectoryNotExist |
|
else: |
|
return Existence.FileNotExist |
|
|
|
|
|
def prepare_output_path(output_path: str, |
|
allowed_suffix: List[str] = [], |
|
tag: str = 'output file', |
|
path_type: Literal['file', 'dir', 'auto'] = 'auto', |
|
overwrite: bool = True) -> None: |
|
"""Check output folder or file. |
|
|
|
Args: |
|
output_path (str): could be folder or file. |
|
allowed_suffix (List[str], optional): |
|
Check the suffix of `output_path`. If folder, should be [] or ['']. |
|
If could both be folder or file, should be [suffixs..., '']. |
|
Defaults to []. |
|
tag (str, optional): The `string` tag to specify the output type. |
|
Defaults to 'output file'. |
|
path_type (Literal[, optional): |
|
Choose `file` for file and `dir` for folder. |
|
Choose `auto` if allowed to be both. |
|
Defaults to 'auto'. |
|
overwrite (bool, optional): |
|
Whether overwrite the existing file or folder. |
|
Defaults to True. |
|
|
|
Raises: |
|
FileNotFoundError: suffix does not match. |
|
FileExistsError: file or folder already exists and `overwrite` is |
|
False. |
|
|
|
Returns: |
|
None |
|
""" |
|
if path_type.lower() == 'dir': |
|
allowed_suffix = [] |
|
exist_result = check_path_existence(output_path, path_type=path_type) |
|
if exist_result == Existence.MissingParent: |
|
warnings.warn( |
|
f'The parent folder of {tag} does not exist: {output_path},' + |
|
f' will make dir {Path(output_path).parent.absolute().__str__()}') |
|
os.makedirs(Path(output_path).parent.absolute().__str__(), |
|
exist_ok=True) |
|
|
|
elif exist_result == Existence.DirectoryNotExist: |
|
os.mkdir(output_path) |
|
print(f'Making directory {output_path} for saving results.') |
|
elif exist_result == Existence.FileNotExist: |
|
suffix_matched = \ |
|
check_path_suffix(output_path, allowed_suffix=allowed_suffix) |
|
if not suffix_matched: |
|
raise FileNotFoundError( |
|
f'The {tag} should be {", ".join(allowed_suffix)}: ' |
|
f'{output_path}.') |
|
elif exist_result == Existence.FileExist: |
|
if not overwrite: |
|
raise FileExistsError( |
|
f'{output_path} exists (set overwrite = True to overwrite).') |
|
else: |
|
print(f'Overwriting {output_path}.') |
|
elif exist_result == Existence.DirectoryExistEmpty: |
|
pass |
|
elif exist_result == Existence.DirectoryExistNotEmpty: |
|
if not overwrite: |
|
raise FileExistsError( |
|
f'{output_path} is not empty (set overwrite = ' |
|
'True to overwrite the files).') |
|
else: |
|
print(f'Overwriting {output_path} and its files.') |
|
else: |
|
raise FileNotFoundError(f'No Existence type for {output_path}.') |
|
|
|
|
|
def check_input_path( |
|
input_path: str, |
|
allowed_suffix: List[str] = [], |
|
tag: str = 'input file', |
|
path_type: Literal['file', 'dir', 'auto'] = 'auto', |
|
): |
|
"""Check input folder or file. |
|
|
|
Args: |
|
input_path (str): input folder or file path. |
|
allowed_suffix (List[str], optional): |
|
Check the suffix of `input_path`. If folder, should be [] or ['']. |
|
If could both be folder or file, should be [suffixs..., '']. |
|
Defaults to []. |
|
tag (str, optional): The `string` tag to specify the output type. |
|
Defaults to 'output file'. |
|
path_type (Literal[, optional): |
|
Choose `file` for file and `directory` for folder. |
|
Choose `auto` if allowed to be both. |
|
Defaults to 'auto'. |
|
|
|
Raises: |
|
FileNotFoundError: file does not exists or suffix does not match. |
|
|
|
Returns: |
|
None |
|
""" |
|
if path_type.lower() == 'dir': |
|
allowed_suffix = [] |
|
exist_result = check_path_existence(input_path, path_type=path_type) |
|
|
|
if exist_result in [ |
|
Existence.FileExist, Existence.DirectoryExistEmpty, |
|
Existence.DirectoryExistNotEmpty |
|
]: |
|
suffix_matched = \ |
|
check_path_suffix(input_path, allowed_suffix=allowed_suffix) |
|
if not suffix_matched: |
|
raise FileNotFoundError( |
|
f'The {tag} should be {", ".join(allowed_suffix)}:' + |
|
f'{input_path}.') |
|
else: |
|
raise FileNotFoundError(f'The {tag} does not exist: {input_path}.') |
|
|