def test_2(self): """Test persistency of cached results.""" c = Cache(TESTFILE) @c def f1(a, b): print("computing new result") self.frun = True return a @c def f2(a, b): print("computing new result") self.frun = True return a c = Cache(TESTFILE) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,2L), {}, 1, True) self.call(f1, "f1", (1,3), {}, 1, True) self.call(f2, "f2", (1,3), {}, 1, True) self.call(f2, "f2", ("2",3), {}, "2", False) self.call(f2, "f2", ("2",3), {}, "2", True) c.close()
def test_2(self): """Test persistency of cached results.""" self.c = Cache(TESTFILE) @self.c def f1(a, b): print("computing new result") self.frun = True return a @self.c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 3), {}, 1, True) self.call(f2, "f2", (1, 3), {}, 1, True) self.call(f2, "f2", ("2", 3), {}, "2", False) self.call(f2, "f2", ("2", 3), {}, "2", True) self.c.close()
def test_check(self): """Test if old `check` interface still works.""" self.c = Cache(TESTFILE) @self.c.check def f1(a, b): print("computing new result") self.frun = True return a @self.c.check def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1, 2), {}, 1, False) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, True) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, False) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, True) self.c.close()
def test_7(self): """Test overridden __repr__ method.""" self.c = Cache(TESTFILE) class X(object): def __init__(self, a): self.a = a def __repr__(self): return repr(self.a) class Y(object): def __init__(self, a): self.a = a @self.c def f7(a): print("computing new result") self.frun = True return 0 self.call(f7, "f7", (X(1), ), {}, 0, False) self.call(f7, "f7", (X(1), ), {}, 0, True) self.call(f7, "f7", (X(2), ), {}, 0, False) y1, y2 = Y(1), Y(1) self.call(f7, "f7", (y1, ), {}, 0, False) self.call(f7, "f7", (y2, ), {}, 0, False) # bad __repr__ method self.c.close()
def test_1(self): """Test differentiation of basic numeric arguments.""" c = Cache(TESTFILE) @c def f1(a, b): print("computing new result") self.frun = True return a @c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1,2), {}, 1, False) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,2L), {}, 1, False) self.call(f1, "f1", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, True) self.call(f2, "f2", (1.1,0.1), {}, 1.1, False) self.call(f2, "f2", (1.1,0.1), {}, 1.1, True) c.close()
def test_1(self): """Test differentiation of basic numeric arguments.""" self.c = Cache(TESTFILE) @self.c def f1(a, b): print("computing new result") self.frun = True return a @self.c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1, 2), {}, 1, False) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, True) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, False) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, True) self.c.close()
def test_check(self): """Test if old `check` interface still works.""" c = Cache(TESTFILE) @c.check def f1(a, b): print("computing new result") self.frun = True return a @c.check def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1,2), {}, 1, False) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,2L), {}, 1, False) self.call(f1, "f1", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, True) self.call(f2, "f2", (1.1,0.1), {}, 1.1, False) self.call(f2, "f2", (1.1,0.1), {}, 1.1, True) c.close()
def test_7(self): """Test overridden __repr__ method.""" c = Cache(TESTFILE) class X(object): def __init__(self, a): self.a = a def __repr__(self): return repr(self.a) class Y(object): def __init__(self, a): self.a = a @c def f7(a): print("computing new result") self.frun = True return 0 self.call(f7, "f7", (X(1),), {}, 0, False) self.call(f7, "f7", (X(1),), {}, 0, True) self.call(f7, "f7", (X(2),), {}, 0, False) y1, y2 = Y(1), Y(1) self.call(f7, "f7", (y1,), {}, 0, False) self.call(f7, "f7", (y2,), {}, 0, False) # bad __repr__ method c.close()
def __init__(self, backend, fileDependencyList=None, maxAgeSec=60 * 60 * 24 * 7): ''' Note: Since there are decorator arguments, the function is passed to __call__() instead. The arguments here are the arguments to the decorator. Since this inherits the Cache Inputs: backend - If backend is a string, it is interpreted as a filename and a Python shelve is used as the backend. Shelf creates multiple files using that basename. Otherwise it is interpreted as a mapping-like object with a `close()` and a `sync()` method. This allows to use alternative backends like *shove* or *redis*. fileDependencyList - a list of files that the results of the function depend on. maxAgeSec - The number of seconds since last use before something is automatically removed from the cache, on initialization. #Note: You can overwrite the __repr function by passing it to the Cache__init__ as well. Right now, we're just using the default. See the documentation for details. ''' #print('file dependencies are: ', fileDependencyList, file=sys.stderr) #Start calculating a hash: h = hashlib.md5() #Create our hash of the file contents: for filePath in fileDependencyList: with open(filePath, 'rb') as file: h.update(file.read()) #Calculate the hash and store it: self.__fileDependencyHash = h.hexdigest() #Initialize our persistent cache: Cache.__init__(self, backend) #Clean our cache of any old stuff: self.clear(maxAgeSec)
def test_3(self): """Test differentiation of normal and unicode strings.""" c = Cache(TESTFILE) @c def f3(s): print("computing new result") self.frun = True return None self.call(f3, "f3", ("a",), {}, None, False) self.call(f3, "f3", (u"a",), {}, None, False) self.call(f3, "f3", ("a",), {}, None, True) self.call(f3, "f3", (u"a",), {}, None, True) c.close()
def test_6(self): """Test keyword arguments.""" self.c = Cache(TESTFILE) @self.c def f6(a, x=1, y=2, z=3): print("computing new result") self.frun = True return a + x + y + z self.call(f6, "f6", (1, ), {"z": 1, "y": 1}, 4, False) self.call(f6, "f6", (1, ), {"z": 1, "y": 1}, 4, True) self.call(f6, "f6", (1, ), {"y": 1, "z": 1}, 4, True) self.call(f6, "f6", (1, ), {"y": 0, "z": 2}, 4, False) self.call(f6, "f6", (1, ), {"z": 2, "y": 0}, 4, True) self.c.close()
def test_6(self): """Test keyword arguments.""" c = Cache(TESTFILE) @c def f6(a, x=1, y=2, z=3): print("computing new result") self.frun = True return a + x + y + z self.call(f6, "f6", (1,), {"z":1,"y":1}, 4, False) self.call(f6, "f6", (1,), {"z":1,"y":1}, 4, True) self.call(f6, "f6", (1,), {"y":1,"z":1}, 4, True) self.call(f6, "f6", (1,), {"y":0,"z":2}, 4, False) self.call(f6, "f6", (1,), {"z":2,"y":0}, 4, True) c.close()
def test_4(self): """Test non-ascii strings as args""" self.c = Cache(TESTFILE) @self.c def f4(a): print("computing new result") self.frun = True return a us = u'über' self.call(f4, "f4", (us, ), {}, us, False) self.call(f4, "f4", (us, ), {}, us, True) us = u'über'.encode('UTF8') self.call(f4, "f4", (us, ), {}, us, False) self.call(f4, "f4", (us, ), {}, us, True) self.c.close()
def test_3(self): """Test differentiation of normal and unicode strings.""" if sys.version_info[0] == 3: return # Python 3 only has strings self.c = Cache(TESTFILE) @self.c def f3(s): print("computing new result") self.frun = True return None self.call(f3, "f3", ("a", ), {}, None, False) self.call(f3, "f3", (u"a", ), {}, None, False) self.call(f3, "f3", ("a", ), {}, None, True) self.call(f3, "f3", (u"a", ), {}, None, True) self.c.close()
def test_5(self): """Test clearing of old cached results.""" self.c = Cache(TESTFILE) @self.c def f5(a): print("computing new result") self.frun = True return a self.call(f5, "f5", (1, ), {}, 1, False) time.sleep(2) self.call(f5, "f5", (2, ), {}, 2, False) self.c.clear(maxage=1) self.call(f5, "f5", (1, ), {}, 1, False) self.call(f5, "f5", (2, ), {}, 2, True) self.c.close()
def test_5(self): """Test clearing of old cached results.""" c = Cache(TESTFILE) @c def f5(a): print("computing new result") self.frun = True return a self.call(f5, "f5", (1,), {}, 1, False) time.sleep(2) self.call(f5, "f5", (2,), {}, 2, False) c.clear(maxage=1) self.call(f5, "f5", (1,), {}, 1, False) self.call(f5, "f5", (2,), {}, 2, True) c.close()
def test_8(self): """Test custom repr function.""" def myrepr(a): return "foobar" self.c = Cache(TESTFILE, repr=myrepr) class X(object): pass @self.c def f8(a): print("computing new result") self.frun = True return 0 x1, x2, x3 = X(), X(), X() self.call(f8, "f8", (x1, ), {}, 0, False) self.call(f8, "f8", (x2, ), {}, 0, True) self.call(f8, "f8", (x3, ), {}, 0, True) # stupid repr function self.call(f8, "f8", (5, ), {}, 0, True) # stupid repr function self.c.close()
def test_8(self): """Test custom repr function.""" def myrepr(a): return "foobar" c = Cache(TESTFILE, repr=myrepr) class X(object): pass @c def f8(a): print("computing new result") self.frun = True return 0 x1, x2, x3 = X(), X(), X() self.call(f8, "f8", (x1,), {}, 0, False) self.call(f8, "f8", (x2,), {}, 0, True) self.call(f8, "f8", (x3,), {}, 0, True) # stupid repr function self.call(f8, "f8", (5,), {}, 0, True) # stupid repr function c.close()
def test_4(self): """Test non-ascii strings as args""" self.c = Cache(TESTFILE) @self.c def f4(a): print("computing new result") self.frun = True return a us = u'über' self.call(f4, "f4", (us,), {}, us, False) self.call(f4, "f4", (us,), {}, us, True) us = u'über'.encode('UTF8') self.call(f4, "f4", (us,), {}, us, False) self.call(f4, "f4", (us,), {}, us, True) self.c.close()
def test_3(self): """Test differentiation of normal and unicode strings.""" if sys.version_info[0] == 3: return # Python 3 only has strings self.c = Cache(TESTFILE) @self.c def f3(s): print("computing new result") self.frun = True return None self.call(f3, "f3", ("a",), {}, None, False) self.call(f3, "f3", (u"a",), {}, None, False) self.call(f3, "f3", ("a",), {}, None, True) self.call(f3, "f3", (u"a",), {}, None, True) self.c.close()
def test_alternative_backend(self): """Test alternative backend and live-sync mode.""" class Backend(dict): """Dummy backend.""" closed = False synced = False def close(self): self.closed = True def sync(self): self.synced = True b = Backend() self.c = Cache(b, livesync=True) @self.c def f1(a, b): print("computing new result") self.frun = True return a @self.c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1, 2), {}, 1, False) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, True) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, False) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, True) self.assertTrue(b.synced) self.assertFalse(b.closed) self.c.close() self.assertTrue(b.closed) # now without live-sync b = Backend() self.c = Cache(b, livesync=False) @self.c def f3(a, b): print("computing new result") self.frun = True return a @self.c def f4(a, b): print("computing new result") self.frun = True return a self.call(f3, "f1", (1, 2), {}, 1, False) self.call(f3, "f1", (1, 2), {}, 1, True) self.call(f3, "f1", (1, 2), {}, 1, True) self.call(f3, "f1", (1, 3), {}, 1, False) self.call(f4, "f2", (1, 3), {}, 1, False) self.call(f4, "f2", (1, 3), {}, 1, True) self.call(f4, "f2", (1.1, 0.1), {}, 1.1, False) self.call(f4, "f2", (1.1, 0.1), {}, 1.1, True) self.assertFalse(b.synced) self.c.close()
class TestCase(unittest.TestCase): def __init__(self, *args): if os.path.exists(TESTFILE): os.remove(TESTFILE) super(TestCase, self).__init__(*args) def setUp(self): unittest.TestCase.setUp(self) self.c = None def tearDown(self): unittest.TestCase.tearDown(self) if self.c: self.c.close() def call(self, fn, name, args, kwargs, result, cached): expstr = "expecting %s result" % (cached and "cached" or "new") print("calling %s(%s | %s) (%s)" % (name, args, kwargs, expstr)) self.frun = False r = fn(*args, **kwargs) self.assertTrue(cached ^ self.frun) self.assertTrue(result == r) def test_1(self): """Test differentiation of basic numeric arguments.""" self.c = Cache(TESTFILE) @self.c def f1(a, b): print("computing new result") self.frun = True return a @self.c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1, 2), {}, 1, False) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, True) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, False) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, True) self.c.close() def test_2(self): """Test persistency of cached results.""" self.c = Cache(TESTFILE) @self.c def f1(a, b): print("computing new result") self.frun = True return a @self.c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 3), {}, 1, True) self.call(f2, "f2", (1, 3), {}, 1, True) self.call(f2, "f2", ("2", 3), {}, "2", False) self.call(f2, "f2", ("2", 3), {}, "2", True) self.c.close() def test_3(self): """Test differentiation of normal and unicode strings.""" if sys.version_info[0] == 3: return # Python 3 only has strings self.c = Cache(TESTFILE) @self.c def f3(s): print("computing new result") self.frun = True return None self.call(f3, "f3", ("a", ), {}, None, False) self.call(f3, "f3", (u"a", ), {}, None, False) self.call(f3, "f3", ("a", ), {}, None, True) self.call(f3, "f3", (u"a", ), {}, None, True) self.c.close() def test_4(self): """Test non-ascii strings as args""" self.c = Cache(TESTFILE) @self.c def f4(a): print("computing new result") self.frun = True return a us = u'über' self.call(f4, "f4", (us, ), {}, us, False) self.call(f4, "f4", (us, ), {}, us, True) us = u'über'.encode('UTF8') self.call(f4, "f4", (us, ), {}, us, False) self.call(f4, "f4", (us, ), {}, us, True) self.c.close() def test_5(self): """Test clearing of old cached results.""" self.c = Cache(TESTFILE) @self.c def f5(a): print("computing new result") self.frun = True return a self.call(f5, "f5", (1, ), {}, 1, False) time.sleep(2) self.call(f5, "f5", (2, ), {}, 2, False) self.c.clear(maxage=1) self.call(f5, "f5", (1, ), {}, 1, False) self.call(f5, "f5", (2, ), {}, 2, True) self.c.close() def test_6(self): """Test keyword arguments.""" self.c = Cache(TESTFILE) @self.c def f6(a, x=1, y=2, z=3): print("computing new result") self.frun = True return a + x + y + z self.call(f6, "f6", (1, ), {"z": 1, "y": 1}, 4, False) self.call(f6, "f6", (1, ), {"z": 1, "y": 1}, 4, True) self.call(f6, "f6", (1, ), {"y": 1, "z": 1}, 4, True) self.call(f6, "f6", (1, ), {"y": 0, "z": 2}, 4, False) self.call(f6, "f6", (1, ), {"z": 2, "y": 0}, 4, True) self.c.close() def test_7(self): """Test overridden __repr__ method.""" self.c = Cache(TESTFILE) class X(object): def __init__(self, a): self.a = a def __repr__(self): return repr(self.a) class Y(object): def __init__(self, a): self.a = a @self.c def f7(a): print("computing new result") self.frun = True return 0 self.call(f7, "f7", (X(1), ), {}, 0, False) self.call(f7, "f7", (X(1), ), {}, 0, True) self.call(f7, "f7", (X(2), ), {}, 0, False) y1, y2 = Y(1), Y(1) self.call(f7, "f7", (y1, ), {}, 0, False) self.call(f7, "f7", (y2, ), {}, 0, False) # bad __repr__ method self.c.close() def test_8(self): """Test custom repr function.""" def myrepr(a): return "foobar" self.c = Cache(TESTFILE, repr=myrepr) class X(object): pass @self.c def f8(a): print("computing new result") self.frun = True return 0 x1, x2, x3 = X(), X(), X() self.call(f8, "f8", (x1, ), {}, 0, False) self.call(f8, "f8", (x2, ), {}, 0, True) self.call(f8, "f8", (x3, ), {}, 0, True) # stupid repr function self.call(f8, "f8", (5, ), {}, 0, True) # stupid repr function self.c.close() def test_check(self): """Test if old `check` interface still works.""" self.c = Cache(TESTFILE) @self.c.check def f1(a, b): print("computing new result") self.frun = True return a @self.c.check def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1, 2), {}, 1, False) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, True) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, False) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, True) self.c.close() def test_alternative_backend(self): """Test alternative backend and live-sync mode.""" class Backend(dict): """Dummy backend.""" closed = False synced = False def close(self): self.closed = True def sync(self): self.synced = True b = Backend() self.c = Cache(b, livesync=True) @self.c def f1(a, b): print("computing new result") self.frun = True return a @self.c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1, 2), {}, 1, False) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 2), {}, 1, True) self.call(f1, "f1", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, False) self.call(f2, "f2", (1, 3), {}, 1, True) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, False) self.call(f2, "f2", (1.1, 0.1), {}, 1.1, True) self.assertTrue(b.synced) self.assertFalse(b.closed) self.c.close() self.assertTrue(b.closed) # now without live-sync b = Backend() self.c = Cache(b, livesync=False) @self.c def f3(a, b): print("computing new result") self.frun = True return a @self.c def f4(a, b): print("computing new result") self.frun = True return a self.call(f3, "f1", (1, 2), {}, 1, False) self.call(f3, "f1", (1, 2), {}, 1, True) self.call(f3, "f1", (1, 2), {}, 1, True) self.call(f3, "f1", (1, 3), {}, 1, False) self.call(f4, "f2", (1, 3), {}, 1, False) self.call(f4, "f2", (1, 3), {}, 1, True) self.call(f4, "f2", (1.1, 0.1), {}, 1.1, False) self.call(f4, "f2", (1.1, 0.1), {}, 1.1, True) self.assertFalse(b.synced) self.c.close()
def test_alternative_backend(self): """Test alternative backend and live-sync mode.""" class Backend(dict): """Dummy backend.""" closed = False synced = False def close(self): self.closed = True def sync(self): self.synced = True b = Backend() c = Cache(b, livesync=True) @c def f1(a, b): print("computing new result") self.frun = True return a @c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1,2), {}, 1, False) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,2L), {}, 1, False) self.call(f1, "f1", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, True) self.call(f2, "f2", (1.1,0.1), {}, 1.1, False) self.call(f2, "f2", (1.1,0.1), {}, 1.1, True) self.assertTrue(b.synced) self.assertFalse(b.closed) c.close() self.assertTrue(b.closed) # now without live-sync b = Backend() c = Cache(b, livesync=False) @c def f3(a, b): print("computing new result") self.frun = True return a @c def f4(a, b): print("computing new result") self.frun = True return a self.call(f3, "f1", (1,2), {}, 1, False) self.call(f3, "f1", (1,2), {}, 1, True) self.call(f3, "f1", (1,2L), {}, 1, False) self.call(f3, "f1", (1,3), {}, 1, False) self.call(f4, "f2", (1,3), {}, 1, False) self.call(f4, "f2", (1,3), {}, 1, True) self.call(f4, "f2", (1.1,0.1), {}, 1.1, False) self.call(f4, "f2", (1.1,0.1), {}, 1.1, True) self.assertFalse(b.synced) c.close()
from types import SimpleNamespace from collections import Counter from itertools import product from more_itertools import pairwise, first, last from contextlib import suppress from progressbar import progressbar import seaborn as sb import matplotlib as mpl import matplotlib.pyplot as plt from percache import Cache cache = Cache(makedirs(os.path.join(os.path.dirname(__file__), "synthetic/UV/percache_runs")), livesync=True) # ~~~~ LOGGING ~~~~ # import logging as logger logger.basicConfig(level=logger.DEBUG, format="%(levelname)-8s [%(asctime)s] @%(funcName)s : %(message)s", datefmt="%Y%m%d %H:%M:%S %Z") logger.getLogger('matplotlib').setLevel(logger.WARNING) logger.getLogger('PIL').setLevel(logger.WARNING) # ~~~~ SETTINGS ~~~~ # PARAM = { 'out_experiment_results': os.path.join(os.path.dirname(__file__), "synthetic", "{aliquot}", "results.{ext}"), 'savefig_args': dict(bbox_inches='tight', pad_inches=0, jpeg_quality=0.9, dpi=300), }
class TestCase(unittest.TestCase): def __init__(self, *args): if os.path.exists(TESTFILE): os.remove(TESTFILE) super(TestCase, self).__init__(*args) def setUp(self): unittest.TestCase.setUp(self) self.c = None def tearDown(self): unittest.TestCase.tearDown(self) if self.c: self.c.close() def call(self, fn, name, args, kwargs, result, cached): expstr = "expecting %s result" % (cached and "cached" or "new") print("calling %s(%s | %s) (%s)" % (name, args, kwargs, expstr)) self.frun = False r = fn(*args, **kwargs) self.assertTrue(cached ^ self.frun) self.assertTrue(result == r) def test_1(self): """Test differentiation of basic numeric arguments.""" self.c = Cache(TESTFILE) @self.c def f1(a, b): print("computing new result") self.frun = True return a @self.c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1,2), {}, 1, False) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, True) self.call(f2, "f2", (1.1,0.1), {}, 1.1, False) self.call(f2, "f2", (1.1,0.1), {}, 1.1, True) self.c.close() def test_2(self): """Test persistency of cached results.""" self.c = Cache(TESTFILE) @self.c def f1(a, b): print("computing new result") self.frun = True return a @self.c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,3), {}, 1, True) self.call(f2, "f2", (1,3), {}, 1, True) self.call(f2, "f2", ("2",3), {}, "2", False) self.call(f2, "f2", ("2",3), {}, "2", True) self.c.close() def test_3(self): """Test differentiation of normal and unicode strings.""" if sys.version_info[0] == 3: return # Python 3 only has strings self.c = Cache(TESTFILE) @self.c def f3(s): print("computing new result") self.frun = True return None self.call(f3, "f3", ("a",), {}, None, False) self.call(f3, "f3", (u"a",), {}, None, False) self.call(f3, "f3", ("a",), {}, None, True) self.call(f3, "f3", (u"a",), {}, None, True) self.c.close() def test_4(self): """Test non-ascii strings as args""" self.c = Cache(TESTFILE) @self.c def f4(a): print("computing new result") self.frun = True return a us = u'über' self.call(f4, "f4", (us,), {}, us, False) self.call(f4, "f4", (us,), {}, us, True) us = u'über'.encode('UTF8') self.call(f4, "f4", (us,), {}, us, False) self.call(f4, "f4", (us,), {}, us, True) self.c.close() def test_5(self): """Test clearing of old cached results.""" self.c = Cache(TESTFILE) @self.c def f5(a): print("computing new result") self.frun = True return a self.call(f5, "f5", (1,), {}, 1, False) time.sleep(2) self.call(f5, "f5", (2,), {}, 2, False) self.c.clear(maxage=1) self.call(f5, "f5", (1,), {}, 1, False) self.call(f5, "f5", (2,), {}, 2, True) self.c.close() def test_6(self): """Test keyword arguments.""" self.c = Cache(TESTFILE) @self.c def f6(a, x=1, y=2, z=3): print("computing new result") self.frun = True return a + x + y + z self.call(f6, "f6", (1,), {"z":1,"y":1}, 4, False) self.call(f6, "f6", (1,), {"z":1,"y":1}, 4, True) self.call(f6, "f6", (1,), {"y":1,"z":1}, 4, True) self.call(f6, "f6", (1,), {"y":0,"z":2}, 4, False) self.call(f6, "f6", (1,), {"z":2,"y":0}, 4, True) self.c.close() def test_7(self): """Test overridden __repr__ method.""" self.c = Cache(TESTFILE) class X(object): def __init__(self, a): self.a = a def __repr__(self): return repr(self.a) class Y(object): def __init__(self, a): self.a = a @self.c def f7(a): print("computing new result") self.frun = True return 0 self.call(f7, "f7", (X(1),), {}, 0, False) self.call(f7, "f7", (X(1),), {}, 0, True) self.call(f7, "f7", (X(2),), {}, 0, False) y1, y2 = Y(1), Y(1) self.call(f7, "f7", (y1,), {}, 0, False) self.call(f7, "f7", (y2,), {}, 0, False) # bad __repr__ method self.c.close() def test_8(self): """Test custom repr function.""" def myrepr(a): return "foobar" self.c = Cache(TESTFILE, repr=myrepr) class X(object): pass @self.c def f8(a): print("computing new result") self.frun = True return 0 x1, x2, x3 = X(), X(), X() self.call(f8, "f8", (x1,), {}, 0, False) self.call(f8, "f8", (x2,), {}, 0, True) self.call(f8, "f8", (x3,), {}, 0, True) # stupid repr function self.call(f8, "f8", (5,), {}, 0, True) # stupid repr function self.c.close() def test_check(self): """Test if old `check` interface still works.""" self.c = Cache(TESTFILE) @self.c.check def f1(a, b): print("computing new result") self.frun = True return a @self.c.check def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1,2), {}, 1, False) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, True) self.call(f2, "f2", (1.1,0.1), {}, 1.1, False) self.call(f2, "f2", (1.1,0.1), {}, 1.1, True) self.c.close() def test_alternative_backend(self): """Test alternative backend and live-sync mode.""" class Backend(dict): """Dummy backend.""" closed = False synced = False def close(self): self.closed = True def sync(self): self.synced = True b = Backend() self.c = Cache(b, livesync=True) @self.c def f1(a, b): print("computing new result") self.frun = True return a @self.c def f2(a, b): print("computing new result") self.frun = True return a self.call(f1, "f1", (1,2), {}, 1, False) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,2), {}, 1, True) self.call(f1, "f1", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, False) self.call(f2, "f2", (1,3), {}, 1, True) self.call(f2, "f2", (1.1,0.1), {}, 1.1, False) self.call(f2, "f2", (1.1,0.1), {}, 1.1, True) self.assertTrue(b.synced) self.assertFalse(b.closed) self.c.close() self.assertTrue(b.closed) # now without live-sync b = Backend() self.c = Cache(b, livesync=False) @self.c def f3(a, b): print("computing new result") self.frun = True return a @self.c def f4(a, b): print("computing new result") self.frun = True return a self.call(f3, "f1", (1,2), {}, 1, False) self.call(f3, "f1", (1,2), {}, 1, True) self.call(f3, "f1", (1,2), {}, 1, True) self.call(f3, "f1", (1,3), {}, 1, False) self.call(f4, "f2", (1,3), {}, 1, False) self.call(f4, "f2", (1,3), {}, 1, True) self.call(f4, "f2", (1.1,0.1), {}, 1.1, False) self.call(f4, "f2", (1.1,0.1), {}, 1.1, True) self.assertFalse(b.synced) self.c.close()