1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import os
25 from StringIO import StringIO
26
27 from fife.extensions.serializers import ET, SerializerError, InvalidFormat, NotFound
28
29
30 EMPTY_XML_FILE="""\
31 <?xml version='1.0' encoding='UTF-8'?>
32 <Settings>
33
34 </Settings>
35 """
36
38 """
39 Use this as a base class for custom setting loaders/savers to use with the Setting class.
40 """
41
44
45 - def get(self, module, name, defaultValue=None):
47
48 - def set(self, module, name, value, extra_attrs={}):
50
51 - def load(self, filename=None):
52 """
53 @note: If the filename specified is empty this function MUST initialize an empty settings
54 file in whatever format you need.
55 """
56 pass
57
58 - def save(self, filename=None):
60
62 """
63 @note: Returns all the module names that are present in the settings.xml file
64 as a list of strings
65 """
66 pass
67
69 """
70 @note: Returns all the setting names under the Module name module as a dictionary structure
71 """
72 pass
73
75 """
76 This class is a simple interface to get and store data in XML files.
77
78 Usage::
79 from fife.extensions.serializers.simplexml import SimpleXMLSerializer
80 serializer = SimpleXMLSerializer(filename="somefile.xml")
81 serializer.set("module_name", "variable_name", "value")
82 somevariable = serializer.get("module_name", "variable_name", "default_value")
83 """
85 self._file = filename
86 self._tree = None
87 self._root_element = None
88
89 self._initialized = False
90
91 - def load(self, filename=None):
92 """
93 Loads the XML file into memory and validates it.
94
95 Raises a SerializerError exception if the file is not specified.
96
97 @param filename: The file to load
98 @type filename: C{str}
99
100 @note: If the file does not exist it will automatically create a blank file for you.
101 """
102 if filename:
103 self._file = filename
104
105 if not self._file:
106 raise SerializerError("Cannot load file or create file. No filename specified!")
107
108 if not os.path.exists(self._file):
109 self._tree = ET.parse(StringIO(EMPTY_XML_FILE))
110 self._tree.write(self._file, 'UTF-8')
111 else:
112 self._tree = ET.parse(self._file)
113
114 self._root_element = self._tree.getroot()
115 self._validateTree()
116
117 - def save(self, filename=None):
118 """
119 Saves the XML file.
120
121 @param filename: The file to save
122 @type filename: C{str}
123
124 @note: This Overwrites the file if it exists.
125 """
126 if not self._initialized:
127 self.load()
128 self._initialized = True
129
130 if filename:
131 savefile = filename
132 else:
133 savefile = self._file
134
135 if not savefile:
136 raise SerializerError("Cannot save file. No filename specified!")
137
138 """ Writes the settings to file """
139 self._indent(self._root_element)
140 self._tree.write(savefile, 'UTF-8')
141
142
144 if e_type == 'int':
145 return int(e_value)
146 elif e_type == 'float':
147 return float(e_value)
148 elif e_type == 'bool':
149 e_value = e_value.lower()
150 if e_value == "" or e_value == "false" or e_value == "no" or e_value == "0":
151 return False
152 else:
153 return True
154 elif e_type == 'str' or e_type == 'string':
155 return str(e_value)
156 elif e_type == 'unicode':
157 return unicode(e_value)
158 elif e_type == 'list':
159 return self._deserializeList(e_value)
160 elif e_type == 'dict':
161 return self._deserializeDict(e_value)
162
163
164 - def get(self, module, name, defaultValue=None):
165 """ Gets the value of a specified variable
166
167 @param module: Name of the module to get the variable from
168 @param name: Variable name
169 @param defaultValue: Specifies the default value to return if the variable is not found
170 @type defaultValue: C{str} or C{unicode} or C{int} or C{float} or C{bool} or C{list} or C{dict}
171 """
172 if not self._initialized:
173 self.load()
174 self._initialized = True
175
176 if not isinstance(name, str) and not isinstance(name, unicode):
177 raise AttributeError("SimpleXMLSerializer.get(): Invalid type for name argument.")
178
179
180 moduleTree = self._getModuleTree(module)
181 element = None
182 for e in moduleTree.getchildren():
183 if e.tag == "Setting" and e.get("name", "") == name:
184 element = e
185 break
186 else:
187 return defaultValue
188
189 e_value = element.text
190 e_strip = element.get("strip", "1").strip().lower()
191 e_type = str(element.get("type", "str")).strip()
192
193 if e_value is None:
194 return defaultValue
195
196
197 if e_strip == "" or e_strip == "false" or e_strip == "no" or e_strip == "0":
198 e_strip = False
199 else: e_strip = True
200
201 if e_type == "str" or e_type == "unicode":
202 if e_strip: e_value = e_value.strip()
203 else:
204 e_value = e_value.strip()
205
206
207 e_value = self.getValue(e_type,e_value)
208
209 return e_value
210
211 - def set(self, module, name, value, extra_attrs={}):
212 """
213 Sets a variable to specified value.
214
215 @param module: Module where the variable should be set
216 @param name: Name of the variable
217 @param value: Value to assign to the variable
218 @type value: C{str} or C{unicode} or C{int} or C{float} or C{bool} or C{list} or C{dict}
219 @param extra_attrs: Extra attributes to be stored in the XML-file
220 @type extra_attrs: C{dict}
221 """
222 if not self._initialized:
223 self.load()
224 self._initialized = True
225
226 if not isinstance(name, str) and not isinstance(name, unicode):
227 raise AttributeError("SimpleXMLSerializer.set(): Invalid type for name argument.")
228
229 moduleTree = self._getModuleTree(module)
230 e_type = "str"
231
232 if isinstance(value, bool):
233 e_type = "bool"
234 value = str(value)
235 elif isinstance(value, int):
236 e_type = "int"
237 value = str(value)
238 elif isinstance(value, float):
239 e_type = "float"
240 value = str(value)
241 elif isinstance(value, unicode):
242 e_type = "unicode"
243 value = unicode(value)
244 elif isinstance(value, list):
245 e_type = "list"
246 value = self._serializeList(value)
247 elif isinstance(value, dict):
248 e_type = "dict"
249 value = self._serializeDict(value)
250 else:
251 e_type = "str"
252 value = str(value)
253
254 for e in moduleTree.getchildren():
255 if e.tag != "Setting": continue
256 if e.get("name", "") == name:
257 e.text = value
258 break
259 else:
260 attrs = {"name":name, "type":e_type}
261 for k in extra_attrs:
262 if k not in attrs:
263 attrs[k] = extra_args[k]
264 elm = ET.SubElement(moduleTree, "Setting", attrs)
265 elm.text = value
266
267 """
268 returns a list of string, where each string is a module name
269 """
271 self._moduleNames = []
272 for c in self._root_element.getchildren():
273 if c.tag == "Module":
274 name = c.get("name","")
275 if not isinstance(name, str) and not isinstance(name, unicode):
276 raise AttributeError("SimpleXMLSerializer.get(): Invalid type for name argument.")
277
278 self._moduleNames.append(name)
279 return self._moduleNames
280
281
283 self._settingsFromFile = {}
284
285
286 if not self._initialized:
287 self.load()
288 self._initialized = True
289
290
291 moduleTree = self._getModuleTree(module)
292
293
294
295 for e in moduleTree.getchildren():
296 if e.tag == "Setting":
297 name = e.get("name", "")
298
299
300 if not isinstance(name, str) and not isinstance(name, unicode):
301 raise AttributeError("SimpleXMLSerializer.get(): Invalid type for name argument.")
302 element = e
303
304 e_value = element.text
305 e_strip = element.get("strip", "1").strip().lower()
306 e_type = str(element.get("type", "str")).strip()
307
308
309 if e_strip == "" or e_strip == "false" or e_strip == "no" or e_strip == "0":
310 e_strip = False
311 else: e_strip = True
312
313 if e_type == "str" or e_type == "unicode":
314 if e_strip and e_value:
315 e_value = e_value.strip()
316 else:
317 if e_value:
318 e_value = e_value.strip()
319
320
321 e_value = self.getValue(e_type,e_value)
322 self._settingsFromFile[name] = e_value;
323
324 return self._settingsFromFile
325
326
327
329 """
330 Iterates the XML tree and prints warning when an invalid tag is found.
331
332 Raises an InvalidFormat exception if there is a format error.
333 """
334 for c in self._root_element.getchildren():
335 if c.tag != "Module":
336 raise InvalidFormat("Invalid tag in " + self._file + ". Expected Module, got: " + c.tag)
337 elif c.get("name", "") == "":
338 raise InvalidFormat("Invalid tag in " + self._file + ". Module name is empty.")
339 else:
340 for e in c.getchildren():
341 if e.tag != "Setting":
342 raise InvalidFormat("Invalid tag in " + self._file + " in module: " + c.tag + ". Expected Setting, got: " + e.tag)
343 elif c.get("name", "") == "":
344 raise InvalidFormat("Invalid tag in " + self._file + " in module: " + c.tag + ". Setting name is empty" + e.tag)
345
347 """
348 Returns a module element from the XML tree. If no module with the specified
349 name exists, a new element will be created.
350
351 @param module: The module to get from the settings tree
352 @type module: C{string}
353 """
354 if not isinstance(module, str) and not isinstance(module, unicode):
355 raise AttributeError("Settings:_getModuleTree: Invalid type for module argument.")
356
357 for c in self._root_element.getchildren():
358 if c.tag == "Module" and c.get("name", "") == module:
359 return c
360
361
362 return ET.SubElement(self._root_element, "Module", {"name":module})
363
365 """
366 Adds whitespace, so the resulting XML-file is properly indented.
367 Shamelessly stolen from http://effbot.org/zone/element-lib.htm
368 """
369 i = os.linesep + level*" "
370 if len(elem):
371 if not elem.text or not elem.text.strip():
372 elem.text = i + " "
373 if not elem.tail or not elem.tail.strip():
374 elem.tail = i
375 for elem in elem:
376 self._indent(elem, level+1)
377 if not elem.tail or not elem.tail.strip():
378 elem.tail = i
379 else:
380 if level and (not elem.tail or not elem.tail.strip()):
381 elem.tail = i
382
383
384
385
386
387
389 """ Serializes a list, so it can be stored in a text file """
390 return " ; ".join(list)
391
393 """ Deserializes a list back into a list object """
394 return string.split(" ; ")
395
397 """ Serializes a list, so it can be stored in a text file """
398 serial = ""
399 for key in dict:
400 value = dict[key]
401 if serial != "": serial += " ; "
402 serial += str(key)+" : "+str(value)
403
404 return serial
405
407 """ Deserializes a list back into a dict object """
408 dict = {}
409 items = serial.split(" ; ")
410 for i in items:
411 kv_pair = i.split(" : ")
412 dict[kv_pair[0]] = kv_pair[1]
413 return dict
414