00001 """
00002 silme.core.Entity represents single key:value pair (with possibility og having different values for different locale codes)
00003 silme.core.EntityList is a list of entities.
00004 """
00005
00006 class Entity(object):
00007 default_code = None
00008
00009 def __init__(self, id, value=None, code='default'):
00010 """
00011 It is possible to initialize Entity only with id:
00012 Entity('id')
00013
00014 or giving an initial value (and optionally locale_code):
00015 Entity('id', 'value'[, 'ab-CD'])
00016 """
00017 self.id = id
00018 self.params = {}
00019 if value is not None:
00020 self.default_code = code
00021 self._value = {code: value}
00022 else:
00023 self._value = {}
00024
00025 def __getattribute__(self, key):
00026 """Returns a value for given locale: entity['ab-CD']."""
00027 if key == 'value':
00028 try:
00029 return self._value[self.default_code]
00030 except:
00031 raise ValueError('Entity has no value')
00032 else:
00033 return super(Entity, self).__getattribute__(key)
00034
00035
00036
00037
00038
00039
00040 def __repr__(self):
00041 """Prints entity debug text representation."""
00042 if len(self._value) == 0:
00043 return '<entity: "%s">' % self.id
00044 elif len(self._value) == 1:
00045 if self.default_code == 'default':
00046 return '<entity: "%s", value: "%s">' % (self.id, self.get_value())
00047 else:
00048 return '<entity: "%s", value[%s]: "%s">' % \
00049 (self.id, self.default_code, self.get_value())
00050 else:
00051 keys = self._value.keys()
00052 l = len(self.default_code)
00053 string = '<entity: "%s", value[%s]: "%s",\n' % \
00054 (self.id, self.default_code, self.get_value())
00055 while len(keys):
00056 i = keys.pop()
00057 if not i == self.default_code:
00058 string += ' '*(18 + len(self.id) + l - len(i)) + \
00059 '[%s]: "%s"' % (i, self._value[i])
00060 if len(keys):
00061 string += ',\n'
00062 else:
00063 string += '>'
00064 return string
00065
00066 def __delitem__(self, code):
00067 """Deletes value in given locale: del entity['ab-CD']."""
00068 del self._value[code]
00069 if self.default_code == code:
00070 try:
00071 self.default_code = self._value.keys()[0]
00072 except:
00073 self.default_code = None
00074
00075 def __getitem__(self, code): return self._value[code]
00076
00077 def __setitem__(self, code, value): self.set_value(value, code)
00078
00079 def set_default_code(self, code):
00080 """Overwrites default code."""
00081 self.default_code = code
00082
00083 def get_default_code(self):
00084 """Returns default locale code for Entity."""
00085 return self.default_code
00086
00087 def set_value(self, value, code=None):
00088 """Sets an entity value in given locale code.
00089 If not locale code is given, the default is 'default'."""
00090 if code:
00091 if not self.default_code:
00092 self.default_code = code
00093 else:
00094 if not self.default_code:
00095 self.default_code = 'default'
00096 code = self.default_code
00097 self._value[code] = value
00098
00099 def get_value(self, fallback=None):
00100 """Returns entity value.
00101
00102 fallback options makes it possible to declare a list of
00103 optional codes to try in the order.
00104 If not fallback is declared default code is used.
00105
00106 Raises KeyError in case no code will work."""
00107 try:
00108 return self._value[fallback]
00109 except:
00110 if not fallback:
00111 if not self._value:
00112 return u''
00113 return self._value[self.default_code]
00114 else:
00115 for code in fallback:
00116 try:
00117 return self._value[code]
00118 except:
00119 pass
00120 raise KeyError()
00121
00122 def get_value_with_code(self, fallback=None):
00123 """Returns entity value together with used locale_code
00124 in form of tuple (value, code).
00125
00126 fallback options makes it possible to declare a list of
00127 optional codes to try in the order.
00128 If not fallback is declared default code is used.
00129
00130 Raises KeyError in case no code will work."""
00131 try:
00132 return (self._value[fallback], fallback)
00133 except:
00134 if not fallback:
00135 return (self._value[self.default_code], None)
00136 else:
00137 for code in fallback:
00138 try:
00139 return (self._value[code], code)
00140 except:
00141 pass
00142 raise KeyError()
00143
00144 def remove_value(self, code):
00145 """Removes value from entity.
00146
00147 It also clears default_code to first available or None.
00148 """
00149 del self._value[code]
00150 if self.default_code == code:
00151 try:
00152 self.default_code = self._value.keys()[0]
00153 except:
00154 self.default_code = None
00155
00156 def get_locale_codes(self):
00157 """Returns list of all locale codes available in this entity."""
00158 return self._value.keys()
00159
00160 def get_locales(self, localelist):
00161 """Returns new Entity with locales filtered by
00162 localelist argument of locale codes."""
00163 entity = Entity(self.id)
00164 entity.params = self.params
00165 for (key, value) in self._value.items():
00166 if key in localelist:
00167 if not entity.default_code:
00168 entity.default_code = key
00169 entity._value[key] = value
00170 return entity
00171
00172 def merge(self, entity):
00173 """Merges entity with another by adding and
00174 overwriting all values from argument."""
00175 for (key, value) in entity._value.items():
00176 self.set_value(value, key)
00177
00178
00179 class EntityList(dict):
00180 uri = None
00181 id = None
00182 _keys = None
00183
00184 def __init__(self, id=None, elist=None, order=True):
00185 """
00186 id - id for EntityList
00187 list - list of entities to add to EntityList
00188 order - if EntityList should keep entities order according to the order
00189 in which they were added
00190 """
00191 dict.__init__(self)
00192 self.fallback = []
00193 if id:
00194 self.id = id
00195 if elist:
00196 if isinstance(elist, list):
00197 map(self.add_entity, elist)
00198 elif isinstance(elist, dict):
00199 map(self.add_entity, elist.values())
00200 else:
00201 raise ValueError('could not assign list')
00202 if order:
00203 self._keys = []
00204
00205 def add_entity(self, entity):
00206 """Adds new entity to EntityList"""
00207 self[entity.id] = entity
00208 if not self._keys is None:
00209 self._keys.append(entity.id)
00210
00211 def get_entities(self):
00212 """Returns a list of all entities from EntityList."""
00213 if self._keys is None:
00214 return self.values()
00215 else:
00216 return [self[i] for i in self._keys]
00217
00218 def get_entity_ids(self):
00219 """Returns all entity ids from EntityList."""
00220 if self._keys is None:
00221 return self.keys()
00222 else:
00223 return self._keys
00224
00225 def has_entity(self, id):
00226 """Returns bool result of testing if entity with given id is in EntityList."""
00227 return self.has_key(id)
00228
00229 def modify_entity(self, id, value, code='default'):
00230 """Modifies entity value in EntityList, optionally with given locale code."""
00231 self[id].set_value(value, code)
00232 return True
00233
00234 def get_entity(self, id):
00235 """Returns entity with given id."""
00236 return self[id]
00237
00238 def remove_entity(self, id):
00239 """Removes entity with given id from EntityList."""
00240 del self[id]
00241 if not self._keys is None:
00242 self._keys.remove(id)
00243
00244 def get_value(self, id, fallback=None):
00245 """Returns entity value from EntityList.
00246
00247 fallback -- list of locale codes to try when getting value from entity.
00248 """
00249 if fallback == None and self.fallback:
00250 return self[id].get_value(self.fallback)
00251 return self[id].get_value(fallback)
00252
00253 def get_locale_codes(self):
00254 """Returns list of locale codes existing in entities in EntityList."""
00255 locales = []
00256 for entity in self.values():
00257 for key in entity.value.keys():
00258 if key not in locales:
00259 locales.append(key)
00260 return locales
00261
00262 def set_fallback(self, fallback):
00263 """Defines locale code fallback list for EntityList."""
00264 self.fallback = fallback
00265
00266 def get_locales(self, localelist):
00267 """Returns a new EntityList filtered to entities with locale codes listed in localelist argument."""
00268 elist = EntityList()
00269 elist.id = self.id
00270 elist.uri = self.uri
00271 elist._keys = self._keys
00272 elist.fallback = self.fallback
00273 for entity in self.values():
00274 elist.add_entity(entity.get_locales(localelist))
00275 return elist
00276
00277 def merge(self, elist):
00278 """Merges one EntityList with another."""
00279 for entity in elist:
00280 if self.has_key(entity.id):
00281 self[entity.id].merge(entity)
00282 else:
00283 self[entity.id] = entity