root/branch/PacketManipulator/PM/Gui/Plugins/Parser.py @ 3686

Revision 3686, 17.2 kB (checked in by nopper, 5 years ago)

Adding plugins support

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright (C) 2008 Adriano Monteiro Marques
4#
5# Author: Francesco Piccinno <stack.box@gmail.com>
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
21import re
22from xml.dom.minidom import parse, parseString
23
24class Variable(object):
25    """
26    A simple base class to create Variable that
27    are stored in xml file
28    """
29   
30    def __init__(self, value, \
31                 name=None, def_value=None, desc=None, \
32                 attrs=(), parent=None):
33        """
34        Create a variable
35
36        @param value the value for variable
37        @param name the name for variable (optional if are in list)
38        @param def_val the default value for variable (optional if is user conf)
39        @param desc the description of value (optional if in user conf)
40        @param attrs a list of attributes
41        @param sectiondict the section dict
42        """
43        self._value = self.__class__.convert(value)
44        self._name = name
45        self._def_val = self.__class__.convert(def_value)
46        self._desc = desc
47        self._parent = parent
48
49        # Compatibility for child objects
50        self.add_attribute(attrs, 'id', Integer, '_id')
51
52        self.set_attributes(attrs)
53        self.check_validity()
54
55        if not Variable.setted(self._value):
56            raise Exception("Value not setted")
57       
58        if not isinstance(self._value, self.__class__.element_type):
59            raise Exception("Unable to set a valid type")
60       
61        print ">>> Variable()", self._name, self._value
62
63    @staticmethod
64    def setted(value):
65        "Just convenient method to check a value"
66        return value != None
67
68    @staticmethod
69    def convert(value, exc_on_error=False):
70        """
71        @param value the str value to be converted
72        @param exc_on_error if an Exception should be raised on error
73        """
74
75        if isinstance(value, basestring):
76            return value
77
78        if exc_on_error:
79            raise Exception("Cannot convert %s" % value)
80        else:
81            return None
82
83    def add_attribute(self, attrs, name, typ, varname):
84        """
85        Set the variable named varname in self
86
87        @param attrs the attributes dict
88        @param name the name of variable to be getted from dict
89        @param type the variable object to be used for converting
90        @param varname the variable name to be setted in self
91
92        @return True if the var was setted and it's not None or
93                False in case of not-setted variable
94        """
95
96        # Set to None for default
97        setattr(self, varname, None)
98
99        try:
100            setattr(self, varname, typ.convert(attrs[name].nodeValue))
101        except Exception:
102            pass
103
104        if getattr(self, varname) != None:
105            return True
106
107        return False
108
109    def set_attributes(self, attrs):
110        """
111        Ovverride this and call add_attribute
112        """
113        pass
114
115    def check_validity(self):
116        """
117        Check the value validity and if fail set value to defaul
118        """
119        if not Variable.setted(self._value):
120            print "check_validity(): Value not setted"
121            self._value = self._def_val
122        elif not isinstance(self._value, self.__class__.element_type):
123            print "check_validity(): Not same type"
124            self._value = self._def_val
125        elif not self.validate():
126            print "check_validity(): Not valid!"
127            self._value = self._def_val
128        else:
129            print "check_validity(): OK"
130
131        print "check_validity():", self._value
132
133    def validate(self):
134        """
135        Validate the value or other fields for Variable
136       
137        @return True if value is ok or False
138        """
139        return True
140
141    def __repr__(self):
142        return "%s -> %s" % (self._name, self._value)
143
144    def get_id(self):
145        if not isinstance(self._id, int) and isinstance(self._parent, List):
146            try:
147                self._id = self._parent.list.index(self)
148            except:
149                pass
150
151        return self._id
152
153    def set_id(self, val):
154        if isinstance(val, int) and isinstance(self._parent, List):
155            self._id = val
156            self._parent.update(self)
157
158    def get_name(self):
159        return self._name
160    def set_name(self, val):
161        if isinstance(val, basestring) and isinstance(self._parent, dict):
162            self._parent.pop(self._name)
163            self._name = val
164            self._parent[self._name] = self
165
166    def get_value(self):
167        return self._value
168    def set_value(self, val):
169        if isinstance(val, self.__class__.element_type):
170            self._value = val
171
172    def get_desc(self):
173        return self._desc
174    def set_desc(self, val):
175        if isinstance(val, basestring):
176            self._desc = val
177
178    # Common properties
179    id = property(get_id, set_id)
180    name = property(get_name, set_name)
181    value = property(get_value, set_value)
182    description = property(get_desc, set_desc)
183
184class String(Variable):
185    __var_names__ = ('string', 'str', 's')
186
187    __attribs__ = ('max', 'min', 'pattern')
188    __tattribs__ = (int, int, str)
189
190    element_type = basestring
191
192    def set_attributes(self, attribs):
193        self._pattern_re = None
194        self.add_attribute(attribs, 'min', Integer, '_min')
195        self.add_attribute(attribs, 'max', Integer, '_max')
196
197        # Compile pattern if it's setted
198        if self.add_attribute(attribs, 'pattern', String, '_pattern'):
199            try:
200                self._pattern_re = re.compile(self._pattern)
201            except Exception:
202                pass
203
204    def validate(self):
205        if Variable.setted(self._min) and len(self._value) < self._min:
206            return False
207        if Variable.setted(self._max) and len(self._value) > self._max:
208            return False
209        if Variable.setted(self._pattern_re) and \
210           not self._pattern_re.match(self._value):
211            return False
212
213        return True
214
215    def get_min(self):
216        return self._min
217    def set_min(self, val):
218        if isinstance(val, int):
219            self._min = val
220            self.check_validity()
221
222    def get_max(self):
223        return self._max
224    def set_max(self, val):
225        if isinstance(val, int):
226            self._max = val
227            self.check_validity()
228
229    min = property(get_min, set_min)
230    max = property(get_max, set_max)
231
232    def get_pattern(self):
233        return self._pattern
234    def set_pattern(self, val):
235        if isinstance(val, basestring):
236            try:
237                r = re.compile(val)
238                self._pattern = val
239                self._pattern_re = r
240            except Exception:
241                pass
242            self.check_validity()
243
244    pattern = property(get_pattern, set_pattern)
245
246class Integer(Variable):
247    __var_names__ = ('integer', 'int', 'i')
248
249    __attribs__ = ('max', 'min')
250    __tattribs__ = (int, int)
251
252    element_type = int
253
254    @staticmethod
255    def convert(value, exc_on_error=False):
256        if isinstance(value, basestring):
257            try:
258                return int(value)
259            except Exception:
260                pass
261
262        if exc_on_error:
263            return Exception("Cannot convert %s to float" % value)
264        else:
265            return None
266
267    def set_attributes(self, attribs):
268        self.add_attribute(attribs, 'min', Integer, '_min')
269        self.add_attribute(attribs, 'max', Integer, '_max')
270
271    def validate(self):
272        if Variable.setted(self._min) and self._value < self._min:
273            return False
274        if Variable.setted(self._max) and self._value > self._max:
275            return False
276
277        return True
278
279    def get_min(self):
280        return self._min
281    def set_min(self, val):
282        if isinstance(val, self.__class__.element_type):
283            self._min = val
284            self.check_validity()
285
286    def get_max(self):
287        return self._max
288    def set_max(self, val):
289        if isinstance(val, self.__class__.element_type):
290            self._max = val
291            self.check_validity()
292
293    min = property(get_min, set_min)
294    max = property(get_max, set_max)
295
296class Float(Integer):
297    __var_names__ = ('float', 'flt', 'f')
298
299    __attribs__ = ('min', 'max')
300    __tattribs__ = (float, float)
301
302    element_type = float
303
304    @staticmethod
305    def convert(value, exc_on_error=False):
306        if isinstance(value, basestring):
307            try:
308                return float(value)
309            except Exception:
310                pass
311
312        if exc_on_error:
313            return Exception("Cannot convert %s to float" % value)
314        else:
315            return None
316
317    def set_attributes(self, attribs):
318        self.add_attribute(attribs, 'min', Float, '_min')
319        self.add_attribute(attribs, 'max', Float, '_max')
320
321class Boolean(Variable):
322    __var_names__ = ('boolean', 'bool', 'b')
323   
324    __attribs__ = ()
325    __tattribs__ = ()
326
327    element_type = bool
328
329    @staticmethod
330    def convert(value, exc_on_error=False):
331        if isinstance(value, basestring):
332            if value == '1' or value.upper() == 'TRUE':
333                return True
334            if value == '0' or value.upper() == 'FALSE':
335                return False
336
337        if exc_on_error:
338            return Exception("Cannot convert %s to bool" % value)
339        else:
340            return None
341
342class List(Variable):
343    "max/min/pattern/maxe/mine -> id"
344    __var_names__ = ('list', 'lst', 'l')
345
346    __attribs__ = ('min', 'max', 'minelements', 'maxelements', 'pattern')
347    __tattribs__ = (int, int, int, int, str)
348
349    element_type = list
350
351    def __init__(self, value, \
352                 name=None, def_value=None, desc=None, \
353                 attrs=(), childs=(), dict=None):
354        try:
355            Variable.__init__(self, value, name, def_value, desc, attrs, dict)
356        except Exception, err:
357            print ">>> Ignoring exception.. we are List sir ;)"
358            print err
359
360        for child in childs:
361            try:
362                obj = Parser.create_var(child, self)
363
364                if not Variable.setted(self._type):
365                    self._type = type(obj)
366
367                if not isinstance(obj, self._type):
368                    continue
369
370                if Variable.setted(obj.id):
371                    self._list.insert(obj.id, obj)
372                else:
373                    self._list.append(obj)
374
375            except Exception, err:
376                continue
377
378        self.check_validity()
379
380    def set_attributes(self, attribs):
381        self._list = []
382        self._pattern_re = None
383
384        self.add_attribute(attribs, 'min', Integer, '_min')
385        self.add_attribute(attribs, 'max', Integer, '_max')
386        self.add_attribute(attribs, 'min-elements', Integer, '_lmin')
387        self.add_attribute(attribs, 'max-elements', Integer, '_lmax')
388
389        if self.add_attribute(attribs, 'pattern', String, '_pattern'):
390            try:
391                self._pattern_re = re.compile(self._pattern)
392            except Exception:
393                pass
394
395        # We must get the type attribute
396        try:
397            self._type = Parser.get_type(attribs['type'].nodeValue)
398        except Exception:
399            self._type = None
400
401    def check_validity(self):
402        # Becouse value cannot be setted in list object
403        # this is only an empty function that call validate
404        if self._list and not self.validate():
405            self._list.clear()
406
407    def validate(self):
408        ret = []
409
410        for elem in self._list:
411            if Variable.setted(self._max) and len(elem.value) > self._max:
412                continue
413            if Variable.setted(self._min) and len(elem.value) < self._min:
414                continue
415            if self._type == String and \
416               Variable.setted(self._pattern_re) and self._pattern and \
417               not self._pattern_re.match(elem.value):
418                continue
419            ret.append(elem)
420
421        self._list = ret
422
423        if Variable.setted(self._lmax) and len(self._list) > self._lmax:
424            return False
425        if Variable.setted(self._lmin) and len(self._list) < self._lmin:
426            return False
427
428        return True
429   
430    def update(self, obj):
431        self._list.remove(obj)
432        self._list.insert(obj.id, obj)
433
434    def __repr__(self):
435        return "%s -> %s" % (self._name, self._list)
436
437    def __getitem__(self, idx):
438        return self._list[idx]
439
440    list = property(lambda x: x._list)
441
442    # Attributes
443
444    def get_min(self):
445        return self._min
446    def set_min(self, val):
447        if isinstance(val, int):
448            self._min = val
449            self.check_validity()
450
451    def get_max(self):
452        return self._max
453    def set_max(self, val):
454        if isinstance(val, int):
455            self._max = val
456            self.check_validity()
457
458    min = property(get_min, set_min)
459    max = property(get_max, set_max)
460
461    def get_lmin(self):
462        return self._lmin
463    def set_lmin(self, val):
464        if isinstance(val, int):
465            self._lmin = val
466            self.check_validity()
467
468    def get_lmax(self):
469        return self._lmax
470    def set_lmax(self, val):
471        if isinstance(val, int):
472            self._lmax = val
473            self.check_validity()
474
475    minelements = property(get_lmin, set_lmin)
476    maxelements = property(get_lmax, set_lmax)
477
478    def get_pattern(self):
479        return self._pattern
480    def set_pattern(self, val):
481        if isinstance(val, basestring):
482            try:
483                r = re.compile(val)
484                self._pattern = val
485                self._pattern_re = r
486            except Exception:
487                pass
488            self.check_validity()
489
490    pattern = property(get_pattern, set_pattern)
491
492class Parser(object):
493    TYPES = (
494        String,
495        Integer,
496        Float,
497        Boolean,
498        List
499    )
500    def __getitem__(self, x):
501        return self.sections[x]
502
503    def __init__(self):
504        self.sections = {}
505    def parse_string(self, txt):
506        self.parse_doc(parseString(txt))
507    def parse_file(self, path):
508        self.parse_doc(parse(path))
509    def parse_doc(self, doc):
510        if not doc.documentElement.tagName == "preferences":
511            return
512
513        for node in doc.documentElement.childNodes:
514            if node.nodeName == "section":
515                self.parse_section(node)
516    def parse_section(self, node):
517        if not node or \
518           not node.attributes.has_key('name') or \
519           not node.attributes['name'].nodeValue:
520            return
521
522        section_name = node.attributes['name'].nodeValue
523
524        if not section_name in self.sections:
525            self.sections[section_name] = {}
526
527        section_dict = self.sections[section_name]
528
529        for n in node.childNodes:
530            try:
531                obj = self.create_var(n, section_dict)
532                section_dict[obj.name] = obj
533            except Exception, err:
534                continue
535
536    @staticmethod
537    def create_var(node, sdict):
538        name = node.nodeName
539        type = Parser.get_type(name)
540
541        if not type:
542            raise Exception("Not a valid type")
543
544        # We need to get various fields
545
546        name  = Parser.get_attribute(node, 'name')
547        val   = Parser.get_attribute(node, 'value')
548        deflt = Parser.get_attribute(node, 'default')
549        descr = Parser.get_attribute(node, 'description')
550
551        # We are atomic variable so we *MUST* have setted
552        # at least a name and a value/default value
553        if isinstance(sdict, dict):
554            if not Variable.setted(name):
555                raise Exception("No name setted for atomic variable")
556
557            if type == List:
558                return type( \
559                    None, name, None, descr, \
560                    node.attributes, node.childNodes, sdict \
561                )
562
563        # For child variables only a value/default value
564        conv = type.convert
565
566        if not Variable.setted(conv(val)) and not Variable.setted(conv(deflt)):
567            raise Exception("No value/default setted for atomic variable")
568
569        return type(val, name, deflt, descr, node.attributes, parent=sdict)
570
571    @staticmethod
572    def get_attribute(node, value):
573        try:
574            return node.attributes[value].nodeValue
575        except Exception:
576            return None
577
578    @staticmethod
579    def get_type(name):
580        for type in Parser.TYPES:
581            if name in type.__var_names__:
582                return type
583        return None
584
585if __name__ == "__main__":
586    p = Parser()
587    p.parse_file("test.xml")
588    o = p["General"]["bool1"]
589    p["General"]["bool1"].name = "booooool"
590    print p["General"]["booooool"]
591    print p["General"]["booooool"] is o
592
593    print p["General"]["default-list"]
594    p["General"]["default-list"][2].id = 0
595    print p["General"]["default-list"]
596
597    print p["General"]["default-list"][1].id
Note: See TracBrowser for help on using the browser.