14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"""A dumb and slow but simple dbm clone. 24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmFor database spam, spam.dir contains the index (a text file), 44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmspam.bak *may* contain a backup of the index (also a text file), 54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmwhile spam.dat contains the data (a binary file). 64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmXXX TO DO: 84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm- seems to contain a bug when updating... 104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm- reclaim free space (currently, space once occupied by deleted or expanded 124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmitems is never reused) 134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm- support concurrent access (currently, if two processes take turns making 154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmupdates, they can mess up the index) 164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm- support efficient access to large databases (currently, the whole index 184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmis read when the database is opened, and some updates rewrite the whole index) 194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm- support opening for read-only (flag = 'm') 214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm""" 234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport os as _os 254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport __builtin__ 264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport UserDict 274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_open = __builtin__.open 294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_BLOCKSIZE = 512 314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmerror = IOError # For anydbm 334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass _Database(UserDict.DictMixin): 354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # The on-disk directory and data files can remain in mutually 374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # inconsistent states for an arbitrarily long time (see comments 384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # at the end of __setitem__). This is only repaired when _commit() 394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # gets called. One place _commit() gets called is from __del__(), 404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # and if that occurs at program shutdown time, module globals may 414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # already have gotten rebound to None. Since it's crucial that 424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # _commit() finish successfully, we can't ignore shutdown races 434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # here, and _commit() must not reference any globals. 444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _os = _os # for _commit() 454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _open = _open # for _commit() 464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, filebasename, mode): 484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._mode = mode 494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # The directory file is a text file. Each line looks like 514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # "%r, (%d, %d)\n" % (key, pos, siz) 524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # where key is the string key, pos is the offset into the dat 534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # file of the associated value's first byte, and siz is the number 544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # of bytes in the associated value. 554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._dirfile = filebasename + _os.extsep + 'dir' 564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # The data file is a binary file pointed into by the directory 584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # file, and holds the values associated with keys. Each value 594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # begins at a _BLOCKSIZE-aligned byte offset, and is a raw 604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # binary 8-bit string value. 614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._datfile = filebasename + _os.extsep + 'dat' 624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._bakfile = filebasename + _os.extsep + 'bak' 634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # The index is an in-memory dict, mirroring the directory file. 654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._index = None # maps keys to (pos, siz) pairs 664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Mod by Jack: create data file if needed 684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f = _open(self._datfile, 'r') 704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except IOError: 714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f = _open(self._datfile, 'w') 724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._chmod(self._datfile) 734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.close() 744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._update() 754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Read directory file into the in-memory index dict. 774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _update(self): 784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._index = {} 794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f = _open(self._dirfile) 814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except IOError: 824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for line in f: 854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm line = line.rstrip() 864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm key, pos_and_siz_pair = eval(line) 874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._index[key] = pos_and_siz_pair 884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.close() 894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Write the index dict to the directory file. The original directory 914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # file (if any) is renamed with a .bak extension first. If a .bak 924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # file currently exists, it's deleted. 934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _commit(self): 944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # CAUTION: It's vital that _commit() succeed, and _commit() can 954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # be called from __del__(). Therefore we must never reference a 964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # global in this routine. 974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._index is None: 984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return # nothing to do 994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._os.unlink(self._bakfile) 1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except self._os.error: 1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._os.rename(self._dirfile, self._bakfile) 1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except self._os.error: 1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f = self._open(self._dirfile, 'w') 1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._chmod(self._dirfile) 1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for key, pos_and_siz_pair in self._index.iteritems(): 1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.write("%r, %r\n" % (key, pos_and_siz_pair)) 1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.close() 1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sync = _commit 1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __getitem__(self, key): 1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pos, siz = self._index[key] # may raise KeyError 1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f = _open(self._datfile, 'rb') 1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.seek(pos) 1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm dat = f.read(siz) 1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.close() 1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return dat 1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Append val to the data file, starting at a _BLOCKSIZE-aligned 1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # offset. The data file is first padded with NUL bytes (if needed) 1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # to get to an aligned offset. Return pair 1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # (starting offset of val, len(val)) 1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _addval(self, val): 1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f = _open(self._datfile, 'rb+') 1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.seek(0, 2) 1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pos = int(f.tell()) 1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm npos = ((pos + _BLOCKSIZE - 1) // _BLOCKSIZE) * _BLOCKSIZE 1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.write('\0'*(npos-pos)) 1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pos = npos 1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.write(val) 1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.close() 1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return (pos, len(val)) 1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Write val to the data file, starting at offset pos. The caller 1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # is responsible for ensuring that there's enough room starting at 1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # pos to hold val, without overwriting some other value. Return 1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # pair (pos, len(val)). 1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _setval(self, pos, val): 1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f = _open(self._datfile, 'rb+') 1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.seek(pos) 1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.write(val) 1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.close() 1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return (pos, len(val)) 1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # key is a new key whose associated value starts in the data file 1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # at offset pos and with length siz. Add an index record to 1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # the in-memory index dict, and append one to the directory file. 1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _addkey(self, key, pos_and_siz_pair): 1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._index[key] = pos_and_siz_pair 1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f = _open(self._dirfile, 'a') 1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._chmod(self._dirfile) 1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.write("%r, %r\n" % (key, pos_and_siz_pair)) 1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm f.close() 1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __setitem__(self, key, val): 1634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not type(key) == type('') == type(val): 1644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise TypeError, "keys and values must be strings" 1654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if key not in self._index: 1664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._addkey(key, self._addval(val)) 1674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 1684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # See whether the new value is small enough to fit in the 1694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # (padded) space currently occupied by the old value. 1704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pos, siz = self._index[key] 1714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm oldblocks = (siz + _BLOCKSIZE - 1) // _BLOCKSIZE 1724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm newblocks = (len(val) + _BLOCKSIZE - 1) // _BLOCKSIZE 1734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if newblocks <= oldblocks: 1744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._index[key] = self._setval(pos, val) 1754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 1764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # The new value doesn't fit in the (padded) space used 1774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # by the old value. The blocks used by the old value are 1784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # forever lost. 1794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._index[key] = self._addval(val) 1804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Note that _index may be out of synch with the directory 1824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # file now: _setval() and _addval() don't update the directory 1834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # file. This also means that the on-disk directory and data 1844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # files are in a mutually inconsistent state, and they'll 1854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # remain that way until _commit() is called. Note that this 1864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # is a disaster (for the database) if the program crashes 1874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # (so that _commit() never gets called). 1884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __delitem__(self, key): 1904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # The blocks used by the associated value are lost. 1914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm del self._index[key] 1924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # XXX It's unclear why we do a _commit() here (the code always 1934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # XXX has, so I'm not changing it). _setitem__ doesn't try to 1944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # XXX keep the directory file in synch. Why should we? Or 1954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # XXX why shouldn't __setitem__? 1964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._commit() 1974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def keys(self): 1994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return self._index.keys() 2004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def has_key(self, key): 2024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return key in self._index 2034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __contains__(self, key): 2054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return key in self._index 2064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def iterkeys(self): 2084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return self._index.iterkeys() 2094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm __iter__ = iterkeys 2104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __len__(self): 2124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return len(self._index) 2134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def close(self): 2154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._commit() 2164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._index = self._datfile = self._dirfile = self._bakfile = None 2174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm __del__ = close 2194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _chmod (self, file): 2214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if hasattr(self._os, 'chmod'): 2224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._os.chmod(file, self._mode) 2234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef open(file, flag=None, mode=0666): 2264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Open the database file, filename, and return corresponding object. 2274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm The flag argument, used to control how the database is opened in the 2294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm other DBM implementations, is ignored in the dumbdbm module; the 2304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm database is always opened for update, and will be created if it does 2314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm not exist. 2324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm The optional mode argument is the UNIX mode of the file, used only when 2344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm the database has to be created. It defaults to octal code 0666 (and 2354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm will be modified by the prevailing umask). 2364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """ 2384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # flag argument is currently ignored 2394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Modify mode depending on the umask 2414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 2424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm um = _os.umask(0) 2434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _os.umask(um) 2444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except AttributeError: 2454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 2464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 2474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Turn off any bits that are set in the umask 2484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm mode = mode & (~um) 2494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return _Database(file, mode) 251