167 lines
5.0 KiB
Python
167 lines
5.0 KiB
Python
from __future__ import annotations
|
|
|
|
import shutil
|
|
from collections.abc import Sequence
|
|
from pathlib import Path
|
|
|
|
from dopt_basics.datetime import TIMEZONE_CEST, get_timestamp
|
|
|
|
|
|
def create_folder(
|
|
path: Path,
|
|
delete_existing: bool = False,
|
|
) -> None:
|
|
if delete_existing and path.exists():
|
|
shutil.rmtree(path)
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
def prepare_save_path(
|
|
root_folder: Path,
|
|
dirs: Sequence[str] | None,
|
|
filename: str | None,
|
|
suffix: str | None,
|
|
include_timestamp: bool = False,
|
|
create_folder: bool = False,
|
|
) -> Path:
|
|
if not any((dirs, filename, suffix)):
|
|
raise ValueError("Dirs or filename must be provided")
|
|
if not (
|
|
all(x is None for x in (filename, suffix))
|
|
or all(x is not None for x in (filename, suffix))
|
|
):
|
|
raise ValueError("Filename and suffix must be provided together")
|
|
if include_timestamp and filename is None:
|
|
raise ValueError("Timestamp only with filename")
|
|
|
|
folders: str = ""
|
|
if dirs is not None:
|
|
folders = "/".join(dirs)
|
|
filename = "" if filename is None else filename
|
|
if include_timestamp:
|
|
timestamp = get_timestamp(tz=TIMEZONE_CEST, with_time=True)
|
|
filename = f"{timestamp}_{filename}"
|
|
|
|
if suffix is None:
|
|
suffix = ""
|
|
elif suffix is not None and suffix == ".":
|
|
raise ValueError("Suffix can not be just dot.")
|
|
elif suffix is not None and not suffix.startswith("."):
|
|
suffix = f".{suffix}"
|
|
|
|
pth_parent = (root_folder / folders).resolve()
|
|
if create_folder and not pth_parent.exists():
|
|
pth_parent.mkdir(parents=True)
|
|
|
|
return (pth_parent / filename).with_suffix(suffix)
|
|
|
|
|
|
def search_cwd(
|
|
glob_pattern: str,
|
|
) -> Path | None:
|
|
"""Searches the current working directory and looks for files
|
|
matching the glob pattern.
|
|
Returns the first match encountered.
|
|
|
|
Parameters
|
|
----------
|
|
glob_pattern : str, optional
|
|
pattern to look for, first match will be returned
|
|
|
|
Returns
|
|
-------
|
|
Path | None
|
|
Path if corresponding object was found, None otherwise
|
|
"""
|
|
path_found: Path | None = None
|
|
res = tuple(Path.cwd().glob(glob_pattern))
|
|
if res:
|
|
path_found = res[0]
|
|
|
|
return path_found
|
|
|
|
|
|
def search_file_iterative(
|
|
starting_path: Path,
|
|
glob_pattern: str,
|
|
stop_folder_name: str | None = None,
|
|
) -> Path | None:
|
|
"""Iteratively searches the parent directories of the starting path
|
|
and look for files matching the glob pattern. The starting path is not
|
|
searched, only its parents. Therefore the starting path can also point
|
|
to a file. The folder in which it is placed in will be searched.
|
|
Returns the first match encountered.
|
|
The parent of the stop folder will be searched if it exists.
|
|
|
|
Parameters
|
|
----------
|
|
starting_path : Path
|
|
non-inclusive starting path
|
|
glob_pattern : str, optional
|
|
pattern to look for, first match will be returned
|
|
stop_folder_name : str, optional
|
|
name of the last folder in the directory tree where search should stop
|
|
(parent is searched), by default None
|
|
|
|
Returns
|
|
-------
|
|
Path | None
|
|
Path if corresponding object was found, None otherwise
|
|
"""
|
|
file_path: Path | None = None
|
|
stop_folder_reached: bool = False
|
|
for search_path in starting_path.parents:
|
|
res = tuple(search_path.glob(glob_pattern))
|
|
if res:
|
|
file_path = res[0]
|
|
break
|
|
elif stop_folder_reached:
|
|
break
|
|
|
|
if stop_folder_name is not None and search_path.name == stop_folder_name:
|
|
# library is placed inside a whole python installation for deployment
|
|
# if this folder is reached, only look up one parent above
|
|
stop_folder_reached = True
|
|
|
|
return file_path
|
|
|
|
|
|
def search_folder_path(
|
|
starting_path: Path,
|
|
stop_folder_name: str | None = None,
|
|
) -> Path | None:
|
|
"""Iteratively searches the parent directories of the starting path
|
|
and look for folders matching the given name. If a match is encountered,
|
|
the parent path will be returned.
|
|
|
|
Example:
|
|
starting_path = path/to/start/folder
|
|
stop_folder_name = 'to'
|
|
returned path = 'path/'
|
|
|
|
Parameters
|
|
----------
|
|
starting_path : Path
|
|
non-inclusive starting path
|
|
stop_folder_name : str, optional
|
|
name of the last folder in the directory tree to search, by default None
|
|
|
|
Returns
|
|
-------
|
|
Path | None
|
|
Path if corresponding base path was found, None otherwise
|
|
"""
|
|
stop_folder_path: Path | None = None
|
|
base_path: Path | None = None
|
|
for search_path in starting_path.parents:
|
|
if stop_folder_name is not None and search_path.name == stop_folder_name:
|
|
# library is placed inside a whole python installation for deployment
|
|
# only look up to this folder
|
|
stop_folder_path = search_path
|
|
break
|
|
|
|
if stop_folder_path is not None:
|
|
base_path = stop_folder_path.parent
|
|
|
|
return base_path
|