Source code for cacheblob.item
# -*- coding: utf-8 -*-
"""
This module defines the CacheItem class, which represents key-value pairs that have an
associated time of expiry.
"""
from __future__ import absolute_import
import datetime
import pytz
from . import constants as C
[docs]class CacheItem(object):
"""This class represents items, which are key-value pairs that have an associated
time of expiry.
:class:`cacheblob.CacheItem`
"""
def __init__(self, index, value, created=None, expiry=None, duration=None):
self._index = index
self._value = None
self._length = None
self._created = None
self._duration = None
self._expiry = None
self._updated = None
if duration is not None and expiry is not None:
raise ValueError("Cannot simultaneously specify both duration and expiry")
if created is not None:
self.created = created
else:
self.created = pytz.utc.localize(datetime.datetime.now())
if expiry is not None:
self.expiry = expiry
elif duration is not None:
self.duration = duration
self.expiry = self.created + self._duration
else:
# This can safely be an else case because of the error thrown earlier
# Note that if the user wants an item with no expiry, cannot do that here
self.duration = C.DEFAULT_DURATION
self.expiry = self.created + self.duration
self.value = value
def __str__(self):
return "{0}:{1}".format(self.index, self.value)
def __repr__(self):
return "<{0} {1}>".format(self.__class__.__name__,
str({'index': self._index,
'value': self._value,
'length': self.length,
'created': self.created,
'duration': self.duration,
'expiry': self.expiry,
'updated': self.updated}))
@property
def index(self):
"""Access the index, or key, of a key-value pair.
:returns: The index, or key, of the key-value pair.
"""
return self._index
@index.setter
def index(self, value):
"""Set the index, or key, of a key-value pair.
:param value: The value to set.
"""
self._index = value
@property
def value(self):
"""Access the value of a key-value pair.
:returns: The value of the key-value pair.
"""
return self._value
@value.setter
def value(self, value):
"""Access the value of a key-value pair. This will set the updated field to the
current time, in UTC.
:param value: The value to set.
"""
self._value = value
self._updated = pytz.utc.localize(datetime.datetime.now())
if isinstance(value, str):
self._length = len(value)
@property
def duration(self):
"""Access the duration of the key-value pair. This is the length of time that the
pair was intended to live for.
:returns: The duration of the key-value pair."""
return self._duration
@duration.setter
def duration(self, value):
"""Set the duration of a key-value pair. If the value is none, then the pair is
designed to never expire. The duration must be positive.
:param value: The value to set. Must be a datetime.timedelta value.
"""
if value is None:
self._duration = None
self._expiry = None
return
if not isinstance(value, datetime.timedelta):
raise TypeError("duration must be None or a datetime.timedelta value.")
if value < datetime.timedelta(0):
raise ValueError("Duration must be None or positive")
self._duration = value
self._expiry = self.created + value
@property
def created(self):
"""Access the creation time of the key-value pair, which is stored in UTC.
:returns: The creation time of the key-value pair."""
return self._created
@created.setter
def created(self, value):
"""Set the creation time of a key-value pair. The time is stored in UTC but does
not need to be provided as a UTC-localized value.
:param value: The value to set. Must be a datetime.datetime value.
"""
if not isinstance(value, datetime.datetime):
raise TypeError("created must be a datetime.datetime value.")
if value.tzinfo is None or value.tzinfo.utcoffset(value) is None:
value_utc = pytz.utc.localize(value)
else:
value_utc = value
self._created = value_utc
@property
def expiry(self):
"""Access the expiry time of the key-value pair, which is stored in UTC.
:returns: The expiry time of the key-value pair."""
return self._expiry
@expiry.setter
def expiry(self, value):
"""Set the expiry time of a key-value pair. If the value is none, then the pair
is designed to never expire. The expiry must not be earlier than the creation
time. The time is stored in UTC but does not need to be provided as a
UTC-localized value.
:param value: The value to set. Must be a datetime.datetime value.
"""
if value is None:
self._duration = None
self._expiry = None
return
if not isinstance(value, datetime.datetime):
raise TypeError("expiry must be a datetime.datetime value.")
if value.tzinfo is None or value.tzinfo.utcoffset(value) is None:
value_utc = pytz.utc.localize(value)
else:
value_utc = value
if value_utc < self.created:
raise ValueError("Expiry must be None or in the future")
self._duration = value_utc - self.created
self._expiry = value_utc
@property
def is_expired(self):
"""Determine whether or not the item is expired.
:returns: Whether the item is currently expired or not.
"""
return self.expiry < pytz.utc.localize(datetime.datetime.now())
@property
def updated(self):
"""Access the last update time of the item.
:returns: When the item was updated, in UTC.
"""
return self._updated
@property
def length(self):
"""Access the length of the item's value. If the item was a string type then this
will be the length of the string. Otherwise this will be None, which does not
indicate that the item has no value.
:returns: The length of the item's value.
"""
return self._length