Source code for neuralib.util.utils

import re
from collections.abc import Collection
from dataclasses import is_dataclass
from pathlib import Path
from typing import Any, Literal, TypeVar, overload

from neuralib.typing import PathLike
from neuralib.typing.func import is_namedtuple
from neuralib.util.verbose import fprint

__all__ = ['uglob',
           'filter_matched',
           'joinn',
           'ensure_dir',
           'keys_with_value',
           'cls_hasattr']


[docs] def uglob(directory: PathLike, pattern: str, is_dir: bool = False) -> Path: """ Use glob pattern to find the unique file in the directory. :param directory: Directory :param pattern: Glob pattern :param is_dir: Is the pattern point to a directory? :return: The unique path :raise FileNotFoundError: the unique path is not existed. :raise NotADirectoryError: *directory* is not a directory :raise RuntimeError: more than one path are found. """ directory = Path(directory) if not directory.exists(): raise FileNotFoundError(f'{directory} not exit') if not directory.is_dir(): raise NotADirectoryError(f'{directory} is not a directory') f = list(directory.glob(pattern)) if is_dir: f = [ff for ff in f if ff.is_dir()] else: f = [ff for ff in f if not ff.is_dir()] if len(f) == 0: t = 'directory' if is_dir else 'file' raise FileNotFoundError(f'{directory} not have {t} with the pattern: {pattern}') elif len(f) == 1: return f[0] else: f.sort() t = 'directories' if is_dir else 'files' raise RuntimeError(f'multiple {t} were found in {directory} with the pattern {pattern} >>> {f}')
[docs] def filter_matched(pattern: str, strings: list[str]) -> list[str]: """ Filter a list of string element that match the pattern. :param pattern: Regular expression :param strings: List of strings to find the pattern :return: """ return list(filter(re.compile(pattern).match, strings))
[docs] def ensure_dir(p: PathLike, verbose: bool = True) -> Path: """ Ensure the path is a directory. Create if it is not exist. :param p: path to be checked :param verbose: print verbose message """ p = Path(p) if not p.exists(): p.mkdir(parents=True) if verbose: fprint(f'create dir {p}', vtype='io') if not p.is_dir(): raise NotADirectoryError(f'not a dir: {p}') return p
[docs] def joinn(sep: str, *part: str | None) -> str: """join non-None str with sep.""" return sep.join([str(it) for it in part if it is not None])
# ============================== # KT = TypeVar('KT') VT = TypeVar('VT') @overload def keys_with_value(dy: dict[KT, Any | Collection[VT]], value: VT, to_item: Literal[False] = False) -> list[KT]: pass @overload def keys_with_value(dy: dict[KT, VT | Collection[VT]], value: VT, to_item: Literal[True] = True) -> KT: pass
[docs] def keys_with_value(dy, value, to_item=False): """ Get keys from a dict that are associated with the value. Supports value types: str, int, float (with tolerance), and any collection types. :param dy: The value to match against the dictionary values :param value: The value to match against the dictionary value :param to_item: List of item to item if unique :return: A list of keys whose values match the provided value """ matching_keys = [] def _float_eq(v1, v2, tol=1e-9) -> bool: return abs(v1 - v2) < tol for key, val in dy.items(): if isinstance(val, float) and isinstance(value, float): if _float_eq(val, value): matching_keys.append(key) elif isinstance(val, (str, int, Collection)) or is_namedtuple(val) or is_dataclass(val): if val == value: matching_keys.append(key) if to_item: if len(matching_keys) == 0: raise KeyError(f'{value} does not match any keys') elif len(matching_keys) == 1: return matching_keys[0] else: raise ValueError(f'multiple match keys: {matching_keys}') else: return matching_keys
[docs] def cls_hasattr(cls: type, attr: str) -> bool: """ Check if attributes in class :param cls: The class to check for the attribute. :param attr: The name of the attribute to look for within the class and its hierarchy. :return: True if the class or any of its parent classes has the specified attribute, False otherwise. """ if attr in getattr(cls, '__annotations__', {}): return True for c in cls.mro()[1:]: # Skip the first class as it's already checked if attr in getattr(c, '__annotations__', {}): return True return False