[utils] Fixes compatiblity of QueryCache with expected dict interface
QueryCache is expected to mimick the interface of the dict built-in. The current
__iter__ implementation breaks this expectation by iterating over key, value
pairs instead of only the keys.
This changeset fixes this issue by changing the __iter__ implementation to
iterate over the keys in the cache and providing an implementation of the items
method with a contract identical to the dict build-in (return a copy of the key-
value pairs within the dictionary as a list).
--- a/cubicweb/test/unittest_utils.py Tue Apr 24 15:21:18 2018 +0200
+++ b/cubicweb/test/unittest_utils.py Wed Apr 25 15:29:25 2018 +0200
@@ -154,8 +154,28 @@
v = c.get(x, -1)
self.assertEqual(v, -1)
+ def test_iterkeys(self):
+ """
+ Tests the iterating on keys in the cache
+ """
+ c = QueryCache(ceiling=20)
+ # set 10 values
+ for x in range(10):
+ c[x] = x
+ # arrange for the first 5 to be permanent
+ for x in range(5):
+ for r in range(QueryCache._maxlevel + 2):
+ v = c[x]
+ self.assertEqual(v, x)
+ self.assertEqual(c._usage_report(),
+ {'transientcount': 0,
+ 'itemcount': 10,
+ 'permanentcount': 5})
+ keys = sorted(c)
+ for x in range(10):
+ self.assertEquals(x, keys[x])
- def test_iterator(self):
+ def test_items(self):
"""
Tests the iterating on key-value couples in the cache
"""
@@ -172,7 +192,7 @@
{'transientcount': 0,
'itemcount': 10,
'permanentcount': 5})
- content = sorted(c)
+ content = sorted(c.items())
for x in range(10):
self.assertEquals(x, content[x][0])
self.assertEquals(x, content[x][1])
--- a/cubicweb/utils.py Tue Apr 24 15:21:18 2018 +0200
+++ b/cubicweb/utils.py Wed Apr 25 15:29:25 2018 +0200
@@ -627,6 +627,12 @@
with self._lock:
return len(self._data)
+ def items(self):
+ """Get an iterator over the dictionary's items: (key, value) pairs"""
+ with self._lock:
+ for k, v in self._data.items():
+ yield k, v
+
def get(self, k, default=None):
"""Get the value associated to the specified key
@@ -641,8 +647,8 @@
def __iter__(self):
with self._lock:
- for k, v in self._data.items():
- yield k, v
+ for k in iter(self._data):
+ yield k
def __getitem__(self, k):
with self._lock: