comparison grease/component/field.py @ 13:bf165b30254f

Added dict and list as possible component field types
author KarstenBock@gmx.net
date Sun, 31 Jul 2011 21:53:38 +0200
parents bc88f7d5ca8b
children
comparison
equal deleted inserted replaced
12:9c7a96c6fe41 13:bf165b30254f
18 from grease import color 18 from grease import color
19 19
20 # Allowed field types -> default values 20 # Allowed field types -> default values
21 types = {int:lambda: 0, 21 types = {int:lambda: 0,
22 float:lambda: 0.0, 22 float:lambda: 0.0,
23 bool:lambda: False, 23 bool:lambda: False,
24 str:lambda:"", 24 str:lambda:"",
25 object:lambda:None, 25 object:lambda:None,
26 Vec2d:lambda: Vec2d(0,0), 26 Vec2d:lambda: Vec2d(0,0),
27 Vec2dArray:lambda: Vec2dArray(), 27 Vec2dArray:lambda: Vec2dArray(),
28 color.RGBA: lambda: color.RGBA(0.0, 0.0, 0.0, 0.0), 28 color.RGBA: lambda: color.RGBA(0.0, 0.0, 0.0, 0.0),
29 Rect: lambda: Rect(0.0, 0.0, 0.0, 0.0)} 29 Rect: lambda: Rect(0.0, 0.0, 0.0, 0.0),
30 list: lambda: list(),
31 dict: lambda: dict(),
32 }
30 33
31 class Schema(dict): 34 class Schema(dict):
32 """Field schema definition for custom components""" 35 """Field schema definition for custom components"""
33 36
34 def __init__(self, **fields): 37 def __init__(self, **fields):
35 for ftype in fields.values(): 38 for ftype in fields.values():
36 assert ftype in types, fname + " has an illegal field type" 39 assert ftype in types, fname + " has an illegal field type"
37 self.update(fields) 40 self.update(fields)
38 41
39 42
40 class FieldAccessor(object): 43 class FieldAccessor(object):
41 """Facade for manipulating a field for a set of entities""" 44 """Facade for manipulating a field for a set of entities"""
42 45
43 __field = None 46 __field = None
44 __entities = None 47 __entities = None
45 __attrs = None 48 __attrs = None
46 __getter = None 49 __getter = None
47 __parent_getters = () 50 __parent_getters = ()
48 51
49 def __init__(self, field, entities, attrs=()): 52 def __init__(self, field, entities, attrs=()):
50 self.__field = field 53 self.__field = field
51 self.__entities = entities 54 self.__entities = entities
52 field_getter = operator.attrgetter(field.name) 55 field_getter = operator.attrgetter(field.name)
53 self.__attrs = attrs 56 self.__attrs = attrs
54 if attrs: 57 if attrs:
55 getters = [field_getter] + [operator.attrgetter(attr) for attr in attrs] 58 getters = [field_getter] + [operator.attrgetter(attr) for attr in attrs]
56 def get(entity): 59 def get(entity):
57 value = entity 60 value = entity
58 for getter in getters: 61 for getter in getters:
59 value = getter(value) 62 value = getter(value)
60 return value 63 return value
61 self.__getter = get 64 self.__getter = get
62 self.__parent_getters = getters[:-1] 65 self.__parent_getters = getters[:-1]
63 else: 66 else:
64 self.__getter = field_getter 67 self.__getter = field_getter
65 68
66 def __getattr__(self, name): 69 def __getattr__(self, name):
67 """Return a FieldAccessor for the child attribute""" 70 """Return a FieldAccessor for the child attribute"""
68 return self.__class__(self.__field, self.__entities, self.__attrs + (name,)) 71 return self.__class__(self.__field, self.__entities, self.__attrs + (name,))
69 72
70 def __setattr__(self, name, value): 73 def __setattr__(self, name, value):
71 if value is self: 74 if value is self:
72 return # returned by mutators 75 return # returned by mutators
73 if hasattr(self.__class__, name): 76 if hasattr(self.__class__, name):
74 # Set local attr 77 # Set local attr
75 self.__dict__[name] = value 78 self.__dict__[name] = value
76 elif not name.startswith('_'): 79 elif not name.startswith('_'):
77 getattr(self, name).__set__(value) 80 getattr(self, name).__set__(value)
78 else: 81 else:
79 raise AttributeError("Cannot set field attribute: %s" % name) 82 raise AttributeError("Cannot set field attribute: %s" % name)
80 83
81 @property 84 @property
82 def __setter(self): 85 def __setter(self):
83 """Return the proper setter function for setting the field value""" 86 """Return the proper setter function for setting the field value"""
84 if not self.__attrs: 87 if not self.__attrs:
85 return setattr 88 return setattr
86 else: 89 else:
87 parent_getters = self.__parent_getters 90 parent_getters = self.__parent_getters
88 def setter(data, name, value): 91 def setter(data, name, value):
89 for getter in parent_getters: 92 for getter in parent_getters:
90 data = getter(data) 93 data = getter(data)
91 setattr(data, name, value) 94 setattr(data, name, value)
92 self.__setter = setter 95 self.__setter = setter
93 return setter 96 return setter
94 97
95 def __set__(self, value): 98 def __set__(self, value):
96 """Set field values en masse""" 99 """Set field values en masse"""
97 # Mass set field attr 100 # Mass set field attr
98 setter = self.__setter 101 setter = self.__setter
99 component = self.__field.component 102 component = self.__field.component
100 if self.__attrs: 103 if self.__attrs:
101 name = self.__attrs[-1] 104 name = self.__attrs[-1]
102 else: 105 else:
103 name = self.__field.name 106 name = self.__field.name
104 if isinstance(value, FieldAccessor): 107 if isinstance(value, FieldAccessor):
105 # Join set between two entity sets 108 # Join set between two entity sets
106 if not self.__attrs: 109 if not self.__attrs:
107 cast = self.__field.cast 110 cast = self.__field.cast
108 else: 111 else:
109 cast = lambda x: x 112 cast = lambda x: x
110 for entity in self.__entities: 113 for entity in self.__entities:
111 try: 114 try:
112 setter(component[entity], name, cast(value[entity])) 115 setter(component[entity], name, cast(value[entity]))
113 except KeyError: 116 except KeyError:
114 pass 117 pass
115 else: 118 else:
116 if not self.__attrs: 119 if not self.__attrs:
117 value = self.__field.cast(value) 120 value = self.__field.cast(value)
118 for entity in self.__entities: 121 for entity in self.__entities:
119 try: 122 try:
120 setter(component[entity], name, value) 123 setter(component[entity], name, value)
121 except KeyError: 124 except KeyError:
122 pass 125 pass
123 126
124 def __getitem__(self, entity): 127 def __getitem__(self, entity):
125 """Return the field value for a single entity (used for joins)""" 128 """Return the field value for a single entity (used for joins)"""
126 if entity in self.__entities: 129 if entity in self.__entities:
127 return self.__getter(self.__field.component[entity]) 130 return self.__getter(self.__field.component[entity])
128 raise KeyError(entity) 131 raise KeyError(entity)
129 132
130 def __contains__(self, entity): 133 def __contains__(self, entity):
131 return entity in self.__entities 134 return entity in self.__entities
132 135
133 def __repr__(self): 136 def __repr__(self):
134 return '<%s %s @ %x>' % ( 137 return '<%s %s @ %x>' % (
135 self.__class__.__name__, 138 self.__class__.__name__,
136 '.'.join((self.__field.name,) + self.__attrs), id(self)) 139 '.'.join((self.__field.name,) + self.__attrs), id(self))
137 140
138 def __nonzero__(self): 141 def __nonzero__(self):
139 return bool(self.__entities) 142 return bool(self.__entities)
140 143
141 def __iter__(self): 144 def __iter__(self):
142 """Return an iterator of all field values in the set""" 145 """Return an iterator of all field values in the set"""
143 component = self.__field.component 146 component = self.__field.component
144 getter = self.__getter 147 getter = self.__getter
145 for entity in self.__entities: 148 for entity in self.__entities:
146 try: 149 try:
147 data = component[entity] 150 data = component[entity]
148 except KeyError: 151 except KeyError:
149 continue 152 continue
150 yield getter(data) 153 yield getter(data)
151 154
152 ## batch comparison operators ## 155 ## batch comparison operators ##
153 156
154 def __match(self, value, op): 157 def __match(self, value, op):
155 component = self.__field.component 158 component = self.__field.component
156 getter = self.__getter 159 getter = self.__getter
157 matches = set() 160 matches = set()
158 add = matches.add 161 add = matches.add
159 if isinstance(value, FieldAccessor): 162 if isinstance(value, FieldAccessor):
160 # Join match between entity sets 163 # Join match between entity sets
161 for entity in self.__entities: 164 for entity in self.__entities:
162 try: 165 try:
163 data = component[entity] 166 data = component[entity]
164 other = value[entity] 167 other = value[entity]
165 except KeyError: 168 except KeyError:
166 continue 169 continue
167 if op(getter(data), other): 170 if op(getter(data), other):
168 add(entity) 171 add(entity)
169 else: 172 else:
170 for entity in self.__entities: 173 for entity in self.__entities:
171 try: 174 try:
172 data = component[entity] 175 data = component[entity]
173 except KeyError: 176 except KeyError:
174 continue 177 continue
175 if op(getter(data), value): 178 if op(getter(data), value):
176 add(entity) 179 add(entity)
177 return matches 180 return matches
178 181
179 def __eq__(self, value): 182 def __eq__(self, value):
180 """Return an entity set of all entities with a matching field value""" 183 """Return an entity set of all entities with a matching field value"""
181 return self.__match(value, operator.eq) 184 return self.__match(value, operator.eq)
182 185
183 def __ne__(self, value): 186 def __ne__(self, value):
184 """Return an entity set of all entities not matching field value""" 187 """Return an entity set of all entities not matching field value"""
185 return self.__match(value, operator.ne) 188 return self.__match(value, operator.ne)
186 189
187 def __gt__(self, value): 190 def __gt__(self, value):
188 """Return an entity set of all entities with a greater field value""" 191 """Return an entity set of all entities with a greater field value"""
189 return self.__match(value, operator.gt) 192 return self.__match(value, operator.gt)
190 193
191 def __ge__(self, value): 194 def __ge__(self, value):
192 """Return an entity set of all entities with a greater or equal field value""" 195 """Return an entity set of all entities with a greater or equal field value"""
193 return self.__match(value, operator.ge) 196 return self.__match(value, operator.ge)
194 197
195 def __lt__(self, value): 198 def __lt__(self, value):
196 """Return an entity set of all entities with a lesser field value""" 199 """Return an entity set of all entities with a lesser field value"""
197 return self.__match(value, operator.lt) 200 return self.__match(value, operator.lt)
198 201
199 def __le__(self, value): 202 def __le__(self, value):
200 """Return an entity set of all entities with a lesser or equal field value""" 203 """Return an entity set of all entities with a lesser or equal field value"""
201 return self.__match(value, operator.le) 204 return self.__match(value, operator.le)
202 205
203 def _contains(self, values): 206 def _contains(self, values):
204 """Return an entity set of all entities with a field value contained in values""" 207 """Return an entity set of all entities with a field value contained in values"""
205 return self.__match(values, operator.contains) 208 return self.__match(values, operator.contains)
206 209
207 ## Batch in-place mutator methods 210 ## Batch in-place mutator methods
208 211
209 def __mutate(self, value, op): 212 def __mutate(self, value, op):
210 component = self.__field.component 213 component = self.__field.component
211 if self.__attrs: 214 if self.__attrs:
212 name = self.__attrs[-1] 215 name = self.__attrs[-1]
213 else: 216 else:
214 name = self.__field.name 217 name = self.__field.name
215 getter = self.__getter 218 getter = self.__getter
216 setter = self.__setter 219 setter = self.__setter
217 if isinstance(value, FieldAccessor): 220 if isinstance(value, FieldAccessor):
218 # Join between entity sets 221 # Join between entity sets
219 for entity in self.__entities: 222 for entity in self.__entities:
220 try: 223 try:
221 data = component[entity] 224 data = component[entity]
222 other = value[entity] 225 other = value[entity]
223 except KeyError: 226 except KeyError:
224 continue 227 continue
225 setter(data, name, op(getter(data), other)) 228 setter(data, name, op(getter(data), other))
226 else: 229 else:
227 for entity in self.__entities: 230 for entity in self.__entities:
228 try: 231 try:
229 data = component[entity] 232 data = component[entity]
230 except KeyError: 233 except KeyError:
231 continue 234 continue
232 setter(data, name, op(getter(data), value)) 235 setter(data, name, op(getter(data), value))
233 return self 236 return self
234 237
235 def __iadd__(self, value): 238 def __iadd__(self, value):
236 return self.__mutate(value, operator.iadd) 239 return self.__mutate(value, operator.iadd)
237 240
238 def __isub__(self, value): 241 def __isub__(self, value):
239 return self.__mutate(value, operator.isub) 242 return self.__mutate(value, operator.isub)
240 243
241 def __imul__(self, value): 244 def __imul__(self, value):
242 return self.__mutate(value, operator.imul) 245 return self.__mutate(value, operator.imul)
243 246
244 def __idiv__(self, value): 247 def __idiv__(self, value):
245 return self.__mutate(value, operator.idiv) 248 return self.__mutate(value, operator.idiv)
246 249
247 def __itruediv__(self, value): 250 def __itruediv__(self, value):
248 return self.__mutate(value, operator.itruediv) 251 return self.__mutate(value, operator.itruediv)
249 252
250 def __ifloordiv__(self, value): 253 def __ifloordiv__(self, value):
251 return self.__mutate(value, operator.ifloordiv) 254 return self.__mutate(value, operator.ifloordiv)
252 255
253 def __imod__(self, value): 256 def __imod__(self, value):
254 return self.__mutate(value, operator.imod) 257 return self.__mutate(value, operator.imod)
255 258
256 def __ipow__(self, value): 259 def __ipow__(self, value):
257 return self.__mutate(value, operator.ipow) 260 return self.__mutate(value, operator.ipow)
258 261
259 def __ilshift__(self, value): 262 def __ilshift__(self, value):
260 return self.__mutate(value, operator.ilshift) 263 return self.__mutate(value, operator.ilshift)
261 264
262 def __irshift__(self, value): 265 def __irshift__(self, value):
263 return self.__mutate(value, operator.irshift) 266 return self.__mutate(value, operator.irshift)
264 267
265 def __iand__(self, value): 268 def __iand__(self, value):
266 return self.__mutate(value, operator.iand) 269 return self.__mutate(value, operator.iand)
267 270
268 def __ior__(self, value): 271 def __ior__(self, value):
269 return self.__mutate(value, operator.ior) 272 return self.__mutate(value, operator.ior)
270 273
271 def __ixor__(self, value): 274 def __ixor__(self, value):
272 return self.__mutate(value, operator.ixor) 275 return self.__mutate(value, operator.ixor)
273 276
274 277
275 class Field(object): 278 class Field(object):
276 """Component field metadata and accessor interface""" 279 """Component field metadata and accessor interface"""
277 280
278 def __init__(self, component, name, type, accessor_factory=FieldAccessor): 281 def __init__(self, component, name, type, accessor_factory=FieldAccessor):
279 self.component = component 282 self.component = component
280 self.name = name 283 self.name = name
281 self.type = type 284 self.type = type
282 self.default = types.get(type) 285 self.default = types.get(type)
283 self.accessor_factory = accessor_factory 286 self.accessor_factory = accessor_factory
284 287
285 def cast(self, value): 288 def cast(self, value):
286 """Cast value to the appropriate type for thi field""" 289 """Cast value to the appropriate type for thi field"""
287 if self.type is not object: 290 if self.type is not object:
288 return self.type(value) 291 return self.type(value)
289 else: 292 else:
290 return value 293 return value
291 294
292 def accessor(self, entities=None): 295 def accessor(self, entities=None):
293 """Return the field accessor for the entities in the component, 296 """Return the field accessor for the entities in the component,
294 or all entities in the set specified that are also in the component 297 or all entities in the set specified that are also in the component
295 """ 298 """
296 if entities is None or entities is self.component.entities: 299 if entities is None or entities is self.component.entities:
297 entities = self.component.entities 300 entities = self.component.entities
298 else: 301 else:
299 entities = entities & self.component.entities 302 entities = entities & self.component.entities
300 return self.accessor_factory(self, entities) 303 return self.accessor_factory(self, entities)
301