# """
# # Dictionary converter for extremely nested dictionary to and from to excel data tabular format
# """
import pandas as pd
# ----------------------------------------------------------------------------
INDEX_KEY_PARENTS = {'instances', 'ifphysicals', 'ifvlans', 'ifloopbacks', 'ifaggregates' }
# ----------------------------------------------------------------------------
[docs]
def varsheet(dic):
"""convert and return captured var dictionary to FIND/REPLACE pairs of dict
to generate the DataFrame.
constraint: var-sheet has column names "FIND" & "REPLACE"
Args:
dic (dict): dictionary with find/replace pairs as key/value pair
Returns:
dict: dictionary which is friendly to convert to DataFrame and ultimately to Excel
"""
ndic = {'FIND':[], 'REPLACE':[]}
for k, v in dic.items():
ndic['FIND'].append(k)
ndic['REPLACE'].append(v)
return ndic
[docs]
def appendkey(dic, prefix=""):
"""add the prefix to keys of dictionary and return updated dictionary.
conjuction will be "_".
Args:
dic (dict): dictionary
prefix (str, optional): prefix to add on key while removing nesting. Defaults to "".
Returns:
dict: updated dictionary
"""
if not prefix: return dic
ndic = {}
for key, value in dic.items():
ndic[prefix + "_" + key ] = value
return ndic
[docs]
def recursive_dic(dic, prevkey=''):
"""recursive lookup in provided dictionary and serialize it to convert it to
pandas data frame which can be later used to convert to excel.
returns updated dictionary with key:[list of values]
Args:
dic (dict): nested dictionary
prevkey (str, optional): previous key to add as prefix. Defaults to ''.
Returns:
dict: updated dictionary
"""
opd = {}
for dickey, dicvalue in dic.items():
if isinstance(dicvalue, dict):
opd.update( appendkey(recursive_dic(dicvalue, dickey), dickey ))
else:
opd[dickey] = dicvalue
return opd
[docs]
def standup_dic(dic, ikp):
"""create and return a dictionary with basic basic keys/header
OBSOLETE NOW.
Args:
dic (dict): dictionary
ikp (_type_): basic mandatory interface id/types/value
Returns:
dict: dictionary with mandatory items
"""
ndic = {'inttype':[], 'intid':[], 'intvalues':[]}
for dickey, dicvalue in dic.items():
for dicvaluek, dicvaluev in dicvalue.items():
if dickey in ikp:
ndic['inttype'].append(dickey)
ndic['intid'].append(dicvaluek)
else:
ndic['inttype'].append('')
ndic['intid'].append('')
ndic['intvalues'].append(dicvaluev) # Hungami
return ndic
[docs]
def expand_var_dict(dic):
"""rollback of varsheet(), revert the values to its original dictionary format.
Args:
dic (dict): dictionary
Returns:
dict: updated dictionary
"""
return {k:v for k, v in zip(dic['FIND'].values(), dic['REPLACE'].values() )}
[docs]
def expand_table_dict(dic):
"""rollback of recursive_dic(), revert the key:value nested pairs to its original position.
returns nested dictionary
Args:
dic (dict): dictionary
Returns:
dict: updated dictionary
"""
opd = {}
inttypeset = set(dic['inttype'].values())
for i, intid in dic['intid'].items():
respectiveinttype = dic['inttype'][i]
if not opd.get(respectiveinttype):
opd[respectiveinttype] = {}
if not opd[respectiveinttype].get(intid):
opd[respectiveinttype][intid] = {}
diccopy = dic.copy()
for k, v in diccopy.items():
if k in ('intid', 'inttype'): continue
keys = k.split("_")
for i, vitem in v.items():
if not vitem: continue
respectiveinttype = dic['inttype'][i]
respectiveint = dic['intid'][i]
dd = opd[respectiveinttype][respectiveint]
opd[respectiveinttype][respectiveint] = update_nested_key(dd, keys, vitem)
for k, v in diccopy.items():
del(dic[k])
return opd
[docs]
def update_nested_key(dic, keys, vitem):
"""add the nested keys in dictionary if missing, update value for trailing key,
and returns updated dictionary
Args:
dic (dict): dictionary
keys (str): keys
vitem (str,iterator,dict): any nested items
Returns:
dict: updated dictionary
"""
nd = dic
for i, key in enumerate(keys):
if i > 0:
nd = dic[prevkey]
if not nd.get(key): nd[key] = {}
prevkey = key
nd[key] = vitem
return dic
# ----------------------------------------------------------------------------
# Class to convert dictionary
# ----------------------------------------------------------------------------
[docs]
class ConvDict():
"""convert dictionary to and from between nested and serialzed format
"""
def __init__(self, dic=None):
"""initialize object
Args:
dic (dict, optional): dictionary to be convert to. Defaults to None.
"""
self.dic = dic
self.set_var_table_keys()
self.set_index_keys_parents()
[docs]
def set_var_table_keys(self, var='var', table='table'):
"""standup variable of tab name, static variables:var , tabular data:table
Args:
var (str, optional): static find/replace kind data variable referance. Defaults to 'var'.
table (str, optional): tabular data variable referance. Defaults to 'table'.
"""
self.var = var
self.table = table
[docs]
def set_index_keys_parents(self, ikp=INDEX_KEY_PARENTS):
"""set the parents of index keys
Args:
ikp (set, optional): Parent Index keys. Defaults to INDEX_KEY_PARENTS.
"""
self.index_keys_parents = ikp
[docs]
def convert_table_dic(self):
"""convert the nested table dictionary to serialized format, returns serialized dict
Returns:
dict: updated table dictionary
"""
ndic = standup_dic(self.dic[self.table], self.index_keys_parents)
ndiclen = len(ndic['intvalues'])
for i, d in enumerate(ndic['intvalues']):
rd = recursive_dic(d)
for k, v in rd.items():
if not ndic.get(k):
ndic[k] = ["" for _ in range(ndiclen)]
ndic[k][i] = v
del(ndic['intvalues'])
return ndic
[docs]
def convert_var_dic(self):
"""convert the var key:value pair to a dictionary of list of FIND/REPLACE pairs
Returns:
dict: updated var dictionary
"""
return varsheet(self.dic[self.var])
[docs]
def to_dataframe(self, sheetname):
"""convert the given sheetname dictionary to necessary serialized format and convert and
return to pandas dataframe object
Args:
sheetname (str): Sheet Name
Returns:
DataFrame: dataframe
"""
if sheetname == self.var:
return pd.DataFrame(self.convert_var_dic()).fillna("")
if sheetname == self.table:
return pd.DataFrame(self.convert_table_dic()).fillna("")
[docs]
def expand_to_dict(self, df_var, df_table):
"""expand the provided dataframes of var/table to nested dictionary and return it
Args:
df_var (DataFrame): var (find/replace) pairs dictionary
df_table (DataFrame): tabular data dictionary
Returns:
dict: dictionary of converted data
"""
d_var = df_var.to_dict()
opdv = self.expand_dfdic_to_dict(self.var, d_var)
d_table = df_table.to_dict()
opdt = self.expand_dfdic_to_dict(self.table, d_table)
opd = {self.var: opdv}
opd.update(opdt)
return opd
[docs]
def expand_dfdic_to_dict(self, sheetname, dic):
"""expand the provided dictionary to nested dictionary and return it
Args:
sheetname (str): sheet name
dic (dict): dataframe dictionary
Returns:
dict: dictionary of converted dictionary
"""
if sheetname == self.var:
return expand_var_dict(dic)
if sheetname == self.table:
return expand_table_dict(dic)
# ----------------------------------------------------------------------------
if __name__ == '__main__':
pass
# ----------------------------------------------------------------------------