Skip to content

Commit c176988

Browse files
committed
Add Cache.peek, Deque.peek and Deque.peekleft
1 parent e1171b2 commit c176988

2 files changed

Lines changed: 168 additions & 6 deletions

File tree

diskcache/core.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,113 @@ def pull(self, prefix=None, default=(None, None), side='front',
14931493
return key, value
14941494

14951495

1496+
def peek(self, prefix=None, default=(None, None), side='front',
1497+
expire_time=False, tag=False, retry=False):
1498+
"""Peek at key and value item pair from `side` of queue in cache.
1499+
1500+
When prefix is None, integer keys are used. Otherwise, string keys are
1501+
used in the format "prefix-integer". Integer starts at 500 trillion.
1502+
1503+
If queue is empty, return default.
1504+
1505+
Defaults to peeking at key and value item pairs from front of queue.
1506+
Set side to 'back' to pull from back of queue. Side must be one of
1507+
'front' or 'back'.
1508+
1509+
Expired items are deleted from cache. Operation is atomic. Concurrent
1510+
operations will be serialized.
1511+
1512+
Raises :exc:`Timeout` error when database timeout occurs and `retry` is
1513+
`False` (default).
1514+
1515+
See also `Cache.pull` and `Cache.push`.
1516+
1517+
>>> cache = Cache('/tmp/diskcache')
1518+
>>> _ = cache.clear()
1519+
>>> for letter in 'abc':
1520+
... print(cache.push(letter))
1521+
500000000000000
1522+
500000000000001
1523+
500000000000002
1524+
>>> key, value = cache.peek()
1525+
>>> print(key)
1526+
500000000000000
1527+
>>> value
1528+
'a'
1529+
>>> key, value = cache.peek(side='back')
1530+
>>> print(key)
1531+
500000000000002
1532+
>>> value
1533+
'c'
1534+
1535+
:param str prefix: key prefix (default None, key is integer)
1536+
:param default: value to return if key is missing
1537+
(default (None, None))
1538+
:param str side: either 'front' or 'back' (default 'front')
1539+
:param bool expire_time: if True, return expire_time in tuple
1540+
(default False)
1541+
:param bool tag: if True, return tag in tuple (default False)
1542+
:param bool retry: retry if database timeout occurs (default False)
1543+
:return: key and value item pair or default if queue is empty
1544+
:raises Timeout: if database timeout occurs
1545+
1546+
"""
1547+
if prefix is None:
1548+
min_key = 0
1549+
max_key = 999999999999999
1550+
else:
1551+
min_key = prefix + '-000000000000000'
1552+
max_key = prefix + '-999999999999999'
1553+
1554+
order = {'front': 'ASC', 'back': 'DESC'}
1555+
select = (
1556+
'SELECT rowid, key, expire_time, tag, mode, filename, value'
1557+
' FROM Cache WHERE ? < key AND key < ? AND raw = 1'
1558+
' ORDER BY key %s LIMIT 1'
1559+
) % order[side]
1560+
1561+
if expire_time and tag:
1562+
default = default, None, None
1563+
elif expire_time or tag:
1564+
default = default, None
1565+
1566+
while True:
1567+
with self._transact(retry) as (sql, cleanup):
1568+
rows = sql(select, (min_key, max_key)).fetchall()
1569+
1570+
if not rows:
1571+
return default
1572+
1573+
(rowid, key, db_expire, db_tag, mode, name, db_value), = rows
1574+
1575+
if db_expire is not None and db_expire < time.time():
1576+
sql('DELETE FROM Cache WHERE rowid = ?', (rowid,))
1577+
cleanup(name)
1578+
else:
1579+
break
1580+
1581+
try:
1582+
value = self._disk.fetch(mode, name, db_value, False)
1583+
except IOError as error:
1584+
if error.errno == errno.ENOENT:
1585+
# Key was deleted before we could retrieve result.
1586+
return default
1587+
else:
1588+
raise
1589+
finally:
1590+
if name is not None:
1591+
self._disk.remove(name)
1592+
1593+
if expire_time and tag:
1594+
return (key, value), db_expire, db_tag
1595+
elif expire_time:
1596+
return (key, value), db_expire
1597+
elif tag:
1598+
return (key, value), db_tag
1599+
else:
1600+
return key, value
1601+
1602+
14961603
memoize = memoize
14971604

14981605

diskcache/persistent.py

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,16 @@ def __getitem__(self, index):
185185
186186
Return corresponding item for `index` in deque.
187187
188+
See also `Deque.peekleft` and `Deque.peek` for indexing deque at index
189+
``0`` or ``-1``.
190+
188191
>>> deque = Deque(directory='/tmp/diskcache/deque')
189192
>>> deque.clear()
190193
>>> deque.extend('abcde')
191-
>>> deque[0]
192-
'a'
193-
>>> deque[-1]
194-
'e'
195-
>>> deque[2]
196-
'c'
194+
>>> deque[1]
195+
'b'
196+
>>> deque[-2]
197+
'd'
197198
198199
:param int index: index of item
199200
:return: corresponding item
@@ -417,6 +418,60 @@ def extendleft(self, iterable):
417418
self.appendleft(value)
418419

419420

421+
def peek(self):
422+
"""Peek at value at back of deque.
423+
424+
Faster than indexing deque at -1.
425+
426+
If deque is empty then raise IndexError.
427+
428+
>>> deque = Deque(directory='/tmp/diskcache/deque')
429+
>>> deque.clear()
430+
>>> deque.peek()
431+
Traceback (most recent call last):
432+
...
433+
IndexError: peek from an empty deque
434+
>>> deque += 'abc'
435+
>>> deque.peek()
436+
'c'
437+
438+
:raises IndexError: if deque is empty
439+
440+
"""
441+
default = None, ENOVAL
442+
_, value = self._cache.peek(default=default, side='back', retry=True)
443+
if value is ENOVAL:
444+
raise IndexError('peek from an empty deque')
445+
return value
446+
447+
448+
def peekleft(self):
449+
"""Peek at value at back of deque.
450+
451+
Faster than indexing deque at 0.
452+
453+
If deque is empty then raise IndexError.
454+
455+
>>> deque = Deque(directory='/tmp/diskcache/deque')
456+
>>> deque.clear()
457+
>>> deque.peekleft()
458+
Traceback (most recent call last):
459+
...
460+
IndexError: peek from an empty deque
461+
>>> deque += 'abc'
462+
>>> deque.peekleft()
463+
'a'
464+
465+
:raises IndexError: if deque is empty
466+
467+
"""
468+
default = None, ENOVAL
469+
_, value = self._cache.peek(default=default, side='front', retry=True)
470+
if value is ENOVAL:
471+
raise IndexError('peek from an empty deque')
472+
return value
473+
474+
420475
def pop(self):
421476
"""Remove and return value at back of deque.
422477

0 commit comments

Comments
 (0)