1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348 |
- """Persistent Data Types
-
- """
-
- import operator as op
- import sys
-
- from collections import MutableMapping, OrderedDict, Sequence
- from collections import KeysView, ValuesView, ItemsView
- from itertools import islice
- from shutil import rmtree
- from tempfile import mkdtemp
-
- from .core import BytesType, Cache, ENOVAL, TextType, Timeout
-
- if sys.hexversion < 0x03000000:
- from itertools import izip as zip # pylint: disable=redefined-builtin,no-name-in-module,ungrouped-imports
- range = xrange # pylint: disable=redefined-builtin,invalid-name,undefined-variable
-
-
- def _make_compare(seq_op, doc):
- "Make compare method with Sequence semantics."
- def compare(self, that):
- "Compare method for deque and sequence."
- if not isinstance(that, Sequence):
- return NotImplemented
-
- len_self = len(self)
- len_that = len(that)
-
- if len_self != len_that:
- if seq_op is op.eq:
- return False
- if seq_op is op.ne:
- return True
-
- for alpha, beta in zip(self, that):
- if alpha != beta:
- return seq_op(alpha, beta)
-
- return seq_op(len_self, len_that)
-
- compare.__name__ = '__{0}__'.format(seq_op.__name__)
- doc_str = 'Return True if and only if deque is {0} `that`.'
- compare.__doc__ = doc_str.format(doc)
-
- return compare
-
-
- class Deque(Sequence):
- """Persistent sequence with double-ended queue semantics.
-
- Double-ended queue is an ordered collection with optimized access at its
- endpoints.
-
- Items are serialized to disk. Deque may be initialized from directory path
- where items are stored.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque
- Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque += range(5)
- >>> list(deque)
- [0, 1, 2, 3, 4]
- >>> for value in range(5):
- ... deque.appendleft(-value)
- >>> len(deque)
- 10
- >>> list(deque)
- [-4, -3, -2, -1, 0, 0, 1, 2, 3, 4]
- >>> deque.pop()
- 4
- >>> deque.popleft()
- -4
- >>> deque.reverse()
- >>> list(deque)
- [3, 2, 1, 0, 0, -1, -2, -3]
-
- """
- def __init__(self, iterable=(), directory=None):
- """Initialize deque instance.
-
- If directory is None then temporary directory created. The directory
- will *not* be automatically removed.
-
- :param iterable: iterable of items to append to deque
- :param directory: deque directory (default None)
-
- """
- if directory is None:
- directory = mkdtemp()
- self._cache = Cache(directory, eviction_policy='none')
- self.extend(iterable)
-
-
- @classmethod
- def fromcache(cls, cache, iterable=()):
- """Initialize deque using `cache`.
-
- >>> cache = Cache('/tmp/diskcache/index')
- >>> _ = cache.clear()
- >>> deque = Deque.fromcache(cache, [5, 6, 7, 8])
- >>> len(deque)
- 4
- >>> 7 in deque
- True
- >>> deque.popleft()
- 5
-
- :param Cache cache: cache to use
- :param iterable: iterable of items
- :return: initialized Deque
-
- """
- # pylint: disable=no-member,protected-access
- self = cls.__new__(cls)
- self._cache = cache
- self.extend(iterable)
- return self
-
-
- @property
- def directory(self):
- "Directory path where deque is stored."
- return self._cache.directory
-
-
- def _key(self, index):
- len_self = len(self)
-
- if index < 0:
- index += len_self
- if index < 0:
- raise IndexError('deque index out of range')
- elif index >= len_self:
- raise IndexError('deque index out of range')
-
- diff = len_self - index - 1
- _cache_iterkeys = self._cache.iterkeys
-
- try:
- if index <= diff:
- iter_keys = _cache_iterkeys()
- key = next(islice(iter_keys, index, index + 1))
- else:
- iter_keys = _cache_iterkeys(reverse=True)
- key = next(islice(iter_keys, diff, diff + 1))
- except StopIteration:
- raise IndexError('deque index out of range')
-
- return key
-
-
- def __getitem__(self, index):
- """deque.__getitem__(index) <==> deque[index]
-
- Return corresponding item for `index` in deque.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque.extend('abcde')
- >>> deque[0]
- 'a'
- >>> deque[-1]
- 'e'
- >>> deque[2]
- 'c'
-
- :param int index: index of item
- :return: corresponding item
- :raises IndexError: if index out of range
-
- """
- _key = self._key
- _cache = self._cache
-
- while True:
- try:
- key = _key(index)
- return _cache[key]
- except (KeyError, Timeout):
- continue
-
-
- def __setitem__(self, index, value):
- """deque.__setitem__(index, value) <==> deque[index] = value
-
- Store `value` in deque at `index`.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque.extend([None] * 3)
- >>> deque[0] = 'a'
- >>> deque[1] = 'b'
- >>> deque[-1] = 'c'
- >>> ''.join(deque)
- 'abc'
-
- :param int index: index of value
- :param value: value to store
- :raises IndexError: if index out of range
-
- """
- _key = self._key
- _cache = self._cache
-
- while True:
- try:
- key = _key(index)
- _cache[key] = value
- return
- except Timeout:
- continue
-
-
- def __delitem__(self, index):
- """deque.__delitem__(index) <==> del deque[index]
-
- Delete item in deque at `index`.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque.extend([None] * 3)
- >>> del deque[0]
- >>> del deque[1]
- >>> del deque[-1]
- >>> len(deque)
- 0
-
- :param int index: index of item
- :raises IndexError: if index out of range
-
- """
- _key = self._key
- _cache = self._cache
-
- while True:
- try:
- key = _key(index)
- del _cache[key]
- return
- except (KeyError, Timeout):
- continue
-
-
- def __repr__(self):
- """deque.__repr__() <==> repr(deque)
-
- Return string with printable representation of deque.
-
- """
- name = type(self).__name__
- return '{0}(directory={1!r})'.format(name, self.directory)
-
-
- __eq__ = _make_compare(op.eq, 'equal to')
- __ne__ = _make_compare(op.ne, 'not equal to')
- __lt__ = _make_compare(op.lt, 'less than')
- __gt__ = _make_compare(op.gt, 'greater than')
- __le__ = _make_compare(op.le, 'less than or equal to')
- __ge__ = _make_compare(op.ge, 'greater than or equal to')
-
-
- def __iadd__(self, iterable):
- """deque.__iadd__(iterable) <==> deque += iterable
-
- Extend back side of deque with items from iterable.
-
- """
- self.extend(iterable)
- return self
-
-
- def __iter__(self):
- """deque.__iter__() <==> iter(deque)
-
- Return iterator of deque from front to back.
-
- """
- _cache = self._cache
-
- for key in _cache.iterkeys():
- try:
- yield _cache[key]
- except (KeyError, Timeout):
- pass
-
-
- def __len__(self):
- """deque.__len__() <==> len(deque)
-
- Return length of deque.
-
- """
- return len(self._cache)
-
-
- def __reversed__(self):
- """deque.__reversed__() <==> reversed(deque)
-
- Return iterator of deque from back to front.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque.extend('abcd')
- >>> iterator = reversed(deque)
- >>> next(iterator)
- 'd'
- >>> list(iterator)
- ['c', 'b', 'a']
-
- """
- _cache = self._cache
-
- for key in _cache.iterkeys(reverse=True):
- try:
- yield _cache[key]
- except (KeyError, Timeout):
- pass
-
-
- def __getstate__(self):
- return self.directory
-
-
- def __setstate__(self, state):
- self.__init__(directory=state)
-
-
- def append(self, value):
- """Add `value` to back of deque.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque.append('a')
- >>> deque.append('b')
- >>> deque.append('c')
- >>> list(deque)
- ['a', 'b', 'c']
-
- :param value: value to add to back of deque
-
- """
- _cache_push = self._cache.push
-
- while True:
- try:
- _cache_push(value)
- return
- except Timeout:
- continue
-
-
- def appendleft(self, value):
- """Add `value` to front of deque.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque.appendleft('a')
- >>> deque.appendleft('b')
- >>> deque.appendleft('c')
- >>> list(deque)
- ['c', 'b', 'a']
-
- :param value: value to add to front of deque
-
- """
- _cache_push = self._cache.push
-
- while True:
- try:
- _cache_push(value, side='front')
- return
- except Timeout:
- continue
-
-
- def clear(self):
- """Remove all elements from deque.
-
- """
- _cache_clear = self._cache.clear
-
- while True:
- try:
- _cache_clear()
- return
- except Timeout:
- continue
-
-
- def count(self, value):
- """Return number of occurrences of `value` in deque.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque += [num for num in range(1, 5) for _ in range(num)]
- >>> deque.count(0)
- 0
- >>> deque.count(1)
- 1
- >>> deque.count(4)
- 4
-
- :param value: value to count in deque
-
- """
- return sum(1 for item in self if item == value)
-
-
- def extend(self, iterable):
- """Extend back side of deque with values from `iterable`.
-
- :param iterable: iterable of values
-
- """
- for value in iterable:
- self.append(value)
-
-
- def extendleft(self, iterable):
- """Extend front side of deque with value from `iterable`.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque.extendleft('abc')
- >>> list(deque)
- ['c', 'b', 'a']
-
- :param iterable: iterable of values
-
- """
- for value in iterable:
- self.appendleft(value)
-
-
- def pop(self):
- """Remove and return value at back of deque.
-
- If deque is empty then raise IndexError.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque += 'ab'
- >>> deque.pop()
- 'b'
- >>> deque.pop()
- 'a'
- >>> deque.pop()
- Traceback (most recent call last):
- ...
- IndexError: pop from an empty deque
-
- :raises IndexError: if deque is empty
-
- """
- _cache_pull = self._cache.pull
-
- while True:
- try:
- default = None, ENOVAL
- _, value = _cache_pull(default=default, side='back')
- except Timeout:
- continue
- else:
- if value is ENOVAL:
- raise IndexError('pop from an empty deque')
- return value
-
-
- def popleft(self):
- """Remove and return value at front of deque.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque += 'ab'
- >>> deque.popleft()
- 'a'
- >>> deque.popleft()
- 'b'
- >>> deque.popleft()
- Traceback (most recent call last):
- ...
- IndexError: pop from an empty deque
-
- """
- _cache_pull = self._cache.pull
-
- while True:
- try:
- default = None, ENOVAL
- _, value = _cache_pull(default=default)
- except Timeout:
- continue
- else:
- if value is ENOVAL:
- raise IndexError('pop from an empty deque')
- return value
-
-
- def remove(self, value):
- """Remove first occurrence of `value` in deque.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque += 'aab'
- >>> deque.remove('a')
- >>> list(deque)
- ['a', 'b']
- >>> deque.remove('b')
- >>> list(deque)
- ['a']
- >>> deque.remove('c')
- Traceback (most recent call last):
- ...
- ValueError: deque.remove(value): value not in deque
-
- :param value: value to remove
- :raises ValueError: if value not in deque
-
- """
- _cache = self._cache
-
- for key in _cache.iterkeys():
- try:
- while True:
- try:
- item = _cache[key]
- except Timeout:
- continue
- else:
- break
- except KeyError:
- continue
- else:
- if value == item:
- try:
- while True:
- try:
- del _cache[key]
- except Timeout:
- continue
- else:
- return
- except KeyError:
- continue
-
- raise ValueError('deque.remove(value): value not in deque')
-
-
- def reverse(self):
- """Reverse deque in place.
-
- """
- # pylint: disable=protected-access
- directory = mkdtemp()
- temp = None
-
- try:
- temp = Deque(iterable=reversed(self), directory=directory)
- self.clear()
- self.extend(temp)
- finally:
- if temp is not None:
- temp._cache.close()
- del temp
- rmtree(directory)
-
-
- def rotate(self, steps=1):
- """Rotate deque right by `steps`.
-
- If steps is negative then rotate left.
-
- >>> deque = Deque(directory='/tmp/diskcache/deque')
- >>> deque.clear()
- >>> deque += range(5)
- >>> deque.rotate(2)
- >>> list(deque)
- [3, 4, 0, 1, 2]
- >>> deque.rotate(-1)
- >>> list(deque)
- [4, 0, 1, 2, 3]
-
- :param int steps: number of steps to rotate (default 1)
-
- """
- if not isinstance(steps, int):
- type_name = type(steps).__name__
- raise TypeError('integer argument expected, got %s' % type_name)
-
- len_self = len(self)
-
- if not len_self:
- return
-
- if steps >= 0:
- steps %= len_self
-
- for _ in range(steps):
- try:
- value = self.pop()
- except IndexError:
- return
- else:
- self.appendleft(value)
- else:
- steps *= -1
- steps %= len_self
-
- for _ in range(steps):
- try:
- value = self.popleft()
- except IndexError:
- return
- else:
- self.append(value)
-
-
- def __del__(self):
- self._cache.close()
-
-
- __hash__ = None
-
-
- class Index(MutableMapping):
- """Persistent mutable mapping with insertion order iteration.
-
- Items are serialized to disk. Index may be initialized from directory path
- where items are stored.
-
- Hashing protocol is not used. Keys are looked up by their serialized
- format. See ``diskcache.Disk`` for details.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index
- Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> index['a']
- 1
- >>> list(index)
- ['a', 'b', 'c']
- >>> len(index)
- 3
- >>> del index['b']
- >>> index.popitem()
- ('c', 3)
-
- """
- def __init__(self, *args, **kwargs):
- """Initialize index in directory and update items.
-
- Optional first argument may be string specifying directory where items
- are stored. When None or not given, temporary directory is created.
-
- >>> index = Index({'a': 1, 'b': 2, 'c': 3})
- >>> len(index)
- 3
- >>> directory = index.directory
- >>> inventory = Index(directory, d=4)
- >>> inventory['b']
- 2
- >>> len(inventory)
- 4
-
- """
- if args and isinstance(args[0], (BytesType, TextType)):
- directory = args[0]
- args = args[1:]
- else:
- if args and args[0] is None:
- args = args[1:]
- directory = mkdtemp(prefix='diskcache-')
- self._cache = Cache(directory, eviction_policy='none')
- self.update(*args, **kwargs)
-
-
- @classmethod
- def fromcache(cls, cache, *args, **kwargs):
- """Initialize index using `cache` and update items.
-
- >>> cache = Cache('/tmp/diskcache/index')
- >>> _ = cache.clear()
- >>> index = Index.fromcache(cache, {'a': 1, 'b': 2, 'c': 3})
- >>> len(index)
- 3
- >>> 'b' in index
- True
- >>> index['c']
- 3
-
- :param Cache cache: cache to use
- :param args: mapping or sequence of items
- :param kwargs: mapping of items
- :return: initialized Index
-
- """
- # pylint: disable=no-member,protected-access
- self = cls.__new__(cls)
- self._cache = cache
- self.update(*args, **kwargs)
- return self
-
-
- @property
- def directory(self):
- "Directory path where items are stored."
- return self._cache.directory
-
-
- def __getitem__(self, key):
- """index.__getitem__(key) <==> index[key]
-
- Return corresponding value for `key` in index.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update({'a': 1, 'b': 2})
- >>> index['a']
- 1
- >>> index['b']
- 2
- >>> index['c']
- Traceback (most recent call last):
- ...
- KeyError: 'c'
-
- :param key: key for item
- :return: value for item in index with given key
- :raises KeyError: if key is not found
-
- """
- _cache = self._cache
-
- while True:
- try:
- return _cache[key]
- except Timeout:
- continue
-
-
- def __setitem__(self, key, value):
- """index.__setitem__(key, value) <==> index[key] = value
-
- Set `key` and `value` item in index.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index['a'] = 1
- >>> index[0] = None
- >>> len(index)
- 2
-
- :param key: key for item
- :param value: value for item
-
- """
- _cache = self._cache
-
- while True:
- try:
- _cache[key] = value
- except Timeout:
- continue
- else:
- return
-
-
- def __delitem__(self, key):
- """index.__delitem__(key) <==> del index[key]
-
- Delete corresponding item for `key` from index.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update({'a': 1, 'b': 2})
- >>> del index['a']
- >>> del index['b']
- >>> len(index)
- 0
- >>> del index['c']
- Traceback (most recent call last):
- ...
- KeyError: 'c'
-
- :param key: key for item
- :raises KeyError: if key is not found
-
- """
- _cache = self._cache
-
- while True:
- try:
- del _cache[key]
- except Timeout:
- continue
- else:
- return
-
-
- def setdefault(self, key, default=None):
- """Set and get value for `key` in index using `default`.
-
- If `key` is not in index then set corresponding value to `default`. If
- `key` is in index then ignore `default` and return existing value.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.setdefault('a', 0)
- 0
- >>> index.setdefault('a', 1)
- 0
-
- :param key: key for item
- :param default: value if key is missing (default None)
- :return: value for item in index with given key
-
- """
- _cache = self._cache
-
- while True:
- try:
- return self[key]
- except KeyError:
- while True:
- try:
- _cache.add(key, default)
- except Timeout:
- continue
- else:
- break
-
-
- def pop(self, key, default=ENOVAL):
- """Remove corresponding item for `key` from index and return value.
-
- If `key` is missing then return `default`. If `default` is `ENOVAL`
- then raise KeyError.
-
- >>> index = Index('/tmp/diskcache/index', {'a': 1, 'b': 2})
- >>> index.pop('a')
- 1
- >>> index.pop('b')
- 2
- >>> index.pop('c', default=3)
- 3
- >>> index.pop('d')
- Traceback (most recent call last):
- ...
- KeyError: 'd'
-
- :param key: key for item
- :param default: return value if key is missing (default ENOVAL)
- :return: value for item if key is found else default
- :raises KeyError: if key is not found and default is ENOVAL
-
- """
-
- _cache = self._cache
-
- while True:
- try:
- value = _cache.pop(key, default=default)
- except Timeout:
- continue
- else:
- if value is ENOVAL:
- raise KeyError(key)
- return value
-
-
- def popitem(self, last=True):
- """Remove and return item pair.
-
- Item pairs are returned in last-in-first-out (LIFO) order if last is
- True else first-in-first-out (FIFO) order. LIFO order imitates a stack
- and FIFO order imitates a queue.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> index.popitem()
- ('c', 3)
- >>> index.popitem(last=False)
- ('a', 1)
- >>> index.popitem()
- ('b', 2)
- >>> index.popitem()
- Traceback (most recent call last):
- ...
- KeyError
-
- :param bool last: pop last item pair (default True)
- :return: key and value item pair
- :raises KeyError: if index is empty
-
- """
- # pylint: disable=arguments-differ
- _cache = self._cache
-
- while True:
- try:
- if last:
- key = next(reversed(_cache))
- else:
- key = next(iter(_cache))
- except StopIteration:
- raise KeyError
-
- try:
- value = _cache.pop(key)
- except (KeyError, Timeout):
- continue
- else:
- return key, value
-
-
- def push(self, value, prefix=None, side='back'):
- """Push `value` onto `side` of queue in index identified by `prefix`.
-
- When prefix is None, integer keys are used. Otherwise, string keys are
- used in the format "prefix-integer". Integer starts at 500 trillion.
-
- Defaults to pushing value on back of queue. Set side to 'front' to push
- value on front of queue. Side must be one of 'back' or 'front'.
-
- See also `Index.pull`.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> print(index.push('apples'))
- 500000000000000
- >>> print(index.push('beans'))
- 500000000000001
- >>> print(index.push('cherries', side='front'))
- 499999999999999
- >>> index[500000000000001]
- 'beans'
- >>> index.push('dates', prefix='fruit')
- 'fruit-500000000000000'
-
- :param value: value for item
- :param str prefix: key prefix (default None, key is integer)
- :param str side: either 'back' or 'front' (default 'back')
- :return: key for item in cache
-
- """
- _cache_push = self._cache.push
-
- while True:
- try:
- return _cache_push(value, prefix, side)
- except Timeout:
- continue
-
-
- def pull(self, prefix=None, default=(None, None), side='front'):
- """Pull key and value item pair from `side` of queue in index.
-
- When prefix is None, integer keys are used. Otherwise, string keys are
- used in the format "prefix-integer". Integer starts at 500 trillion.
-
- If queue is empty, return default.
-
- Defaults to pulling key and value item pairs from front of queue. Set
- side to 'back' to pull from back of queue. Side must be one of 'front'
- or 'back'.
-
- See also `Index.push`.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> for letter in 'abc':
- ... print(index.push(letter))
- 500000000000000
- 500000000000001
- 500000000000002
- >>> key, value = index.pull()
- >>> print(key)
- 500000000000000
- >>> value
- 'a'
- >>> _, value = index.pull(side='back')
- >>> value
- 'c'
- >>> index.pull(prefix='fruit')
- (None, None)
-
- :param str prefix: key prefix (default None, key is integer)
- :param default: value to return if key is missing
- (default (None, None))
- :param str side: either 'front' or 'back' (default 'front')
- :return: key and value item pair or default if queue is empty
-
- """
- _cache_pull = self._cache.pull
-
- while True:
- try:
- return _cache_pull(prefix, default, side)
- except Timeout:
- continue
-
-
- def clear(self):
- """Remove all items from index.
-
- """
- _cache_clear = self._cache.clear
-
- while True:
- try:
- _cache_clear()
- return
- except Timeout:
- continue
-
-
- def __iter__(self):
- """index.__iter__() <==> iter(index)
-
- Return iterator of index keys in insertion order.
-
- """
- return iter(self._cache)
-
-
- def __reversed__(self):
- """index.__reversed__() <==> reversed(index)
-
- Return iterator of index keys in reversed insertion order.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> iterator = reversed(index)
- >>> next(iterator)
- 'c'
- >>> list(iterator)
- ['b', 'a']
-
- """
- return reversed(self._cache)
-
-
- def __len__(self):
- """index.__len__() <==> len(index)
-
- Return length of index.
-
- """
- return len(self._cache)
-
-
- if sys.hexversion < 0x03000000:
- def keys(self):
- """List of index keys.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> index.keys()
- ['a', 'b', 'c']
-
- :return: list of keys
-
- """
- return list(self._cache)
-
-
- def values(self):
- """List of index values.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> index.values()
- [1, 2, 3]
-
- :return: list of values
-
- """
- return list(self.itervalues())
-
-
- def items(self):
- """List of index items.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> index.items()
- [('a', 1), ('b', 2), ('c', 3)]
-
- :return: list of items
-
- """
- return list(self.iteritems())
-
-
- def iterkeys(self):
- """Iterator of index keys.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> list(index.iterkeys())
- ['a', 'b', 'c']
-
- :return: iterator of keys
-
- """
- return iter(self._cache)
-
-
- def itervalues(self):
- """Iterator of index values.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> list(index.itervalues())
- [1, 2, 3]
-
- :return: iterator of values
-
- """
- _cache = self._cache
-
- for key in _cache:
- while True:
- try:
- yield _cache[key]
- except KeyError:
- break
- except Timeout:
- continue
- else:
- break
-
-
- def iteritems(self):
- """Iterator of index items.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> list(index.iteritems())
- [('a', 1), ('b', 2), ('c', 3)]
-
- :return: iterator of items
-
- """
- _cache = self._cache
-
- for key in _cache:
- while True:
- try:
- yield key, _cache[key]
- except KeyError:
- break
- except Timeout:
- continue
- else:
- break
-
-
- def viewkeys(self):
- """Set-like object providing a view of index keys.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update({'a': 1, 'b': 2, 'c': 3})
- >>> keys_view = index.viewkeys()
- >>> 'b' in keys_view
- True
-
- :return: keys view
-
- """
- return KeysView(self)
-
-
- def viewvalues(self):
- """Set-like object providing a view of index values.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update({'a': 1, 'b': 2, 'c': 3})
- >>> values_view = index.viewvalues()
- >>> 2 in values_view
- True
-
- :return: values view
-
- """
- return ValuesView(self)
-
-
- def viewitems(self):
- """Set-like object providing a view of index items.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update({'a': 1, 'b': 2, 'c': 3})
- >>> items_view = index.viewitems()
- >>> ('b', 2) in items_view
- True
-
- :return: items view
-
- """
- return ItemsView(self)
-
-
- else:
- def keys(self):
- """Set-like object providing a view of index keys.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update({'a': 1, 'b': 2, 'c': 3})
- >>> keys_view = index.keys()
- >>> 'b' in keys_view
- True
-
- :return: keys view
-
- """
- return KeysView(self)
-
-
- def values(self):
- """Set-like object providing a view of index values.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update({'a': 1, 'b': 2, 'c': 3})
- >>> values_view = index.values()
- >>> 2 in values_view
- True
-
- :return: values view
-
- """
- return ValuesView(self)
-
-
- def items(self):
- """Set-like object providing a view of index items.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update({'a': 1, 'b': 2, 'c': 3})
- >>> items_view = index.items()
- >>> ('b', 2) in items_view
- True
-
- :return: items view
-
- """
- return ItemsView(self)
-
-
- __hash__ = None
-
-
- def __getstate__(self):
- return self.directory
-
-
- def __setstate__(self, state):
- self.__init__(state)
-
-
- def __eq__(self, other):
- """index.__eq__(other) <==> index == other
-
- Compare equality for index and `other`.
-
- Comparison to another index or ordered dictionary is
- order-sensitive. Comparison to all other mappings is order-insensitive.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> pairs = [('a', 1), ('b', 2), ('c', 3)]
- >>> index.update(pairs)
- >>> from collections import OrderedDict
- >>> od = OrderedDict(pairs)
- >>> index == od
- True
- >>> index == {'c': 3, 'b': 2, 'a': 1}
- True
-
- :param other: other mapping in equality comparison
-
- """
- if len(self) != len(other):
- return False
-
- if isinstance(other, (Index, OrderedDict)):
- alpha = ((key, self[key]) for key in self)
- beta = ((key, other[key]) for key in other)
- pairs = zip(alpha, beta)
- return not any(a != x or b != y for (a, b), (x, y) in pairs)
- else:
- return all(self[key] == other.get(key, ENOVAL) for key in self)
-
-
- def __ne__(self, other):
- """index.__ne__(other) <==> index != other
-
- Compare inequality for index and `other`.
-
- Comparison to another index or ordered dictionary is
- order-sensitive. Comparison to all other mappings is order-insensitive.
-
- >>> index = Index('/tmp/diskcache/index')
- >>> index.clear()
- >>> index.update([('a', 1), ('b', 2), ('c', 3)])
- >>> from collections import OrderedDict
- >>> od = OrderedDict([('c', 3), ('b', 2), ('a', 1)])
- >>> index != od
- True
- >>> index != {'a': 1, 'b': 2}
- True
-
- :param other: other mapping in inequality comparison
-
- """
- return not self == other
-
-
- def __repr__(self):
- """index.__repr__() <==> repr(index)
-
- Return string with printable representation of index.
-
- """
- name = type(self).__name__
- return '{0}({1!r})'.format(name, self.directory)
-
-
- def __del__(self):
- self._cache.close()
|