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