def trace(self, obj, **kwargs): '''DictShapes are defined by a mapping from keys to the shapes of their values. The outline is stored as a frozendict since Shapes must be immutable and hashable. ''' outline = {} for k,v in obj.items(): outline[k] = factory(v, **kwargs) return frozendict(outline)
def generator(cls, **kwargs): '''Generate a random DictShape''' output = {} no_keys = random.randint(1,3) keys = [value_generator(str) for _ in range(0,no_keys)] for key in keys: output[key] = random_shape(hashable=kwargs.get('hashable')) return DictShape(frozendict(output), from_outline=True)
def shrink(self, **kwargs): '''Delete a random number of keys and shrink a random number of remaining values''' compression = {} no_keys_to_delete = random.randint(0,len(self) - 1) keys_to_keep = random.sample(self.keys(), len(self) - no_keys_to_delete) shrink_probability = min(0.5, 1/(len(keys_to_keep)+1)) for key in keys_to_keep: if random.random() <= shrink_probability: compression[key] = self[key].shrink() else: compression[key] = self[key] return DictShape(frozendict(compression), from_outline=True)
def __add__(self, other): '''Two DictShapes may be added if any keys that they share have the same shaped value. The sum is comprised of all key/value pairs in both DictShapes.''' if isinstance(other, DictShape): output = {} shared_keys = set(self.keys()).intersection(other.keys()) for key in shared_keys: if self[key] != other[key]: raise CouldNotAddError('You can not add these DictShapes as their shared keys have differing shapes for their values.') for key,value in set(self.items()).union(other.items()): output[key] = value return DictShape(frozendict(output), from_outline=True) return NotImplemented
def extend(self, **kwargs): '''Extend the values of the current keys, and add a random number of new key/shape pairs''' extension = {} for k,v in self.items(): extension[k] = v.extend(**kwargs) no_extra_keys = random.randint(0,1) for _ in range(0,no_extra_keys): while True: key = value_generator(str) if not key in self: break else: continue extension[key] = random_shape() return DictShape(frozendict(extension), from_outline=True)
def _make_hashable(obj): # If we're a list or a tuple, make each object hashable. if isinstance(obj, list) or isinstance(obj, tuple): return tuple(_make_hashable(x) for x in obj) # If we're not a dictionary, no need to make hashable. if not isinstance(obj, dict): return obj # Dictionaries need to recursively freeze inner dictionaries. new_dict = dict() for (key, val) in obj.items(): if isinstance(val, dict): val = _make_hashable(val) new_dict[key] = val return frozendict(new_dict)