Coverage for src/extratools_core/functools.py: 100%
48 statements
« prev ^ index » next coverage.py v7.8.1, created at 2025-06-24 04:41 -0700
« prev ^ index » next coverage.py v7.8.1, created at 2025-06-24 04:41 -0700
1from collections import Counter
2from collections.abc import Awaitable, Callable, Iterable
3from decimal import Decimal
4from inspect import Signature, signature
5from statistics import mean
6from typing import Any, cast
9# Name it in this way to mimic as a function
10class lazy_call[T: Any]: # noqa: N801
11 __DEFAULT_OBJECT = object()
13 def __init__(
14 self,
15 func: Callable[..., T],
16 *args: Any,
17 **kwargs: Any,
18 ) -> None:
19 self.__func = func
20 self.__args = args
21 self.__kwargs = kwargs
23 self.__object: object | T = self.__DEFAULT_OBJECT
25 def __call__(self) -> T:
26 if self.__object == self.__DEFAULT_OBJECT:
27 self.__object = self.__func(*self.__args, **self.__kwargs)
29 return cast("T", self.__object)
32# Name it in this way to mimic as a function
33class multi_call[T: Any]: # noqa: N801
34 def __init__(
35 self,
36 times: int,
37 agg_func: Callable[[Iterable[T]], T],
38 ) -> None:
39 self.__times = times
40 self.__agg_func = agg_func
42 def __call__(
43 self,
44 func: Callable[..., T],
45 *args: Any,
46 **kwargs: Any,
47 ) -> T:
48 results = (
49 func(*args, **kwargs)
50 for i in range(self.__times)
51 )
53 return self.__agg_func(results)
56# Name it in this way to mimic as a function
57class multi_call_for_average[T: int | float | Decimal](multi_call[T]): # noqa: N801
58 def __init__(
59 self,
60 times: int,
61 ) -> None:
62 super().__init__(
63 times,
64 mean,
65 )
68# Name it in this way to mimic as a function
69class multi_call_for_most_common[T: Any](multi_call[T]): # noqa: N801
70 def __init__(
71 self,
72 times: int,
73 ) -> None:
74 def most_commmon(results: Iterable[T]) -> T:
75 return Counter(results).most_common(1)[0][0]
77 super().__init__(
78 times,
79 most_commmon,
80 )
83class Intercept[T: Any]:
84 def __init__(
85 self,
86 replacement: Callable[[dict[str, Any]], T],
87 ) -> None:
88 self.__replacement = replacement
90 def __call__[**P](self, f: Callable[P, T]) -> Callable[P, T]:
91 sig: Signature = signature(f)
93 def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
94 return self.__replacement(
95 sig.bind(*args, **kwargs).arguments,
96 )
98 return wrapper
101class InterceptAsync[T: Any]:
102 def __init__(
103 self,
104 replacement: Callable[[dict[str, Any]], Awaitable[T]],
105 ) -> None:
106 self.__replacement = replacement
108 def __call__[**P](self, f: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:
109 sig: Signature = signature(f)
111 async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
112 return await self.__replacement(
113 sig.bind(*args, **kwargs).arguments,
114 )
116 return wrapper