Package SCons :: Module dblite
[hide private]
[frames] | no frames]

Source Code for Module SCons.dblite

  1  # dblite.py module contributed by Ralf W. Grosse-Kunstleve. 
  2  # Extended for Unicode by Steven Knight. 
  3   
  4  import cPickle 
  5  import time 
  6  import shutil 
  7  import os 
  8  import os.path 
  9  import types 
 10  import __builtin__ 
 11   
 12  _open = __builtin__.open # avoid name clash 
 13   
 14  keep_all_files = 00000 
 15  ignore_corrupt_dbfiles = 0 
 16   
17 -def corruption_warning(filename):
18 print "Warning: Discarding corrupt database:", filename
19 20 if hasattr(types, 'UnicodeType'):
21 - def is_string(s):
22 t = type(s) 23 return t is types.StringType or t is types.UnicodeType
24 else:
25 - def is_string(s):
26 return type(s) is types.StringType
27 28 try: 29 unicode('a') 30 except NameError:
31 - def unicode(s): return s
32 33 dblite_suffix = '.dblite' 34 tmp_suffix = '.tmp' 35
36 -class dblite:
37
38 - def __init__(self, file_base_name, flag, mode):
39 assert flag in (None, "r", "w", "c", "n") 40 if (flag is None): flag = "r" 41 base, ext = os.path.splitext(file_base_name) 42 if ext == dblite_suffix: 43 # There's already a suffix on the file name, don't add one. 44 self._file_name = file_base_name 45 self._tmp_name = base + tmp_suffix 46 else: 47 self._file_name = file_base_name + dblite_suffix 48 self._tmp_name = file_base_name + tmp_suffix 49 self._flag = flag 50 self._mode = mode 51 self._dict = {} 52 self._needs_sync = 00000 53 if (self._flag == "n"): 54 _open(self._file_name, "wb", self._mode) 55 else: 56 try: 57 f = _open(self._file_name, "rb") 58 except IOError, e: 59 if (self._flag != "c"): 60 raise e 61 _open(self._file_name, "wb", self._mode) 62 else: 63 p = f.read() 64 if (len(p) > 0): 65 try: 66 self._dict = cPickle.loads(p) 67 except (cPickle.UnpicklingError, EOFError): 68 if (ignore_corrupt_dbfiles == 0): raise 69 if (ignore_corrupt_dbfiles == 1): 70 corruption_warning(self._file_name)
71
72 - def __del__(self):
73 if (self._needs_sync): 74 self.sync()
75
76 - def sync(self):
77 self._check_writable() 78 f = _open(self._tmp_name, "wb", self._mode) 79 cPickle.dump(self._dict, f, 1) 80 f.close() 81 # Windows doesn't allow renaming if the file exists, so unlink 82 # it first, chmod'ing it to make sure we can do so. On UNIX, we 83 # may not be able to chmod the file if it's owned by someone else 84 # (e.g. from a previous run as root). We should still be able to 85 # unlink() the file if the directory's writable, though, so ignore 86 # any OSError exception thrown by the chmod() call. 87 try: os.chmod(self._file_name, 0777) 88 except OSError: pass 89 os.unlink(self._file_name) 90 os.rename(self._tmp_name, self._file_name) 91 self._needs_sync = 00000 92 if (keep_all_files): 93 shutil.copyfile( 94 self._file_name, 95 self._file_name + "_" + str(int(time.time())))
96
97 - def _check_writable(self):
98 if (self._flag == "r"): 99 raise IOError("Read-only database: %s" % self._file_name)
100
101 - def __getitem__(self, key):
102 return self._dict[key]
103
104 - def __setitem__(self, key, value):
105 self._check_writable() 106 if (not is_string(key)): 107 raise TypeError, "key `%s' must be a string but is %s" % (key, type(key)) 108 if (not is_string(value)): 109 raise TypeError, "value `%s' must be a string but is %s" % (value, type(value)) 110 self._dict[key] = value 111 self._needs_sync = 0001
112
113 - def keys(self):
114 return self._dict.keys()
115
116 - def has_key(self, key):
117 return key in self._dict
118
119 - def __contains__(self, key):
120 return key in self._dict
121
122 - def iterkeys(self):
123 return self._dict.iterkeys()
124 125 __iter__ = iterkeys 126
127 - def __len__(self):
128 return len(self._dict)
129
130 -def open(file, flag=None, mode=0666):
131 return dblite(file, flag, mode)
132
133 -def _exercise():
134 db = open("tmp", "n") 135 assert len(db) == 0 136 db["foo"] = "bar" 137 assert db["foo"] == "bar" 138 db[unicode("ufoo")] = unicode("ubar") 139 assert db[unicode("ufoo")] == unicode("ubar") 140 db.sync() 141 db = open("tmp", "c") 142 assert len(db) == 2, len(db) 143 assert db["foo"] == "bar" 144 db["bar"] = "foo" 145 assert db["bar"] == "foo" 146 db[unicode("ubar")] = unicode("ufoo") 147 assert db[unicode("ubar")] == unicode("ufoo") 148 db.sync() 149 db = open("tmp", "r") 150 assert len(db) == 4, len(db) 151 assert db["foo"] == "bar" 152 assert db["bar"] == "foo" 153 assert db[unicode("ufoo")] == unicode("ubar") 154 assert db[unicode("ubar")] == unicode("ufoo") 155 try: 156 db.sync() 157 except IOError, e: 158 assert str(e) == "Read-only database: tmp.dblite" 159 else: 160 raise RuntimeError, "IOError expected." 161 db = open("tmp", "w") 162 assert len(db) == 4 163 db["ping"] = "pong" 164 db.sync() 165 try: 166 db[(1,2)] = "tuple" 167 except TypeError, e: 168 assert str(e) == "key `(1, 2)' must be a string but is <type 'tuple'>", str(e) 169 else: 170 raise RuntimeError, "TypeError exception expected" 171 try: 172 db["list"] = [1,2] 173 except TypeError, e: 174 assert str(e) == "value `[1, 2]' must be a string but is <type 'list'>", str(e) 175 else: 176 raise RuntimeError, "TypeError exception expected" 177 db = open("tmp", "r") 178 assert len(db) == 5 179 db = open("tmp", "n") 180 assert len(db) == 0 181 _open("tmp.dblite", "w") 182 db = open("tmp", "r") 183 _open("tmp.dblite", "w").write("x") 184 try: 185 db = open("tmp", "r") 186 except cPickle.UnpicklingError: 187 pass 188 else: 189 raise RuntimeError, "cPickle exception expected." 190 global ignore_corrupt_dbfiles 191 ignore_corrupt_dbfiles = 2 192 db = open("tmp", "r") 193 assert len(db) == 0 194 os.unlink("tmp.dblite") 195 try: 196 db = open("tmp", "w") 197 except IOError, e: 198 assert str(e) == "[Errno 2] No such file or directory: 'tmp.dblite'", str(e) 199 else: 200 raise RuntimeError, "IOError expected." 201 print "OK"
202 203 if (__name__ == "__main__"): 204 _exercise() 205