File size: 2,111 Bytes
bab1031
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"""Utility module.

Commonly used functions and classes are here.
"""

from datetime import datetime

from src.common.logger import log_info


vars_ = lambda obj: {k: v for k, v in vars(obj).items() if not k.startswith("__")}
str2dt = lambda s, format="%Y-%m-%d": datetime.strptime(s, format)
dt2str = lambda dt, format="%Y-%m-%d": dt.strftime(format)


def lmap(fn: callable, arr: list, scheduler: str | None = None) -> list:
    """List map.

    Args:
        fn (callable): Function to apply
        arr (list): List to apply function
        scheduler (str, optional): Dask scheduler. Defaults to None.
            - None | "single-threaded": Single-threaded
            - "threads": Multi-threaded
            - "processes": Multi-process

    Returns:
        list: List of results
    """
    if scheduler is None:
        return list(map(fn, arr))
    else:
        from dask import delayed, compute

        assert scheduler in [
            "single-threaded",
            "threads",
            "processes",
        ], f"Invalid scheduler: {scheduler}"
        tasks = (delayed(fn)(e) for e in arr)
        return list(compute(*tasks, scheduler=scheduler))


def tprint(dic: dict) -> None:
    """Table print."""
    import tabulate

    # print with fancy 'psql' format
    log_info(tabulate(dic, headers="keys", tablefmt="psql"))


def str2bool(s: str | bool) -> bool:
    """String to boolean."""
    if isinstance(s, bool):
        return s
    if s.lower() in ("yes", "true", "t", "y", "1"):
        return True
    elif s.lower() in ("no", "false", "f", "n", "0"):
        return False
    else:
        raise ValueError(f"Invalid input: {s} (type: {type(s)})")


class MetaSingleton(type):
    """Meta singleton.

    Example:
        >>> class A(metaclass=MetaSingleton):
        ...     pass
        >>> a1 = A()
        >>> a2 = A()
        >>> assert a1 is a2
    """

    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]