fixed shebangs in non executable .py files
[nepi.git] / src / nepi / core / attributes.py
1 # -*- coding: utf-8 -*-
2
3 class Attribute(object):
4     ### Attribute types
5     STRING  = "STRING"
6     BOOL    = "BOOL"
7     ENUM    = "ENUM"
8     DOUBLE  = "DOUBLE"
9     INTEGER = "INTEGER"
10
11     types = [
12         STRING, 
13         BOOL, 
14         ENUM, 
15         DOUBLE, 
16         INTEGER
17     ]
18     
19     type_parsers = {
20         STRING : str,
21         BOOL : lambda x : str(x).lower() in ("1","on","yes","true"),
22         ENUM : str,
23         DOUBLE : float,
24         INTEGER : int,
25     }
26
27     ### Attribute Flags
28     NoFlags          = 0x00
29     # Read-only attribute at design time
30     DesignReadOnly   = 0x01
31     # Invisible attribute at design time
32     DesignInvisible  = 0x02
33     # Read-only attribute at execution time
34     ExecReadOnly     = 0x04
35     # Invisible attribute at execution time
36     ExecInvisible    = 0x08
37     # Attribute doesn't change value during execution time
38     ExecImmutable    = 0x10
39     # Attribute has no default value in the testbed
40     NoDefaultValue   = 0x20
41     # Metadata attribute (is not directly reflected by a real object attribute)
42     Metadata         = 0x40
43
44     def __init__(self, name, help, type, value = None, range = None,
45         allowed = None, flags = None, validation_function = None, 
46         category = None):
47         if not type in Attribute.types:
48             raise AttributeError("invalid type %s " % type)
49         self._name = name
50         self._type = type
51         self._help = help
52         self._value = value
53         self._flags = flags if flags != None else Attribute.NoFlags
54         # range: max and min possible values
55         self._range = range
56         # list of possible values
57         self._allowed = allowed
58         self._validation_function = validation_function
59         self._modified = False
60         self._category = category
61
62     @property
63     def name(self):
64         return self._name
65
66     @property
67     def type(self):
68         return self._type
69
70     @property
71     def help(self):
72         return self._help
73
74     @property
75     def flags(self):
76         return self._flags
77
78     @property
79     def is_design_invisible(self):
80         return self.has_flag(Attribute.DesignInvisible)
81
82     @property
83     def is_design_read_only(self):
84         return self.has_flag(Attribute.DesignReadOnly)
85
86     @property
87     def is_exec_invisible(self):
88         return self.has_flag(Attribute.ExecInvisible)
89
90     @property
91     def is_exec_read_only(self):
92         return self.has_flag(Attribute.ExecReadOnly)
93
94     @property
95     def is_exec_immutable(self):
96         return self.has_flag(Attribute.ExecImmutable)
97
98     @property
99     def is_metadata(self):
100         return self.has_flag(Attribute.Metadata)
101
102     @property
103     def has_no_default_value(self):
104         return self.has_flag(Attribute.NoDefaultValue)
105
106     @property
107     def modified(self):
108         return self._modified
109
110     @property
111     def category(self):
112         return self._category
113
114     @property
115     def range(self):
116         return self._range
117
118     @property
119     def allowed(self):
120         return self._allowed
121
122     @property
123     def validation_function(self):
124         return self._validation_function
125
126     def has_flag(self, flag):
127         return (self._flags & flag) == flag
128
129     def get_value(self):
130         return self._value
131
132     def set_value(self, value):
133         if self.is_valid_value(value):
134             self._value = value
135             self._modified = True
136         else:
137             raise ValueError("Invalid value %s for attribute %s" %
138                     (str(value), self.name))
139
140     value = property(get_value, set_value)
141
142     def is_valid_value(self, value):
143         return self._is_in_range(value) and \
144             self._is_in_allowed_values(value) and \
145                 self._is_valid(value)    
146
147     def _is_in_range(self, value):
148         return not self.range or \
149                 (value >= self.range[0] and value <= self.range[1])
150
151     def _is_in_allowed_values(self, value):
152         return not self._allowed or value in self._allowed
153
154     def _is_valid(self, value):
155         return not self._validation_function or \
156                 self._validation_function(self, value)
157
158 class AttributesMap(object):
159     """AttributesMap is the base class for every object whose attributes 
160     are going to be manipulated by the end-user in a script or GUI.
161     """
162     def __init__(self):
163         super(AttributesMap, self).__init__()
164         self._attributes = dict()
165
166     @property
167     def attributes(self):
168         return self._attributes.values()
169
170     def get_attribute_list(self, filter_flags = None, exclude = False):
171         """
172         Returns the list of attributes.
173         
174         Params:
175             filter_flags: if given, only attributes with (all) the specified
176                 flags will be returned.
177             
178             exclude: if True, only attributes without (any of) the specified
179                 flags will be returned.
180         """
181         attributes = self._attributes
182         if filter_flags != None:
183             def filter_attrs(attr_data):
184                 (attr_id, attr) = attr_data
185                 return attr.has_flag(filter_flags) == (not exclude)
186             attributes = dict(filter(filter_attrs, attributes.iteritems()))
187         return attributes.keys()
188
189     def set_attribute_value(self, name, value):
190         self._attributes[name].value = value
191
192     def get_attribute_value(self, name):
193         return self._attributes[name].value
194
195     def get_attribute_help(self, name):
196         return self._attributes[name].help
197
198     def get_attribute_type(self, name):
199         return self._attributes[name].type
200
201     def get_attribute_range(self, name):
202         if not self._attributes[name].range:
203             return (None, None)
204         return self._attributes[name].range
205
206     def get_attribute_allowed(self, name):
207         return self._attributes[name].allowed
208
209     def get_attribute_category(self, name):
210         return self._attributes[name].category
211
212     def is_attribute_design_invisible(self, name):
213         return self._attributes[name].is_design_invisible
214
215     def is_attribute_design_read_only(self, name):
216         return self._attributes[name].is_design_read_only
217
218     def is_attribute_exec_invisible(self, name):
219         return self._attributes[name].is_exec_invisible
220
221     def is_attribute_exec_read_only(self, name):
222         return self._attributes[name].is_exec_read_only
223
224     def is_attribute_exec_immutable(self, name):
225         return self._attributes[name].is_exec_immutable
226
227     def is_attribute_metadata(self, name):
228         return self._attributes[name].is_metadata
229
230     def has_attribute_no_default_value(self, name):
231         return self._attributes[name].has_no_default_value
232
233     def is_attribute_modified(self, name):
234         return self._attributes[name].modified
235
236     def is_attribute_value_valid(self, name, value):
237         return self._attributes[name].is_valid_value(value)
238
239     def add_attribute(self, name, help, type, value = None, range = None,
240         allowed = None, flags = Attribute.NoFlags, validation_function = None,
241         category = None):
242         if name in self._attributes:
243             raise AttributeError("Attribute %s already exists" % name)
244         attribute = Attribute(name, help, type, value, range, allowed, flags,
245                 validation_function, category)
246         self._attributes[name] = attribute
247
248     def del_attribute(self, name):
249         del self._attributes[name]
250
251     def has_attribute(self, name):
252         return name in self._attributes    
253     
254     def destroy(self):
255         self._attributes = dict()
256