Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added the cache_file decorator #221

Merged
merged 9 commits into from
May 7, 2024
Merged
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ name = "TCutility"
# Original authors
authors = [{ name = "TheoCheM group" }]
dependencies = [
"lxml==5.2.0",
"gitpython",
"numpy>=1.20.0",
"matplotlib>=3.4.0",
Expand Down
106 changes: 102 additions & 4 deletions src/tcutility/cache.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import time
import functools
import json
import os


_timed_func_cache = {}
Expand All @@ -9,6 +11,8 @@

_general_cache = {}

_cache_dir = os.path.join(os.path.split(__file__)[0], '.cache')


def timed_cache(delay: float):
'''
Expand Down Expand Up @@ -72,7 +76,101 @@ def inner_decorator(*args, **kwargs):
return inner_decorator


if __name__ == '__main__':
@timed_cache(1)
def test_timer(a, b):
return a * b
def _get_from_cache_file(file, func, args, kwargs):
'''
Retrieve results from a JSON file.
'''
# open the file and parse the data
with open(os.path.join(_cache_dir, file)) as cfile:
data = json.loads(cfile.read())

# we now go through the data
# it is formatted as a list of dicts
# each dict has the 'func', 'args', 'kwargs' and 'value' keys
for datum in data:
# func is set as the function qualname
if datum['func'] != func.__qualname__:
continue

# args is retrieved as a list
if datum['args'] != list(args):
continue

# kwargs is simply a dict
if datum['kwargs'] != kwargs:
continue

# if we did not exit the loop yet we return the value
return datum['value']


def _write_to_cache_file(file, func, args, kwargs, value):
'''
Write results to the file.
'''
# we open the file to get the data
with open(os.path.join(_cache_dir, file)) as cfile:
data = json.loads(cfile.read())

# add the new results to the file
new = {
'func': func.__qualname__,
'args': args,
'kwargs': kwargs,
'value': value
}
data.append(new)

with open(os.path.join(_cache_dir, file), 'w+') as cfile:
cfile.write(json.dumps(data, indent=4))


def _clear_cache_file(file):
'''
Function that clears a file and writes a new beginning of a list.
'''
os.makedirs(_cache_dir, exist_ok=True)
with open(os.path.join(_cache_dir, file), 'w+') as cfile:
cfile.write('[]')


def cache_file(file):
'''
Function decorator that stores results of a function to a file.

Args:
file: the filepath to store function call results to.
'''
def decorator(func):
# make the file if it doesnt exist
if not os.path.exists(os.path.join(_cache_dir, file)):
_clear_cache_file(file)

@functools.wraps(func)
def inner_decorator(*args, **kwargs):
# check if the arguments were called before
cached = _get_from_cache_file(file, func, args, kwargs)
if cached is not None:
return cached

# if it is not present we add it to the cache file
res = func(*args, **kwargs)
_write_to_cache_file(file, func, args, kwargs, res)
return res

return inner_decorator
return decorator




# if __name__ == '__main__':
@cache_file('test.json')
def test(a, b, c):
return a + b * c

test(1, 2, 3)
test(1, 2, 3)
test(1, 4, 3)
test(1, 2, 3)
test(1, 4, 3)
Loading