#!/usr/bin/env python3 from __future__ import print_function import logging import numbers import sys class DictUtils: @staticmethod # if a value for a given key is "empty" (like '',[],{}, None etc, except for zero) then the pair is removed def cleanDictionary(dictIn): for k,v in list(dictIn.items()): if (not v) and not isinstance(v,numbers.Number): del dictIn[k] #keep going down the tree elif isinstance(v,dict): DictUtils.cleanDictionary(v) return dictIn # doesn't have to return it, but just in case one wants to use it this way instead of passing by ref @staticmethod def renormalizeKey(s): """ staticmethod renormalizeKey(s): Apply renormalization to a dictionary key, i.e., transform key to a standard format, by removing all white space and canverting to lower case. """ from isceobj.Util.StringUtils import StringUtils return StringUtils.lower_no_spaces(s) #renormalize all the keys in the dictionary @staticmethod def renormalizeKeys(dictNow): """ staticmethod renormalizeKeys(d): renormalize all keys in dictionary d by applying renormalizeKey static method. """ for k,v in list(dictNow.items()): kNow = DictUtils.renormalizeKey(k) if kNow != k: dictNow[kNow] = dictNow.pop(k) if isinstance(v,dict): DictUtils.renormalizeKeys(v) return dictNow #compares keys in dict with an input one. it's case and whitespace insensitive #if replace is true it also changes the equivalent key with k @staticmethod def keyIsIn(k,dictNow,replace = None): if(replace == None): replace = True ret = False for k1 in dictNow.keys(): if (''.join(k1.split())).lower() == (''.join(k.split())).lower(): if replace: dictNow[k] = dictNow.pop(k1) ret = True break return ret @staticmethod # update the dictionary dict1 by the value in dict2. # If the key exists and replace = True, then the value is overwritten # otherwise it is appended. # If it does not exist a new node is created. # When replace is True if spare (a list of key or single key) is defined the values of these # keys will be appended if they are not already present. Use it only for str values, i.e. for doc string def updateDictionary(dict1,dict2,replace = None,spare = None): if replace is None: replace = False if spare:#if it's a single key, put it into a list if isinstance(spare,str): spare = [spare] else: spare = [] # dict1 is the one to update for k2,v2 in dict(dict2).items(): if DictUtils.keyIsIn(k2,dict1): if isinstance(v2,dict):#if is a dict keep going down the node DictUtils.updateDictionary(dict1[k2],v2,replace,spare) else: if replace:#replace the entry append = False if k2 in spare: #check if the key needs to be spared append = True if isinstance(dict1[k2],list): if v2 in dict1[k2]: # if so then append the content append = False break else: if dict1[k2] == v2: append = False break if not append:# same key but item already in. it will rewrite it. not a big deal break if append: #convert everything into a list if not isinstance(v2,list): v2 = [v2] if not isinstance(dict1[k2],list): dict1[k2] = [dict1[k2]] #do not append if already there for v22 in v2: if v22 not in dict1[k2]: dict1[k2].append(v22) else: dict1.update({k2:v2}) else:#update only if is not the same item or the item is not already present (if dict1[k2] is a list) if isinstance(dict1[k2],list): if v2 not in dict1[k2]: # if so then append the content dict1[k2].append(v2) else: if dict1[k2] != v2: dict1[k2] = [dict1[k2],v2] else: dict1.update({k2:v2}) #probably need to create a class with some dictionary utils. put also some of the methods in Parser() # if we have a dict of dicts, keeping the structure, extract a particular key # ex. {'n1':{n1_1:{'k1':v1},{'k2':v2},n1_2:{'k1':v11},{'k2':v22}}} extract the 'k2' the result is # {'n1':{n1_1:{'k2':v2},n1_2:{'k2':v22}}}. in this case k1 could be the 'doc' string and 'k2' the units @staticmethod def extractDict(dictIn,key): import copy #put everything i dictOut = copy.deepcopy(dictIn) DictUtils.searchKey(dictIn,dictOut,key) return dictOut @staticmethod #just wrapper of the _getDictWithey so the result can be returned instead of being an argument def getDictWithKey(dictIn,key,includeKey=True): dictOut = {} DictUtils._getDictWithKey(dictIn,dictOut,key,includeKey) return dictOut @staticmethod #it returns the first occurance of {key,val} where val is the corresponding value for that key #if includeKey is True otherwise returns val def _getDictWithKey(dictIn,dictOut,key,includeKey=True): if(isinstance(dictIn,dict)): for k in dictIn.keys(): if(k == key): if includeKey: dictOut.update({k:dictIn[k]}) else: dictOut.update(dictIn[k]) break else: DictUtils._getDictWithKey(dictIn[k],dictOut,key,includeKey) @staticmethod #returns a dictionary where all the keys are removed but key def searchKey(dictIn,dictOut,key): for k,v in dictIn.items(): if(k == key): break if isinstance(v,dict): DictUtils.searchKey(v,dictOut[k],key) if dictOut[k] == {}:#if we removed everything in dictOut[k], then remove the branch dictOut.pop(k) elif (key != k):#this is a simple pair (k,v) but the key is not the one we want dictOut.pop(k) def __getstate__(self): d = dict(self.__dict__) del d['logger'] return d def __setstate__(self,d): self.__dict__.update(d) self.logger = logging.getLogger('isce.iscesys.DictUtils') def __init__(self): self.logger = logging.getLogger('isce.iscesys.DictUtils')