2008-07-23 15:01:27 +00:00
|
|
|
# -*- encoding: utf-8 -*-
|
2006-12-07 13:41:40 +00:00
|
|
|
##############################################################################
|
|
|
|
#
|
2008-11-04 06:33:23 +00:00
|
|
|
# OpenERP, Open Source Management Solution
|
2009-01-04 22:13:29 +00:00
|
|
|
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
2008-11-03 18:27:16 +00:00
|
|
|
# $Id$
|
2006-12-07 13:41:40 +00:00
|
|
|
#
|
2008-11-03 18:27:16 +00:00
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
2006-12-07 13:41:40 +00:00
|
|
|
#
|
2008-11-03 18:27:16 +00:00
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
2006-12-07 13:41:40 +00:00
|
|
|
#
|
2008-11-03 18:27:16 +00:00
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2006-12-07 13:41:40 +00:00
|
|
|
#
|
2008-11-03 18:27:16 +00:00
|
|
|
##############################################################################
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
"""
|
2008-09-10 08:46:40 +00:00
|
|
|
Miscelleanous tools used by OpenERP.
|
2006-12-07 13:41:40 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
import os, time, sys
|
|
|
|
import inspect
|
|
|
|
|
|
|
|
from config import config
|
|
|
|
|
2007-04-21 13:32:18 +00:00
|
|
|
import zipfile
|
2007-07-30 13:35:27 +00:00
|
|
|
import release
|
2007-08-01 14:04:09 +00:00
|
|
|
import socket
|
2007-04-21 13:32:18 +00:00
|
|
|
|
2006-12-07 13:41:40 +00:00
|
|
|
if sys.version_info[:2] < (2, 4):
|
2008-07-22 14:24:36 +00:00
|
|
|
from threadinglocal import local
|
2006-12-07 13:41:40 +00:00
|
|
|
else:
|
2008-07-22 14:24:36 +00:00
|
|
|
from threading import local
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-08-14 09:51:20 +00:00
|
|
|
from itertools import izip
|
|
|
|
|
2008-09-16 13:32:15 +00:00
|
|
|
# initialize a database with base/base.sql
|
2006-12-07 13:41:40 +00:00
|
|
|
def init_db(cr):
|
2008-07-22 14:24:36 +00:00
|
|
|
import addons
|
|
|
|
f = addons.get_module_resource('base', 'base.sql')
|
|
|
|
for line in file(f).read().split(';'):
|
|
|
|
if (len(line)>0) and (not line.isspace()):
|
|
|
|
cr.execute(line)
|
|
|
|
cr.commit()
|
|
|
|
|
|
|
|
for i in addons.get_modules():
|
|
|
|
terp_file = addons.get_module_resource(i, '__terp__.py')
|
|
|
|
mod_path = addons.get_module_path(i)
|
2008-10-27 12:18:52 +00:00
|
|
|
if not mod_path:
|
|
|
|
continue
|
2008-07-22 14:24:36 +00:00
|
|
|
info = False
|
|
|
|
if os.path.isfile(terp_file) and not os.path.isfile(mod_path+'.zip'):
|
|
|
|
info = eval(file(terp_file).read())
|
|
|
|
elif zipfile.is_zipfile(mod_path+'.zip'):
|
|
|
|
zfile = zipfile.ZipFile(mod_path+'.zip')
|
|
|
|
i = os.path.splitext(i)[0]
|
|
|
|
info = eval(zfile.read(os.path.join(i, '__terp__.py')))
|
|
|
|
if info:
|
|
|
|
categs = info.get('category', 'Uncategorized').split('/')
|
|
|
|
p_id = None
|
|
|
|
while categs:
|
|
|
|
if p_id is not None:
|
|
|
|
cr.execute('select id \
|
|
|
|
from ir_module_category \
|
2008-12-09 13:35:40 +00:00
|
|
|
where name=%s and parent_id=%s', (categs[0], p_id))
|
2008-07-22 14:24:36 +00:00
|
|
|
else:
|
|
|
|
cr.execute('select id \
|
|
|
|
from ir_module_category \
|
|
|
|
where name=%s and parent_id is NULL', (categs[0],))
|
|
|
|
c_id = cr.fetchone()
|
|
|
|
if not c_id:
|
|
|
|
cr.execute('select nextval(\'ir_module_category_id_seq\')')
|
|
|
|
c_id = cr.fetchone()[0]
|
|
|
|
cr.execute('insert into ir_module_category \
|
|
|
|
(id, name, parent_id) \
|
2008-12-09 13:35:40 +00:00
|
|
|
values (%s, %s, %s)', (c_id, categs[0], p_id))
|
2008-07-22 14:24:36 +00:00
|
|
|
else:
|
|
|
|
c_id = c_id[0]
|
|
|
|
p_id = c_id
|
|
|
|
categs = categs[1:]
|
|
|
|
|
|
|
|
active = info.get('active', False)
|
|
|
|
installable = info.get('installable', True)
|
|
|
|
if installable:
|
|
|
|
if active:
|
|
|
|
state = 'to install'
|
|
|
|
else:
|
|
|
|
state = 'uninstalled'
|
|
|
|
else:
|
|
|
|
state = 'uninstallable'
|
|
|
|
cr.execute('select nextval(\'ir_module_module_id_seq\')')
|
|
|
|
id = cr.fetchone()[0]
|
|
|
|
cr.execute('insert into ir_module_module \
|
2008-12-11 11:44:13 +00:00
|
|
|
(id, author, website, name, shortdesc, description, \
|
2008-07-22 14:24:36 +00:00
|
|
|
category_id, state) \
|
2008-12-11 11:44:13 +00:00
|
|
|
values (%s, %s, %s, %s, %s, %s, %s, %s)', (
|
2008-07-22 14:24:36 +00:00
|
|
|
id, info.get('author', ''),
|
|
|
|
info.get('website', ''), i, info.get('name', False),
|
|
|
|
info.get('description', ''), p_id, state))
|
|
|
|
dependencies = info.get('depends', [])
|
|
|
|
for d in dependencies:
|
|
|
|
cr.execute('insert into ir_module_module_dependency \
|
|
|
|
(module_id,name) values (%s, %s)', (id, d))
|
|
|
|
cr.commit()
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
def find_in_path(name):
|
2008-07-22 14:24:36 +00:00
|
|
|
if os.name == "nt":
|
|
|
|
sep = ';'
|
|
|
|
else:
|
|
|
|
sep = ':'
|
|
|
|
path = [dir for dir in os.environ['PATH'].split(sep)
|
|
|
|
if os.path.isdir(dir)]
|
|
|
|
for dir in path:
|
|
|
|
val = os.path.join(dir, name)
|
|
|
|
if os.path.isfile(val) or os.path.islink(val):
|
|
|
|
return val
|
|
|
|
return None
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
def find_pg_tool(name):
|
2008-07-22 14:24:36 +00:00
|
|
|
if config['pg_path'] and config['pg_path'] != 'None':
|
|
|
|
return os.path.join(config['pg_path'], name)
|
|
|
|
else:
|
|
|
|
return find_in_path(name)
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
def exec_pg_command(name, *args):
|
2008-07-22 14:24:36 +00:00
|
|
|
prog = find_pg_tool(name)
|
|
|
|
if not prog:
|
|
|
|
raise Exception('Couldn\'t find %s' % name)
|
|
|
|
args2 = (os.path.basename(prog),) + args
|
|
|
|
return os.spawnv(os.P_WAIT, prog, args2)
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
def exec_pg_command_pipe(name, *args):
|
2008-07-22 14:24:36 +00:00
|
|
|
prog = find_pg_tool(name)
|
|
|
|
if not prog:
|
|
|
|
raise Exception('Couldn\'t find %s' % name)
|
|
|
|
if os.name == "nt":
|
|
|
|
cmd = '"' + prog + '" ' + ' '.join(args)
|
|
|
|
else:
|
|
|
|
cmd = prog + ' ' + ' '.join(args)
|
|
|
|
return os.popen2(cmd, 'b')
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2007-03-15 12:26:40 +00:00
|
|
|
def exec_command_pipe(name, *args):
|
2008-07-22 14:24:36 +00:00
|
|
|
prog = find_in_path(name)
|
|
|
|
if not prog:
|
|
|
|
raise Exception('Couldn\'t find %s' % name)
|
|
|
|
if os.name == "nt":
|
|
|
|
cmd = '"'+prog+'" '+' '.join(args)
|
|
|
|
else:
|
|
|
|
cmd = prog+' '+' '.join(args)
|
|
|
|
return os.popen2(cmd, 'b')
|
2007-03-15 12:26:40 +00:00
|
|
|
|
2006-12-07 13:41:40 +00:00
|
|
|
#----------------------------------------------------------
|
|
|
|
# File paths
|
|
|
|
#----------------------------------------------------------
|
|
|
|
#file_path_root = os.getcwd()
|
|
|
|
#file_path_addons = os.path.join(file_path_root, 'addons')
|
|
|
|
|
2008-07-17 09:55:16 +00:00
|
|
|
def file_open(name, mode="r", subdir='addons', pathinfo=False):
|
2008-09-10 08:46:40 +00:00
|
|
|
"""Open a file from the OpenERP root, using a subdir folder.
|
2008-07-22 14:24:36 +00:00
|
|
|
|
|
|
|
>>> file_open('hr/report/timesheer.xsl')
|
|
|
|
>>> file_open('addons/hr/report/timesheet.xsl')
|
|
|
|
>>> file_open('../../base/report/rml_template.xsl', subdir='addons/hr/report', pathinfo=True)
|
|
|
|
|
|
|
|
@param name: name of the file
|
|
|
|
@param mode: file open mode
|
|
|
|
@param subdir: subdirectory
|
|
|
|
@param pathinfo: if True returns tupple (fileobject, filepath)
|
|
|
|
|
|
|
|
@return: fileobject if pathinfo is False else (fileobject, filepath)
|
|
|
|
"""
|
|
|
|
|
|
|
|
adp = os.path.normcase(os.path.abspath(config['addons_path']))
|
|
|
|
rtp = os.path.normcase(os.path.abspath(config['root_path']))
|
|
|
|
|
|
|
|
if name.replace(os.path.sep, '/').startswith('addons/'):
|
|
|
|
subdir = 'addons'
|
|
|
|
name = name[7:]
|
|
|
|
|
|
|
|
# First try to locate in addons_path
|
|
|
|
if subdir:
|
|
|
|
subdir2 = subdir
|
|
|
|
if subdir2.replace(os.path.sep, '/').startswith('addons/'):
|
|
|
|
subdir2 = subdir2[7:]
|
|
|
|
|
|
|
|
subdir2 = (subdir2 != 'addons' or None) and subdir2
|
|
|
|
|
|
|
|
try:
|
|
|
|
if subdir2:
|
|
|
|
fn = os.path.join(adp, subdir2, name)
|
|
|
|
else:
|
|
|
|
fn = os.path.join(adp, name)
|
|
|
|
fn = os.path.normpath(fn)
|
|
|
|
fo = file_open(fn, mode=mode, subdir=None, pathinfo=pathinfo)
|
|
|
|
if pathinfo:
|
|
|
|
return fo, fn
|
|
|
|
return fo
|
|
|
|
except IOError, e:
|
|
|
|
pass
|
|
|
|
|
|
|
|
if subdir:
|
|
|
|
name = os.path.join(rtp, subdir, name)
|
|
|
|
else:
|
|
|
|
name = os.path.join(rtp, name)
|
|
|
|
|
|
|
|
name = os.path.normpath(name)
|
|
|
|
|
|
|
|
# Check for a zipfile in the path
|
|
|
|
head = name
|
|
|
|
zipname = False
|
|
|
|
name2 = False
|
|
|
|
while True:
|
|
|
|
head, tail = os.path.split(head)
|
|
|
|
if not tail:
|
|
|
|
break
|
|
|
|
if zipname:
|
|
|
|
zipname = os.path.join(tail, zipname)
|
|
|
|
else:
|
|
|
|
zipname = tail
|
|
|
|
if zipfile.is_zipfile(head+'.zip'):
|
|
|
|
import StringIO
|
|
|
|
zfile = zipfile.ZipFile(head+'.zip')
|
|
|
|
try:
|
|
|
|
fo = StringIO.StringIO(zfile.read(os.path.join(
|
|
|
|
os.path.basename(head), zipname).replace(
|
|
|
|
os.sep, '/')))
|
|
|
|
|
|
|
|
if pathinfo:
|
|
|
|
return fo, name
|
|
|
|
return fo
|
|
|
|
except:
|
|
|
|
name2 = os.path.normpath(os.path.join(head + '.zip', zipname))
|
|
|
|
pass
|
|
|
|
for i in (name2, name):
|
|
|
|
if i and os.path.isfile(i):
|
|
|
|
fo = file(i, mode)
|
|
|
|
if pathinfo:
|
|
|
|
return fo, i
|
|
|
|
return fo
|
2008-11-12 13:05:09 +00:00
|
|
|
if os.path.splitext(name)[1] == '.rml':
|
|
|
|
raise IOError, 'Report %s doesn\'t exist or deleted : ' %str(name)
|
2008-07-22 14:24:36 +00:00
|
|
|
raise IOError, 'File not found : '+str(name)
|
2007-05-03 13:34:39 +00:00
|
|
|
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-06-03 11:14:02 +00:00
|
|
|
#----------------------------------------------------------
|
|
|
|
# iterables
|
|
|
|
#----------------------------------------------------------
|
|
|
|
def flatten(list):
|
|
|
|
"""Flatten a list of elements into a uniqu list
|
|
|
|
Author: Christophe Simonis (christophe@tinyerp.com)
|
2008-09-16 13:32:15 +00:00
|
|
|
|
2008-06-03 11:14:02 +00:00
|
|
|
Examples:
|
|
|
|
>>> flatten(['a'])
|
|
|
|
['a']
|
|
|
|
>>> flatten('b')
|
|
|
|
['b']
|
|
|
|
>>> flatten( [] )
|
|
|
|
[]
|
|
|
|
>>> flatten( [[], [[]]] )
|
|
|
|
[]
|
|
|
|
>>> flatten( [[['a','b'], 'c'], 'd', ['e', [], 'f']] )
|
|
|
|
['a', 'b', 'c', 'd', 'e', 'f']
|
|
|
|
>>> t = (1,2,(3,), [4, 5, [6, [7], (8, 9), ([10, 11, (12, 13)]), [14, [], (15,)], []]])
|
|
|
|
>>> flatten(t)
|
|
|
|
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
|
|
"""
|
2008-09-16 13:32:15 +00:00
|
|
|
|
2008-06-03 11:14:02 +00:00
|
|
|
def isiterable(x):
|
|
|
|
return hasattr(x, "__iter__")
|
|
|
|
|
|
|
|
r = []
|
|
|
|
for e in list:
|
|
|
|
if isiterable(e):
|
|
|
|
map(r.append, flatten(e))
|
|
|
|
else:
|
|
|
|
r.append(e)
|
|
|
|
return r
|
|
|
|
|
2008-08-18 07:56:02 +00:00
|
|
|
def reverse_enumerate(l):
|
|
|
|
"""Like enumerate but in the other sens
|
|
|
|
>>> a = ['a', 'b', 'c']
|
|
|
|
>>> it = reverse_enumerate(a)
|
|
|
|
>>> it.next()
|
|
|
|
(2, 'c')
|
|
|
|
>>> it.next()
|
|
|
|
(1, 'b')
|
|
|
|
>>> it.next()
|
|
|
|
(0, 'a')
|
|
|
|
>>> it.next()
|
|
|
|
Traceback (most recent call last):
|
|
|
|
File "<stdin>", line 1, in <module>
|
|
|
|
StopIteration
|
|
|
|
"""
|
|
|
|
return izip(xrange(len(l)-1, -1, -1), reversed(l))
|
2008-06-03 11:14:02 +00:00
|
|
|
|
2006-12-07 13:41:40 +00:00
|
|
|
#----------------------------------------------------------
|
|
|
|
# Emails
|
|
|
|
#----------------------------------------------------------
|
2008-11-24 11:13:20 +00:00
|
|
|
def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, attach=None, tinycrm=False, ssl=False, debug=False,subtype='plain'):
|
2008-07-22 14:24:36 +00:00
|
|
|
"""Send an email."""
|
|
|
|
import smtplib
|
|
|
|
from email.MIMEText import MIMEText
|
|
|
|
from email.MIMEBase import MIMEBase
|
|
|
|
from email.MIMEMultipart import MIMEMultipart
|
|
|
|
from email.Header import Header
|
|
|
|
from email.Utils import formatdate, COMMASPACE
|
2008-11-24 11:13:20 +00:00
|
|
|
from email.Utils import formatdate, COMMASPACE
|
2008-07-22 14:24:36 +00:00
|
|
|
from email import Encoders
|
|
|
|
|
2008-07-29 07:28:04 +00:00
|
|
|
if not ssl:
|
2008-10-27 10:46:50 +00:00
|
|
|
ssl = config.get('smtp_ssl', False)
|
2008-09-16 13:32:15 +00:00
|
|
|
|
2008-11-24 11:13:20 +00:00
|
|
|
if not email_cc:
|
|
|
|
email_cc = []
|
|
|
|
if not email_bcc:
|
|
|
|
email_bcc = []
|
|
|
|
|
|
|
|
if not attach:
|
|
|
|
msg = MIMEText(body or '',_subtype=subtype,_charset='utf-8')
|
|
|
|
else:
|
|
|
|
msg = MIMEMultipart()
|
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
|
|
|
|
msg['From'] = email_from
|
|
|
|
del msg['Reply-To']
|
|
|
|
if reply_to:
|
2008-11-24 11:13:20 +00:00
|
|
|
msg['Reply-To'] = msg['From']+', '+reply_to
|
2008-07-22 14:24:36 +00:00
|
|
|
msg['To'] = COMMASPACE.join(email_to)
|
|
|
|
if email_cc:
|
|
|
|
msg['Cc'] = COMMASPACE.join(email_cc)
|
|
|
|
if email_bcc:
|
|
|
|
msg['Bcc'] = COMMASPACE.join(email_bcc)
|
|
|
|
msg['Date'] = formatdate(localtime=True)
|
2008-11-24 11:13:20 +00:00
|
|
|
|
|
|
|
if tinycrm:
|
|
|
|
msg['Message-Id'] = "<%s-tinycrm-%s@%s>" % (time.time(), tinycrm, socket.gethostname())
|
|
|
|
|
|
|
|
if attach:
|
|
|
|
msg.attach( MIMEText(body or '', _charset='utf-8', _subtype=subtype) )
|
|
|
|
|
|
|
|
for (fname,fcontent) in attach:
|
|
|
|
part = MIMEBase('application', "octet-stream")
|
|
|
|
part.set_payload( fcontent )
|
|
|
|
Encoders.encode_base64(part)
|
|
|
|
part.add_header('Content-Disposition', 'attachment; filename="%s"' % (fname,))
|
|
|
|
msg.attach(part)
|
2008-07-22 14:24:36 +00:00
|
|
|
try:
|
|
|
|
s = smtplib.SMTP()
|
2008-09-16 13:32:15 +00:00
|
|
|
|
2008-07-23 16:33:28 +00:00
|
|
|
if debug:
|
2008-09-16 13:32:15 +00:00
|
|
|
s.debuglevel = 5
|
2008-09-25 19:40:50 +00:00
|
|
|
s.connect(config['smtp_server'], config['smtp_port'])
|
2008-07-23 16:33:28 +00:00
|
|
|
if ssl:
|
|
|
|
s.ehlo()
|
|
|
|
s.starttls()
|
|
|
|
s.ehlo()
|
2008-09-16 13:32:15 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
if config['smtp_user'] or config['smtp_password']:
|
|
|
|
s.login(config['smtp_user'], config['smtp_password'])
|
2008-11-24 11:13:20 +00:00
|
|
|
|
|
|
|
s.sendmail(email_from,
|
|
|
|
flatten([email_to, email_cc, email_bcc]),
|
|
|
|
msg.as_string()
|
|
|
|
)
|
2008-07-22 14:24:36 +00:00
|
|
|
s.quit()
|
|
|
|
except Exception, e:
|
|
|
|
import logging
|
|
|
|
logging.getLogger().error(str(e))
|
2008-07-23 16:33:28 +00:00
|
|
|
return False
|
2008-07-22 14:24:36 +00:00
|
|
|
return True
|
2007-04-13 05:03:14 +00:00
|
|
|
|
2006-12-07 13:41:40 +00:00
|
|
|
#----------------------------------------------------------
|
|
|
|
# SMS
|
|
|
|
#----------------------------------------------------------
|
|
|
|
# text must be latin-1 encoded
|
|
|
|
def sms_send(user, password, api_id, text, to):
|
2008-07-22 14:24:36 +00:00
|
|
|
import urllib
|
|
|
|
params = urllib.urlencode({'user': user, 'password': password, 'api_id': api_id, 'text': text, 'to':to})
|
|
|
|
#f = urllib.urlopen("http://api.clickatell.com/http/sendmsg", params)
|
|
|
|
f = urllib.urlopen("http://196.7.150.220/http/sendmsg", params)
|
2008-12-10 21:36:04 +00:00
|
|
|
# FIXME: Use the logger if there is an error
|
2008-07-22 14:24:36 +00:00
|
|
|
return True
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
#---------------------------------------------------------
|
|
|
|
# Class that stores an updateable string (used in wizards)
|
|
|
|
#---------------------------------------------------------
|
|
|
|
class UpdateableStr(local):
|
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __init__(self, string=''):
|
|
|
|
self.string = string
|
2008-09-16 13:32:15 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __str__(self):
|
|
|
|
return str(self.string)
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return str(self.string)
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __nonzero__(self):
|
|
|
|
return bool(self.string)
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2007-10-11 13:56:36 +00:00
|
|
|
|
|
|
|
class UpdateableDict(local):
|
2008-07-22 14:24:36 +00:00
|
|
|
'''Stores an updateable dict to use in wizards'''
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __init__(self, dict=None):
|
|
|
|
if dict is None:
|
|
|
|
dict = {}
|
|
|
|
self.dict = dict
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __str__(self):
|
|
|
|
return str(self.dict)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return str(self.dict)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def clear(self):
|
|
|
|
return self.dict.clear()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def keys(self):
|
|
|
|
return self.dict.keys()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __setitem__(self, i, y):
|
|
|
|
self.dict.__setitem__(i, y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __getitem__(self, i):
|
|
|
|
return self.dict.__getitem__(i)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def copy(self):
|
|
|
|
return self.dict.copy()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def iteritems(self):
|
|
|
|
return self.dict.iteritems()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def iterkeys(self):
|
|
|
|
return self.dict.iterkeys()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def itervalues(self):
|
|
|
|
return self.dict.itervalues()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def pop(self, k, d=None):
|
|
|
|
return self.dict.pop(k, d)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def popitem(self):
|
|
|
|
return self.dict.popitem()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def setdefault(self, k, d=None):
|
|
|
|
return self.dict.setdefault(k, d)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def update(self, E, **F):
|
|
|
|
return self.dict.update(E, F)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def values(self):
|
|
|
|
return self.dict.values()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def get(self, k, d=None):
|
|
|
|
return self.dict.get(k, d)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def has_key(self, k):
|
|
|
|
return self.dict.has_key(k)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def items(self):
|
|
|
|
return self.dict.items()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __cmp__(self, y):
|
|
|
|
return self.dict.__cmp__(y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __contains__(self, k):
|
|
|
|
return self.dict.__contains__(k)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __delitem__(self, y):
|
|
|
|
return self.dict.__delitem__(y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __eq__(self, y):
|
|
|
|
return self.dict.__eq__(y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __ge__(self, y):
|
|
|
|
return self.dict.__ge__(y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __getitem__(self, y):
|
|
|
|
return self.dict.__getitem__(y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __gt__(self, y):
|
|
|
|
return self.dict.__gt__(y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __hash__(self):
|
|
|
|
return self.dict.__hash__()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __iter__(self):
|
|
|
|
return self.dict.__iter__()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __le__(self, y):
|
|
|
|
return self.dict.__le__(y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __len__(self):
|
|
|
|
return self.dict.__len__()
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __lt__(self, y):
|
|
|
|
return self.dict.__lt__(y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __ne__(self, y):
|
|
|
|
return self.dict.__ne__(y)
|
2007-10-11 13:56:36 +00:00
|
|
|
|
|
|
|
|
2006-12-28 09:44:56 +00:00
|
|
|
# Don't use ! Use res.currency.round()
|
2007-10-11 13:56:36 +00:00
|
|
|
class currency(float):
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __init__(self, value, accuracy=2, rounding=None):
|
|
|
|
if rounding is None:
|
|
|
|
rounding=10**-accuracy
|
|
|
|
self.rounding=rounding
|
|
|
|
self.accuracy=accuracy
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def __new__(cls, value, accuracy=2, rounding=None):
|
|
|
|
return float.__new__(cls, round(value, accuracy))
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
#def __str__(self):
|
|
|
|
# display_value = int(self*(10**(-self.accuracy))/self.rounding)*self.rounding/(10**(-self.accuracy))
|
|
|
|
# return str(display_value)
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
|
2008-10-16 18:28:16 +00:00
|
|
|
def is_hashable(h):
|
|
|
|
try:
|
|
|
|
hash(h)
|
|
|
|
return True
|
|
|
|
except TypeError:
|
|
|
|
return False
|
|
|
|
|
2006-12-07 13:41:40 +00:00
|
|
|
class cache(object):
|
2008-12-15 11:58:01 +00:00
|
|
|
"""
|
|
|
|
Use it as a decorator of the function you plan to cache
|
|
|
|
Timeout: 0 = no timeout, otherwise in seconds
|
|
|
|
"""
|
2008-12-24 00:24:18 +00:00
|
|
|
|
|
|
|
__caches = []
|
|
|
|
|
|
|
|
def __init__(self, timeout=None, skiparg=2, multi=None):
|
2008-12-15 11:58:01 +00:00
|
|
|
assert skiparg >= 2 # at least self and cr
|
2008-12-24 00:24:18 +00:00
|
|
|
if timeout is None:
|
|
|
|
self.timeout = config['cache_timeout']
|
|
|
|
else:
|
|
|
|
self.timeout = timeout
|
2008-12-13 06:01:18 +00:00
|
|
|
self.skiparg = skiparg
|
|
|
|
self.multi = multi
|
2008-12-18 19:41:14 +00:00
|
|
|
self.lasttime = time.time()
|
2008-07-22 14:24:36 +00:00
|
|
|
self.cache = {}
|
2008-12-24 00:24:18 +00:00
|
|
|
|
|
|
|
cache.__caches.append(self)
|
|
|
|
|
2008-12-31 16:06:10 +00:00
|
|
|
@classmethod
|
2008-12-24 00:24:18 +00:00
|
|
|
def clean_cache_for_db(cls, dbname):
|
|
|
|
def get_dbname_from_key(key):
|
|
|
|
for e in key:
|
|
|
|
if e[0] == 'dbname':
|
|
|
|
return e[1]
|
|
|
|
return None
|
|
|
|
|
|
|
|
for cache in cls.__caches:
|
|
|
|
keys_to_del = [key for key in cache.cache if get_dbname_from_key(key) == dbname]
|
|
|
|
for key in keys_to_del:
|
|
|
|
del cache.cache[key]
|
2008-07-22 14:24:36 +00:00
|
|
|
|
|
|
|
def __call__(self, fn):
|
2008-12-13 06:01:18 +00:00
|
|
|
arg_names = inspect.getargspec(fn)[0][self.skiparg:]
|
2008-12-18 19:41:14 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
def cached_result(self2, cr=None, *args, **kwargs):
|
2008-12-18 19:41:14 +00:00
|
|
|
if time.time()-self.timeout > self.lasttime:
|
|
|
|
self.lasttime = time.time()
|
|
|
|
t = time.time()-self.timeout
|
2008-12-24 10:48:11 +00:00
|
|
|
for key in self.cache.keys():
|
|
|
|
if self.cache[key][1]<t:
|
|
|
|
del self.cache[key]
|
2008-12-18 19:41:14 +00:00
|
|
|
|
2008-07-22 14:24:36 +00:00
|
|
|
if cr is None:
|
|
|
|
self.cache = {}
|
|
|
|
return True
|
2008-12-13 06:01:18 +00:00
|
|
|
if ('clear_keys' in kwargs):
|
|
|
|
if (kwargs['clear_keys'] in self.cache):
|
|
|
|
del self.cache[kwargs['clear_keys']]
|
|
|
|
return True
|
2008-07-22 14:24:36 +00:00
|
|
|
|
2008-12-15 11:58:01 +00:00
|
|
|
# Update named arguments with positional argument values (without self and cr)
|
2008-12-13 06:01:18 +00:00
|
|
|
kwargs2 = kwargs.copy()
|
2008-12-15 11:58:01 +00:00
|
|
|
kwargs2.update(dict(zip(arg_names, args[self.skiparg-2:])))
|
2008-12-13 06:01:18 +00:00
|
|
|
for k in kwargs2:
|
|
|
|
if isinstance(kwargs2[k], (list, dict, set)):
|
|
|
|
kwargs2[k] = tuple(kwargs2[k])
|
|
|
|
elif not is_hashable(kwargs2[k]):
|
|
|
|
kwargs2[k] = repr(kwargs2[k])
|
2008-12-18 19:41:14 +00:00
|
|
|
|
|
|
|
if self.multi:
|
|
|
|
kwargs3 = kwargs2.copy()
|
|
|
|
notincache = []
|
|
|
|
result = {}
|
|
|
|
for id in kwargs3[self.multi]:
|
|
|
|
kwargs2[self.multi] = [id]
|
|
|
|
kwargs4 = kwargs2.items()
|
|
|
|
kwargs4.sort()
|
|
|
|
|
|
|
|
# Work out key as a tuple of ('argname', value) pairs
|
|
|
|
key = (('dbname', cr.dbname),) + tuple(kwargs4)
|
|
|
|
if key in self.cache:
|
|
|
|
result[id] = self.cache[key][0]
|
|
|
|
else:
|
|
|
|
notincache.append(id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if notincache:
|
|
|
|
kwargs2[self.multi] = notincache
|
|
|
|
result2 = fn(self2, cr, *args[2:self.skip], **kwargs3)
|
|
|
|
for id in result2:
|
|
|
|
kwargs2[self.multi] = [id]
|
|
|
|
kwargs4 = kwargs2.items()
|
|
|
|
kwargs4.sort()
|
|
|
|
key = (('dbname', cr.dbname),) + tuple(kwargs4)
|
|
|
|
self.cache[key] = result2[id]
|
|
|
|
result.updat(result2)
|
|
|
|
return result
|
|
|
|
|
2008-12-13 06:01:18 +00:00
|
|
|
kwargs2 = kwargs2.items()
|
|
|
|
kwargs2.sort()
|
2008-09-16 13:32:15 +00:00
|
|
|
|
2008-12-13 06:01:18 +00:00
|
|
|
key = (('dbname', cr.dbname),) + tuple(kwargs2)
|
2008-07-22 14:24:36 +00:00
|
|
|
if key in self.cache:
|
2008-12-18 19:41:14 +00:00
|
|
|
return self.cache[key][0]
|
|
|
|
|
2008-12-15 11:58:01 +00:00
|
|
|
result = fn(self2, cr, *args, **kwargs)
|
2008-07-22 14:24:36 +00:00
|
|
|
|
|
|
|
self.cache[key] = (result, time.time())
|
|
|
|
return result
|
|
|
|
return cached_result
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2008-03-03 11:54:45 +00:00
|
|
|
def to_xml(s):
|
2008-07-22 14:24:36 +00:00
|
|
|
return s.replace('&','&').replace('<','<').replace('>','>')
|
2008-03-03 11:54:45 +00:00
|
|
|
|
2008-12-09 13:35:40 +00:00
|
|
|
def ustr(value):
|
|
|
|
"""This method is similar to the builtin `str` method, except
|
|
|
|
it will return Unicode string.
|
|
|
|
|
|
|
|
@param value: the value to convert
|
|
|
|
|
|
|
|
@rtype: unicode
|
|
|
|
@return: unicode string
|
|
|
|
"""
|
|
|
|
|
|
|
|
if isinstance(value, unicode):
|
|
|
|
return value
|
|
|
|
|
|
|
|
if hasattr(value, '__unicode__'):
|
|
|
|
return unicode(value)
|
|
|
|
|
|
|
|
if not isinstance(value, str):
|
|
|
|
value = str(value)
|
|
|
|
|
|
|
|
return unicode(value, 'utf-8')
|
|
|
|
|
2008-12-26 10:18:58 +00:00
|
|
|
# to be compatible with python 2.4
|
|
|
|
import __builtin__
|
|
|
|
if not hasattr(__builtin__, 'all'):
|
|
|
|
def all(iterable):
|
|
|
|
for element in iterable:
|
|
|
|
if not element:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
__builtin__.all = all
|
|
|
|
del all
|
|
|
|
|
|
|
|
if not hasattr(__builtin__, 'any'):
|
|
|
|
def any(iterable):
|
|
|
|
for element in iterable:
|
|
|
|
if element:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
__builtin__.any = any
|
|
|
|
del any
|
|
|
|
|
|
|
|
|
2008-12-09 13:35:40 +00:00
|
|
|
|
2006-12-07 13:41:40 +00:00
|
|
|
def get_languages():
|
2008-07-22 14:24:36 +00:00
|
|
|
languages={
|
2008-12-22 19:34:26 +00:00
|
|
|
'ar_AR': u'Arabic / الْعَرَبيّة',
|
2008-11-21 19:50:42 +00:00
|
|
|
'bg_BG': u'Bulgarian / български',
|
2009-01-03 11:14:41 +00:00
|
|
|
'bs_BS': u'Bosnian / bosanski jezik',
|
2008-11-21 19:50:42 +00:00
|
|
|
'ca_ES': u'Catalan / Català',
|
|
|
|
'cs_CZ': u'Czech / Čeština',
|
|
|
|
'de_DE': u'German / Deutsch',
|
2008-11-22 00:09:35 +00:00
|
|
|
'en_CA': u'English (CA)',
|
2008-11-21 19:50:42 +00:00
|
|
|
'en_EN': u'English (default)',
|
2008-11-22 00:09:35 +00:00
|
|
|
'en_GB': u'English (UK)',
|
|
|
|
'en_US': u'English (US)',
|
|
|
|
'es_AR': u'Spanish (AR) / Español (AR)',
|
2008-11-21 19:50:42 +00:00
|
|
|
'es_ES': u'Spanish / Español',
|
|
|
|
'et_ET': u'Estonian / Eesti keel',
|
2008-11-22 00:09:35 +00:00
|
|
|
'fr_BE': u'French (BE) / Français (BE)',
|
|
|
|
'fr_CH': u'French (CH) / Français (CH)',
|
2008-11-21 19:50:42 +00:00
|
|
|
'fr_FR': u'French / Français',
|
|
|
|
'hr_HR': u'Croatian / hrvatski jezik',
|
|
|
|
'hu_HU': u'Hungarian / Magyar',
|
|
|
|
'it_IT': u'Italian / Italiano',
|
|
|
|
'lt_LT': u'Lithuanian / Lietuvių kalba',
|
|
|
|
'nl_NL': u'Dutch / Nederlands',
|
2008-12-22 19:34:26 +00:00
|
|
|
'pl_PL': u'Polish / Język polski',
|
2008-11-22 00:09:35 +00:00
|
|
|
'pt_BR': u'Portugese (BR) / português (BR)',
|
2008-11-21 19:50:42 +00:00
|
|
|
'pt_PT': u'Portugese / português',
|
|
|
|
'ro_RO': u'Romanian / limba română',
|
|
|
|
'ru_RU': u'Russian / русский язык',
|
|
|
|
'sl_SL': u'Slovenian / slovenščina',
|
|
|
|
'sv_SE': u'Swedish / svenska',
|
2008-12-22 19:34:26 +00:00
|
|
|
'tr_TR': u'Turkish / Türkçe',
|
2008-11-21 19:50:42 +00:00
|
|
|
'uk_UK': u'Ukrainian / украї́нська мо́ва',
|
2008-11-22 00:09:35 +00:00
|
|
|
'zh_CN': u'Chinese (CN) / 简体中文' ,
|
|
|
|
'zh_TW': u'Chinese (TW) / 正體字',
|
2008-07-22 14:24:36 +00:00
|
|
|
}
|
|
|
|
return languages
|
2006-12-07 13:41:40 +00:00
|
|
|
|
|
|
|
def scan_languages():
|
2008-07-22 14:24:36 +00:00
|
|
|
import glob
|
2008-10-16 08:54:28 +00:00
|
|
|
file_list = [os.path.splitext(os.path.basename(f))[0] for f in glob.glob(os.path.join(config['root_path'],'addons', 'base', 'i18n', '*.po'))]
|
2008-07-22 14:24:36 +00:00
|
|
|
lang_dict = get_languages()
|
2008-11-21 19:50:42 +00:00
|
|
|
ret = [(lang, lang_dict.get(lang, lang)) for lang in file_list]
|
|
|
|
ret.sort(key=lambda k:k[1])
|
|
|
|
return ret
|
2006-12-07 13:41:40 +00:00
|
|
|
|
2007-04-23 13:13:47 +00:00
|
|
|
|
|
|
|
def get_user_companies(cr, user):
|
2008-07-22 14:24:36 +00:00
|
|
|
def _get_company_children(cr, ids):
|
|
|
|
if not ids:
|
|
|
|
return []
|
|
|
|
cr.execute('SELECT id FROM res_company WHERE parent_id = any(array[%s])' %(','.join([str(x) for x in ids]),))
|
|
|
|
res=[x[0] for x in cr.fetchall()]
|
|
|
|
res.extend(_get_company_children(cr, res))
|
|
|
|
return res
|
2008-12-09 13:35:40 +00:00
|
|
|
cr.execute('SELECT comp.id FROM res_company AS comp, res_users AS u WHERE u.id = %s AND comp.id = u.company_id' % (user,))
|
2008-07-22 14:24:36 +00:00
|
|
|
compids=[cr.fetchone()[0]]
|
|
|
|
compids.extend(_get_company_children(cr, compids))
|
|
|
|
return compids
|
2007-04-23 13:13:47 +00:00
|
|
|
|
2007-10-04 05:59:39 +00:00
|
|
|
def mod10r(number):
|
2008-07-22 14:24:36 +00:00
|
|
|
"""
|
|
|
|
Input number : account or invoice number
|
|
|
|
Output return: the same number completed with the recursive mod10
|
|
|
|
key
|
|
|
|
"""
|
|
|
|
codec=[0,9,4,6,8,2,7,1,3,5]
|
|
|
|
report = 0
|
|
|
|
result=""
|
|
|
|
for digit in number:
|
|
|
|
result += digit
|
|
|
|
if digit.isdigit():
|
|
|
|
report = codec[ (int(digit) + report) % 10 ]
|
|
|
|
return result + str((10 - report) % 10)
|
2007-10-04 05:59:39 +00:00
|
|
|
|
2008-06-03 11:14:02 +00:00
|
|
|
|
2008-09-02 10:09:28 +00:00
|
|
|
def human_size(sz):
|
|
|
|
"""
|
|
|
|
Return the size in a human readable format
|
|
|
|
"""
|
|
|
|
if not sz:
|
|
|
|
return False
|
|
|
|
units = ('bytes', 'Kb', 'Mb', 'Gb')
|
2008-09-16 13:32:15 +00:00
|
|
|
if isinstance(sz,basestring):
|
|
|
|
sz=len(sz)
|
2008-09-02 10:09:28 +00:00
|
|
|
s, i = float(sz), 0
|
|
|
|
while s >= 1024 and i < len(units)-1:
|
|
|
|
s = s / 1024
|
|
|
|
i = i + 1
|
|
|
|
return "%0.2f %s" % (s, units[i])
|
2008-06-03 11:14:02 +00:00
|
|
|
|
2008-12-12 10:51:23 +00:00
|
|
|
def logged(f):
|
2008-12-12 11:49:45 +00:00
|
|
|
from tools.func import wraps
|
2008-12-12 10:51:23 +00:00
|
|
|
|
|
|
|
@wraps(f)
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
import netsvc
|
|
|
|
from pprint import pformat
|
|
|
|
|
|
|
|
vector = ['Call -> function: %r' % f]
|
2008-09-09 16:15:17 +00:00
|
|
|
for i, arg in enumerate(args):
|
2008-12-12 10:51:23 +00:00
|
|
|
vector.append(' arg %02d: %s' % (i, pformat(arg)))
|
2008-09-09 16:15:17 +00:00
|
|
|
for key, value in kwargs.items():
|
2008-12-12 10:51:23 +00:00
|
|
|
vector.append(' kwarg %10s: %s' % (key, pformat(value)))
|
|
|
|
|
|
|
|
timeb4 = time.time()
|
|
|
|
res = f(*args, **kwargs)
|
|
|
|
|
|
|
|
vector.append(' result: %s' % pformat(res))
|
|
|
|
vector.append(' time delta: %s' % (time.time() - timeb4))
|
2008-12-18 10:20:03 +00:00
|
|
|
netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, '\n'.join(vector))
|
2008-12-12 10:51:23 +00:00
|
|
|
return res
|
|
|
|
|
|
|
|
return wrapper
|
2008-09-09 16:15:17 +00:00
|
|
|
|
2008-12-18 10:20:03 +00:00
|
|
|
def debug(what):
|
|
|
|
"""
|
|
|
|
This method allow you to debug your code without print
|
|
|
|
Example:
|
|
|
|
>>> def func_foo(bar)
|
|
|
|
... baz = bar
|
|
|
|
... debug(baz)
|
|
|
|
... qnx = (baz, bar)
|
|
|
|
... debug(qnx)
|
|
|
|
...
|
|
|
|
>>> func_foo(42)
|
|
|
|
|
|
|
|
This will output on the logger:
|
|
|
|
|
|
|
|
[Wed Dec 25 00:00:00 2008] DEBUG:func_foo:baz = 42
|
|
|
|
[Wed Dec 25 00:00:00 2008] DEBUG:func_foo:qnx = (42, 42)
|
|
|
|
|
|
|
|
To view the DEBUG lines in the logger you must start the server with the option
|
|
|
|
--log-level=debug
|
|
|
|
|
|
|
|
"""
|
|
|
|
import netsvc
|
|
|
|
from inspect import stack
|
|
|
|
import re
|
|
|
|
from pprint import pformat
|
|
|
|
st = stack()[1]
|
|
|
|
param = re.split("debug *\((.+)\)", st[4][0].strip())[1].strip()
|
|
|
|
while param.count(')') > param.count('('): param = param[:param.rfind(')')]
|
2008-12-22 16:55:15 +00:00
|
|
|
what = pformat(what)
|
|
|
|
if param != what:
|
|
|
|
what = "%s = %s" % (param, what)
|
|
|
|
netsvc.Logger().notifyChannel(st[3], netsvc.LOG_DEBUG, what)
|
2008-12-18 10:20:03 +00:00
|
|
|
|
2008-06-03 11:14:02 +00:00
|
|
|
|
2008-09-16 12:26:07 +00:00
|
|
|
icons = map(lambda x: (x,x), ['STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD',
|
|
|
|
'STOCK_CANCEL', 'STOCK_CDROM', 'STOCK_CLEAR', 'STOCK_CLOSE', 'STOCK_COLOR_PICKER',
|
|
|
|
'STOCK_CONNECT', 'STOCK_CONVERT', 'STOCK_COPY', 'STOCK_CUT', 'STOCK_DELETE',
|
|
|
|
'STOCK_DIALOG_AUTHENTICATION', 'STOCK_DIALOG_ERROR', 'STOCK_DIALOG_INFO',
|
|
|
|
'STOCK_DIALOG_QUESTION', 'STOCK_DIALOG_WARNING', 'STOCK_DIRECTORY', 'STOCK_DISCONNECT',
|
|
|
|
'STOCK_DND', 'STOCK_DND_MULTIPLE', 'STOCK_EDIT', 'STOCK_EXECUTE', 'STOCK_FILE',
|
|
|
|
'STOCK_FIND', 'STOCK_FIND_AND_REPLACE', 'STOCK_FLOPPY', 'STOCK_GOTO_BOTTOM',
|
|
|
|
'STOCK_GOTO_FIRST', 'STOCK_GOTO_LAST', 'STOCK_GOTO_TOP', 'STOCK_GO_BACK',
|
|
|
|
'STOCK_GO_DOWN', 'STOCK_GO_FORWARD', 'STOCK_GO_UP', 'STOCK_HARDDISK',
|
|
|
|
'STOCK_HELP', 'STOCK_HOME', 'STOCK_INDENT', 'STOCK_INDEX', 'STOCK_ITALIC',
|
|
|
|
'STOCK_JUMP_TO', 'STOCK_JUSTIFY_CENTER', 'STOCK_JUSTIFY_FILL',
|
|
|
|
'STOCK_JUSTIFY_LEFT', 'STOCK_JUSTIFY_RIGHT', 'STOCK_MEDIA_FORWARD',
|
|
|
|
'STOCK_MEDIA_NEXT', 'STOCK_MEDIA_PAUSE', 'STOCK_MEDIA_PLAY',
|
|
|
|
'STOCK_MEDIA_PREVIOUS', 'STOCK_MEDIA_RECORD', 'STOCK_MEDIA_REWIND',
|
|
|
|
'STOCK_MEDIA_STOP', 'STOCK_MISSING_IMAGE', 'STOCK_NETWORK', 'STOCK_NEW',
|
|
|
|
'STOCK_NO', 'STOCK_OK', 'STOCK_OPEN', 'STOCK_PASTE', 'STOCK_PREFERENCES',
|
|
|
|
'STOCK_PRINT', 'STOCK_PRINT_PREVIEW', 'STOCK_PROPERTIES', 'STOCK_QUIT',
|
|
|
|
'STOCK_REDO', 'STOCK_REFRESH', 'STOCK_REMOVE', 'STOCK_REVERT_TO_SAVED',
|
|
|
|
'STOCK_SAVE', 'STOCK_SAVE_AS', 'STOCK_SELECT_COLOR', 'STOCK_SELECT_FONT',
|
|
|
|
'STOCK_SORT_ASCENDING', 'STOCK_SORT_DESCENDING', 'STOCK_SPELL_CHECK',
|
|
|
|
'STOCK_STOP', 'STOCK_STRIKETHROUGH', 'STOCK_UNDELETE', 'STOCK_UNDERLINE',
|
|
|
|
'STOCK_UNDO', 'STOCK_UNINDENT', 'STOCK_YES', 'STOCK_ZOOM_100',
|
|
|
|
'STOCK_ZOOM_FIT', 'STOCK_ZOOM_IN', 'STOCK_ZOOM_OUT',
|
|
|
|
'terp-account', 'terp-crm', 'terp-mrp', 'terp-product', 'terp-purchase',
|
|
|
|
'terp-sale', 'terp-tools', 'terp-administration', 'terp-hr', 'terp-partner',
|
|
|
|
'terp-project', 'terp-report', 'terp-stock', 'terp-calendar', 'terp-graph',
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-06-03 11:14:02 +00:00
|
|
|
if __name__ == '__main__':
|
|
|
|
import doctest
|
|
|
|
doctest.testmod()
|
|
|
|
|
|
|
|
|
2008-07-23 15:01:27 +00:00
|
|
|
|
|
|
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
|
|
|