def test_all_mappings_yields_all_mappings(): x = ClassMap() x[object] = 1 x[BC] = 2 x[B] = 3 x[C] = 4 x[A] = 5 assert list(x.all_mappings(BC)) == [2, 3, 4, 5, 1]
def test_setting_child_does_not_set_parent(): x = ClassMap() x[B] = 1 with pytest.raises(KeyError): x[A]
def test_prefers_first_parent_in_mro(): x = ClassMap() x[C] = 3 x[B] = 2 assert x[BC] == 2
def test_child_values_will_be_used_if_set(): x = ClassMap() x[A] = 1 x[B] = 2 assert x[B] == 2
def test_grand_parent_values_will_be_used_if_child_is_not_set(): x = ClassMap() x[A] = 1 assert x[B] == 1
def test_can_set_and_lookup_class(): x = ClassMap() x[A] = 1 assert x[A] == 1
def __init__(self): self.mapping = ClassMap() self.static_mapping = ClassMap()
def __init__(self): self.mapping = ClassMap()
class SpecificationMapper(object): """Maps descriptions of some type to a type. Has configurable handlers for what a description may look like. Handlers for descriptions may take either a specific value or all instances of a type and have access to the mapper to look up types. Also supports prototype based inheritance, with children being able to override specific handlers There is a single default() object per subclass of SpecificationMapper which everything has as a prototype if it's not assigned any other prototype. This allows you to define the mappers on the default object and have them inherited by any custom mappers you want. """ @classmethod def default(cls): key = '_%s_default_mapper' % (cls.__name__, ) try: return getattr(cls, key) except AttributeError: pass result = cls() setattr(cls, key, result) return result @classmethod def clear_default(cls): try: delattr(cls, '_%s_default_mapper' % (cls.__name__, )) except AttributeError: pass def __init__(self, prototype=None): self.value_mappers = {} self.instance_mappers = ClassMap() self.__prototype = prototype self.__descriptor_cache = {} def prototype(self): if self.__prototype: return self.__prototype if self is self.default(): return None return self.default() def define_specification_for(self, value, specification): self.value_mappers.setdefault(value, []).append(specification) self.clear_cache() def clear_cache(self): self.__descriptor_cache = {} def define_specification_for_instances(self, cls, specification): self.instance_mappers.setdefault(cls, []).append(specification) self.clear_cache() def define_specification_for_classes(self, specification, subclasses_of=None): if subclasses_of: original_specification = specification @wraps(specification) def restricted(sms, descriptor): if issubclass(descriptor, subclasses_of): return original_specification(sms, descriptor) else: return next_in_chain() specification = restricted self.define_specification_for_instances(typekey(SpecificationMapper), specification) self.clear_cache() def new_child_mapper(self): return self.__class__(prototype=self) def specification_for(self, descriptor): k = HashItAnyway(descriptor) try: return self.__descriptor_cache[k] except KeyError: pass r = self._calculate_specification_for(descriptor) self.__descriptor_cache[k] = r return r def _calculate_specification_for(self, descriptor): for h in self.find_specification_handlers_for(descriptor): try: r = h(self, descriptor) break except NextInChain: pass else: r = self.missing_specification(descriptor) return r def has_specification_for(self, descriptor): try: self.specification_for(descriptor) return True except MissingSpecification: return False def find_specification_handlers_for(self, descriptor): if safe_in(descriptor, self.value_mappers): for h in reversed(self.value_mappers[descriptor]): yield h tk = typekey(descriptor) for h in self.__instance_handlers(tk): yield h if self.prototype(): for h in self.prototype().find_specification_handlers_for( descriptor): yield h def __instance_handlers(self, tk): for hs in self.instance_mappers.all_mappings(tk): for h in reversed(hs): yield h def missing_specification(self, descriptor): raise MissingSpecification(descriptor)
def __init__(self, prototype=None): self.value_mappers = {} self.instance_mappers = ClassMap() self.__prototype = prototype self.__descriptor_cache = {}