diff --git a/expiringdict/__init__.py b/expiringdict/__init__.py index 56ba71d..dc8ee00 100755 --- a/expiringdict/__init__.py +++ b/expiringdict/__init__.py @@ -55,6 +55,28 @@ def __init__(self, max_len, max_age_seconds, items=None): else: raise ValueError('can not unpack items') + def __len__(self): + with self.lock: + current_key = iter(self) + keys_to_del = [] + for k in current_key: + item = OrderedDict.__getitem__(self, k) + time_added = item[1] + item_age = time.time() - time_added + if item_age > self.max_age: + keys_to_del.append(k) + else: + break + for k in keys_to_del: + del self[k] + + return super(ExpiringDict, self).__len__() + + def __repr__(self): + if len(self) == 0: + return "ExpiringDict([])" + return super(ExpiringDict, self).__repr__() + def __contains__(self, key): """ Return True if the dict has a key, else return False. """ try: diff --git a/tests/expiringdict_test.py b/tests/expiringdict_test.py index 78929f1..6663981 100644 --- a/tests/expiringdict_test.py +++ b/tests/expiringdict_test.py @@ -122,3 +122,46 @@ def test_not_implemented(): assert_raises(NotImplementedError, d.viewitems) assert_raises(NotImplementedError, d.viewkeys) assert_raises(NotImplementedError, d.viewvalues) + + +def test_cleanup_on_length(): + d = ExpiringDict(max_len=10, max_age_seconds=0.01) + d['a'] = 'x' + eq_(1, len(d)) + sleep(0.01) + eq_(0, len(d)) + + d = ExpiringDict(max_len=10, max_age_seconds=0.02) + d['a'] = 1 + sleep(0.01) + eq_(1, len(d)) + d['b'] = 2 + sleep(0.01) + eq_(1, len(d)) + d['c'] = 3 + sleep(0.01) + eq_(1, len(d)) + d['d'] = 4 + sleep(0.01) + eq_(1, len(d)) + + d = ExpiringDict(max_len=1000, max_age_seconds=.5) + d[1] = 1 + d[2] = 2 + d[3] = 3 + d[4] = 4 + + ok_(1 in d) + ok_(2 in d) + ok_(3 in d) + ok_(4 in d) + eq_(4, len(d)) + + sleep(.25) + d[1] = 1 + d[2] = 2 + sleep(.40) + ok_(1 in d) + ok_(2 in d) + ok_(3 not in d) + ok_(4 not in d)