Source code for dicts

from cell import *
import operator
import datetime
import time
import itertools

SIMPLE_TYPES = (int, long, float, bool, dict, basestring, list)

[docs]class DictCell(Cell): """ This is a wrapper for a dictionary of cells. Can be compared with another DictCell. Unlike the other primitive structures, a DictCell cannot be coerced into something else. :param from_dict: Optional parameter specifying initial dictionary, where the value of each (key,value) pair must be a Cell. Defaults to an empty dictionary. :type from_dict: dict """ HASATTR = 0 PRIMES = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179] def __init__(self, from_dict=None): """ Takes a dictionary object that contains the names (keys) and their corresponding cells (values) """ # check key names for conflicts with the classes own attributes # and verify that all values are subclasses of Cell if from_dict is None: from_dict = {} for key, val in from_dict.items(): if not isinstance(val, Cell): if isinstance(val, dict): from_dict[key] = DictCell(val) else: raise CellConstructionFailure("Value of property '%s' must be " % (key,) + "an instance of Cell, not %s" % (type(val))) self.__dict__['p'] = from_dict def __setattr__(self, k, v): """ Merges or creates a new value for a property in the dictionary """ if k in self.__dict__['p']: return self[k].merge(v) else: self.__dict__['p'][k] = v return self[k] def __getitem__(self, k): """ Standard dictionary member access syntax. Given a DictCell, `d`, to access property `size`, you would call: `d['size']` """ if not hasattr(self, 'p'): raise AttributeError("No property attribute 'p'") if k in self.__dict__['p']: return self.p[k] elif hasattr(self, k): return self.__dict__[k] else: raise AttributeError("No attribute '%s'" % (k,)) def __setitem__(self, k, val): """ Standard dictionary member update syntax Given a DictCell, `d`, to set property `size` to value 3, you would call: `d['size']` = 3 """ if not hasattr(self, 'p'): raise AttributeError("No property attribute 'p'") if k in self.__dict__['p']: return self.p[k].merge(val) else: return object.__setattr__(self, k, val) def __delitem__(self, k): """ Deletes an attribute k """ if not hasattr(self, 'p'): raise AttributeError("No property attribute 'p'") if k in self.__dict__['p']: del self.__dict__['p'][k]
[docs] def contains(self, key_or_keypath): """ Allows the 'in' operator to work for checking if a particular key (or keypath) is inside the dictionary. :param key_or_keypath: A single key or a path of keys in the form of a list :returns: bool""" if isinstance(key_or_keypath, list): if len(key_or_keypath) == 0: # empty list is root return False val = self next_key = None for next_key in key_or_keypath: if next_key in val: val = val[next_key] else: return False return True else: return key_or_keypath in self.__dict__['p']
[docs] def get_value_from_path(self, keypath): """ Returns the value at the end of keypath (or None) keypath is a list of keys, e.g., ["key", "subkey", "subsubkey"] :param keypath: A list of keys representing a path through nested dictionaries :type keypath: list :returns: value associated with final key in *keypath* """ if isinstance(keypath, list): if len(keypath) == 0: # empty list is root return val = self for next_key in keypath: val = val[next_key] return val else: return self.__dict__['p'][keypath]
[docs] def is_entailed_by(self, other): """ Whether all of self's keys (and values) are in (and within) other's :param other: A DictCell to check :type other: DictCell :returns: bool """ for (s_key, s_val) in self: if s_key in other: if not other[s_key].entails(s_val): return False else: return False return True
[docs] def entails(self, other): """ Whether the target of the other belief state is strictly more general than the caller belief state :param other: A DictCell to check :type other: DictCell :returns: bool """ return other.is_entailed_by(self)
[docs] def is_contradictory(self, other): """ Returns True if the two DictCells are unmergeable, i.e. if the two DictCells share a key, but the Cells associated with those keys are unMergeable. :param other: DictCell to check :type other: DictCell :returns: bool :raises: Exception """ if not isinstance(other, DictCell): raise Exception("Incomparable") for key, val in self: if key in other.__dict__['p'] \ and val.is_contradictory(other.__dict__['p'][key]): return True return False
[docs] def is_equal(self, other): """ Two DictCells are equal when they share ALL Keys, and all of their ``is_equal()`` methods return True. This ensures substructure equality. :parameter other: DictCell to compare :type other: DictCell :returns: bool """ if not isinstance(other, DictCell): return False for (this, that) in itertools.izip_longest(self, other): if this[0] != that[0]: # compare key names return False if not this[1].is_equal(that[1]): # compare cells return False return True
def __iter__(self): """ Iterate through first-level of sorted keys and values """ return iter(sorted(self.__dict__['p'].items(), key=operator.itemgetter(0))) def __hash__(self): """ Iterate through all members and hash 'em """ hash_val = 0 for i, (key, val) in enumerate(self): hash_val += hash(key) * hash(val) * DictCell.PRIMES[i] if hash_val == -2: hash_val = -1 return hash_val
[docs] def merge(self, other): """ Merges two complex structures (by recursively merging their parts). Missing-parts do not trigger contradictions. :param other: DictCell to merge :type other: DictCell :returns: DictCell :raises: Exception, Contradiction """ if not isinstance(other, DictCell): raise Exception("Incomparable") if self.is_equal(other): # pick among dependencies return self elif other.is_entailed_by(self): return self elif self.is_entailed_by(other): self.__dict__['p'] = other.__dict__['p'].copy() elif not self.is_contradictory(other): # partial information in both, add from other for o_key, o_val in other: if not o_key in self.__dict__['p']: self.__dict__['p'][o_key] = o_val else: self.__dict__['p'][o_key].merge(o_val) else: raise Contradiction("Dictionaries are contractory, cannot Merge") return self
def __repr__(self, indent=0): """ Pretty prints a string representing the structure of the tree. """ result = "" for i, key in list(enumerate(self.__dict__)): if i != 0: result += " " * indent if isinstance(self[key], DictCell): result += "%s : " % (key) result += self[key].__repr__(indent+len(key)+3) else: result += "%s : %s " % (key, self[key]) result += "\n" return result
[docs] def to_dict(self): """ This method converts the DictCell into a python `dict`. This is useful for JSON serialization. :returns: dict """ output = {} for key, value in self.__dict__['p'].iteritems(): if value is None or isinstance(value, SIMPLE_TYPES): output[key] = value elif hasattr(value, 'to_dot'): output[key] = value.to_dot() elif hasattr(value, 'to_dict'): output[key] = value.to_dict() elif isinstance(value, datetime.date): # Convert date/datetime to ms-since-epoch ("new Date()"). ms = time.mktime(value.utctimetuple()) * 1000 ms += getattr(value, 'microseconds', 0) / 1000 output[key] = int(ms) elif isinstance(value, dict): output[key] = [] else: raise ValueError('cannot encode ' + repr(key)) return output
[docs] def to_latex(self): """ Returns a LaTeX representation of an attribute-value matrix """ latex = r"[{} " for attribute, value in self: if attribute in ['speaker_model', 'is_in_commonground']: continue value_l = value.to_latex() if value_l == "": continue latex += "{attribute:<15} & {value:<20} \\\\ \n".format(attribute=attribute, value=value_l) latex += "]\n" return latex
[docs] def empty(self): """ Returns True iff the dictionary doesn't have any keys """ return self.__dict__['p'].keys() == []
[docs] def keys(self): """ Returns a list of the top-level keys in the DictCell :returns: list """ return [k for k, _ in self]
[docs] def values(self): """ Returns a list of the top-level values in the DictCell :returns: list """ return [v for _, v in self]
[docs] def items(self): """ Returns both keys and values in dictionary :returns: list of tuples """ return [(k,v) for k, v in self]
__eq__ = is_equal __contains__ = contains