Skip to content

Commit

Permalink
raise PicklingError instead of TypeError if the args or result arent …
Browse files Browse the repository at this point in the history
…picklable
  • Loading branch information
dwiel committed Apr 19, 2016
1 parent 6300e45 commit 4b23dcf
Showing 1 changed file with 24 additions and 14 deletions.
38 changes: 24 additions & 14 deletions functioncache/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
USAGE:
from functioncache import functioncache
@functioncache(24 * 60 * 60)
def time_consuming_function(args):
# etc
@functioncache(functioncache.YEAR)
def another_function(args):
# etc
Expand Down Expand Up @@ -55,7 +55,7 @@ def query(...):
@functioncache.functioncache
def somefunc(x, y, z):
return x * y * z
del somefunc._db[functioncache._args_key(somefunc, (1,2,3), {})]
# or just iterate of somefunc._db (it's a shelve, like a dict) to find the right key.
Expand Down Expand Up @@ -135,6 +135,10 @@ def _log_error(error_str):
pass


class PicklingError(TypeError):
pass


def function_name(fn):
return fn.__name__

Expand All @@ -143,14 +147,17 @@ def _args_key(function, args, kwargs, function_key=function_name):
arguments = (args, kwargs)
# Check if you have a valid, cached answer, and return it.
# Sadly this is python version dependant
if _sys.version_info[0] == 2:
arguments_pickle = _pickle.dumps(arguments)
else:
# NOTE: protocol=0 so it's ascii, this is crucial for py3k
# because shelve only works with proper strings.
# Otherwise, we'd get an exception because
# function.__name__ is str but dumps returns bytes.
arguments_pickle = _pickle.dumps(arguments, protocol=0).decode('ascii')
try:
if _sys.version_info[0] == 2:
arguments_pickle = _pickle.dumps(arguments)
else:
# NOTE: protocol=0 so it's ascii, this is crucial for py3k
# because shelve only works with proper strings.
# Otherwise, we'd get an exception because
# function.__name__ is str but dumps returns bytes.
arguments_pickle = _pickle.dumps(arguments, protocol=0).decode('ascii')
except TypeError as e:
raise PicklingError(str(e))

key = function_key(function) + arguments_pickle
return key
Expand Down Expand Up @@ -214,20 +221,23 @@ def __setitem__(self, key, value):
try:
file = open(self._get_filename(key), 'w')
portalocker.Lock(file)
_pickle.dump(value, file, _pickle.HIGHEST_PROTOCOL)
try:
_pickle.dump(value, file, _pickle.HIGHEST_PROTOCOL)
except TypeError as e:
raise PicklingError(str(e))
except portalocker.LockException, e:
# someone else had the lock, thats ok, we don't have to
# write the value if someone else already is
pass
except Exception, e:
except Exception as e:
# delete the file in the event of an exception during saving
# to protect from corrupted files causing problems later
try:
_os.remove(self._get_filename(key))
except OSError:
pass

raise e
raise

def _get_filename(self, key):
# hash the key and use as a filename
Expand Down

0 comments on commit 4b23dcf

Please sign in to comment.