151cab061c4b2133f2d56dc958d83d9f7b1c8ff5
[nepi.git] / src / nepi / core / attributes.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 class Attribute(object):
5     ### Attribute types
6     STRING  = "STRING"
7     BOOL    = "BOOL"
8     ENUM    = "ENUM"
9     DOUBLE  = "DOUBLE"
10     INTEGER = "INTEGER"
11
12     types = [
13         STRING, 
14         BOOL, 
15         ENUM, 
16         DOUBLE, 
17         INTEGER
18     ]
19     
20     type_parsers = {
21         STRING : str,
22         BOOL : lambda x : str(x).lower() in ("1","on","yes","true"),
23         ENUM : str,
24         DOUBLE : float,
25         INTEGER : int,
26     }
27
28     ### Attribute Flags
29     NoFlags     = 0x00
30     # Attribute is only modifiable during experiment design
31     DesignOnly  = 0x01
32     # Attribute is read only and can't be modified by the user
33     # Note: ReadOnly implies DesignOnly
34     ReadOnly    = 0x03
35     # Attribute is invisible to the user but can be modified
36     Invisible   = 0x04
37     # Attribute has no default value in the testbed instance. 
38     # So it needs to be set explicitely
39     HasNoDefaultValue = 0x08
40
41     def __init__(self, name, help, type, value = None, range = None,
42         allowed = None, flags = NoFlags, validation_function = None, 
43         category = None):
44         if not type in Attribute.types:
45             raise AttributeError("invalid type %s " % type)
46         self._name = name
47         self._type = type
48         self._help = help
49         self._value = value
50         self._flags = flags
51         # range: max and min possible values
52         self._range = range
53         # list of possible values
54         self._allowed = allowed
55         self._validation_function = validation_function
56         self._modified = False
57         self._category = category
58
59     @property
60     def name(self):
61         return self._name
62
63     @property
64     def type(self):
65         return self._type
66
67     @property
68     def help(self):
69         return self._help
70
71     @property
72     def flags(self):
73         return self._flags
74
75     @property
76     def invisible(self):
77         return (self._flags & Attribute.Invisible) == Attribute.Invisible
78
79     @property
80     def read_only(self):
81         return (self._flags & Attribute.ReadOnly) == Attribute.ReadOnly
82
83     @property
84     def has_no_default_value(self):
85         return (self._flags & Attribute.HasNoDefaultValue) == \
86                 Attribute.HasNoDefaultValue
87
88     @property
89     def design_only(self):
90         return (self._flags & Attribute.DesignOnly) == Attribute.DesignOnly
91
92     @property
93     def modified(self):
94         return self._modified
95
96     @property
97     def category(self):
98         return self._category
99
100     @property
101     def range(self):
102         return self._range
103
104     @property
105     def allowed(self):
106         return self._allowed
107
108     @property
109     def validation_function(self):
110         return self._validation_function
111
112     def get_value(self):
113         return self._value
114
115     def set_value(self, value):
116         if self.is_valid_value(value):
117             self._value = value
118             self._modified = True
119         else:
120             raise ValueError("Invalid value %s for attribute %s" %
121                     (str(value), self.name))
122
123     value = property(get_value, set_value)
124
125     def is_valid_value(self, value):
126         return self._is_in_range(value) and \
127             self._is_in_allowed_values(value) and \
128                 self._is_valid(value)    
129
130     def _is_in_range(self, value):
131         return not self.range or \
132                 (value >= self.range[0] and value <= self.range[1])
133
134     def _is_in_allowed_values(self, value):
135         return not self._allowed or value in self._allowed
136
137     def _is_valid(self, value):
138         return not self._validation_function or \
139                 self._validation_function(self, value)
140
141 class AttributesMap(object):
142     """AttributesMap is the base class for every object whose attributes 
143     are going to be manipulated by the end-user in a script or GUI.
144     """
145     def __init__(self):
146         self._attributes = dict()
147
148     @property
149     def attributes(self):
150         return self._attributes.values()
151
152     @property
153     def attributes_list(self):
154         return self._attributes.keys()
155
156     def set_attribute_value(self, name, value):
157         self._attributes[name].value = value
158
159     def get_attribute_value(self, name):
160         return self._attributes[name].value
161
162     def get_attribute_help(self, name):
163         return self._attributes[name].help
164
165     def get_attribute_type(self, name):
166         return self._attributes[name].type
167
168     def get_attribute_range(self, name):
169         if not self._attributes[name].range:
170             return (None, None)
171         return self._attributes[name].range
172
173     def get_attribute_allowed(self, name):
174         return self._attributes[name].allowed
175
176     def get_attribute_category(self, name):
177         return self._attributes[name].category
178
179     def is_attribute_read_only(self, name):
180         return self._attributes[name].read_only
181
182     def is_attribute_invisible(self, name):
183         return self._attributes[name].invisible
184
185     def is_attribute_design_only(self, name):
186         return self._attributes[name].design_only
187
188     def has_attribute_no_default_value(self, name):
189         return self._attributes[name].has_no_default_value
190
191     def is_attribute_modified(self, name):
192         return self._attributes[name].modified
193
194     def is_attribute_value_valid(self, name, value):
195         return self._attributes[name].is_valid_value(value)
196
197     def add_attribute(self, name, help, type, value = None, range = None,
198         allowed = None, flags = Attribute.NoFlags, validation_function = None,
199         category = None):
200         if name in self._attributes:
201             raise AttributeError("Attribute %s already exists" % name)
202         attribute = Attribute(name, help, type, value, range, allowed, flags,
203                 validation_function, category)
204         self._attributes[name] = attribute
205
206     def del_attribute(self, name):
207         del self._attributes[name]
208
209     def has_attribute(self, name):
210         return name in self._attributes    
211     
212     def destroy(self):
213         self._attributes = dict()
214