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