[Merge] Converted xml reports from xmldom to etree and better error message with environment information

bzr revid: hda@hda-20090626093432-g3q19s4eoydfr7qo
This commit is contained in:
nch
2009-06-26 15:04:32 +05:30
committed by husen daudi
3 changed files with 126 additions and 159 deletions
+68 -113
View File
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@@ -21,12 +21,11 @@
##############################################################################
import os,types
from xml.dom import minidom
from lxml import etree
import netsvc
import tools
import print_fnc
import copy
from osv.orm import browse_null, browse_record
import pooler
@@ -35,7 +34,7 @@ class InheritDict(dict):
def __init__(self, parent=None):
self.parent = parent
def __getitem__(self, name):
if name in self:
return super(InheritDict, self).__getitem__(name)
@@ -51,36 +50,32 @@ def tounicode(val):
elif isinstance(val, unicode):
unicode_val = val
else:
unicode_val = unicode(val)
unicode_val = unicode(val)
return unicode_val
class document(object):
def __init__(self, cr, uid, datas, func=False):
# create a new document
self.cr = cr
self.cr = cr
self.pool = pooler.get_pool(cr.dbname)
self.doc = minidom.Document()
self.func = func or {}
self.datas = datas
self.uid = uid
self.bin_datas = {}
def node_attrs_get(self, node):
attrs = {}
nattr = node.attributes
for i in range(nattr.length):
attr = nattr.item(i)
attrs[attr.localName] = attr.nodeValue
# attrs[attr.name] = attr.nodeValue
return attrs
if len(node.attrib):
return node.attrib
return {}
def get_value(self, browser, field_path):
fields = field_path.split('.')
if not len(fields):
return ''
value = browser
for f in fields:
if isinstance(value, list):
if len(value)==0:
@@ -90,12 +85,12 @@ class document(object):
return ''
else:
value = value[f]
if isinstance(value, browse_null) or (type(value)==bool and not value):
return ''
else:
else:
return value
def get_value2(self, browser, field_path):
value = self.get_value(browser, field_path)
if isinstance(value, browse_record):
@@ -104,10 +99,10 @@ class document(object):
return False
else:
return value
def eval(self, record, expr):
#TODO: support remote variables (eg address.title) in expr
# how to do that: parse the string, find dots, replace those dotted variables by temporary
# how to do that: parse the string, find dots, replace those dotted variables by temporary
# "simple ones", fetch the value of those variables and add them (temporarily) to the _data
# dictionary passed to eval
@@ -120,13 +115,6 @@ class document(object):
return eval(expr, {}, {'obj': record})
def parse_node(self, node, parent, browser, datas=None):
# node is the node of the xml template to be parsed
# parent = the parent node in the xml data tree we are creating
if node.nodeType == node.ELEMENT_NODE:
# convert the attributes of the node to a dictionary
attrs = self.node_attrs_get(node)
if 'type' in attrs:
if attrs['type']=='field':
@@ -134,28 +122,26 @@ class document(object):
#TODO: test this
if value == '' and 'default' in attrs:
value = attrs['default']
el = self.doc.createElement(node.localName)
parent.appendChild(el)
el_txt = self.doc.createTextNode(tounicode(value))
el.appendChild(el_txt)
el = etree.Element(node.tag)
parent.append(el)
el.text = tounicode(value)
#TODO: test this
for key, value in attrs.iteritems():
if key not in ('type', 'name', 'default'):
el.setAttribute(key, value)
el.set(key, value)
elif attrs['type']=='attachment':
if isinstance(browser, list):
model = browser[0]._table_name
else:
else:
model = browser._table_name
value = self.get_value(browser, attrs['name'])
service = netsvc.LocalService("object_proxy")
ids = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'search', [('res_model','=',model),('res_id','=',int(value))])
datas = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'read', ids)
if len(datas):
# if there are several, pick first
datas = datas[0]
@@ -169,37 +155,31 @@ class document(object):
fp.write(dt)
i = str(len(self.bin_datas))
self.bin_datas[i] = fp
el = self.doc.createElement(node.localName)
parent.appendChild(el)
# node content is the length of the image
el_txt = self.doc.createTextNode(i)
el.appendChild(el_txt)
el = etree.Element(node.tag)
el.text = i
parent.append(el)
elif attrs['type']=='data':
#TODO: test this
el = self.doc.createElement(node.localName)
parent.appendChild(el)
txt = self.datas.get('form', {}).get(attrs['name'], '')
el_txt = self.doc.createTextNode(tounicode(txt))
el.appendChild(el_txt)
el = etree.Element(node.tag)
el.text = txt
parent.append(el)
elif attrs['type']=='function':
el = self.doc.createElement(node.localName)
parent.appendChild(el)
if attrs['name'] in self.func:
txt = self.func[attrs['name']](node)
else:
txt = print_fnc.print_fnc(attrs['name'], node)
el_txt = self.doc.createTextNode(txt)
el.appendChild(el_txt)
el = etree.Element(node.tag)
el.text = txt
parent.append(el)
elif attrs['type']=='eval':
el = self.doc.createElement(node.localName)
parent.appendChild(el)
value = self.eval(browser, attrs['expr'])
el_txt = self.doc.createTextNode(str(value))
el.appendChild(el_txt)
el = etree.Element(node.tag)
el.text = str(value)
parent.append(el)
elif attrs['type']=='fields':
fields = attrs['name'].split(',')
@@ -216,26 +196,24 @@ class document(object):
keys.reverse()
v_list = [vals[k] for k in keys]
for v in v_list:
el = self.doc.createElement(node.localName)
parent.appendChild(el)
el_cld = node.firstChild
while el_cld:
for v in v_list:
el = etree.Element(node.tag)
parent.append(el)
for el_cld in node:
self.parse_node(el_cld, el, v)
el_cld = el_cld.nextSibling
elif attrs['type']=='call':
if len(attrs['args']):
#TODO: test this
#TODO: test this
# fetches the values of the variables which names where passed in the args attribute
args = [self.eval(browser, arg) for arg in attrs['args'].split(',')]
else:
args = []
# get the object
if attrs.has_key('model'):
obj = self.pool.get(attrs['model'])
else:
else:
if isinstance(browser, list):
obj = browser[0]._table
else:
@@ -244,38 +222,28 @@ class document(object):
# get the ids
if attrs.has_key('ids'):
ids = self.eval(browser, attrs['ids'])
else:
else:
if isinstance(browser, list):
ids = [b.id for b in browser]
ids = [b.id for b in browser]
else:
ids = [browser.id]
# call the method itself
newdatas = getattr(obj, attrs['name'])(self.cr, self.uid, ids, *args)
def parse_result_tree(node, parent, datas):
if node.nodeType == node.ELEMENT_NODE:
el = self.doc.createElement(node.localName)
parent.appendChild(el)
el = etree.Element(node.tag)
parent.append(el)
atr = self.node_attrs_get(node)
if 'value' in atr:
if not isinstance(datas[atr['value']], (str, unicode)):
txt = self.doc.createTextNode(str(datas[atr['value']]))
txt = str(datas[atr['value']])
else:
# txt = self.doc.createTextNode(datas[atr['value']].decode('utf-8'))
txt = self.doc.createTextNode(datas[atr['value']])
el.appendChild(txt)
txt = datas[atr['value']]
el.append(txt)
else:
el_cld = node.firstChild
while el_cld:
for el_cld in node:
parse_result_tree(el_cld, el, datas)
el_cld = el_cld.nextSibling
elif node.nodeType==node.TEXT_NODE:
el = self.doc.createTextNode(node.nodeValue)
parent.appendChild(el)
else:
pass
if not isinstance(newdatas, list):
newdatas = [newdatas]
for newdata in newdatas:
@@ -283,50 +251,38 @@ class document(object):
elif attrs['type']=='zoom':
value = self.get_value(browser, attrs['name'])
if value:
if not isinstance(value, list):
v_list = [value]
else:
v_list = value
for v in v_list:
el = self.doc.createElement(node.localName)
parent.appendChild(el)
el_cld = node.firstChild
while el_cld:
el = etree.Element(node.tag)
parent.append(el)
for el_cld in node:
self.parse_node(el_cld, el, v)
el_cld = el_cld.nextSibling
else:
# if there is no "type" attribute in the node, copy it to the xml data and parse its childs
el = self.doc.createElement(node.localName)
parent.appendChild(el)
el_cld = node.firstChild
while el_cld:
self.parse_node(el_cld, el, browser)
el_cld = el_cld.nextSibling
elif node.nodeType==node.TEXT_NODE:
# if it's a text node, copy it to the xml data
el = self.doc.createTextNode(node.nodeValue)
parent.appendChild(el)
else:
pass
for el_cld in node:
self.parse_node(el_cld, parent, browser)
def xml_get(self):
return self.doc.toxml('utf-8')
#return self.doc.toxml('utf-8')
return etree.tostring(self.doc,encoding="utf-8",xml_declaration=True)
def parse_tree(self, ids, model, context=None):
if not context:
context={}
browser = self.pool.get(model).browse(self.cr, self.uid, ids, context)
self.parse_node(self.dom.documentElement, self.doc, browser)
self.parse_node(self.dom, self.doc, browser)
def parse_string(self, xml, ids, model, context=None):
if not context:
context={}
# parses the xml template to memory
self.dom = minidom.parseString(xml)
self.dom = etree.XML(xml)
# create the xml data from the xml template
self.parse_tree(ids, model, context)
@@ -334,9 +290,8 @@ class document(object):
if not context:
context={}
# parses the xml template to memory
self.dom = minidom.parseString(tools.file_open(filename).read())
# create the xml data from the xml template
self.dom = etree.XML(tools.file_open(filename).read())
self.doc = etree.Element(self.dom.tag)
self.parse_tree(ids, model, context)
def close(self):
+22 -34
View File
@@ -26,7 +26,6 @@ import tools
from report import render
from lxml import etree
from xml.dom import minidom
import libxml2
import libxslt
@@ -38,24 +37,19 @@ class report_printscreen_list(report_int):
def _parse_node(self, root_node):
result = []
for node in root_node.getchildren():
for node in root_node:
if node.tag == 'field':
#attrsa = node.attributes
attrsa = node.attrib
print "typppppp",type(attrsa),dir(attrsa)
attrs = {}
if not attrsa is None:
for key,val in attrsa.items():
for key,val in attrsa.items():
attrs[key] = val
#for i in range(attrsa.length):
# attrs[attrsa.item(i).localName] = attrsa.item(i).nodeValue
result.append(attrs['name'])
else:
result.extend(self._parse_node(node))
return result
def _parse_string(self, view):
#dom = minidom.parseString(view)
dom = etree.XML(view)
return self._parse_node(dom)
@@ -85,16 +79,14 @@ class report_printscreen_list(report_int):
pageSize=[297.0,210.0]
impl = minidom.getDOMImplementation()
new_doc = impl.createDocument(None, "report", None)
new_doc = etree.Element("report")
config = etree.Element("config")
# build header
config = new_doc.createElement("config")
def _append_node(name, text):
n = new_doc.createElement(name)
t = new_doc.createTextNode(text)
n.appendChild(t)
config.appendChild(n)
n = etree.Element(name)
n.text = text
config.append(n)
_append_node('date', time.strftime('%d/%m/%Y'))
_append_node('PageSize', '%.2fmm,%.2fmm' % tuple(pageSize))
@@ -119,20 +111,17 @@ class report_printscreen_list(report_int):
s = fields[fields_order[pos]].get('size', 56) / 28 + 1
l[pos] = strmax * s / t
_append_node('tableSize', ','.join(map(str,l)) )
new_doc.childNodes[0].appendChild(config)
header = new_doc.createElement("header")
new_doc.append(config)
header=etree.Element("header")
for f in fields_order:
field = new_doc.createElement("field")
field_txt = new_doc.createTextNode(str(fields[f]['string']))
field.appendChild(field_txt)
header.appendChild(field)
new_doc.childNodes[0].appendChild(header)
lines = new_doc.createElement("lines")
field = etree.Element("field")
field.text = fields[f]['string'] or ''
header.append(field)
new_doc.append(header)
lines = etree.Element("lines")
for line in results:
node_line = new_doc.createElement("row")
node_line = etree.Element("row")
for f in fields_order:
if fields[f]['type']=='many2one' and line[f]:
line[f] = line[f][1]
@@ -141,16 +130,15 @@ class report_printscreen_list(report_int):
if fields[f]['type'] == 'float':
precision=(('digits' in fields[f]) and fields[f]['digits'][1]) or 2
line[f]=round(line[f],precision)
col = new_doc.createElement("col")
col.setAttribute('tree','no')
col = etree.Element("col")
col.set('tree','no')
if line[f] != None:
txt = new_doc.createTextNode(str(line[f] or ''))
col.text = tools.ustr(line[f] or '')
else:
txt = new_doc.createTextNode('/')
col.appendChild(txt)
node_line.appendChild(col)
lines.appendChild(node_line)
new_doc.childNodes[0].appendChild(lines)
col.text = '/'
node_line.append(col)
lines.append(node_line)
new_doc.append(node_line)
styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
style = libxslt.parseStylesheetDoc(styledoc)
+36 -12
View File
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@@ -20,7 +20,7 @@
#
##############################################################################
import base64
import base64
import logging
import os
import security
@@ -258,7 +258,7 @@ class db(netsvc.Service):
fs = os.path.join(tools.config['root_path'], 'filestore')
if os.path.exists(os.path.join(fs, old_name)):
os.rename(os.path.join(fs, old_name), os.path.join(fs, new_name))
logger.notifyChannel("web-services", netsvc.LOG_INFO,
'RENAME DB: %s -> %s' % (old_name, new_name))
finally:
@@ -326,7 +326,7 @@ class db(netsvc.Service):
try:
l.notifyChannel('migration', netsvc.LOG_INFO, 'migrate database %s' % (db,))
tools.config['update']['base'] = True
pooler.restart_pool(db, force_demo=False, update_module=True)
pooler.restart_pool(db, force_demo=False, update_module=True)
except except_orm, inst:
self.abortResponse(1, inst.name, 'warning', inst.value)
except except_osv, inst:
@@ -352,6 +352,7 @@ class common(netsvc.Service):
self.exportMethod(self.timezone_get)
self.exportMethod(self.get_available_updates)
self.exportMethod(self.get_migration_scripts)
self.exportMethod(self.get_server_environment)
def ir_set(self, db, uid, password, keys, args, name, value, replace=True, isobject=False):
security.check(db, uid, password)
@@ -416,36 +417,36 @@ GNU Public Licence.
def timezone_get(self, db, login, password):
return time.tzname[0]
def get_available_updates(self, password, contract_id, contract_password):
security.check_super(password)
import tools.maintenance as tm
try:
rc = tm.remote_contract(contract_id, contract_password)
if not rc.id:
raise tm.RemoteContractException('This contract does not exist or is not active')
raise tm.RemoteContractException('This contract does not exist or is not active')
return rc.get_available_updates(rc.id, addons.get_modules_with_version())
except tm.RemoteContractException, e:
self.abortResponse(1, 'Migration Error', 'warning', str(e))
def get_migration_scripts(self, password, contract_id, contract_password):
security.check_super(password)
l = netsvc.Logger()
import tools.maintenance as tm
try:
try:
rc = tm.remote_contract(contract_id, contract_password)
if not rc.id:
raise tm.RemoteContractException('This contract does not exist or is not active')
raise tm.RemoteContractException('This contract does not exist or is not active')
if rc.status != 'full':
raise tm.RemoteContractException('Can not get updates for a partial contract')
l.notifyChannel('migration', netsvc.LOG_INFO, 'starting migration with contract %s' % (rc.name,))
zips = rc.retrieve_updates(rc.id, addons.get_modules_with_version())
from shutil import rmtree, copytree, copy
backup_directory = os.path.join(tools.config['root_path'], 'backup', time.strftime('%Y-%m-%d-%H-%M'))
@@ -503,7 +504,29 @@ GNU Public Licence.
tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback))
l.notifyChannel('migration', netsvc.LOG_ERROR, tb_s)
raise
def get_server_environment(self,lang=False):
try:
if '.bzr' in os.listdir((os.getcwd()[0:-3])):
fp = open(os.path.join(os.getcwd()[0:-3],'.bzr/branch/last-revision'))
rev_no = fp.read()
fp.close()
else:
rev_no = 'Bazaar Not Installed !'
except:
rev_no = 'Bazaar Not Installed !'
if not lang:
lang = os.environ.get('LANG', '').split('.')[0]
environment = 'Environment_Information : \n' \
'Operating System : %s\n' \
'PlatForm : %s\n' \
'Operating System Version : %s\n' \
'Python Version : %s\n'\
'Locale : %s\n' \
'OpenERP-Server Version : %s\n'\
'OpenERP-Server Last Revision ID : %s' \
%(os.name,sys.platform,str(sys.version.split('\n')[1]),str(sys.version[0:5]), lang, release.version,rev_no)
return environment
common()
class objects_proxy(netsvc.Service):
@@ -637,6 +660,7 @@ class report_spool(netsvc.Service):
tb = sys.exc_info()
tb_s = "".join(traceback.format_exception(*tb))
logger = netsvc.Logger()
logger.notifyChannel('web-services', netsvc.LOG_ERROR,common().get_server_environment(context.get('lang',False)))
logger.notifyChannel('web-services', netsvc.LOG_ERROR,
'Exception: %s\n%s' % (str(exception), tb_s))
self._reports[id]['exception'] = ExceptionWithTraceback(tools.exception_to_unicode(exception), tb)