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

Refactor default lock #322

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 43 additions & 91 deletions src/cachetools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,12 +624,32 @@ def __getitem(self, key):
)


class _NoLock:

__slots__ = ()

def __enter__(self):
pass

def __exit__(self, *exc):
pass

def __call__(self, *args, **kwargs):
return self

def acquire(self, *args, **kwargs):
pass

def release(self):
pass


def cached(cache, key=keys.hashkey, lock=None, info=False):
"""Decorator to wrap a function with a memoizing callable that saves
results in a cache.

"""

lock = lock or _NoLock()
def decorator(func):
if info:
hits = misses = 0
Expand Down Expand Up @@ -665,31 +685,6 @@ def cache_clear():

cache_info = getinfo

elif lock is None:

def wrapper(*args, **kwargs):
nonlocal hits, misses
k = key(*args, **kwargs)
try:
result = cache[k]
hits += 1
return result
except KeyError:
misses += 1
v = func(*args, **kwargs)
try:
cache[k] = v
except ValueError:
pass # value too large
return v

def cache_clear():
nonlocal hits, misses
cache.clear()
hits = misses = 0

cache_info = getinfo

else:

def wrapper(*args, **kwargs):
Expand Down Expand Up @@ -730,24 +725,6 @@ def wrapper(*args, **kwargs):
def cache_clear():
pass

elif lock is None:

def wrapper(*args, **kwargs):
k = key(*args, **kwargs)
try:
return cache[k]
except KeyError:
pass # key not found
v = func(*args, **kwargs)
try:
cache[k] = v
except ValueError:
pass # value too large
return v

def cache_clear():
cache.clear()

else:

def wrapper(*args, **kwargs):
Expand Down Expand Up @@ -787,57 +764,32 @@ def cachedmethod(cache, key=keys.methodkey, lock=None):
callable that saves results in a cache.

"""

lock = lock or _NoLock()
def decorator(method):
if lock is None:

def wrapper(self, *args, **kwargs):
c = cache(self)
if c is None:
return method(self, *args, **kwargs)
k = key(self, *args, **kwargs)
try:
def wrapper(self, *args, **kwargs):
c = cache(self)
if c is None:
return method(self, *args, **kwargs)
k = key(self, *args, **kwargs)
try:
with lock(self):
return c[k]
except KeyError:
pass # key not found
v = method(self, *args, **kwargs)
try:
c[k] = v
except ValueError:
pass # value too large
return v

def clear(self):
c = cache(self)
if c is not None:
except KeyError:
pass # key not found
v = method(self, *args, **kwargs)
# in case of a race, prefer the item already in the cache
try:
with lock(self):
return c.setdefault(k, v)
except ValueError:
return v # value too large

def clear(self):
c = cache(self)
if c is not None:
with lock(self):
c.clear()

else:

def wrapper(self, *args, **kwargs):
c = cache(self)
if c is None:
return method(self, *args, **kwargs)
k = key(self, *args, **kwargs)
try:
with lock(self):
return c[k]
except KeyError:
pass # key not found
v = method(self, *args, **kwargs)
# in case of a race, prefer the item already in the cache
try:
with lock(self):
return c.setdefault(k, v)
except ValueError:
return v # value too large

def clear(self):
c = cache(self)
if c is not None:
with lock(self):
c.clear()

wrapper.cache = cache
wrapper.cache_key = key
wrapper.cache_lock = lock
Expand Down
4 changes: 2 additions & 2 deletions tests/test_cached.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def test_decorator_attributes(self):

self.assertIs(wrapper.cache, cache)
self.assertIs(wrapper.cache_key, cachetools.keys.hashkey)
self.assertIs(wrapper.cache_lock, None)
self.assertIsInstance(wrapper.cache_lock, cachetools._NoLock)

def test_decorator_attributes_lock(self):
cache = self.cache(2)
Expand Down Expand Up @@ -226,7 +226,7 @@ def test_decorator_attributes(self):

self.assertIs(wrapper.cache, None)
self.assertIs(wrapper.cache_key, cachetools.keys.hashkey)
self.assertIs(wrapper.cache_lock, None)
self.assertIsInstance(wrapper.cache_lock, cachetools._NoLock)

def test_decorator_clear(self):
wrapper = cachetools.cached(None)(self.func)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_cachedmethod.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import unittest

import cachetools
from cachetools import LRUCache, cachedmethod, keys


Expand Down Expand Up @@ -203,7 +203,7 @@ def test_attributes(self):

self.assertIs(cached.get.cache(cached), cache)
self.assertIs(cached.get.cache_key, keys.methodkey)
self.assertIs(cached.get.cache_lock, None)
self.assertIsInstance(cached.get.cache_lock, cachetools._NoLock)

def test_attributes_lock(self):
cache = {}
Expand Down