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