Spaces:
Sleeping
Sleeping
Create utils/f.py
Browse files- server/utils/f.py +100 -0
server/utils/f.py
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""General programming utils, inclined toward functional programming.
|
2 |
+
If ever a function changes its input in place, it is denoted by a trailing `_`
|
3 |
+
"""
|
4 |
+
|
5 |
+
import inspect
|
6 |
+
from itertools import zip_longest
|
7 |
+
from typing import List, Set, Union, Dict
|
8 |
+
|
9 |
+
|
10 |
+
def ifnone(*xs):
|
11 |
+
"""Return the first item in 'x' that is not None"""
|
12 |
+
for x in xs:
|
13 |
+
if x is not None: return x
|
14 |
+
return None
|
15 |
+
|
16 |
+
def custom_dir(c, add): return dir(type(c)) + list(c.__dict__.keys()) + add
|
17 |
+
|
18 |
+
class GetAttr:
|
19 |
+
"""Base class for attr accesses in `self._xtra` passed down to `self.default`
|
20 |
+
|
21 |
+
Taken from article by Jeremy Howard: https://www.fast.ai/2019/08/06/delegation/
|
22 |
+
Usage:
|
23 |
+
```
|
24 |
+
class ProductPage(GetAttr):
|
25 |
+
def __init__(self, page, price, cost):
|
26 |
+
self.page,self.price,self.cost = page,price,cost
|
27 |
+
self.default = page
|
28 |
+
```
|
29 |
+
"""
|
30 |
+
@property
|
31 |
+
def _xtra(self): return [o for o in dir(self.default) if not o.startswith('_')]
|
32 |
+
def __getattr__(self,k):
|
33 |
+
if k in self._xtra: return getattr(self.default, k)
|
34 |
+
raise AttributeError(k)
|
35 |
+
def __dir__(self): return custom_dir(self, self._xtra)
|
36 |
+
|
37 |
+
# Can i delegate many different functions?
|
38 |
+
# Can i add a new docstring to the existing docstring of the delgated function? Or at least point to the function delegated?
|
39 |
+
def delegates(to=None, keep=False):
|
40 |
+
""" Decorator: replace `**kwargs` in signature with params from `to`.
|
41 |
+
|
42 |
+
Taken from article by Jeremy Howard: https://www.fast.ai/2019/08/06/delegation/
|
43 |
+
"""
|
44 |
+
|
45 |
+
def _f(f):
|
46 |
+
if to is None: to_f,from_f = f.__base__.__init__,f.__init__
|
47 |
+
else: to_f,from_f = to,f
|
48 |
+
sig = inspect.signature(from_f)
|
49 |
+
sigd = dict(sig.parameters)
|
50 |
+
k = sigd.pop('kwargs')
|
51 |
+
s2 = {k:v for k,v in inspect.signature(to_f).parameters.items()
|
52 |
+
if v.default != inspect.Parameter.empty and k not in sigd}
|
53 |
+
sigd.update(s2)
|
54 |
+
if keep: sigd['kwargs'] = k
|
55 |
+
from_f.__signature__ = sig.replace(parameters=sigd.values())
|
56 |
+
return f
|
57 |
+
return _f
|
58 |
+
|
59 |
+
def pick(keys:Union[List, Set], obj:Dict) -> Dict:
|
60 |
+
""" Return a NEW object containing `keys` from the original `obj` """
|
61 |
+
return {k: obj[k] for k in keys}
|
62 |
+
|
63 |
+
def memoize(f):
|
64 |
+
"""Memoize a function.
|
65 |
+
|
66 |
+
Use lookup table when the same inputs are passed to the function instead of running that function again
|
67 |
+
"""
|
68 |
+
memo = {}
|
69 |
+
def helper(*x):
|
70 |
+
if x not in memo:
|
71 |
+
memo[x] = f(*x)
|
72 |
+
return memo[x]
|
73 |
+
return helper
|
74 |
+
|
75 |
+
def assoc(k, v, orig):
|
76 |
+
"""Given an original dictionary orig, return a cloned dictionary with `k` set to `v`"""
|
77 |
+
out = orig.copy()
|
78 |
+
out[k] = v
|
79 |
+
return out
|
80 |
+
|
81 |
+
def make_unique(f):
|
82 |
+
"""The input function will only run and return if it hasn't seen its argument before.
|
83 |
+
|
84 |
+
Otherwise, it will return `None`.
|
85 |
+
"""
|
86 |
+
s = set()
|
87 |
+
def helper(x):
|
88 |
+
if x in s:
|
89 |
+
return None
|
90 |
+
s.add(x)
|
91 |
+
return f(x)
|
92 |
+
|
93 |
+
return helper
|
94 |
+
|
95 |
+
def flatten_(items, seqtypes=(list, tuple)):
|
96 |
+
"""Flattten an arbitrarily nested list IN PLACE"""
|
97 |
+
for i, x in enumerate(items):
|
98 |
+
while i < len(items) and isinstance(items[i], seqtypes):
|
99 |
+
items[i:i+1] = items[i]
|
100 |
+
return items
|