Package horizons :: Package util :: Module yamlcachestorage
[hide private]
[frames] | no frames]

Source Code for Module horizons.util.yamlcachestorage

  1  # ################################################### 
  2  # Copyright (C) 2008-2017 The Unknown Horizons Team 
  3  # team@unknown-horizons.org 
  4  # This file is part of Unknown Horizons. 
  5  # 
  6  # Unknown Horizons is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  # GNU General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the 
 18  # Free Software Foundation, Inc., 
 19  # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 20  # ################################################### 
 21   
 22  import logging 
 23  import os.path 
 24  import pickle 
25 26 27 -class YamlCacheStorage:
28 """ 29 Store the YamlCache data in a cache. 30 31 An instance of this class provides a implements a cache that always has all the data 32 in memory. It tries to also load the data from disk and write it back on disk but 33 if it fails then it just ignores the errors and keeps working. 34 """ 35 36 log = logging.getLogger("yamlcachestorage") 37 38 # Increment this when the users of this class change the way they use it. 39 version = 1 40
41 - def __init__(self, filename):
42 super().__init__() # TODO: check if this call is needed 43 self._filename = filename 44 self._data = {}
45 46 @classmethod
47 - def _validate(cls, data):
48 """Make sure data is a tuple (version no, _data dict) with the right version.""" 49 if not isinstance(data, tuple): 50 return False 51 if len(data) != 2: 52 return False 53 if not isinstance(data[1], dict): 54 return False 55 return data[0] == cls.version
56
57 - def _reload(self):
58 """Load the cache from disk if possible. Create an empty cache otherwise.""" 59 if os.path.exists(self._filename): 60 self.log.debug('%s._reload(): loading cache from disk', self) 61 with open(self._filename, 'rb') as f: 62 data = pickle.load(f) 63 if not self._validate(data): 64 raise RuntimeError('Bad YamlCacheStorage data format') 65 self._data = data[1] 66 self.log.debug('%s._reload(): successfully loaded cache from disk', self) 67 else: 68 self._clear()
69
70 - def _clear(self):
71 """Clear the cache in memory.""" 72 self.log.debug('%s._clear(): creating a new cache', self) 73 self._data = {}
74 75 @classmethod
76 - def open(cls, filename):
77 """Open the cache specified by the file name or create an empty one otherwise.""" 78 cls.log.debug("YamlCacheStorage.open('%s')", filename) 79 obj = YamlCacheStorage(filename) 80 try: 81 obj._reload() 82 except Exception as e: 83 # Ignore all exceptions because loading the cache from disk is not critical. 84 cls.log.warning("Warning: Failed to open {0!s} as cache: {1!s}\nThis " 85 "warning is expected when upgrading from " 86 "old versions.\n".format(filename, e)) 87 obj._clear() 88 return obj
89
90 - def sync(self):
91 """Write the file to disk if possible. Do nothing otherwise.""" 92 try: 93 with open(self._filename, 'wb') as f: 94 pickle.dump((self.version, self._data), f) 95 self.log.debug('%s.sync(): success', self) 96 except Exception as e: 97 # Ignore all exceptions because saving the cache on disk is not critical. 98 self.log.warning("Warning: Unable to save cache into {0!s}: {1!s}". 99 format(self._filename, str(e)))
100
101 - def close(self):
102 """Write the file to disk if possible and then invalidate the object in memory.""" 103 self.log.debug('%s.close()', self) 104 self.sync() 105 self._filename = None 106 self._data = None
107
108 - def __getitem__(self, key):
109 """This function enables the following syntax: cache[key]""" 110 self.log.debug("%s.__getitem__('%s')", self, key) 111 return self._data[key]
112
113 - def __setitem__(self, key, value):
114 """This function enables the following syntax: cache[key] = value""" 115 self.log.debug("%s.__setitem__('%s', data excluded)", self, key) 116 self._data[key] = value
117
118 - def __contains__(self, item):
119 """This function enables the following syntax: item in cache""" 120 self.log.debug("%s.__contains__('%s')", self, item) 121 return item in self._data
122
123 - def __str__(self):
124 return "YamlCacheStorage('{0!s}', {1:d} items)".format(self._filename, len(self._data))
125