# HG changeset patch # User KarstenBock@gmx.net # Date 1312142018 -7200 # Node ID bf165b30254f433069e2c4d184ce58fd7b2c6bad # Parent 9c7a96c6fe41badecb45d1a2e8152f28bb7f21dd Added dict and list as possible component field types diff -r 9c7a96c6fe41 -r bf165b30254f grease/component/field.py --- a/grease/component/field.py Wed Jul 27 12:16:30 2011 -1000 +++ b/grease/component/field.py Sun Jul 31 21:53:38 2011 +0200 @@ -20,282 +20,284 @@ # Allowed field types -> default values types = {int:lambda: 0, float:lambda: 0.0, - bool:lambda: False, - str:lambda:"", - object:lambda:None, - Vec2d:lambda: Vec2d(0,0), - Vec2dArray:lambda: Vec2dArray(), - color.RGBA: lambda: color.RGBA(0.0, 0.0, 0.0, 0.0), - Rect: lambda: Rect(0.0, 0.0, 0.0, 0.0)} + bool:lambda: False, + str:lambda:"", + object:lambda:None, + Vec2d:lambda: Vec2d(0,0), + Vec2dArray:lambda: Vec2dArray(), + color.RGBA: lambda: color.RGBA(0.0, 0.0, 0.0, 0.0), + Rect: lambda: Rect(0.0, 0.0, 0.0, 0.0), + list: lambda: list(), + dict: lambda: dict(), + } class Schema(dict): - """Field schema definition for custom components""" + """Field schema definition for custom components""" - def __init__(self, **fields): - for ftype in fields.values(): - assert ftype in types, fname + " has an illegal field type" - self.update(fields) + def __init__(self, **fields): + for ftype in fields.values(): + assert ftype in types, fname + " has an illegal field type" + self.update(fields) class FieldAccessor(object): - """Facade for manipulating a field for a set of entities""" + """Facade for manipulating a field for a set of entities""" + + __field = None + __entities = None + __attrs = None + __getter = None + __parent_getters = () + + def __init__(self, field, entities, attrs=()): + self.__field = field + self.__entities = entities + field_getter = operator.attrgetter(field.name) + self.__attrs = attrs + if attrs: + getters = [field_getter] + [operator.attrgetter(attr) for attr in attrs] + def get(entity): + value = entity + for getter in getters: + value = getter(value) + return value + self.__getter = get + self.__parent_getters = getters[:-1] + else: + self.__getter = field_getter - __field = None - __entities = None - __attrs = None - __getter = None - __parent_getters = () + def __getattr__(self, name): + """Return a FieldAccessor for the child attribute""" + return self.__class__(self.__field, self.__entities, self.__attrs + (name,)) + + def __setattr__(self, name, value): + if value is self: + return # returned by mutators + if hasattr(self.__class__, name): + # Set local attr + self.__dict__[name] = value + elif not name.startswith('_'): + getattr(self, name).__set__(value) + else: + raise AttributeError("Cannot set field attribute: %s" % name) + + @property + def __setter(self): + """Return the proper setter function for setting the field value""" + if not self.__attrs: + return setattr + else: + parent_getters = self.__parent_getters + def setter(data, name, value): + for getter in parent_getters: + data = getter(data) + setattr(data, name, value) + self.__setter = setter + return setter - def __init__(self, field, entities, attrs=()): - self.__field = field - self.__entities = entities - field_getter = operator.attrgetter(field.name) - self.__attrs = attrs - if attrs: - getters = [field_getter] + [operator.attrgetter(attr) for attr in attrs] - def get(entity): - value = entity - for getter in getters: - value = getter(value) - return value - self.__getter = get - self.__parent_getters = getters[:-1] - else: - self.__getter = field_getter - - def __getattr__(self, name): - """Return a FieldAccessor for the child attribute""" - return self.__class__(self.__field, self.__entities, self.__attrs + (name,)) - - def __setattr__(self, name, value): - if value is self: - return # returned by mutators - if hasattr(self.__class__, name): - # Set local attr - self.__dict__[name] = value - elif not name.startswith('_'): - getattr(self, name).__set__(value) - else: - raise AttributeError("Cannot set field attribute: %s" % name) - - @property - def __setter(self): - """Return the proper setter function for setting the field value""" - if not self.__attrs: - return setattr - else: - parent_getters = self.__parent_getters - def setter(data, name, value): - for getter in parent_getters: - data = getter(data) - setattr(data, name, value) - self.__setter = setter - return setter - - def __set__(self, value): - """Set field values en masse""" - # Mass set field attr - setter = self.__setter - component = self.__field.component - if self.__attrs: - name = self.__attrs[-1] - else: - name = self.__field.name - if isinstance(value, FieldAccessor): - # Join set between two entity sets - if not self.__attrs: - cast = self.__field.cast - else: - cast = lambda x: x - for entity in self.__entities: - try: - setter(component[entity], name, cast(value[entity])) - except KeyError: - pass - else: - if not self.__attrs: - value = self.__field.cast(value) - for entity in self.__entities: - try: - setter(component[entity], name, value) - except KeyError: - pass - - def __getitem__(self, entity): - """Return the field value for a single entity (used for joins)""" - if entity in self.__entities: - return self.__getter(self.__field.component[entity]) - raise KeyError(entity) - - def __contains__(self, entity): - return entity in self.__entities + def __set__(self, value): + """Set field values en masse""" + # Mass set field attr + setter = self.__setter + component = self.__field.component + if self.__attrs: + name = self.__attrs[-1] + else: + name = self.__field.name + if isinstance(value, FieldAccessor): + # Join set between two entity sets + if not self.__attrs: + cast = self.__field.cast + else: + cast = lambda x: x + for entity in self.__entities: + try: + setter(component[entity], name, cast(value[entity])) + except KeyError: + pass + else: + if not self.__attrs: + value = self.__field.cast(value) + for entity in self.__entities: + try: + setter(component[entity], name, value) + except KeyError: + pass + + def __getitem__(self, entity): + """Return the field value for a single entity (used for joins)""" + if entity in self.__entities: + return self.__getter(self.__field.component[entity]) + raise KeyError(entity) + + def __contains__(self, entity): + return entity in self.__entities + + def __repr__(self): + return '<%s %s @ %x>' % ( + self.__class__.__name__, + '.'.join((self.__field.name,) + self.__attrs), id(self)) + + def __nonzero__(self): + return bool(self.__entities) + + def __iter__(self): + """Return an iterator of all field values in the set""" + component = self.__field.component + getter = self.__getter + for entity in self.__entities: + try: + data = component[entity] + except KeyError: + continue + yield getter(data) + + ## batch comparison operators ## - def __repr__(self): - return '<%s %s @ %x>' % ( - self.__class__.__name__, - '.'.join((self.__field.name,) + self.__attrs), id(self)) - - def __nonzero__(self): - return bool(self.__entities) - - def __iter__(self): - """Return an iterator of all field values in the set""" - component = self.__field.component - getter = self.__getter - for entity in self.__entities: - try: - data = component[entity] - except KeyError: - continue - yield getter(data) - - ## batch comparison operators ## - - def __match(self, value, op): - component = self.__field.component - getter = self.__getter - matches = set() - add = matches.add - if isinstance(value, FieldAccessor): - # Join match between entity sets - for entity in self.__entities: - try: - data = component[entity] - other = value[entity] - except KeyError: - continue - if op(getter(data), other): - add(entity) - else: - for entity in self.__entities: - try: - data = component[entity] - except KeyError: - continue - if op(getter(data), value): - add(entity) - return matches - - def __eq__(self, value): - """Return an entity set of all entities with a matching field value""" - return self.__match(value, operator.eq) - - def __ne__(self, value): - """Return an entity set of all entities not matching field value""" - return self.__match(value, operator.ne) - - def __gt__(self, value): - """Return an entity set of all entities with a greater field value""" - return self.__match(value, operator.gt) - - def __ge__(self, value): - """Return an entity set of all entities with a greater or equal field value""" - return self.__match(value, operator.ge) - - def __lt__(self, value): - """Return an entity set of all entities with a lesser field value""" - return self.__match(value, operator.lt) - - def __le__(self, value): - """Return an entity set of all entities with a lesser or equal field value""" - return self.__match(value, operator.le) - - def _contains(self, values): - """Return an entity set of all entities with a field value contained in values""" - return self.__match(values, operator.contains) - - ## Batch in-place mutator methods + def __match(self, value, op): + component = self.__field.component + getter = self.__getter + matches = set() + add = matches.add + if isinstance(value, FieldAccessor): + # Join match between entity sets + for entity in self.__entities: + try: + data = component[entity] + other = value[entity] + except KeyError: + continue + if op(getter(data), other): + add(entity) + else: + for entity in self.__entities: + try: + data = component[entity] + except KeyError: + continue + if op(getter(data), value): + add(entity) + return matches + + def __eq__(self, value): + """Return an entity set of all entities with a matching field value""" + return self.__match(value, operator.eq) + + def __ne__(self, value): + """Return an entity set of all entities not matching field value""" + return self.__match(value, operator.ne) + + def __gt__(self, value): + """Return an entity set of all entities with a greater field value""" + return self.__match(value, operator.gt) + + def __ge__(self, value): + """Return an entity set of all entities with a greater or equal field value""" + return self.__match(value, operator.ge) + + def __lt__(self, value): + """Return an entity set of all entities with a lesser field value""" + return self.__match(value, operator.lt) + + def __le__(self, value): + """Return an entity set of all entities with a lesser or equal field value""" + return self.__match(value, operator.le) + + def _contains(self, values): + """Return an entity set of all entities with a field value contained in values""" + return self.__match(values, operator.contains) + + ## Batch in-place mutator methods - def __mutate(self, value, op): - component = self.__field.component - if self.__attrs: - name = self.__attrs[-1] - else: - name = self.__field.name - getter = self.__getter - setter = self.__setter - if isinstance(value, FieldAccessor): - # Join between entity sets - for entity in self.__entities: - try: - data = component[entity] - other = value[entity] - except KeyError: - continue - setter(data, name, op(getter(data), other)) - else: - for entity in self.__entities: - try: - data = component[entity] - except KeyError: - continue - setter(data, name, op(getter(data), value)) - return self - - def __iadd__(self, value): - return self.__mutate(value, operator.iadd) - - def __isub__(self, value): - return self.__mutate(value, operator.isub) - - def __imul__(self, value): - return self.__mutate(value, operator.imul) - - def __idiv__(self, value): - return self.__mutate(value, operator.idiv) - - def __itruediv__(self, value): - return self.__mutate(value, operator.itruediv) - - def __ifloordiv__(self, value): - return self.__mutate(value, operator.ifloordiv) + def __mutate(self, value, op): + component = self.__field.component + if self.__attrs: + name = self.__attrs[-1] + else: + name = self.__field.name + getter = self.__getter + setter = self.__setter + if isinstance(value, FieldAccessor): + # Join between entity sets + for entity in self.__entities: + try: + data = component[entity] + other = value[entity] + except KeyError: + continue + setter(data, name, op(getter(data), other)) + else: + for entity in self.__entities: + try: + data = component[entity] + except KeyError: + continue + setter(data, name, op(getter(data), value)) + return self + + def __iadd__(self, value): + return self.__mutate(value, operator.iadd) + + def __isub__(self, value): + return self.__mutate(value, operator.isub) - def __imod__(self, value): - return self.__mutate(value, operator.imod) + def __imul__(self, value): + return self.__mutate(value, operator.imul) + + def __idiv__(self, value): + return self.__mutate(value, operator.idiv) - def __ipow__(self, value): - return self.__mutate(value, operator.ipow) + def __itruediv__(self, value): + return self.__mutate(value, operator.itruediv) - def __ilshift__(self, value): - return self.__mutate(value, operator.ilshift) + def __ifloordiv__(self, value): + return self.__mutate(value, operator.ifloordiv) + + def __imod__(self, value): + return self.__mutate(value, operator.imod) - def __irshift__(self, value): - return self.__mutate(value, operator.irshift) + def __ipow__(self, value): + return self.__mutate(value, operator.ipow) - def __iand__(self, value): - return self.__mutate(value, operator.iand) + def __ilshift__(self, value): + return self.__mutate(value, operator.ilshift) + + def __irshift__(self, value): + return self.__mutate(value, operator.irshift) - def __ior__(self, value): - return self.__mutate(value, operator.ior) + def __iand__(self, value): + return self.__mutate(value, operator.iand) - def __ixor__(self, value): - return self.__mutate(value, operator.ixor) + def __ior__(self, value): + return self.__mutate(value, operator.ior) + + def __ixor__(self, value): + return self.__mutate(value, operator.ixor) class Field(object): - """Component field metadata and accessor interface""" + """Component field metadata and accessor interface""" + + def __init__(self, component, name, type, accessor_factory=FieldAccessor): + self.component = component + self.name = name + self.type = type + self.default = types.get(type) + self.accessor_factory = accessor_factory - def __init__(self, component, name, type, accessor_factory=FieldAccessor): - self.component = component - self.name = name - self.type = type - self.default = types.get(type) - self.accessor_factory = accessor_factory - - def cast(self, value): - """Cast value to the appropriate type for thi field""" - if self.type is not object: - return self.type(value) - else: - return value - - def accessor(self, entities=None): - """Return the field accessor for the entities in the component, - or all entities in the set specified that are also in the component - """ - if entities is None or entities is self.component.entities: - entities = self.component.entities - else: - entities = entities & self.component.entities - return self.accessor_factory(self, entities) + def cast(self, value): + """Cast value to the appropriate type for thi field""" + if self.type is not object: + return self.type(value) + else: + return value + def accessor(self, entities=None): + """Return the field accessor for the entities in the component, + or all entities in the set specified that are also in the component + """ + if entities is None or entities is self.component.entities: + entities = self.component.entities + else: + entities = entities & self.component.entities + return self.accessor_factory(self, entities)