-
Notifications
You must be signed in to change notification settings - Fork 0
/
cache_local.py
66 lines (54 loc) · 1.79 KB
/
cache_local.py
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
import os
import json
from functools import wraps
from hashlib import sha1
MAX_FILENAME_LENGTH = 40
CACHE_DIR = os.path.join(os.path.dirname(__file__), '_cache')
if not os.path.exists(CACHE_DIR):
os.makedirs(CACHE_DIR)
class CacheNotFound(Exception):
pass
def _args_to_fname(name, args, kwargs)-> str:
arg_kw = str(args) + str(kwargs)
arg_kw = "".join(c if c.isalnum() else '_' for c in arg_kw)
fname = name + '_' + arg_kw
while '__' in fname:
fname = fname.replace('__', '_')
if len(fname) > MAX_FILENAME_LENGTH:
# name too long. using hash.
fname = sha1(fname.encode()).hexdigest()
return fname
def _save_result_to_file(fname, result):
mode = 'w'
if isinstance(result, dict):
result = json.dumps(result, indent=4)
if isinstance(result, bytes):
mode = 'wb'
with open(os.path.join(CACHE_DIR, fname), mode) as f:
f.write(result)
def _read_cache_from_file(fname):
mode = 'r'
if fname.startswith('fullimage'):
mode = 'rb'
try:
with open(os.path.join(CACHE_DIR, fname), mode) as f:
print(f"reading from cache: {fname}")
result = f.read()
if isinstance(result, str):
if result.startswith('{') or result.startswith('['):
result = json.loads(result)
return result
except FileNotFoundError:
raise CacheNotFound
def cache_local(f):
@wraps(f)
def decorated(*args, **kwargs):
fname = _args_to_fname(decorated.__name__, args, kwargs)
try:
result = _read_cache_from_file(fname)
except CacheNotFound:
result = f(*args, **kwargs)
print(f"saving cache: {fname}")
_save_result_to_file(fname, result)
return result
return decorated