Browse Source

better halflife support, fix some minor bugs..

main
John-Mark Gurney 2 years ago
parent
commit
204233629e
1 changed files with 74 additions and 7 deletions
  1. +74
    -7
      ui/medashare/tags.py

+ 74
- 7
ui/medashare/tags.py View File

@@ -38,12 +38,16 @@ class TagCache:
'''

def __init__(self, tags=(), count=10, **kwargs):
self._cache = collections.OrderedDict((x, None) for x in tags)
values = kwargs.pop('values', None)
if values is None:
values = itertools.repeat((0, 0))
self._cache = collections.OrderedDict(zip(tags, values))
self._count = count
self._modified = False

# λ = ln(2) / t1/2
hl = kwargs.pop('half_life', None)
self._half_life = hl
self._lambda = None if not hl else math.log(2) / hl
self._limit = kwargs.pop('limit', self._count)

@@ -88,6 +92,10 @@ class TagCache:

return self._modified

def _new_values(self, t, oldval, oldtime, addnl):
return (t, oldval * math.exp(-self._lambda * (t -
oldtime)) + addnl)

def add(self, tag):
'''Add a tag (tuple) to the cache, possibly dropping ann older
tag if necessary.'''
@@ -100,8 +108,7 @@ class TagCache:

# N(t) = N0 e^(-λt)
if self._lambda:
v = (t, oldval * math.exp(-self._lambda * (t -
oldtime)) + 1)
v = self._new_values(t, oldval, oldtime, 1)
else:
v = 0, 0

@@ -115,8 +122,7 @@ class TagCache:
t = time.time()

for k, (oldtime, oldval) in self._cache.items():
v = (t, oldval * math.exp(-self._lambda * (t -
oldtime)) + 1)
v = self._new_values(t, oldval, oldtime, 0)
self._cache[k] = v

def tags(self):
@@ -128,7 +134,8 @@ class TagCache:
self._cache[x][1], reverse=True)[:self._count])
else:
return sorted(itertools.islice(self._cache.keys(),
len(self._cache) - self._count, len(self._cache)))
max(0, len(self._cache) - self._count),
len(self._cache)))

def __repr__(self):
return 'TagCache(tags=%s, count=%d, limit=%d)' % \
@@ -151,13 +158,24 @@ class TagCache:

return cls(**cache)

def _to_dict(self):
tags=list(self._cache.keys())

values = None
if self._half_life:
values = [ self._cache[x] for x in tags ]

return dict(tags=tags, count=self._count,
limit=self._limit, half_life=self._half_life,
values=values)

def store(self, fname):
'''Store the cache to fname. The modified property will
be cleared after this.'''

self._modified = False

cache = dict(tags=list(self._cache.keys()), count=self._count)
cache = self._to_dict()

with open(fname, 'wb') as fp:
fp.write(_asn1coder.dumps(cache))
@@ -179,6 +197,30 @@ class _TestTagCache(unittest.TestCase):
with self.assertRaises(TypeError):
TagCache(randomkwargs=True)

@unittest.mock.patch('time.time', return_value=5)
def test_multipletagscalls(self, tt):
# that a half_life tc.

tcdict = dict(tags=[('foo', 'foo')], half_life=10,
values=[( 5, 102.3 )], count=5, limit=5)

tc = TagCache(**tcdict)

# when tags is called multiple times
tc.tags()
tc.tags()
tc.tags()
tc.tags()

# that it doesn't change
self.assertEqual(tc._to_dict(), tcdict)

@unittest.mock.patch('time.time', side_effect=lambda cnt=
itertools.count(): next(cnt) * 1.)
def test_timebackwards(self, tt):
# test for if/when time goes backwards
pass

@unittest.mock.patch('time.time', side_effect=lambda cnt=
itertools.count(): next(cnt) * 1.)
def test_halflife(self, tt):
@@ -198,6 +240,29 @@ class _TestTagCache(unittest.TestCase):
# XXX - deal with limit better, that is, drop the small value,
# not the last

@unittest.mock.patch('time.time', side_effect=lambda cnt=
itertools.count(): next(cnt) * 1.)
def test_halflife(self, tt):
tc = TagCache(count=2, limit=10, half_life=10)

# that when it is added twice
tc.add(('foo', 'foo'))
tc.add(('foo', 'foo'))

# and saved/reloaded
cachefile = self.tempdir / 'somecache'
tc.store(cachefile)

# that it can be loaded
tc = TagCache.load(cachefile)

# and two others are added
tc.add(('bar', 'bar'))
tc.add(('baz', 'baz'))

# it will have preference
self.assertEqual(tc.tags(), [ ('baz', 'baz'), ('foo', 'foo'), ])

def test_limit(self):
tc = TagCache(count=2, limit=3)

@@ -237,6 +302,8 @@ class _TestTagCache(unittest.TestCase):

tc.add(('foo', 'foo'))

self.assertEqual(tc.tags(), [ ('foo', 'foo') ])

tc.add(('bar', 'bar'))

tc.add(('baz', 'baz'))


Loading…
Cancel
Save