3 This module implements a very simple database on the flat ASCII files.
8 from UserList import UserList
11 # Flad restriction error
12 checking_error = "flad.checking_error"
14 # Default key/value separator
20 Class to represent memory database.
21 FLAD database is a list of records,
22 where every record is a dictionary.
25 # Field and record separators are ALWAYS newline. It cannot be changed
26 # without extensive rewriting of this module
27 # field_sep = rec_sep = '\n'
29 def __init__(self, check_record_func = None, key_sep = def_keysep):
30 UserList.__init__(self)
31 self.check_record_func = check_record_func
32 self.key_sep = key_sep
38 def check_record(self, record): # Method can be overriden in subclasses
39 if self.check_record_func:
40 if callable(self.check_record_func):
41 return self.check_record_func(self, record)
43 raise TypeError("non-callable restriction function")
48 def checking_error(self): # Method can be overriden in subclasses
52 def __setitem__(self, i, item):
53 if not self.check_record(item):
56 UserList.__setitem__(self, i, item)
59 def __setslice__(self, i, j, list):
63 if not self.check_record(item):
65 del copy_list[copy_list.index(item)]
66 UserList.__setslice__(self, i, j, copy_list)
69 def append(self, item):
70 if not self.check_record(item):
73 UserList.append(self, item)
76 def insert(self, i, item):
77 if not self.check_record(item):
80 UserList.insert(self, i, item)
83 def split_key(self, line):
85 Split input line to key/value pair and add the pair to dictionary
87 ###line = string.lstrip(line) # Do not rstrip - if empty value, this will remove space from key
89 line = line[:-1] # Chop
91 l = line.split(self.key_sep, 1) # Just split to key and reminder
95 def __parse_line(self, record, line): # Internal function
96 if line == '\n': # Empty line is record separator (but there cannot be more than 1 empty lines)
97 if record: # This helps to skip all empty lines
98 self.append(record) # Check and add the record to list
99 return 1 # Signal to stop filling the record and start a new one
102 key, value = self.split_key(line)
103 if key in record.keys(): # This have to be done with check_record
104 # but the record is not complete now,
105 # so it is not ready to be checked :(
106 # And, of course, two keys with the same name
107 # cannot be added to dictionary
108 raise KeyError("field key \"" + key + "\" already in record")
115 def create_new_record(self): # Method can be overriden in subclasses
119 def feed(self, record, line): # Method can be overriden in subclasses
121 if self.wait_comment:
122 if string.strip(line) == '':
123 self.comment = self.comment + '\n'
127 elif string.lstrip(line)[0] == '#':
128 self.comment = self.comment + line
132 self.wait_comment = 0
133 # Fallback to parsing
135 return self.__parse_line(record, line)
143 def load_file(self, f):
145 Load a database from file as a list of records.
146 Every record is a dictionary of key/value pairs.
147 The file is reading as whole - this is much faster, but require
151 if type(f) == type(''): # If f is string - use it as file's name
152 infile = open(f, 'r')
154 infile = f # else assume it is opened file (fileobject) or
155 # "compatible" object (must has readline() methods)
158 lines = infile.readlines()
161 if type(f) == type(''): # If f was opened - close it
164 record = self.create_new_record()
167 if self.feed(record, line):
168 record = self.create_new_record()
170 # Close record on EOF without empty line
172 self.feed(record, None)
175 def load_from_file(self, f):
177 Load a database from file as a list of records.
178 Every record is a dictionary of key/value pairs.
179 The file is reading line by line - this is much slower, but do not
180 require so much memory. (On systems with limited virtual memory,
181 like DOS, it is even faster - for big files)
184 if type(f) == type(''): # If f is string - use it as file's name
185 infile = open(f, 'r')
187 infile = f # else assume it is opened file (fileobject) or
188 # "compatible" object (must has readline() method)
190 record = self.create_new_record()
193 line = infile.readline()
196 if self.feed(record, line):
197 record = self.create_new_record()
199 line = infile.readline()
202 if type(f) == type(''): # If f was opened - close it
205 # Close record on EOF without empty line
207 self.feed(record, None)
210 def store_to_file(self, f):
211 if type(f) == type(''): # If f is string - use it as file's name
212 outfile = open(f, 'w')
214 outfile = f # else assume it is opened file (fileobject) or
215 # "compatible" object (must has write() method)
217 flush_record = 0 # Do not close record on 1st loop
219 if self.comment != '':
220 outfile.write(self.comment)
223 copy_rec = record.copy() # Make a copy to delete keys
226 outfile.write('\n') # Close record
228 flush_record = 1 # Set flag for all but 1st record
231 for key in copy_rec.keys():
232 outfile.write(key + self.key_sep + copy_rec[key] + '\n')
235 if type(f) == type(''): # If f was opened - close it
239 def load_file(f, check_record_func = None):
241 Create a database object and load it from file
244 db = Flad(check_record_func)
250 def load_from_file(f, check_record_func = None):
252 Create a database object and load it from file
255 db = Flad(check_record_func)