From 102d22dd40988f0a1b3aa581c4f32eed4de81379 Mon Sep 17 00:00:00 2001 From: Jordan Suchow Date: Thu, 22 Jan 2015 01:06:00 -0800 Subject: [PATCH] Allow memoization to disk for shared processing #20 --- .gitignore | 1 + proselint/checks/example_check.py | 3 ++ proselint/memoize.py | 53 +++++++++++++++++++++++++++++++ proselint/reverse.py | 6 ++++ 4 files changed, 63 insertions(+) create mode 100644 proselint/memoize.py create mode 100644 proselint/reverse.py diff --git a/.gitignore b/.gitignore index 66dbf51bd..83e9a1e1c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.egg-info *.pyc +cached_func_calls/* diff --git a/proselint/checks/example_check.py b/proselint/checks/example_check.py index 2f36c22bb..cbd46d042 100644 --- a/proselint/checks/example_check.py +++ b/proselint/checks/example_check.py @@ -14,10 +14,13 @@ The first line always is always wrong. """ +from proselint.reverse import reverse def check(text): + reversed_text = reverse(text) + error_code = "PL000" msg = "First line always has an error." diff --git a/proselint/memoize.py b/proselint/memoize.py new file mode 100644 index 000000000..c413a2536 --- /dev/null +++ b/proselint/memoize.py @@ -0,0 +1,53 @@ +import os +import shelve +import inspect +import functools + +cache_dirname = 'cached_func_calls' + + +def memoize(f): + if not os.path.isdir(cache_dirname): + os.mkdir(cache_dirname) + print 'Created cache directory %s' \ + % os.path.join(os.path.abspath(__file__), cache_dirname) + + cache_filename = f.__module__ + f.__name__ + cachepath = os.path.join(cache_dirname, cache_filename) + + try: + cache = shelve.open(cachepath, protocol=2) + except: + print 'Could not open cache file %s, maybe name collision' % cachepath + cache = None + + @functools.wraps(f) + def wrapped(*args, **kwargs): + argdict = {} + + # handle instance methods + if hasattr(f, '__self__'): + args = args[1:] + # argdict['classname'] = f.__self__.__class__ + + tempargdict = inspect.getcallargs(f, *args, **kwargs) + + # handle numpy arrays + for k, v in tempargdict.iteritems(): + argdict[k] = v + + key = str(hash(frozenset(argdict.items()))) + + try: + return cache[key] + except KeyError: + value = f(*args, **kwargs) + cache[key] = value + cache.sync() + return value + except TypeError: + print 'Warning: could not disk cache call to %s; it probably has unhashable args' \ + % (f.__module__ + '.' + f.__name__) + return f(*args, **kwargs) + + return wrapped diff --git a/proselint/reverse.py b/proselint/reverse.py new file mode 100644 index 000000000..458060b00 --- /dev/null +++ b/proselint/reverse.py @@ -0,0 +1,6 @@ +from memoize import memoize + + +@memoize +def reverse(text): + return text[::-1]