From 034602dfd9f7e1a54f0930d359c3c400423fefaf Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 30 Jun 2011 17:08:24 +0530 Subject: [PATCH] pretty print of doclists --- cgi-bin/webnotes/model/doclist.py | 18 ++-- cgi-bin/webnotes/model/utils.py | 98 ++++++++++++++++++ cgi-bin/webnotes/modules/export_module.py | 9 +- cgi-bin/webnotes/modules/import_module.py | 4 +- cgi-bin/webnotes/utils/__init__.py | 119 ++++++++++++---------- cgi-bin/webnotes/widgets/form.py | 2 +- 6 files changed, 183 insertions(+), 67 deletions(-) diff --git a/cgi-bin/webnotes/model/doclist.py b/cgi-bin/webnotes/model/doclist.py index 778164f083..28e25840fc 100644 --- a/cgi-bin/webnotes/model/doclist.py +++ b/cgi-bin/webnotes/model/doclist.py @@ -32,19 +32,23 @@ class DocList: self.docs = expand(data) self.objectify(docname) - def objectify(self, docname): + def objectify(self, docname=None): """ Converts self.docs from a list of dicts to list of Documents """ from webnotes.model.doc import Document self.docs = [Document(fielddata=d) for d in self.docs] - self.children = [] - for d in self.docs: - if d.name == docname: - self.doc = d - else: - self.children.append(d) + if not docname: + self.doc, self.children = self.docs[0], self.docs[1:] + + else: + self.children = [] + for d in self.docs: + if d.name == docname: + self.doc = d + else: + self.children.append(d) def make_obj(self): """ diff --git a/cgi-bin/webnotes/model/utils.py b/cgi-bin/webnotes/model/utils.py index 3de5dfe997..0d692d8f93 100644 --- a/cgi-bin/webnotes/model/utils.py +++ b/cgi-bin/webnotes/model/utils.py @@ -167,3 +167,101 @@ def to_html(doclist): out += _make_html(d, link_lists[d.doctype]) return out + +def commonify_doclist(doclist): + """ + Makes a doclist more readable by extracting common properties. + This is used for printing Documents in files + """ + from webnotes.utils import get_common_dict, get_diff_dict + + def make_common(doclist): + c = {} + if with_comments: + c['##comment'] = 'These values are common in all dictionaries' + for k in common_keys: + c[k] = doclist[0][k] + return c + + def strip_common(d): + for k in common_keys: + if k in d: del d[k] + return d + + def make_common_dicts(doclist): + + common_dict = {} # one per doctype + + # make common dicts for all records + for d in doclist: + if not d['doctype'] in common_dict: + d1 = d.copy() + del d1['name'] + common_dict[d['doctype']] = d1 + else: + common_dict[d['doctype']] = get_common_dict(common_dict[d['doctype']], d) + return common_dict + + common_keys = ['owner','docstatus','creation','modified','modified_by'] + common_dict = make_common_dicts(doclist) + + # make docs + final = [] + for d in doclist: + f = strip_common(get_diff_dict(common_dict[d['doctype']], d)) + f['doctype'] = d['doctype'] # keep doctype! + + # strip name for child records (only an auto generated number!) + if f['doctype'] != doclist[0]['doctype']: + del f['name'] + + if with_comments: + f['##comment'] = d['doctype'] + ('name' in f and (', ' + f['name']) or '') + final.append(f) + + # add commons + commons = [] + for d in common_dict.values(): + d['name']='__common__' + if with_comments: + d['##comment'] = 'These values are common for all ' + d['doctype'] + commons.append(strip_common(d)) + + common_values = make_common(doclist) + return [common_values]+commons+final + +def uncommonify_doclist(dl): + """ + Expands an commonified doclist + """ + common_values = dl[0] + common_dict = {} + final = [] + + for d in dl[1:]: + if d['name']=='__common__': + del d['name'] + common_dict[d['doctype']] = d + else: + d1 = common_values.copy() + d1.update(common_dict[d['doctype']]) + d1.update(d) + final.append(d1) + + return final + +def pprint_doclist(doclist, with_comments = 1): + """ + Pretty Prints a doclist with common keys separated and comments + """ + from webnotes.utils import pprint_dict + + dictlist =[pprint_dict(d) for d in commonify_doclist(doclist, with_comments)] + title = '# '+doclist[0]['doctype']+', '+doclist[0]['name'] + return title + '\n[\n' + ',\n'.join(dictlist) + '\n]' + +def peval_doclist(txt): + """ + Restore a pretty printed doclist + """ + return uncommonify_doclist(eval(txt)) diff --git a/cgi-bin/webnotes/modules/export_module.py b/cgi-bin/webnotes/modules/export_module.py index b200ffb64a..c9bad8650c 100644 --- a/cgi-bin/webnotes/modules/export_module.py +++ b/cgi-bin/webnotes/modules/export_module.py @@ -69,7 +69,7 @@ def write_document_file(doclist, record_module=None): Write a doclist to file, can optionally specify module name """ import os - from webnotes.utils import pprint_dict + from webnotes.utils import pprint_doclist module = get_module_name(doclist, record_module) @@ -84,10 +84,11 @@ def write_document_file(doclist, record_module=None): # write the data file fname = (code_type and scrub(doclist[0]['name'])) or doclist[0]['name'] - dict_list = [pprint_dict(d) for d in doclist] - txtfile = open(os.path.join(folder, fname +'.txt'),'w+') - txtfile.write('[\n' + ',\n'.join(dict_list) + '\n]') + txtfile = open(os.path.join(folder, fname +'.txt'),'w+') + txtfile.write(pprint_doclist(doclist)) + #dict_list = [pprint_dict(d) for d in doclist] + #txtfile.write('[\n' + ',\n'.join(dict_list) + '\n]') txtfile.close() def clear_code_fields(doclist, folder, code_type): diff --git a/cgi-bin/webnotes/modules/import_module.py b/cgi-bin/webnotes/modules/import_module.py index d0cb048bdd..6be48d646b 100644 --- a/cgi-bin/webnotes/modules/import_module.py +++ b/cgi-bin/webnotes/modules/import_module.py @@ -37,12 +37,14 @@ def import_module(module, verbose=0): def get_doclist(path, doctype, docname): "returns a doclist (list of dictionaries) of multiple records for the given parameters" import os + from webnotes.utils import peval_doclist + do_not_import = ('control_panel') fname = os.path.join(path,doctype,docname,docname+'.txt') if os.path.exists(fname) and (doctype not in do_not_import): f = open(fname,'r') - dl = eval(f.read()) + dl = peval_doclist(f.read()) f.close() return dl else: diff --git a/cgi-bin/webnotes/utils/__init__.py b/cgi-bin/webnotes/utils/__init__.py index 9231c6f057..7a253d9fe2 100644 --- a/cgi-bin/webnotes/utils/__init__.py +++ b/cgi-bin/webnotes/utils/__init__.py @@ -532,78 +532,89 @@ def send_error_report(): ''' % (m, form.getvalue('msg') or '', form.getvalue('err_msg')) sendmail([webnotes.conn.get_value('Control Panel',None,'support_email_id') or 'support@iwebnotes.com'], sender=webnotes.session['user'], msg=err_msg, subject='Error Report '+m) -# pretty print a dict +# Dictionary utils # ============================================================================== +def remove_blanks(d): + """ + Returns d with empty ('' or None) values stripped + """ + empty_keys = [] + for key in d: + if d[key]=='' or d[key]==None: + # del d[key] raises runtime exception, using a workaround + empty_keys.append(key) + for key in empty_keys: + del d[key] + + return d + def pprint_dict(d, level=1, no_blanks=True): + """ + Pretty print a dictionary with indents + """ if no_blanks: - empty_keys = [] - for key in d: - if d[key]=='' or d[key]==None: - # del d[key] raises runtime exception, using a workaround - empty_keys.append(key) - for key in empty_keys: - del d[key] - indent = '' - for i in range(0,level): - indent += '\t' - lines = [] + remove_blanks(d) + + # make indent + indent, ret = '', '' + for i in range(0,level): indent += '\t' + + # add lines + comment, lines = '', [] kl = d.keys() kl.sort() + + # make lines for key in kl: - tmp = {key: d[key]} - lines.append(indent + str(tmp)[1:-1] ) - return indent + '{\n' \ - + indent + ',\n\t'.join(lines) \ - + '\n' + indent + '}' + if key != '##comment': + tmp = {key: d[key]} + lines.append(indent + str(tmp)[1:-1] ) + + # add comment string + if '##comment' in kl: + ret = ('\n' + indent) + '# ' + d['##comment'] + '\n' + # open + ret += indent + '{\n' + + # lines + ret += indent + ',\n\t'.join(lines) + + # close + ret += '\n' + indent + '}' + + return ret + def get_common(d1,d2): """ returns (list of keys) the common part of two dicts """ return [p for p in d1 if p in d2 and d1[p]==d2[p]] -def min_lod(listt): +def get_common_dict(d1, d2): """ - minimized a list of dictionaries using '_from_prev' + return common dictionary of d1 and d2 """ - import copy - l = copy.deepcopy(listt) - prev = {} - for dic in l: - common = get_common(prev,dic) - prev = dic - for i in common : del dic[i] - if not common==[] : dic['_from_prev']= ','.join(str(p) for p in common) - return l + ret = {} + for key in d1: + if key in d2 and d2[key]==d1[key]: + ret[key] = d1[key] + return ret -def max_lod(listt): +def get_diff_dict(d1, d2): """ - maximizes a list of dictionaries using '_from_prev' + return common dictionary of d1 and d2 """ - import copy - l = copy.deepcopy(listt) - prev = {} - for dic in l: - if '_from_prev' in dic: - prevs = dic['_from_prev'].split(',') - for p in prevs : dic[p] = prev[p] - del dic['_from_prev'] - prev = dic - return l + diff_keys = set(d2.keys()).difference(set(d1.keys())) + + ret = {} + for d in diff_keys: ret[d] = d2[d] + return ret -def pprint_lod(l, level=1, no_blanks=True): - """ - returns pretty print string for list of dictionaries - """ - l = min_lod(l) - dictlist = [pprint_dict(d) for d in l] - return '[\n' + ',\n'.join(dictlist) + '\n]' -def peval_lod(string): - """ - pretty eval a pretty printed list of dictionaries (using ) - """ - strdict = eval(string) - strdict = max_lod(strdict) - return strdict + + + + + diff --git a/cgi-bin/webnotes/widgets/form.py b/cgi-bin/webnotes/widgets/form.py index 9a3b9d4006..df75f73297 100644 --- a/cgi-bin/webnotes/widgets/form.py +++ b/cgi-bin/webnotes/widgets/form.py @@ -195,7 +195,7 @@ def runserverobj(): else: doclist = DocList() - doclist.from_compressed(form.getvalue('docs'), form.getvalue('docname')) + doclist.from_compressed(form.getvalue('docs'), dn) so = doclist.make_obj() check_guest_access(so.doc)