diff --git a/lfucache/lfu_cache.py b/lfucache/lfu_cache.py index 4c5a49a..79c52e1 100644 --- a/lfucache/lfu_cache.py +++ b/lfucache/lfu_cache.py @@ -1,5 +1,6 @@ class Node(object): """Node containing data, pointers to previous and next node.""" + def __init__(self, data): self.data = data self.prev = None @@ -15,10 +16,12 @@ def __init__(self): def add_node(self, cls, data): """Add node instance of class cls.""" + return self.insert_node(cls, data, self.tail, None) def insert_node(self, cls, data, prev, next): """Insert node instance of class cls.""" + node = cls(data) node.prev = prev node.next = next @@ -46,6 +49,7 @@ def remove_node(self, node): def remove_node_by_data(self, data): """Remove node which data is equal to data.""" + node = self.head while node: if node.data == data: @@ -55,6 +59,7 @@ def remove_node_by_data(self, data): def get_nodes_data(self): """Return list nodes data as a list.""" + data = [] node = self.head while node: @@ -64,8 +69,11 @@ def get_nodes_data(self): class FreqNode(DoublyLinkedList, Node): - """Frequency node containing linked list of item nodes with - same frequency.""" + """Frequency node. + + Frequency node contains a linked list of item nodes with same frequency. + """ + def __init__(self, data): DoublyLinkedList.__init__(self) Node.__init__(self, data) @@ -122,7 +130,7 @@ def access(self, key): if not next_freq_node or next_freq_node.data != freq_node.data + 1: next_freq_node = self.insert_freq_node(freq_node.data + 1, - freq_node, next_freq_node) + freq_node, next_freq_node) item_node = next_freq_node.add_item_node(key) tmp.parent = next_freq_node @@ -150,6 +158,7 @@ def get_lfu(self): def delete_lfu(self): """Remove the first item node from the first frequency node. + Remove the LFU item from the dictionary. """ if not self.head: @@ -162,8 +171,9 @@ def delete_lfu(self): self.remove_freq_node(freq_node) def __repr__(self): - """Display access frequency list and items list using the - representation: + """Display access frequency list and items. + + Using the representation: freq1: [item, item, ...] freq2: [item, item] ... @@ -179,6 +189,6 @@ def __repr__(self): class DuplicateException(Exception): pass + class NotFoundException(Exception): pass - diff --git a/lfucache/test/all_tests.py b/lfucache/test/all_tests.py new file mode 100644 index 0000000..ba9bc3b --- /dev/null +++ b/lfucache/test/all_tests.py @@ -0,0 +1,20 @@ +"""Run all of the tests.""" +import sys +import unittest2 as unittest + + +def main(args=None): + unittest_dir = '.' + unittest_suite = unittest.defaultTestLoader.discover(unittest_dir) + + kwargs = {} + if args and '-v' in args: + kwargs['verbosity'] = 2 + runner = unittest.TextTestRunner(sys.stdout, "Unittests", + **kwargs) + results = runner.run(unittest_suite) + return results.wasSuccessful() + +if __name__ == '__main__': + status = main(sys.argv[1:]) + sys.exit(int(not status)) diff --git a/lfucache/test/coverage.sh b/lfucache/test/coverage.sh new file mode 100644 index 0000000..e8ebaf8 --- /dev/null +++ b/lfucache/test/coverage.sh @@ -0,0 +1,2 @@ +coverage run --source=$PYTHONPATH/lfucache --omit=$PYTHONPATH/lfucache/test/* all_tests.py +coverage report --omit=$PYTHONPATH/lfucache/test/* -m diff --git a/lfucache/test/test_lfu_cache.py b/lfucache/test/test_lfu_cache.py index 02cd8d1..68b17d5 100644 --- a/lfucache/test/test_lfu_cache.py +++ b/lfucache/test/test_lfu_cache.py @@ -2,6 +2,7 @@ import lfucache.lfu_cache as lfu_cache + class TestLfuCache(unittest.TestCase): def setUp(self): @@ -30,16 +31,16 @@ def test_add_freq_item_nodes(self): freq_node1 = self.cache.insert_freq_node(1, None, None) freq_node2 = self.cache.insert_freq_node(2, freq_node1, None) freq_node1_item_node1 = freq_node1.insert_item_node('a', None, None) - freq_node1_item_node2 = freq_node1.insert_item_node('b', - freq_node1_item_node1, None) + freq_node1.insert_item_node('b', freq_node1_item_node1, None) freq_node2_item_node2 = freq_node2.insert_item_node('d', None, None) - freq_node2_item_node1 = freq_node2.insert_item_node('c', None, + freq_node2_item_node1 = freq_node2.insert_item_node( + 'c', None, freq_node2_item_node2) - freq_node2_item_node4 = freq_node2.insert_item_node('f', - freq_node2_item_node2, None) - freq_node2_item_node3 = freq_node2.insert_item_node('e', - freq_node2_item_node2, freq_node2_item_node4) - freq_node2_item_node5 = freq_node2.add_item_node('g') + freq_node2_item_node4 = freq_node2.insert_item_node( + 'f', freq_node2_item_node2, None) + freq_node2_item_node3 = freq_node2.insert_item_node( + 'e', freq_node2_item_node2, freq_node2_item_node4) + freq_node2.add_item_node('g') nodes_data = freq_node1.get_nodes_data() self.assertEqual(nodes_data, ['a', 'b']) @@ -65,7 +66,7 @@ def test_insert(self): self.cache.insert('k3', 'd3') nodes_data = self.cache.get_nodes_data() - self.assertEqual(nodes_data, [1,]) + self.assertEqual(nodes_data, [1, ]) nodes_data = self.cache.head.get_nodes_data() self.assertEqual(nodes_data, ['k1', 'k2', 'k3']) @@ -76,14 +77,14 @@ def test_insert(self): self.assertEqual(self.cache.items['k2'].data, 'd2') self.assertEqual(self.cache.items['k2'].parent, self.cache.head) self.assertEqual(self.cache.items['k2'].node, - self.cache.head.head.next) + self.cache.head.head.next) self.assertEqual(self.cache.items['k3'].data, 'd3') self.assertEqual(self.cache.items['k3'].parent, self.cache.head) self.assertEqual(self.cache.items['k3'].node, - self.cache.head.head.next.next) + self.cache.head.head.next.next) self.assertRaises(lfu_cache.DuplicateException, self.cache.insert, - 'k3', 'd3') + 'k3', 'd3') def test_access(self): self.cache.insert('k1', 'd1') @@ -121,7 +122,7 @@ def test_access(self): def test_get_lfu(self): self.assertRaises(lfu_cache.NotFoundException, - self.cache.get_lfu) + self.cache.get_lfu) self.cache.insert('k1', 'd1') self.cache.insert('k2', 'd2') @@ -139,7 +140,7 @@ def test_get_lfu(self): def test_delete_lfu(self): self.assertRaises(lfu_cache.NotFoundException, - self.cache.delete_lfu) + self.cache.delete_lfu) self.cache.insert('k1', 'd1') self.cache.insert('k2', 'd2') diff --git a/pep8.sh b/pep8.sh new file mode 100755 index 0000000..6bbfec3 --- /dev/null +++ b/pep8.sh @@ -0,0 +1,2 @@ +flake8 lfucache +exit diff --git a/setup.py b/setup.py index 35d3f10..0697c47 100644 --- a/setup.py +++ b/setup.py @@ -5,5 +5,5 @@ version='0.1', packages=['lfucache',], license='MIT', - long_description=open('README.md').read(), + long_description='Cache with LFU eviction scheme implemented in Python with complexity O(1) for insertion, access and deletion.', )