117 lines
3 KiB
Python
117 lines
3 KiB
Python
from pathlib import Path
|
|
import functools
|
|
from typing import Union, Callable, Dict, List, Iterable, TypeVar
|
|
|
|
# some helper functions
|
|
|
|
def import_file(p: Union[str, Path], name=None):
|
|
p = Path(p)
|
|
if name is None:
|
|
name = p.stem
|
|
import importlib.util
|
|
spec = importlib.util.spec_from_file_location(name, p) # type: ignore
|
|
foo = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(foo) # type: ignore
|
|
return foo
|
|
|
|
def import_from(path, name):
|
|
path = str(path)
|
|
import sys
|
|
try:
|
|
sys.path.append(path)
|
|
import importlib
|
|
return importlib.import_module(name)
|
|
finally:
|
|
sys.path.remove(path)
|
|
|
|
|
|
T = TypeVar('T')
|
|
K = TypeVar('K')
|
|
V = TypeVar('V')
|
|
|
|
def the(l: Iterable[T]) -> T:
|
|
it = iter(l)
|
|
try:
|
|
first = next(it)
|
|
except StopIteration as ee:
|
|
raise RuntimeError('Empty iterator?')
|
|
assert all(e == first for e in it)
|
|
return first
|
|
|
|
|
|
def group_by_key(l: Iterable[T], key: Callable[[T], K]) -> Dict[K, List[T]]:
|
|
res: Dict[K, List[T]] = {}
|
|
for i in l:
|
|
kk = key(i)
|
|
lst = res.get(kk, [])
|
|
lst.append(i)
|
|
res[kk] = lst
|
|
return res
|
|
|
|
|
|
Cl = TypeVar('Cl')
|
|
R = TypeVar('R')
|
|
|
|
def cproperty(f: Callable[[Cl], R]) -> R:
|
|
return property(functools.lru_cache(maxsize=1)(f)) # type: ignore
|
|
|
|
|
|
# https://stackoverflow.com/a/12377059/706389
|
|
def listify(fn=None, wrapper=list):
|
|
"""
|
|
Wraps a function's return value in wrapper (e.g. list)
|
|
Useful when an algorithm can be expressed more cleanly as a generator
|
|
"""
|
|
def listify_return(fn):
|
|
@functools.wraps(fn)
|
|
def listify_helper(*args, **kw):
|
|
return wrapper(fn(*args, **kw))
|
|
return listify_helper
|
|
if fn is None:
|
|
return listify_return
|
|
return listify_return(fn)
|
|
|
|
|
|
# TODO FIXME use in bluemaestro
|
|
# def dictify(fn=None, key=None, value=None):
|
|
# def md(it):
|
|
# return make_dict(it, key=key, value=value)
|
|
# return listify(fn=fn, wrapper=md)
|
|
|
|
|
|
from .kython.klogging import setup_logger, LazyLogger
|
|
|
|
PathIsh = Union[Path, str]
|
|
|
|
|
|
def get_files(pp: PathIsh, glob: str, sort=True) -> List[Path]:
|
|
"""
|
|
Helper function to avoid boilerplate.
|
|
"""
|
|
path = Path(pp)
|
|
if path.is_dir():
|
|
gp: Iterable[Path] = path.glob(glob)
|
|
if sort:
|
|
gp = sorted(gp)
|
|
return list(gp)
|
|
else:
|
|
assert path.is_file(), path
|
|
# TODO FIXME assert matches glob??
|
|
return [path]
|
|
|
|
|
|
def mcachew(*args, **kwargs):
|
|
"""
|
|
Stands for 'Maybe cachew'.
|
|
Defensive wrapper around @cachew to make it an optional dependency.
|
|
"""
|
|
try:
|
|
import cachew
|
|
except ModuleNotFoundError:
|
|
import warnings
|
|
warnings.warn('cachew library not found. You might want to install it to speed things up. See https://github.com/karlicoss/cachew')
|
|
return lambda orig_func: orig_func
|
|
else:
|
|
import cachew.experimental
|
|
cachew.experimental.enable_exceptions() # TODO do it only once?
|
|
return cachew.cachew(*args, **kwargs)
|