def test_keys_are_sorted(keys): items = [(key, key + 1) for key in keys] sorted_items = sorted(items) sorted_keys = sorted(keys) d = SortedDict(items) assert sorted(d) == sorted_keys assert sorted(d.keys()) == sorted_keys assert d.items() == sorted(items) assert d.values() == sorted(v for k, v in items)
class DBF(object): version = 3 header_fmt = '<BBBBLHH20x' fields_fmt = '<11sc4xBB14x' def __init__(self, db, fieldspecs=None): if isinstance(db, basestring): db = open(db, 'w+b') self.db = db self.fields = fieldspecs # try to read the header infos from the db header = db.read(32) if header: header = struct.unpack(self.header_fmt, header) # if the user passed fieldspecs if self.fields: # obtain dbf meta data from them self.numfields = len(self.fields) self.lenheader = self.numfields * 32 + 33 self.lenrecord = 1 self.record_fmt = '1s' for field in self.fields.itervalues(): self.lenrecord += field.size self.record_fmt += '%ds' % field.size # if we have an header if header: # check the header's infos with the ones we have obtained from # our fieldspecs self.numrec, lenheader, lenrecord = header[-3:] assert (lenheader == self.lenheader and lenrecord == self.lenrecord), \ "database's fields doesn't match provided fields" # if no header is present, write it else: self.numrec = 0 # header now = datetime.datetime.now() y, m, d = now.year-1900, now.month, now.day header = struct.pack(self.header_fmt, self.version, y, m, d, self.numrec, self.lenheader, self.lenrecord) self.db.write(header) # field specs for fname, field in self.fields.iteritems(): fname = fname.ljust(11, '\0') field = struct.pack(self.fields_fmt, fname, field.type, field.size, field.deci) self.db.write(field) self.db.write('\r\x1A') else: # if we have no fieldspecs, but we have an header in our dbf, # obtain the fieldspecs from it. if header: self.numrec, self.lenheader, self.lenrecord = header[-3:] self.numfields = (self.lenheader - 33) // 32 self.fields = SortedDict() self.record_fmt = '1s' for fieldno in xrange(self.numfields): fieldinfo = struct.unpack(self.fields_fmt, db.read(32)) name, type, size, deci = fieldinfo name = name.partition('\0')[0] self.fields[name] = fields.guessField(type, size, deci) self.record_fmt += '%ds' % size else: # if we have no header and no fieldspecs, we can't help it ... raise TypeError("nor fields or header present") i = 0 self._fieldpos = [] for field in self.fields.itervalues(): self._fieldpos.append(i) i += field.size def gotoField(self, fname): i = self.fields.keyOrder.index(fname) self.db.seek(self._currec + 1 + self._fieldpos[i]) def newID(self): """ return a new record ID. """ self.db.seek(4) self.numrec = struct.unpack('<L', self.db.read(4))[0] return self.numrec def increase_numrec(self): self.numrec += 1 self.db.seek(4) self.db.write(struct.pack('<L', self.numrec)) def gotoRecord(self, recIndex): """ move before the record specified by the index recIndex """ if recIndex > self.numrec: raise KeyError(recIndex) self._currec = self.lenheader + self.lenrecord * (recIndex) self.db.seek(self._currec) def update(self, record): recId = record['pk'] self.gotoRecord(recId) dflag = self.db.read(1) for fname, field in self.fields.iteritems(): if fname in record: self.db.write(field.encode(record[fname])) self.db.flush() else: self.db.seek(field.size, 1) self.db.flush() def insert(self, record): recId = self.newID() self.gotoRecord(recId) record['pk'] = recId self.db.write(' ') data = '' for fname, field in self.fields.iteritems(): data += field.encode(record[fname]) self.db.write(data) self.db.write('\x1A') self.increase_numrec() self.db.flush() def _iterselect(self, fields=None): for recId in xrange(self.numrec): yield self.select(recId, fields) def select(self, recId=None, fields=None): if recId is None: return self._iterselect(fields) if not recId in self: raise KeyError(recId) if not fields: fields = self.fields.keys() self.gotoRecord(recId) res = {'pk': recId} self.db.read(1) for fname, field in self.fields.iteritems(): if fname in fields: res[fname] = field.decode(self.db.read(field.size)) else: self.db.seek(field.size, 1) return res def close(self): self.db.close() def __contains__(self, recId): if isinstance(recId, int) and recId < self.numrec: return True return False def __iter__(self): for i in xrange(self.numrec): yield self.select(i) def __len__(self): return self.numrec def __getitem__(self, recordID): return self.select(recordID) def __setitem__(self, recordID, dict): self.select(recordID, dict)
class DBF(object): version = 3 header_fmt = '<BBBBLHH20x' fields_fmt = '<11sc4xBB14x' def __init__(self, db, fieldspecs=None): if isinstance(db, basestring): db = open(db, 'w+b') self.db = db self.fields = fieldspecs # try to read the header infos from the db header = db.read(32) if header: header = struct.unpack(self.header_fmt, header) # if the user passed fieldspecs if self.fields: # obtain dbf meta data from them self.numfields = len(self.fields) self.lenheader = self.numfields * 32 + 33 self.lenrecord = 1 self.record_fmt = '1s' for field in self.fields.itervalues(): self.lenrecord += field.size self.record_fmt += '%ds' % field.size # if we have an header if header: # check the header's infos with the ones we have obtained from # our fieldspecs self.numrec, lenheader, lenrecord = header[-3:] assert (lenheader == self.lenheader and lenrecord == self.lenrecord), \ "database's fields doesn't match provided fields" # if no header is present, write it else: self.numrec = 0 # header now = datetime.datetime.now() y, m, d = now.year - 1900, now.month, now.day header = struct.pack(self.header_fmt, self.version, y, m, d, self.numrec, self.lenheader, self.lenrecord) self.db.write(header) # field specs for fname, field in self.fields.iteritems(): fname = fname.ljust(11, '\0') field = struct.pack(self.fields_fmt, fname, field.type, field.size, field.deci) self.db.write(field) self.db.write('\r\x1A') else: # if we have no fieldspecs, but we have an header in our dbf, # obtain the fieldspecs from it. if header: self.numrec, self.lenheader, self.lenrecord = header[-3:] self.numfields = (self.lenheader - 33) // 32 self.fields = SortedDict() self.record_fmt = '1s' for fieldno in xrange(self.numfields): fieldinfo = struct.unpack(self.fields_fmt, db.read(32)) name, type, size, deci = fieldinfo name = name.partition('\0')[0] self.fields[name] = fields.guessField(type, size, deci) self.record_fmt += '%ds' % size else: # if we have no header and no fieldspecs, we can't help it ... raise TypeError("nor fields or header present") i = 0 self._fieldpos = [] for field in self.fields.itervalues(): self._fieldpos.append(i) i += field.size def gotoField(self, fname): i = self.fields.keyOrder.index(fname) self.db.seek(self._currec + 1 + self._fieldpos[i]) def newID(self): """ return a new record ID. """ self.db.seek(4) self.numrec = struct.unpack('<L', self.db.read(4))[0] return self.numrec def increase_numrec(self): self.numrec += 1 self.db.seek(4) self.db.write(struct.pack('<L', self.numrec)) def gotoRecord(self, recIndex): """ move before the record specified by the index recIndex """ if recIndex > self.numrec: raise KeyError(recIndex) self._currec = self.lenheader + self.lenrecord * (recIndex) self.db.seek(self._currec) def update(self, record): recId = record['pk'] self.gotoRecord(recId) dflag = self.db.read(1) for fname, field in self.fields.iteritems(): if fname in record: self.db.write(field.encode(record[fname])) self.db.flush() else: self.db.seek(field.size, 1) self.db.flush() def insert(self, record): recId = self.newID() self.gotoRecord(recId) record['pk'] = recId self.db.write(' ') data = '' for fname, field in self.fields.iteritems(): data += field.encode(record[fname]) self.db.write(data) self.db.write('\x1A') self.increase_numrec() self.db.flush() def _iterselect(self, fields=None): for recId in xrange(self.numrec): yield self.select(recId, fields) def select(self, recId=None, fields=None): if recId is None: return self._iterselect(fields) if not recId in self: raise KeyError(recId) if not fields: fields = self.fields.keys() self.gotoRecord(recId) res = {'pk': recId} self.db.read(1) for fname, field in self.fields.iteritems(): if fname in fields: res[fname] = field.decode(self.db.read(field.size)) else: self.db.seek(field.size, 1) return res def close(self): self.db.close() def __contains__(self, recId): if isinstance(recId, int) and recId < self.numrec: return True return False def __iter__(self): for i in xrange(self.numrec): yield self.select(i) def __len__(self): return self.numrec def __getitem__(self, recordID): return self.select(recordID) def __setitem__(self, recordID, dict): self.select(recordID, dict)
def test_keys_values_items(self): a = SortedDict({'a': 1, 'b': 2}) self.assertListEqual(a.keys(), ['a', 'b']) self.assertListEqual(a.values(), [1, 2]) self.assertListEqual(a.items(), [('a', 1), ('b', 2)])