class ChainSet(object): """ Base class for various methods to rename chains Contains _chains, which maps from the renamed chain to a tuple with the original (object,state,chain). All dict-like accessors work on ChainSets, e.g. chain_set["A"] -> ("obj",1,"A") """ def __init__(self): # Use an OrderedDict in Python >= 1.7 for better printing if _orderedDict: self._chains = OrderedDict() else: self._chains = dict() def map_chain(self, obj, state, origChain ): """ map_chain(string obj,int state, string chain]]) -> string Maps a chain letter to a unique chainID. Results are unique within each instance, and can be used as keys on this chain set. """ raise NotImplementedError("Base class") # delegate most methods to _chains def __getattr__(self,at): if at in "pop popitem update setdefault".split(): raise AttributeError("type object '%s' has no attribute '%s'"%(type(self),at)) return getattr(self._chains,at) def __cmp__(self,other): return self._chains.__cmp__(other) def __eq__(self,other): return self._chains.__eq__(other) def __ge__(self,other): return self._chains.__ge__(other) def __gt__(self,other): return self._chains.__gt__(other) def __le__(self,other): return self._chains.__le__(other) def __lt__(self,other): return self._chains.__lt__(other) def __ne__(self,other): return self._chains.__ne__(other) def __len__(self): return self._chains.__len__() def __contains__(self,key): return self._chains.__contains__(key) def __getitem__(self,key): return self._chains.__getitem__(key) def __iter__(self): return self._chains.__iter__() def __str__(self): return str(self._chains) @staticmethod def _int_to_chain(i,base=_default_base): """ _int_to_chain(int,int) -> str Converts a positive integer to a chain ID. Chain IDs include uppercase characters, numbers, and optionally lowercase letters. i = a positive integer to convert base = the alphabet size to include. Typically 36 or 62. """ if i < 0: raise ValueError("positive integers only") if base < 0 or 62 < base: raise ValueError("Invalid base") quot = int(i)//base rem = i%base if rem < 26: letter = chr( ord("A") + rem) elif rem < 36: letter = str( rem-26) else: letter = chr( ord("a") + rem - 36) if quot == 0: return letter else: return ChainSet._int_to_chain(quot-1,base) + letter
class BaseCache(metaclass=ABCMeta): """ BaseCache is a class that saves and operates on an OrderedDict. It has a certain capacity, stored in the attribute `maxsize`. Whether this capacity is reached, can be checked by using the boolean property `is_full`. To implement a custom cache, inherit from this class and override the methods ``__getitem__`` and ``__setitem__``. Call the method `sunpy.database.caching.BaseCache.callback` as soon as an item from the cache is removed. """ def __init__(self, maxsize=float('inf')): self.maxsize = maxsize self._dict = OrderedDict() def get(self, key, default=None): # pragma: no cover """Return the corresponding value to `key` if `key` is in the cache, `default` otherwise. This method has no side-effects, multiple calls with the same cache and the same passed key must always return the same value. """ try: return self._dict[key] except KeyError: return default @abstractmethod def __getitem__(self, key): """abstract method: this method must be overwritten by inheriting subclasses. It defines what happens if an item from the cache is attempted to be accessed. """ return # pragma: no cover @abstractmethod def __setitem__(self, key, value): """abstract method: this method must be overwritten by inheriting subclasses. It defines what happens if a new value should be assigned to the given key. If the given key does already exist in the cache or not must be checked by the person who implements this method. """ @abstractproperty def to_be_removed(self): """The item that will be removed on the next :meth:`sunpy.database.caching.BaseCache.remove` call. """ @abstractmethod def remove(self): """Call this method to manually remove one item from the cache. Which item is removed, depends on the implementation of the cache. After the item has been removed, the callback method is called. """ def callback(self, key, value): """This method should be called (by convention) if an item is removed from the cache because it is full. The passed key and value are the ones that are removed. By default this method does nothing, but it can be customized in a custom cache that inherits from this base class. """ @property def is_full(self): """True if the number of items in the cache equals :attr:`maxsize`, False otherwise. """ return len(self._dict) == self.maxsize def __delitem__(self, key): self._dict.__delitem__(key) def __contains__(self, key): return key in self._dict.keys() def __len__(self): return len(self._dict) def __iter__(self): yield from self._dict.__iter__() def __reversed__(self): # pragma: no cover yield from self._dict.__reversed__() def clear(self): # pragma: no cover return self._dict.clear() def keys(self): # pragma: no cover return list(self._dict.keys()) def values(self): # pragma: no cover return list(self._dict.values()) def items(self): # pragma: no cover return list(self._dict.items()) def iterkeys(self): # pragma: no cover return iter(self._dict.keys()) def itervalues(self): # pragma: no cover yield from self._dict.values() def iteritems(self): # pragma: no cover yield from self._dict.items() def update(self, *args, **kwds): # pragma: no cover self._dict.update(*args, **kwds) def pop(self, key, default=MutableMapping._MutableMapping__marker ): # pragma: no cover return self._dict.pop(key, default) def setdefault(self, key, default=None): # pragma: no cover return self._dict.setdefault(key, default) def popitem(self, last=True): # pragma: no cover return self._dict.popitem(last) def __reduce__(self): # pragma: no cover return self._dict.__reduce__() def copy(self): # pragma: no cover return self._dict.copy() def __eq__(self, other): # pragma: no cover return self._dict.__eq__(other) def __ne__(self, other): # pragma: no cover return self._dict.__ne__(other) def viewkeys(self): # pragma: no cover return self._dict.keys() def viewvalues(self): # pragma: no cover return self._dict.values() def viewitems(self): # pragma: no cover return self._dict.items() @classmethod def fromkeys(cls, iterable, value=None): # pragma: no cover return OrderedDict.fromkeys(iterable, value) def __repr__(self): # pragma: no cover return '{}({!r})'.format(self.__class__.__name__, dict(self._dict))
class BaseCache(object): """ BaseCache is a class that saves and operates on an OrderedDict. It has a certain capacity, stored in the attribute `maxsize`. Whether this capacity is reached, can be checked by using the boolean property `is_full`. To implement a custom cache, inherit from this class and override the methods ``__getitem__`` and ``__setitem__``. Call the method `sunpy.database.caching.BaseCache.callback` as soon as an item from the cache is removed. """ def __init__(self, maxsize=float('inf')): self.maxsize = maxsize self._dict = OrderedDict() def get(self, key, default=None): # pragma: no cover """Return the corresponding value to `key` if `key` is in the cache, `default` otherwise. This method has no side-effects, multiple calls with the same cache and the same passed key must always return the same value. """ try: return self._dict[key] except KeyError: return default @abstractmethod def __getitem__(self, key): """abstract method: this method must be overwritten by inheriting subclasses. It defines what happens if an item from the cache is attempted to be accessed. """ return # pragma: no cover @abstractmethod def __setitem__(self, key, value): """abstract method: this method must be overwritten by inheriting subclasses. It defines what happens if a new value should be assigned to the given key. If the given key does already exist in the cache or not must be checked by the person who implements this method. """ @abstractproperty def to_be_removed(self): """The item that will be removed on the next :meth:`sunpy.database.caching.BaseCache.remove` call. """ @abstractmethod def remove(self): """Call this method to manually remove one item from the cache. Which item is removed, depends on the implementation of the cache. After the item has been removed, the callback method is called. """ def callback(self, key, value): """This method should be called (by convention) if an item is removed from the cache because it is full. The passed key and value are the ones that are removed. By default this method does nothing, but it can be customized in a custom cache that inherits from this base class. """ @property def is_full(self): """True if the number of items in the cache equals :attr:`maxsize`, False otherwise. """ return len(self._dict) == self.maxsize def __delitem__(self, key): self._dict.__delitem__(key) def __contains__(self, key): return key in self._dict.keys() def __len__(self): return len(self._dict) def __iter__(self): for key in self._dict.__iter__(): yield key def __reversed__(self): # pragma: no cover for key in self._dict.__reversed__(): yield key def clear(self): # pragma: no cover return self._dict.clear() def keys(self): # pragma: no cover return list(self._dict.keys()) def values(self): # pragma: no cover return list(self._dict.values()) def items(self): # pragma: no cover return list(self._dict.items()) def iterkeys(self): # pragma: no cover return iter(self._dict.keys()) def itervalues(self): # pragma: no cover for value in self._dict.values(): yield value def iteritems(self): # pragma: no cover for key, value in six.iteritems(self._dict): yield key, value def update(self, *args, **kwds): # pragma: no cover self._dict.update(*args, **kwds) def pop(self, key, default=MutableMapping._MutableMapping__marker): # pragma: no cover return self._dict.pop(key, default) def setdefault(self, key, default=None): # pragma: no cover return self._dict.setdefault(key, default) def popitem(self, last=True): # pragma: no cover return self._dict.popitem(last) def __reduce__(self): # pragma: no cover return self._dict.__reduce__() def copy(self): # pragma: no cover return self._dict.copy() def __eq__(self, other): # pragma: no cover return self._dict.__eq__(other) def __ne__(self, other): # pragma: no cover return self._dict.__ne__(other) def viewkeys(self): # pragma: no cover return self._dict.keys() def viewvalues(self): # pragma: no cover return self._dict.values() def viewitems(self): # pragma: no cover return self._dict.items() @classmethod def fromkeys(cls, iterable, value=None): # pragma: no cover return OrderedDict.fromkeys(iterable, value) def __repr__(self): # pragma: no cover return '{0}({1!r})'.format(self.__class__.__name__, dict(self._dict))
class DotMap(MutableMapping, OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() self._dynamic = True if kwargs: if '_dynamic' in kwargs: self._dynamic = kwargs['_dynamic'] if args: d = args[0] if isinstance(d, dict): for k, v in self.__call_items(d): if isinstance(v, dict): v = DotMap(v, _dynamic=self._dynamic) if type(v) is list: l = [] for i in v: n = i if type(i) is dict: n = DotMap(i, _dynamic=self._dynamic) l.append(n) v = l self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): if k is not '_dynamic': self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_': # automatically extend to new DotMap self[k] = DotMap() return self._map[k] def __setattr__(self, k, v): if k in { '_map', '_dynamic', '_ipython_canary_method_should_not_exist_' }: super(DotMap, self).__setattr__(k, v) else: self[k] = v def __getattr__(self, k): if k in { '_map', '_dynamic', '_ipython_canary_method_should_not_exist_' }: super(DotMap, self).__getattr__(k) else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k, v in self.__call_items(self._map): # bizarre recursive assignment situation (why someone would do this is beyond me) if id(v) == id(self): items.append('{0}=DotMap(...)'.format(k)) else: items.append('{0}={1}'.format(k, repr(v))) joined = ', '.join(items) out = '{0}({1})'.format(self.__class__.__name__, joined) return out def __repr__(self): return str(self) def toDict(self): d = {} for k, v in self.items(): if type(v) is DotMap: # bizarre recursive assignment support if id(v) == id(self): v = d else: v = v.toDict() elif type(v) in (list, tuple): l = [] for i in v: n = i if type(i) is DotMap: n = i.toDict() l.append(n) if type(v) is tuple: v = tuple(l) else: v = l d[k] = v return d def pprint(self, pformat='dict'): if pformat == 'json': print(dumps(self.toDict(), indent=4, sort_keys=True)) else: pprint(self.toDict()) def empty(self): return (not any(self)) # proper dict subclassing def values(self): return self._map.values() # ipython support def __dir__(self): return self.keys() @classmethod def parseOther(self, other): if type(other) is DotMap: return other._map else: return other def __cmp__(self, other): other = DotMap.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return DotMap(self) def __copy__(self): return self.copy() def __deepcopy__(self, memo=None): return self.copy() def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = DotMap() d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d) # bannerStr def _getListStr(self, items): out = '[' mid = '' for i in items: mid += ' {}\n'.format(i) if mid != '': mid = '\n' + mid out += mid out += ']' return out def _getValueStr(self, k, v): outV = v multiLine = len(str(v).split('\n')) > 1 if multiLine: # push to next line outV = '\n' + v if type(v) is list: outV = self._getListStr(v) out = '{} {}'.format(k, outV) return out def _getSubMapDotList(self, pre, name, subMap): outList = [] if pre == '': pre = name else: pre = '{}.{}'.format(pre, name) def stamp(pre, k, v): valStr = self._getValueStr(k, v) return '{}.{}'.format(pre, valStr) for k, v in subMap.items(): if isinstance(v, DotMap) and v != DotMap(): subList = self._getSubMapDotList(pre, k, v) outList.extend(subList) else: outList.append(stamp(pre, k, v)) return outList def _getSubMapStr(self, name, subMap): outList = ['== {} =='.format(name)] for k, v in subMap.items(): if isinstance(v, DotMap) and v != DotMap(): # break down to dots subList = self._getSubMapDotList('', k, v) # add the divit # subList = ['> {}'.format(i) for i in subList] outList.extend(subList) else: out = self._getValueStr(k, v) # out = '> {}'.format(out) out = '{}'.format(out) outList.append(out) finalOut = '\n'.join(outList) return finalOut def bannerStr(self): lines = [] previous = None for k, v in self.items(): if previous == 'DotMap': lines.append('-') out = '' if isinstance(v, DotMap): name = k subMap = v out = self._getSubMapStr(name, subMap) lines.append(out) previous = 'DotMap' else: out = self._getValueStr(k, v) lines.append(out) previous = 'other' lines.append('--') s = '\n'.join(lines) return s
class DotMap(OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() self._dynamic = True # mettendo False non funzionano più i test di default. E' normale in quanto si aspettano la creazione dinamica dei figli # =================================== if LORETO: global MY_DICT_TYPES # global var per la classe self._dynamic = False # mettendo False non funzionano più i test di default. E' normale in quanto si aspettano la creazione dinamica dei figli MY_DICT_TYPES = [dict, DotMap] # by Loreto (DEFAULT dictionary) # =================================== if kwargs: if '_dynamic' in kwargs: self._dynamic = kwargs['_dynamic'] if args: d = args[0] if isinstance(d, dict): for k,v in self.__call_items(d): if type(v) is dict: v = DotMap(v, _dynamic=self._dynamic) if type(v) is list: l = [] for i in v: n = i if type(i) is dict: n = DotMap(i, _dynamic=self._dynamic) l.append(n) v = l self._map[k] = v if kwargs: for k,v in self.__call_items(kwargs): if k is not '_dynamic': self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_': # automatically extend to new DotMap self[k] = DotMap() return self._map[k] def __setattr__(self, k, v): if k in {'_map','_dynamic', '_ipython_canary_method_should_not_exist_'}: super(DotMap, self).__setattr__(k,v) else: self[k] = v def __getattr__(self, k): if k == {'_map','_dynamic','_ipython_canary_method_should_not_exist_'}: super(DotMap, self).__getattr__(k) else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k,v in self.__call_items(self._map): # bizarre recursive assignment situation (why someone would do this is beyond me) if id(v) == id(self): items.append('{0}=DotMap(...)'.format(k)) else: items.append('{0}={1}'.format(k, repr(v))) out = 'DotMap({0})'.format(', '.join(items)) return out def __repr__(self): return str(self) def toDict(self): d = {} for k,v in self.items(): if type(v) is DotMap: # bizarre recursive assignment support if id(v) == id(self): v = d else: v = v.toDict() elif type(v) is list: l = [] for i in v: n = i if type(i) is DotMap: n = i.toDict() l.append(n) v = l d[k] = v return d def pprint(self): pprint(self.toDict()) # =================================== if LORETO: # MY_DICT_TYPES = [dict, DotMap] def Ptr(self, listOfQualifiers, create=False): ptr = self for item in listOfQualifiers: if item in ptr: ptr = ptr[item] else: if create: ptr[item] = DotMap() ptr = ptr[item] else: return None return ptr def KeyTree(self, fPRINT=False): return DictToList.KeyTree(self, myDictTYPES=MY_DICT_TYPES, fPRINT=fPRINT) def KeyList(self): return DictToList.KeyList(self, myDictTYPES=MY_DICT_TYPES) def PrintTree(self, fEXIT=False, MaxLevel=10, header=None, printTYPE='LTKV', stackLevel=1): PrintDictionaryTree.PrintDictionary(self, myDictTYPES=MY_DICT_TYPES, printTYPE=printTYPE, fEXIT=fEXIT, MaxLevel=MaxLevel, header=header, stackLevel=stackLevel+1) printDict = PrintTree printTree = PrintTree def GetValue(self, listOfQualifiers=[], fPRINT=False): return DictToList.getValue(self, listOfQualifiers=listOfQualifiers, myDictTYPES=MY_DICT_TYPES, fPRINT=fPRINT) # =================================== def empty(self): return (not any(self)) # proper dict subclassing def values(self): return self._map.values() # ipython support def __dir__(self): return self.keys() @classmethod def parseOther(self, other): if type(other) is DotMap: return other._map else: return other def __cmp__(self, other): other = DotMap.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return DotMap(self.toDict()) def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = DotMap() d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d)
class Store(MutableMapping, OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() self._dynamic = True if kwargs: if '_dynamic' in kwargs: self._dynamic = kwargs['_dynamic'] if args: d = args[0] if isinstance(d, dict): for k, v in self.__call_items(d): if isinstance(v, dict): v = Store(v, _dynamic=self._dynamic) if type(v) is list: ele = [] for i in v: n = i if type(i) is dict: n = Store(i, _dynamic=self._dynamic) ele.append(n) v = ele self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): if k is not '_dynamic': self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map and \ self._dynamic and k != '_ipython_canary_method_should_not_exist_': # automatically extend to new Store self[k] = Store() return self._map[k] def __setattr__(self, k, v): if k in { '_map', '_dynamic', '_ipython_canary_method_should_not_exist_' }: super(Store, self).__setattr__(k, v) else: self[k] = v def __getattr__(self, k): if k == { '_map', '_dynamic', '_ipython_canary_method_should_not_exist_' }: super(Store, self).__getattr__(k) else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k, v in self.__call_items(self._map): if id(v) == id(self): items.append('{0}=Store(...)'.format(k)) else: items.append('{0}={1}'.format(k, repr(v))) joined = ', '.join(items) out = '{0}({1})'.format(self.__class__.__name__, joined) return out def __repr__(self): return str(self) def empty(self): return (not any(self)) # proper dict subclassing def values(self): return self._map.values() # ipython support def __dir__(self): return self.keys() @classmethod def parseOther(self, other): if type(other) is Store: return other._map else: return other def __cmp__(self, other): other = Store.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = Store.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = Store.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = Store.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = Store.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = Store.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = Store.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return Store(self) def __copy__(self): return self.copy() def __deepcopy__(self, memo=None): return self.copy() def get(self, key, default=None): return self._map.get(key, default) def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) @classmethod def fromkeys(cls, seq, value=None): d = Store() d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d)
class Maps(MutableMapping): """ Converts a dictionary of key:value pairs into a dotted representation of those keys. Normal string representation of keys is still accessible via normal dictionary indexing. Note: If a key contains non-alphanumeric characters (!@#$%, etc, including spaces), they will be replaced with an underscore (_). Examples: >>> # Normal usage >>> test = {"hello": "world"} >>> print(Maps(test)) Output: Maps(hello="world") >>> test = {"hello": "world"} >>> maps = Maps(test) >>> print(maps.hello) Output: "world" >>> test = {"hello": "world"} >>> maps = Maps(test) >>> print(maps["hello"]) Output: "world" >>> # If a dictionary key has non-alphanumeric characters >>> # Notice how a series of special characters is replaced >>> # by only a single underscore >>> test = {"hello joh*&^n": "hi computer"} >>> maps = Maps(test) >>> print(maps) Output: Maps(hello_joh_n="hi computer") Raises: ValueError: An argument is of a legal type but is, or contains, an illegal value. """ # Class-level variables _dynamic: bool _map: OrderedDict def __init__(self, *args, **kwargs) -> None: super().__init__() self._dynamic = True self._map = OrderedDict() if kwargs: for key, value in self._get_items(kwargs): key = re.sub('[^0-9a-zA-Z]+', '_', key) if key != '_dynamic': self._map[key] = value else: self._dynamic = value if args: dictionary = args[0] if not isinstance(dictionary, dict): raise ValueError( "object passed to constructor must be of type 'dict': " f"'{type(dictionary).__name__}'") # Recursive handling tracked_ids = {id(dictionary): self} for key, value in self._get_items(dictionary): if isinstance(key, str): key = re.sub('[^0-9a-zA-Z]+', '_', key) value_id = id(value) if isinstance(value, dict): if value_id in tracked_ids: value = tracked_ids[value_id] else: value = self.__class__(value, _dynamic=self._dynamic) tracked_ids[value_id] = value if isinstance(value, list): listed_items = [] for item in value: temp_item = item if isinstance(item, dict): temp_item = self.__class__(item, _dynamic=self._dynamic) listed_items.append(temp_item) value = listed_items try: self._map[key] = ast.literal_eval(value) except NameError: if value.lower() == "false": self._map[key] = False elif value.lower() == "true": self._map[key] = True else: self._map[key] = value except (SyntaxError, ValueError): # Cannot eval this value self._map[key] = value # Dunder methods def __add__(self, value: object) -> Union[Any, NoReturn]: if self.empty(): return value else: self_type = type(self).__name__ value_type = type(value).__name__ raise TypeError( f"unsupported operand type(s) for +: '{self_type}' and '{value_type}'" ) def __cmp__(self, value: object) -> Any: value = Maps.parse_value(value) return self._map.__cmp__(value) def __contains__(self, name: str) -> bool: return self._map.__contains__(name) def __copy__(self) -> Maps: return self.__class__(self) def __deepcopy__(self) -> Maps: return self.copy() def __delitem__( self, key: str, dict_delitem: Optional[Callable[..., Any]] = dict.__delitem__) -> Any: return self._map.__delitem__(key, dict_delitem=dict_delitem) def __dir__(self) -> Iterable: return self.keys() def __eq__(self, value: Any) -> bool: value = Maps.parse_value(value) if not isinstance(value, dict): return False return self._map.__eq__(value) def __ge__(self, value: Any) -> bool: value = Maps.parse_value(value) return self._map.__ge__(value) def __gt__(self, value: Any) -> bool: value = Maps.parse_value(value) return self._map.__gt__(value) def __iter__(self) -> Iterable: return self._map.__iter__() def __le__(self, value: Any) -> bool: value = Maps.parse_value(value) return self._map.__le__(value) def __len__(self) -> int: return self._map.__len__() def __lt__(self, value: Any) -> bool: value = Maps.parse_value(value) return self._map.__lt__(value) def __ne__(self, value: Any) -> bool: value = Maps.parse_value(value) return self._map.__ne__(value) def __repr__(self) -> str: return str(self) def __str__(self) -> str: items = [] for key, value in self._get_items(self._map): # Recursive assignment case if id(value) == id(self): items.append("{0}={1}(...)".format(key, self.__class__.__name__)) else: items.append("{0}={1}".format(key, repr(value))) joined = ", ".join(items) return "{0}({1})".format(self.__class__.__name__, joined) def __delattr__(self, name: str) -> None: self._map.__delitem__(name) def __getattr__(self, name: str) -> Any: if name in ('_map', '_dynamic', "_ipython_canary_method_should_not_exist_"): return super().__getattr__(name) try: return super(self.__class__, self).__getattribute__(name) except AttributeError: pass return self[name] def __setattr__(self, name: str, value: Any) -> None: if name in ('_map', '_dynamic', "_ipython_canary_method_should_not_exist_"): super().__setattr__(name, value) else: self[name] = value def __getitem__(self, name: str) -> Union[Any, Maps]: if (name not in self._map and self._dynamic and name != "_ipython_canary_method_should_not_exist_"): self[name] = self.__class__() return self._map[name] def __setitem__(self, name: str, value: Any) -> None: self._map[name] = value def __getstate__(self) -> dict: return self.__dict__ def __setstate__(self, value: dict) -> None: self.__dict__.update(value) # Internal methods def _get_items(self, item: Any) -> Iterable: if hasattr(item, 'iteritems') and ismethod(getattr(item, 'iteritems')): return item.iteritems() else: return item.items() # Public methods def clear(self) -> None: """Remove all items from the Maps object.""" self._map.clear() def copy(self) -> Maps: """Makes a copy of the Maps object in memory.""" return self.__copy__() def empty(self) -> bool: """Returns whether the Maps object is empty.""" return (not any(self)) @classmethod def fromkeys(cls, iterable: Iterable, value: Optional[Any] = None) -> Iterable: """Returns a new :obj:`Maps` object with keys supplied from an iterable setting each key in the object with :term:`value`. Args: iterable (:obj:`Iterable`): Any iterable. value (:obj:`obj`, optional): The value to set for the keys. Default is :obj:`None`. Returns: Maps: The :obj:`Maps` object. """ maps = cls() maps.map = OrderedDict.fromkeys(iterable, value) return maps def get(self, key: str, default: Optional[Any] = None) -> Any: """ Returns the value of 'key'. If :term:`key` does not exist, :term:default` is returned instead. Args: key (:obj:`str`): The key to get the value needed from the dict. default (:obj:`obj`, optional): The value to return if :term:`key` does not exist. Returns: Any: The value at :term:`key` or :term:default`. """ return self._map.get(key, default) def has_key(self, key: str) -> bool: return key in self._map def items(self) -> Generator[Tuple[str, Any]]: """Returns a generator yielding a (key, value) pair.""" return self._get_items(self._map) def iteritems(self) -> Iterator: """ Returns an iterator over the Maps oject's (key, value) pairs. """ return self.items() def iterkeys(self) -> Iterator: """Returns an iterator over the Maps object's keys.""" return self._map.iterkeys() def itervalues(self) -> Iterator: """Returns an iterator over the Maps object's values.""" return self._map.itervalues() def keys(self) -> Iterable: """Returns the keys of the Maps object.""" return self._map.keys() def next(self) -> str: """Returns the next key in the dictionary.""" return self._map.next() @classmethod def parse_ini(cls, ini_dict: ConfigParser, to_maps=False) -> Union[dict, Maps]: """ Converts the values from an INI file from all strings to their actual Python base-types (i.e. int, float, bool, etc). If the value cannot be converted, it is kept as a string. If a value of the key:value pairs is not a string, its type is maintained. Note: Any meant-to-be-bool values in the key:value pairs that are not exactly 'False' or 'True', but are similar like 'false' or 'tRue' for example, will be converted to bools. Args: ini_dict (:obj:`ConfigParser`): The dictionary returned by configparser when an INI file is loaded. to_maps (:obj:`bool`): Return a :obj:`Maps` object instead of a :obj:`dict`. Returns: dict or Maps: A dictionary maintaining the same key:value pairs as the input dictionary; however, the values are their Python base-types. If :obj:`to_maps` is :obj:`True`, return a :obj:`Maps` object. Raises: TypeError: An argument is of an illegal type. """ # Check for dict because of recursion; ini_dict is only meant # to be a dict when the function recursively converts the values # from a ConfigParser if not isinstance(ini_dict, (dict, ConfigParser)): raise TypeError( "argument 'ini_dict' must be of type 'ConfigParser': " f"{type(ini_dict).__name__}") if isinstance(ini_dict, ConfigParser): ini_dict_ = {} for section in ini_dict.sections(): ini_dict_[section] = {} for option in ini_dict.options(section): # Parse using configparser option_value = ini_dict.get(section, option) # Parse using os environ matches = [(m.start(0), m.end(0)) for m in re.finditer("&", option_value)] if len(matches) > 0 and len(matches) % 2 == 0: i = 0 while True: try: index_end = matches.pop(i + 1)[1] index_start = matches.pop(i)[0] sub = option_value[index_start:index_end] sub_replace = os.environ[sub[1:-1]] option_value = option_value.replace( sub, sub_replace) except IndexError: break except KeyError: pass ini_dict_[section][option] = option_value ini_dict = ini_dict_ for key, value in ini_dict.items(): if isinstance(value, dict): # Recursively parse dict ini_dict[key] = Maps.parse_ini(value, to_maps=to_maps) else: if not isinstance(value, str): continue try: ini_dict[key] = ast.literal_eval(value) except NameError: if value.lower() == "false": ini_dict[key] = False elif value.lower() == "true": ini_dict[key] = True else: ini_dict[key] = value except (SyntaxError, ValueError): # Cannot eval this value ini_dict[key] = value return Maps(ini_dict) if to_maps else ini_dict @classmethod def parse_value(cls, value: Any) -> Any: """ Checks if :term:`value` subclasses :obj:`Maps`. If so, it returns the :obj:`Maps` object; otherwise the :term:`value` itself. Args: value (:obj:`Any`): The value to parse. Returns: Any: :obj:`OrderedDict` if :term:`value` subclasses :obj:`Maps`, otherwise :term:`value`. """ if issubclass(type(value), Maps): return value.map else: return value def pop(self, key: str, default: Optional[Any] = None) -> Union[Any, NoReturn]: """ Removes and returns the value in the Maps object at 'key'. If 'key' does not exist, then 'default' is returned. Args: key (:obj:`str`): The key to use to remove a value from the Maps object. default (:obj:`obj`, optional): The value to return if :term:`key` does not exist in the :obj:`Maps` object. Returns: Any: The value at :term:`key`, otherwise :term:`default`. """ return self._map.pop() def popitem(self) -> Any: """Removes and returns an arbitrary (key, value) pair from the :obj:`Maps` object. Returns: Any: The arbitrary (key, value) pair. Raises: KeyError: The :obj:`Maps` object is empty. """ return self._map.popitem() def setdefault(self, key: str, default=None) -> Any: """ Returns a value of the 'key' in the Maps object. If 'key' is not found, then 'default' is inserted at 'key' into the Maps object and then returns that value. Args: key: The key to return the value of. default (:obj:`obj`, optional): The value to insert if 'key' does not exist. Defaults to none. Returns: object: The object at 'key' in the Maps object, default' otherwise. """ return self._map.setdefault(key, default) def to_dict(self) -> Union[dict, NoReturn]: """Converts the :obj:`Maps` object to a stdlib dictionary. Returns: dict: The converted :obj:`Maps` object as a dictionary. """ new_dict = {} for key, value in self.items(): if issubclass(type(value), Maps): if id(value) == id(self): value = new_dict else: value = value.to_dict() elif isinstance(value, (tuple, list)): new_list = [] for item in value: temp_item = item if issubclass(type(item), Maps): temp_item = item.to_dict() new_list.append(temp_item) if isinstance(value, tuple): value = tuple(new_list) else: value = new_list new_dict[key] = value return new_dict def update(self, *args, **kwargs) -> None: """Adds or changes existing values using a dictionary or iterator of key:value pairs.""" if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def values(self) -> Any: """Returns the values of the :obj:`Maps` object.""" return self._map.values() def viewitems(self) -> Any: """Returns a new view of the :obj:`Maps` object's items (key:value pairs).""" return self._map.viewitems() def viewkeys(self) -> Any: """Returns a new view of the :obj:`Maps` object's keys.""" return self._map.viewkeys() def viewvalues(self) -> Any: """Returns a new view of the :obj:`Maps` object's values.""" return self._map.viewvalues()
class DotMap(MutableMapping, OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() if args: assert len(args) == 1 d = args[0] if isinstance(d, dict): for k, v in self.__call_items(d): if isinstance(v, dict): v = DotMap(v) if isinstance(v, list): l = [] for i in v: n = i if isinstance(i, dict): n = DotMap(i) l.append(n) v = l self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map and k != IPYTHON_CANNARY: # automatically extend to new DotMap self[k] = DotMap() return self._map[k] def __setattr__(self, k, v): if k in {'_map', IPYTHON_CANNARY}: super(DotMap, self).__setattr__(k, v) else: self[k] = v def __getattr__(self, k): if k == {'_map', IPYTHON_CANNARY}: super(DotMap, self).__getattr__(k) else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k, v in self.__call_items(self._map): if id(v) == id(self): items.append('{0}=DotMap(...)'.format(k)) else: items.append('{0}={1}'.format(k, repr(v))) joined = ', '.join(items) out = '{0}({1})'.format(self.__class__.__name__, joined) return out __repr__ = __str__ def toDict(self): d = {} for k, v in self.items(): if isinstance(v, DotMap): if id(v) == id(self): v = d else: v = v.toDict() elif isinstance(v, (list, tuple)): l = [] for i in v: n = i if type(i) is DotMap: n = i.toDict() l.append(n) if isinstance(v, tuple): v = tuple(l) else: v = l d[k] = v return d def empty(self): return (not any(self)) def values(self): return self._map.values() # ipython support def __dir__(self): return self.keys() @classmethod def parse_other(cls, other): if isinstance(other, DotMap): return other._map return other def __cmp__(self, other): other = DotMap.parse_other(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parse_other(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parse_other(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parse_other(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parse_other(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parse_other(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parse_other(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return DotMap(self) def __copy__(self): return self.copy() def __deepcopy__(self, memo=None): return self.copy() def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = DotMap() d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d)
class DotMap(OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() if args: d = args[0] if type(d) is dict: for k,v in self.__call_items(d): if type(v) is dict: v = DotMap(v) self._map[k] = v if kwargs: for k,v in self.__call_items(kwargs): self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map: # automatically extend to new DotMap self[k] = DotMap() return self._map[k] def __setattr__(self, k, v): if k == '_map': super(DotMap, self).__setattr__(k,v) else: self[k] = v def __getattr__(self, k): if k == '_map': super(DotMap, self).__getattr__(k) else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k,v in self.__call_items(self._map): items.append('{0}={1}'.format(k, repr(v))) out = 'DotMap({0})'.format(', '.join(items)) return out def __repr__(self): return str(self) def toDict(self): d = {} for k,v in self.items(): if type(v) is DotMap: v = v.toDict() d[k] = v return d def pprint(self): pprint(self.toDict()) # proper dict subclassing def values(self): return self._map.values() @classmethod def parseOther(self, other): if type(other) is DotMap: return other._map else: return other def __cmp__(self, other): other = DotMap.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return self def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = DotMap() d._map = OrderedDict.fromkeys(seq, value) return d
class DotMap(OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() if args: d = args[0] if type(d) is dict: for k, v in self.__call_items(d): if type(v) is dict: v = DotMap(v) self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map: # DON'T automatically extend to new DotMap # self[k] = DotMap() raise AttributeError('%s is not defined in DotMap' % k) return self._map[k] def __setattr__(self, k, v): if k == '_map': super(DotMap, self).__setattr__(k, v) else: self[k] = v def __getattr__(self, k): if k == '_map': super(DotMap, self).__getattr__(k) else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k, v in self.__call_items(self._map): items.append('{0}={1}'.format(k, repr(v))) out = 'DotMap({0})'.format(', '.join(items)) return out def __repr__(self): return str(self) def toDict(self): d = {} for k, v in self.items(): if type(v) is DotMap: v = v.toDict() d[k] = v return d def pprint(self): pprint(self.toDict()) # proper dict subclassing def values(self): return self._map.values() @classmethod def parseOther(self, other): if type(other) is DotMap: return other._map else: return other def __cmp__(self, other): other = DotMap.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return self def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = DotMap() d._map = OrderedDict.fromkeys(seq, value) return d
class ConfigMap(MutableMapping, OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() # todo: simplify self._dynamic = True if kwargs: if '_dynamic' in kwargs: self._dynamic = kwargs['_dynamic'] del kwargs['_dynamic'] self._evaluate = True if kwargs: if '_evaluate' in kwargs: self._evaluate = kwargs['_evaluate'] del kwargs['_evaluate'] self._evaluated = False if kwargs: if '_evaluated' in kwargs: self._evaluated = kwargs['_evaluated'] del kwargs['_evaluated'] if args: d = args[0] if isinstance(d, dict): for k, v in self.__call_items(d): if isinstance(v, dict): v = ConfigMap(v, _dynamic=self._dynamic, _evaluate=self._evaluate, _evaluated=self._evaluated) if type(v) is list: l = [] for i in v: n = i if type(i) is dict: n = ConfigMap(i, _dynamic=self._dynamic, _evaluate=self._evaluate, _evaluated=self._evaluated) l.append(n) v = l self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k, evaluate=None): if evaluate is None: evaluate = self._evaluate if k not in self._map: if k == '_ipython_canary_method_should_not_exist_': raise KeyError if self._dynamic: # automatically extend to new ConfigMap self[k] = ConfigMap() else: # todo: display full recursive path? raise KeyError("'%s' does not exist" % k) var = self._map[k] if evaluate: if isinstance(var, ConfigMethod): var = var.evaluate() # todo: return instead to avoid second config map eval? if isinstance(var, ConfigMap): var = var.evaluate() return var def __setattr__(self, k, v): if k in ['_map', '_dynamic', '_ipython_canary_method_should_not_exist_', '_evaluate', '_evaluated']: super(ConfigMap, self).__setattr__(k, v) else: self[k] = v def __getattr__(self, k): if k in ['_map', '_dynamic', '_ipython_canary_method_should_not_exist_', '_evaluate', '_evaluated']: return self.__getattribute__(k) else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k, v in self.__call_items(self._map): # bizarre recursive assignment situation (why someone would do this is beyond me) if id(v) == id(self): items.append('{0}=ConfigMap(...)'.format(k)) else: items.append('{0}={1}'.format(k, repr(v))) joined = ', '.join(items) out = '{0}({1})'.format(self.__class__.__name__, joined) return out def __repr__(self): return str(self) def toDict(self, evaluate=None, with_hidden=True): if evaluate is None: evaluate = bool(self._evaluate) d = {} for k, v in self.items(): if evaluate and isinstance(v, ConfigMethod): v = v.evaluate() if isinstance(v, ConfigMap): v = v.toDict(evaluate=evaluate, with_hidden=with_hidden) if id(v) != id(self) else d elif isinstance(v, list): v = [i.toDict(evaluate=evaluate, with_hidden=with_hidden) if isinstance(i, ConfigMap) else i for i in v] elif isinstance(v, tuple): v = (i.toDict(evaluate=evaluate, with_hidden=with_hidden) if isinstance(i, ConfigMap) else i for i in v) if with_hidden is False \ and (isinstance(k, str) and ((k.startswith('_') and not k.endswith('_')) or k.startswith('~'))): continue d[k] = v return d def evaluate(self): if self._evaluated: return self # TODO: case where config method access a key of the config that is just being evaluated. # shouldn't give an endless loop # todo: make more efficient return ConfigMap(self.toDict(evaluate=True), _dynamic=False, _evaluated=True) def pprint(self, pformat='json'): if pformat == 'json': print(dumps(self.toDict(), indent=4, sort_keys=True, default=str)) else: pprint(self.toDict()) def empty(self): return not any(self) # proper dict subclassing def values(self): return self._map.values() # ipython support def __dir__(self): return self.keys() @classmethod def parseOther(self, other): if type(other) is ConfigMap: return other._map else: return other def __cmp__(self, other): other = ConfigMap.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = ConfigMap.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = ConfigMap.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = ConfigMap.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = ConfigMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = ConfigMap.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = ConfigMap.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return ConfigMap(self, _dynamic=self._dynamic, _evaluate=self._evaluate, _evaluated=self._evaluated) def __copy__(self): return self.copy() def __deepcopy__(self, memo=None): return self.copy() def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = ConfigMap(_dynamic=False) d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d) # bannerStr def _getListStr(self, items): out = '[' mid = '' for i in items: mid += ' {}\n'.format(i) if mid != '': mid = '\n' + mid out += mid out += ']' return out def _getValueStr(self, k, v): outV = v multiLine = len(str(v).split('\n')) > 1 if multiLine: # push to next line outV = '\n' + v if type(v) is list: outV = self._getListStr(v) out = '{} {}'.format(k, outV) return out def _getSubMapDotList(self, pre, name, subMap): outList = [] if pre == '': pre = name else: pre = '{}.{}'.format(pre, name) def stamp(pre, k, v): valStr = self._getValueStr(k, v) return '{}.{}'.format(pre, valStr) for k, v in subMap.items(): if isinstance(v, ConfigMap) and v != ConfigMap(): subList = self._getSubMapDotList(pre, k, v) outList.extend(subList) else: outList.append(stamp(pre, k, v)) return outList def _getSubMapStr(self, name, subMap): outList = ['== {} =='.format(name)] for k, v in subMap.items(): if isinstance(v, ConfigMap) and v != ConfigMap(): # break down to dots subList = self._getSubMapDotList('', k, v) # add the divit # subList = ['> {}'.format(i) for i in subList] outList.extend(subList) else: out = self._getValueStr(k, v) # out = '> {}'.format(out) out = '{}'.format(out) outList.append(out) finalOut = '\n'.join(outList) return finalOut def bannerStr(self): lines = [] previous = None for k, v in self.items(): if previous == 'ConfigMap': lines.append('-') out = '' if isinstance(v, ConfigMap): name = k subMap = v out = self._getSubMapStr(name, subMap) lines.append(out) previous = 'ConfigMap' else: out = self._getValueStr(k, v) lines.append(out) previous = 'other' lines.append('--') s = '\n'.join(lines) return s
class Dictionary(): def __init__(self): self.__dictionary = OrderedDict() def clear(self): self.__dictionary.clear() def get_json(self): return json.dumps(self.__dictionary) def set_item(self, key, value): self.__dictionary.__setitem__(key, value) return self def values(self): return [value for value in self.__dictionary.values().__iter__()] def items(self): return self.__dictionary.items() def copy(self): self.__dictionary def constain(self, key): return key in self.get_list_of_key() def get(self, key): return self.__dictionary.get(key) def clear(self, key, default): self.__dictionary.pop(key, default) def format(self, *args, **kwargs): return self.__dictionary.__format__(*args, **kwargs) def ne(self, *args, **kwargs): return self.__dictionary.__ne__(*args, **kwargs) def repr(self, *args, **kwargs): return self.__dictionary.__repr__(*args, **kwargs) def ge(self, *args, **kwargs): return self.dictionary__ge__(*args, **kwargs) def __sizeof__(self): return self.__dictionary.__sizeof__() def setattr(self, *args, **kwargs): return self.__dictionary.__setattr__(*args, **kwargs) def dir(self): return self.__dictionary.__dir__() def le(self, *args, **kwargs): return self.__dictionary.__le__(*args, **kwargs) def delattr(self, *args, **kwargs): return self.__dictionary.__delattr__(*args, **kwargs) def hash(self, *args, **kwargs): return self.__dictionary.__hash__(*args, **kwargs) def gt(self, *args, **kwargs): return self.__dictionary.__gt__(*args, **kwargs) def eq(self, *args, **kwargs): return self.__dictionary.__eq__(*args, **kwargs) def getattribute(self, *args, **kwargs): return self.__dictionary.__getattribute__(*args, **kwargs) def str(self, *args, **kwargs): return self.__dictionary.__str__(*args, **kwargs) def reduce(self, *args, **kwargs): return self.__dictionary.__reduce__(*args, **kwargs) def reduce_ex(self, *args, **kwargs): return self.__dictionary.__reduce_ex__(*args, **kwargs) def lt(self, *args, **kwargs): return self.__dictionary.__lt__(*args, **kwargs) def keys(self): return self.get_list_of_key() def get_list_of_key(self): return [key for key in self.__dictionary.keys().__iter__()]
class DotMap(OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() self._dynamic = True # mettendo False non funzionano più i test di default. E' normale in quanto si aspettano la creazione dinamica dei figli # =================================== if LORETO: global MY_DICT_TYPES # global var per la classe self._dynamic = False # mettendo False non funzionano più i test di default. E' normale in quanto si aspettano la creazione dinamica dei figli MY_DICT_TYPES = [dict, DotMap, OrderedDict] # by Loreto (DEFAULT dictionary) # =================================== if kwargs: if '_dynamic' in kwargs: self._dynamic = kwargs['_dynamic'] if args: d = args[0] if isinstance(d, dict): for k, v in self.__call_items(d): if type(v) is dict: v = DotMap(v, _dynamic=self._dynamic) if type(v) is list: l = [] for i in v: n = i if type(i) is dict: n = DotMap(i, _dynamic=self._dynamic) l.append(n) v = l self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): if k is not '_dynamic': self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_': # automatically extend to new DotMap self[k] = DotMap() return self._map[k] def __setattr__(self, k, v): if k in { '_map', '_dynamic', '_ipython_canary_method_should_not_exist_' }: super(DotMap, self).__setattr__(k, v) else: self[k] = v def __getattr__(self, k): if k == { '_map', '_dynamic', '_ipython_canary_method_should_not_exist_' }: super(DotMap, self).__getattr__(k) else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k, v in self.__call_items(self._map): # bizarre recursive assignment situation (why someone would do this is beyond me) if id(v) == id(self): items.append('{0}=DotMap(...)'.format(k)) else: items.append('{0}={1}'.format(k, repr(v))) out = 'DotMap({0})'.format(', '.join(items)) return out def __repr__(self): return str(self) def toDict(self): d = {} for k, v in self.items(): if type(v) is DotMap: # bizarre recursive assignment support if id(v) == id(self): v = d else: v = v.toDict() elif type(v) is list: l = [] for i in v: n = i if type(i) is DotMap: n = i.toDict() l.append(n) v = l d[k] = v return d def pprint(self): pprint(self.toDict()) # =================================== if LORETO: # MY_DICT_TYPES = [dict, DotMap] def Ptr(self, listOfQualifiers, create=False): ptr = self for item in listOfQualifiers: if item in ptr: ptr = ptr[item] else: if create: ptr[item] = DotMap() ptr = ptr[item] else: return None return ptr def KeyTree(self, fPRINT=False): return DictToList.KeyTree(self, myDictTYPES=MY_DICT_TYPES, fPRINT=fPRINT) def KeyList(self): return DictToList.KeyList(self, myDictTYPES=MY_DICT_TYPES) def PrintTree(self, fEXIT=False, maxDepth=10, header=None, whatPrint='LTKV', stackLevel=1): PrintDictionaryTree.PrintDictionary(self, myDictTYPES=MY_DICT_TYPES, whatPrint=whatPrint, fEXIT=fEXIT, maxDepth=maxDepth, header=header, stackLevel=stackLevel + 1) printDict = PrintTree printTree = PrintTree def GetValue(self, listOfQualifiers=[], fPRINT=False): return DictToList.getValue(self, listOfQualifiers=listOfQualifiers, myDictTYPES=MY_DICT_TYPES, fPRINT=fPRINT) # =================================== def empty(self): return (not any(self)) # proper dict subclassing def values(self): return self._map.values() # ipython support def __dir__(self): return self.keys() @classmethod def parseOther(self, other): if type(other) is DotMap: return other._map else: return other def __cmp__(self, other): other = DotMap.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return DotMap(self.toDict()) def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = DotMap() d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d)
class ChainSet(object): """ Base class for various methods to rename chains Contains _chains, which maps from the renamed chain to a tuple with the original (object,state,chain). All dict-like accessors work on ChainSets, e.g. chain_set["A"] -> ("obj",1,"A") """ def __init__(self): # Use an OrderedDict in Python >= 1.7 for better printing if _orderedDict: self._chains = OrderedDict() else: self._chains = dict() def map_chain(self, obj, state, origChain): """ map_chain(string obj,int state, string chain]]) -> string Maps a chain letter to a unique chainID. Results are unique within each instance, and can be used as keys on this chain set. """ raise NotImplementedError("Base class") # delegate most methods to _chains def __getattr__(self, at): if at in "pop popitem update setdefault".split(): raise AttributeError("type object '%s' has no attribute '%s'" % (type(self), at)) return getattr(self._chains, at) def __cmp__(self, other): return self._chains.__cmp__(other) def __eq__(self, other): return self._chains.__eq__(other) def __ge__(self, other): return self._chains.__ge__(other) def __gt__(self, other): return self._chains.__gt__(other) def __le__(self, other): return self._chains.__le__(other) def __lt__(self, other): return self._chains.__lt__(other) def __ne__(self, other): return self._chains.__ne__(other) def __len__(self): return self._chains.__len__() def __contains__(self, key): return self._chains.__contains__(key) def __getitem__(self, key): return self._chains.__getitem__(key) def __iter__(self): return self._chains.__iter__() def __str__(self): return str(self._chains) @staticmethod def _int_to_chain(i, base=_default_base): """ _int_to_chain(int,int) -> str Converts a positive integer to a chain ID. Chain IDs include uppercase characters, numbers, and optionally lowercase letters. i = a positive integer to convert base = the alphabet size to include. Typically 36 or 62. """ if i < 0: raise ValueError("positive integers only") if base < 0 or 62 < base: raise ValueError("Invalid base") quot = int(i) // base rem = i % base if rem < 26: letter = chr(ord("A") + rem) elif rem < 36: letter = str(rem - 26) else: letter = chr(ord("a") + rem - 36) if quot == 0: return letter else: return ChainSet._int_to_chain(quot - 1, base) + letter
class Config(MutableMapping, OrderedDict): @classmethod def load(cls, file_path): with open(file_path) as f: params = yaml.load(f.read(), Loader=yaml.FullLoader) # We expand ~ in those yaml entries with `path` # on their keys for making # config files more platform-independent params = { key: (os.path.expanduser(value) if "path" in key and value is not None else value) for key, value in params.items() } return cls(params) def dump(self, file_path): with open(file_path, "w") as f: d = self.to_dict() f.write(yaml.dump(d)) def __init__(self, *args, **kwargs): self._map = OrderedDict() if args: d = args[0] # for recursive assignment handling trackedIDs = {id(d): self} if isinstance(d, dict): for k, v in self.__call_items(d): if isinstance(v, dict): if id(v) in trackedIDs: v = trackedIDs[id(v)] else: v = self.__class__(v) trackedIDs[id(v)] = v if type(v) is list: l = [] for i in v: n = i if isinstance(i, dict): n = self.__class__(i) l.append(n) v = l self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): self._map[k] = v _path_state = list() def __call_items(self, obj): if hasattr(obj, "iteritems") and ismethod(getattr(obj, "iteritems")): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): # print('Called __setitem__') if (k in self._map and not self._map[k] is None and not isinstance(v, type(self._map[k]))): if v is not None: raise ValueError( f"Updating existing value {type(self._map[k])} " f"with different type ({type(v)}).") split_path = k.split(".") current_option = self._map for p in split_path[:-1]: current_option = current_option[p] current_option[split_path[-1]] = v def __getitem__(self, k): split_path = k.split(".") current_option = self._map for p in split_path: if p not in current_option: raise KeyError(p) current_option = current_option[p] return current_option def __setattr__(self, k, v): if k in {"_map", "_ipython_canary_method_should_not_exist_"}: super(Config, self).__setattr__(k, v) else: self[k].update(v) def __getattr__(self, k): if k in {"_map", "_ipython_canary_method_should_not_exist_"}: return super(Config, self).__getattr__(k) try: v = super(self.__class__, self).__getattribute__(k) return v except AttributeError: self._path_state.append(k) pass return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __add__(self, other): if self.empty(): return other else: self_type = type(self).__name__ other_type = type(other).__name__ msg = "unsupported operand type(s) for +: '{}' and '{}'" raise TypeError(msg.format(self_type, other_type)) def __str__(self): items = [] for k, v in self.__call_items(self._map): # recursive assignment case if id(v) == id(self): items.append("{0}={1}(...)".format(k, self.__class__.__name__)) else: items.append("{0}={1}".format(k, repr(v))) joined = ", ".join(items) out = "{0}({1})".format(self.__class__.__name__, joined) return out def __repr__(self): return str(self) def to_dict(self, flatten=False, parent_key="", sep="."): d = {} for k, v in self.items(): if issubclass(type(v), Config): # bizarre recursive assignment support if id(v) == id(self): v = d else: v = v.to_dict() elif type(v) in (list, tuple): l = [] for i in v: n = i if issubclass(type(i), Config): n = i.to_dict() l.append(n) if type(v) is tuple: v = tuple(l) else: v = l d[k] = v if flatten: d = flatten_dict(d, parent_key=parent_key, sep=sep) return d def pprint(self, ): pprint(self.to_dict()) def empty(self): return not any(self) # proper dict subclassing def values(self): return self._map.values() # ipython support def __dir__(self): return list(self.keys()) def _ipython_key_completions_(self): return list(self.keys()) @classmethod def parseOther(cls, other): if issubclass(type(other), Config): return other._map else: return other def __cmp__(self, other): other = Config.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = Config.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = Config.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = Config.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = Config.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = Config.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = Config.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return self.__class__(self) def __copy__(self): return self.copy() def __deepcopy__(self, memo=None): return self.copy() def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) == 1: for key, value in args[0].items(): if key in self and isinstance(self[key], dict): if value is None: self[key] = value else: self[key].update(value) else: pass raise ValueError() elif len(args) > 1: raise NotImplementedError # self._map.update(*args) else: raise NotImplementedError def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = cls() d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d) # bannerStr def _getListStr(self, items): out = "[" mid = "" for i in items: mid += " {}\n".format(i) if mid != "": mid = "\n" + mid out += mid out += "]" return out def _getValueStr(self, k, v): outV = v multiLine = len(str(v).split("\n")) > 1 if multiLine: # push to next line outV = "\n" + v if type(v) is list: outV = self._getListStr(v) out = "{} {}".format(k, outV) return out def _getSubMapDotList(self, pre, name, subMap): outList = [] if pre == "": pre = name else: pre = "{}.{}".format(pre, name) def stamp(pre, k, v): valStr = self._getValueStr(k, v) return "{}.{}".format(pre, valStr) for k, v in subMap.items(): if isinstance(v, Config) and v != Config(): subList = self._getSubMapDotList(pre, k, v) outList.extend(subList) else: outList.append(stamp(pre, k, v)) return outList def _getSubMapStr(self, name, subMap): outList = ["== {} ==".format(name)] for k, v in subMap.items(): if isinstance(v, self.__class__) and v != self.__class__(): # break down to dots subList = self._getSubMapDotList("", k, v) # add the divit # subList = ['> {}'.format(i) for i in subList] outList.extend(subList) else: out = self._getValueStr(k, v) # out = '> {}'.format(out) out = "{}".format(out) outList.append(out) finalOut = "\n".join(outList) return finalOut def bannerStr(self): lines = [] previous = None for k, v in self.items(): if previous == self.__class__.__name__: lines.append("-") out = "" if isinstance(v, self.__class__): name = k subMap = v out = self._getSubMapStr(name, subMap) lines.append(out) previous = self.__class__.__name__ else: out = self._getValueStr(k, v) lines.append(out) previous = "other" lines.append("--") s = "\n".join(lines) return s
class DotMap(OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() self._dynamic = True if kwargs: if '_dynamic' in kwargs: self._dynamic = kwargs['_dynamic'] if args: d = args[0] if isinstance(d, dict): for k,v in self.__call_items(d): if type(v) is dict: v = DotMap(v, _dynamic=self._dynamic) if type(v) is list: l = [] for i in v: n = i if type(i) is dict: n = DotMap(i, _dynamic=self._dynamic) l.append(n) v = l self._map[k] = v if kwargs: for k,v in self.__call_items(kwargs): if k is not '_dynamic': self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_': # automatically extend to new DotMap self[k] = DotMap() return self._map[k] def __setattr__(self, k, v): if k in {'_map','_dynamic', '_ipython_canary_method_should_not_exist_'}: super(DotMap, self).__setattr__(k,v) else: self[k] = v def __getattr__(self, k): if k == {'_map','_dynamic','_ipython_canary_method_should_not_exist_'}: super(DotMap, self).__getattr__(k) else: return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __str__(self): items = [] for k,v in self.__call_items(self._map): # bizarre recursive assignment situation (why someone would do this is beyond me) if id(v) == id(self): items.append('{0}=DotMap(...)'.format(k)) else: items.append('{0}={1}'.format(k, repr(v))) out = 'DotMap({0})'.format(', '.join(items)) return out def __repr__(self): return str(self) def toDict(self): d = {} for k,v in self.items(): if type(v) is DotMap: # bizarre recursive assignment support if id(v) == id(self): v = d else: v = v.toDict() elif type(v) is list: l = [] for i in v: n = i if type(i) is DotMap: n = i.toDict() l.append(n) v = l d[k] = v return d def pprint(self): pprint(self.toDict()) def empty(self): return (not any(self)) # proper dict subclassing def values(self): return self._map.values() # ipython support def __dir__(self): return self.keys() @classmethod def parseOther(self, other): if type(other) is DotMap: return other._map else: return other def __cmp__(self, other): other = DotMap.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return DotMap(self.toDict()) def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = DotMap() d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d)
class DotMap(MutableMapping, OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() self._dynamic = True if kwargs: if "_dynamic" in kwargs: self._dynamic = kwargs["_dynamic"] if args: d = args[0] # for recursive assignment handling trackedIDs = {id(d): self} if isinstance(d, dict): for k, v in self.__call_items(d): if isinstance(v, dict): if id(v) in trackedIDs: v = trackedIDs[id(v)] else: v = self.__class__(v, _dynamic=self._dynamic) trackedIDs[id(v)] = v if type(v) is list: l = [] for i in v: n = i if isinstance(i, dict): n = self.__class__(i, _dynamic=self._dynamic) l.append(n) v = l self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): if k is not "_dynamic": self._map[k] = v def __call_items(self, obj): if hasattr(obj, "iteritems") and ismethod(getattr(obj, "iteritems")): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): return self._map[k] def __setattr__(self, k, v): if k in { "_map", "_dynamic", "_ipython_canary_method_should_not_exist_", }: super(DotMap, self).__setattr__(k, v) else: self[k] = v def __getattr__(self, k): if k in { "_map", "_dynamic", "_ipython_canary_method_should_not_exist_", }: return super(DotMap, self).__getattr__(k) try: v = super(self.__class__, self).__getattribute__(k) return v except AttributeError: pass return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __add__(self, other): if self.empty(): return other else: self_type = type(self).__name__ other_type = type(other).__name__ msg = "unsupported operand type(s) for +: '{}' and '{}'" raise TypeError(msg.format(self_type, other_type)) def __str__(self): items = [] for k, v in self.__call_items(self._map): # recursive assignment case if id(v) == id(self): items.append("{0}={1}(...)".format(k, self.__class__.__name__)) else: seperator = "\n" if isinstance(v, DotMap) else " " attr_str = f"{k}:{seperator}{v}" attr_str = self._indent(attr_str, 2) items.append(attr_str) joined = "\n".join(items) return joined def __repr__(self): return str(self) def toDict(self): d = {} for k, v in self.items(): if issubclass(type(v), DotMap): # bizarre recursive assignment support if id(v) == id(self): v = d else: v = v.toDict() elif type(v) in (list, tuple): l = [] for i in v: n = i if issubclass(type(i), DotMap): n = i.toDict() l.append(n) if type(v) is tuple: v = tuple(l) else: v = l d[k] = v return d def pprint(self, pformat="dict"): if pformat == "json": print(dumps(self.toDict(), indent=4, sort_keys=True)) else: pprint(self.toDict()) def empty(self): return not any(self) # proper dict subclassing def values(self): return self._map.values() # # ipython support def __dir__(self): return self.keys() @classmethod def parseOther(self, other): if issubclass(type(other), DotMap): return other._map else: return other def __cmp__(self, other): other = DotMap.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return self.__class__(self) def __copy__(self): return self.copy() def __deepcopy__(self, memo=None): return self.copy() def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): return self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = cls() d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d) # bannerStr def _getListStr(self, items): out = "[" mid = "" for i in items: mid += " {}\n".format(i) if mid != "": mid = "\n" + mid out += mid out += "]" return out def _getValueStr(self, k, v): outV = v multiLine = len(str(v).split("\n")) > 1 if multiLine: # push to next line outV = "\n" + v if type(v) is list: outV = self._getListStr(v) out = "{} {}".format(k, outV) return out def _getSubMapDotList(self, pre, name, subMap): outList = [] if pre == "": pre = name else: pre = "{}.{}".format(pre, name) def stamp(pre, k, v): valStr = self._getValueStr(k, v) return "{}.{}".format(pre, valStr) for k, v in subMap.items(): if isinstance(v, DotMap) and v != DotMap(): subList = self._getSubMapDotList(pre, k, v) outList.extend(subList) else: outList.append(stamp(pre, k, v)) return outList def _getSubMapStr(self, name, subMap): outList = ["== {} ==".format(name)] for k, v in subMap.items(): if isinstance(v, self.__class__) and v != self.__class__(): # break down to dots subList = self._getSubMapDotList("", k, v) # add the divit # subList = ['> {}'.format(i) for i in subList] outList.extend(subList) else: out = self._getValueStr(k, v) # out = '> {}'.format(out) out = "{}".format(out) outList.append(out) finalOut = "\n".join(outList) return finalOut def bannerStr(self): lines = [] previous = None for k, v in self.items(): if previous == self.__class__.__name__: lines.append("-") out = "" if isinstance(v, self.__class__): name = k subMap = v out = self._getSubMapStr(name, subMap) lines.append(out) previous = self.__class__.__name__ else: out = self._getValueStr(k, v) lines.append(out) previous = "other" lines.append("--") s = "\n".join(lines) return s def _indent(self, s_, num_spaces): s = s_.split("\n") if len(s) == 1: return s_ first = s.pop(0) s = [(num_spaces * " ") + line for line in s] s = "\n".join(s) s = first + "\n" + s return s
class DotMap(MutableMapping, OrderedDict): def __init__(self, *args, **kwargs): self._map = OrderedDict() self._dynamic = kwargs.pop('_dynamic', True) self._prevent_method_masking = kwargs.pop('_prevent_method_masking', False) trackedIDs = kwargs.pop('_trackedIDs', {}) if args: d = args[0] # for recursive assignment handling trackedIDs[id(d)] = self src = [] if isinstance(d, MutableMapping): src = self.__call_items(d) elif isinstance(d, Iterable): src = d for k, v in src: if self._prevent_method_masking and k in reserved_keys: raise KeyError('"{}" is reserved'.format(k)) if isinstance(v, dict): idv = id(v) if idv in trackedIDs: v = trackedIDs[idv] else: trackedIDs[idv] = v v = self.__class__(v, _dynamic=self._dynamic, _prevent_method_masking=self. _prevent_method_masking, _trackedIDs=trackedIDs) if type(v) is list: l = [] for i in v: n = i if isinstance(i, dict): idi = id(i) if idi in trackedIDs: n = trackedIDs[idi] else: trackedIDs[idi] = i n = self.__class__( i, _dynamic=self._dynamic, _prevent_method_masking=self. _prevent_method_masking) l.append(n) v = l self._map[k] = v if kwargs: for k, v in self.__call_items(kwargs): if self._prevent_method_masking and k in reserved_keys: raise KeyError('"{}" is reserved'.format(k)) self._map[k] = v def __call_items(self, obj): if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')): return obj.iteritems() else: return obj.items() def items(self): return self.iteritems() def iteritems(self): return self.__call_items(self._map) def __iter__(self): return self._map.__iter__() def next(self): return self._map.next() def __setitem__(self, k, v): self._map[k] = v def __getitem__(self, k): if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_': # automatically extend to new DotMap self[k] = self.__class__() return self._map[k] def __setattr__(self, k, v): if k in { '_map', '_dynamic', '_ipython_canary_method_should_not_exist_', '_prevent_method_masking' }: super(DotMap, self).__setattr__(k, v) elif self._prevent_method_masking and k in reserved_keys: raise KeyError('"{}" is reserved'.format(k)) else: self[k] = v def __getattr__(self, k): if k.startswith('__') and k.endswith('__'): raise AttributeError(k) if k in { '_map', '_dynamic', '_ipython_canary_method_should_not_exist_' }: return super(DotMap, self).__getattr__(k) try: v = super(self.__class__, self).__getattribute__(k) return v except AttributeError: pass return self[k] def __delattr__(self, key): return self._map.__delitem__(key) def __contains__(self, k): return self._map.__contains__(k) def __add__(self, other): if self.empty(): return other else: self_type = type(self).__name__ other_type = type(other).__name__ msg = "unsupported operand type(s) for +: '{}' and '{}'" raise TypeError(msg.format(self_type, other_type)) def __str__(self, seen=None): items = [] seen = {id(self)} if seen is None else seen for k, v in self.__call_items(self._map): # circular assignment case if isinstance(v, self.__class__): if id(v) in seen: items.append('{0}={1}(...)'.format( k, self.__class__.__name__)) else: seen.add(id(v)) items.append('{0}={1}'.format(k, v.__str__(seen))) else: items.append('{0}={1}'.format(k, repr(v))) joined = ', '.join(items) out = '{0}({1})'.format(self.__class__.__name__, joined) return out def __repr__(self): return str(self) def toDict(self, seen=None): if seen is None: seen = {} d = {} seen[id(self)] = d for k, v in self.items(): if issubclass(type(v), DotMap): idv = id(v) if idv in seen: v = seen[idv] else: v = v.toDict(seen=seen) elif type(v) in (list, tuple): l = [] for i in v: n = i if issubclass(type(i), DotMap): idv = id(n) if idv in seen: n = seen[idv] else: n = i.toDict(seen=seen) l.append(n) if type(v) is tuple: v = tuple(l) else: v = l d[k] = v return d def pprint(self, pformat='dict'): if pformat == 'json': print(dumps(self.toDict(), indent=4, sort_keys=True)) else: pprint(self.toDict()) def empty(self): return (not any(self)) # proper dict subclassing def values(self): return self._map.values() # ipython support def __dir__(self): return self.keys() @classmethod def parseOther(self, other): if issubclass(type(other), DotMap): return other._map else: return other def __cmp__(self, other): other = DotMap.parseOther(other) return self._map.__cmp__(other) def __eq__(self, other): other = DotMap.parseOther(other) if not isinstance(other, dict): return False return self._map.__eq__(other) def __ge__(self, other): other = DotMap.parseOther(other) return self._map.__ge__(other) def __gt__(self, other): other = DotMap.parseOther(other) return self._map.__gt__(other) def __le__(self, other): other = DotMap.parseOther(other) return self._map.__le__(other) def __lt__(self, other): other = DotMap.parseOther(other) return self._map.__lt__(other) def __ne__(self, other): other = DotMap.parseOther(other) return self._map.__ne__(other) def __delitem__(self, key): return self._map.__delitem__(key) def __len__(self): return self._map.__len__() def clear(self): self._map.clear() def copy(self): return self.__class__(self) def __copy__(self): return self.copy() def __deepcopy__(self, memo=None): return self.copy() def get(self, key, default=None): return self._map.get(key, default) def has_key(self, key): return key in self._map def iterkeys(self): return self._map.iterkeys() def itervalues(self): return self._map.itervalues() def keys(self): return self._map.keys() def pop(self, key, default=None): return self._map.pop(key, default) def popitem(self): return self._map.popitem() def setdefault(self, key, default=None): return self._map.setdefault(key, default) def update(self, *args, **kwargs): if len(args) != 0: self._map.update(*args) self._map.update(kwargs) def viewitems(self): return self._map.viewitems() def viewkeys(self): return self._map.viewkeys() def viewvalues(self): return self._map.viewvalues() @classmethod def fromkeys(cls, seq, value=None): d = cls() d._map = OrderedDict.fromkeys(seq, value) return d def __getstate__(self): return self.__dict__ def __setstate__(self, d): self.__dict__.update(d) # bannerStr def _getListStr(self, items): out = '[' mid = '' for i in items: mid += ' {}\n'.format(i) if mid != '': mid = '\n' + mid out += mid out += ']' return out def _getValueStr(self, k, v): outV = v multiLine = len(str(v).split('\n')) > 1 if multiLine: # push to next line outV = '\n' + v if type(v) is list: outV = self._getListStr(v) out = '{} {}'.format(k, outV) return out def _getSubMapDotList(self, pre, name, subMap): outList = [] if pre == '': pre = name else: pre = '{}.{}'.format(pre, name) def stamp(pre, k, v): valStr = self._getValueStr(k, v) return '{}.{}'.format(pre, valStr) for k, v in subMap.items(): if isinstance(v, DotMap) and v != DotMap(): subList = self._getSubMapDotList(pre, k, v) outList.extend(subList) else: outList.append(stamp(pre, k, v)) return outList def _getSubMapStr(self, name, subMap): outList = ['== {} =='.format(name)] for k, v in subMap.items(): if isinstance(v, self.__class__) and v != self.__class__(): # break down to dots subList = self._getSubMapDotList('', k, v) # add the divit # subList = ['> {}'.format(i) for i in subList] outList.extend(subList) else: out = self._getValueStr(k, v) # out = '> {}'.format(out) out = '{}'.format(out) outList.append(out) finalOut = '\n'.join(outList) return finalOut def bannerStr(self): lines = [] previous = None for k, v in self.items(): if previous == self.__class__.__name__: lines.append('-') out = '' if isinstance(v, self.__class__): name = k subMap = v out = self._getSubMapStr(name, subMap) lines.append(out) previous = self.__class__.__name__ else: out = self._getValueStr(k, v) lines.append(out) previous = 'other' lines.append('--') s = '\n'.join(lines) return s