##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
+# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
def init_db(cr):
import addons
f = addons.get_module_resource('base', 'base.sql')
- for line in file(f).read().split(';'):
+ for line in file_open(f).read().split(';'):
if (len(line)>0) and (not line.isspace()):
cr.execute(line)
cr.commit()
if not mod_path:
continue
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 os.path.isfile(terp_file) or os.path.isfile(mod_path+'.zip'):
+ info = eval(file_open(terp_file).read())
if info:
categs = info.get('category', 'Uncategorized').split('/')
p_id = None
id, info.get('author', ''),
info.get('website', ''), i, info.get('name', False),
info.get('description', ''), p_id, state))
+ cr.execute('insert into ir_model_data \
+ (name,model,module, res_id) values (%s,%s,%s,%s)', (
+ 'module_meta_information', 'ir.module.module', i, id))
dependencies = info.get('depends', [])
for d in dependencies:
cr.execute('insert into ir_module_module_dependency \
else:
zipname = tail
if zipfile.is_zipfile(head+'.zip'):
- import StringIO
+ from cStringIO import StringIO
zfile = zipfile.ZipFile(head+'.zip')
try:
- fo = StringIO.StringIO(zfile.read(os.path.join(
+ fo = StringIO()
+ fo.write(zfile.read(os.path.join(
os.path.basename(head), zipname).replace(
os.sep, '/')))
-
+ fo.seek(0)
if pathinfo:
return fo, name
return fo
#----------------------------------------------------------
# Emails
#----------------------------------------------------------
-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'):
+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', x_headers=None):
"""Send an email."""
import smtplib
from email.MIMEText import MIMEText
from email.Utils import formatdate, COMMASPACE
from email import Encoders
+ if x_headers is None:
+ x_headers = {}
+
if not ssl:
ssl = config.get('smtp_ssl', False)
+ if not email_from and not config['email_from']:
+ raise Exception("No Email sender by default, see config file")
+
if not email_cc:
email_cc = []
if not email_bcc:
else:
msg = MIMEMultipart()
- msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
+ msg['Subject'] = Header(ustr(subject), 'utf-8')
msg['From'] = email_from
del msg['Reply-To']
if reply_to:
- msg['Reply-To'] = msg['From']+', '+reply_to
+ msg['Reply-To'] = reply_to
+ else:
+ msg['Reply-To'] = msg['From']
msg['To'] = COMMASPACE.join(email_to)
if email_cc:
msg['Cc'] = COMMASPACE.join(email_cc)
msg['Bcc'] = COMMASPACE.join(email_bcc)
msg['Date'] = formatdate(localtime=True)
+ # Add OpenERP Server information
+ msg['X-Generated-By'] = 'OpenERP (http://www.openerp.com)'
+ msg['X-OpenERP-Server-Host'] = socket.gethostname()
+ msg['X-OpenERP-Server-Version'] = release.version
+
+ # Add dynamic X Header
+ for key, value in x_headers.items():
+ msg['X-OpenERP-%s' % key] = str(value)
+
if tinycrm:
msg['Message-Id'] = "<%s-tinycrm-%s@%s>" % (time.time(), tinycrm, socket.gethostname())
# text must be latin-1 encoded
def sms_send(user, password, api_id, text, to):
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)
+ url = "http://api.urlsms.com/SendSMS.aspx"
+ #url = "http://196.7.150.220/http/sendmsg"
+ params = urllib.urlencode({'UserID': user, 'Password': password, 'SenderID': api_id, 'MsgText': text, 'RecipientMobileNo':to})
+ f = urllib.urlopen(url+"?"+params)
# FIXME: Use the logger if there is an error
- print f.read()
return True
#---------------------------------------------------------
except TypeError:
return False
-#
-# Use it as a decorator of the function you plan to cache
-# Timeout: 0 = no timeout, otherwise in seconds
-#
class cache(object):
- def __init__(self, timeout=10000, skiparg=2):
- self.timeout = timeout
+ """
+ Use it as a decorator of the function you plan to cache
+ Timeout: 0 = no timeout, otherwise in seconds
+ """
+
+ __caches = []
+
+ def __init__(self, timeout=None, skiparg=2, multi=None):
+ assert skiparg >= 2 # at least self and cr
+ if timeout is None:
+ self.timeout = config['cache_timeout']
+ else:
+ self.timeout = timeout
+ self.skiparg = skiparg
+ self.multi = multi
+ self.lasttime = time.time()
self.cache = {}
+ self.fun = None
+ cache.__caches.append(self)
+
+
+ def _generate_keys(self, dbname, kwargs2):
+ """
+ Generate keys depending of the arguments and the self.mutli value
+ """
+
+ def to_tuple(d):
+ i = d.items()
+ i.sort(key=lambda (x,y): x)
+ return tuple(i)
+
+ if not self.multi:
+ key = (('dbname', dbname),) + to_tuple(kwargs2)
+ yield key, None
+ else:
+ multis = kwargs2[self.multi][:]
+ for id in multis:
+ kwargs2[self.multi] = (id,)
+ key = (('dbname', dbname),) + to_tuple(kwargs2)
+ yield key, id
+
+ def _unify_args(self, *args, **kwargs):
+ # Update named arguments with positional argument values (without self and cr)
+ kwargs2 = self.fun_default_values.copy()
+ kwargs2.update(kwargs)
+ kwargs2.update(dict(zip(self.fun_arg_names, args[self.skiparg-2:])))
+ 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])
+
+ return kwargs2
+
+ def clear(self, dbname, *args, **kwargs):
+ """clear the cache for database dbname
+ if *args and **kwargs are both empty, clear all the keys related to this database
+ """
+ if not args and not kwargs:
+ keys_to_del = [key for key in self.cache if key[0][1] == dbname]
+ else:
+ kwargs2 = self._unify_args(*args, **kwargs)
+ keys_to_del = [key for key, _ in self._generate_keys(dbname, kwargs2) if key in self.cache]
+
+ for key in keys_to_del:
+ del self.cache[key]
+
+ @classmethod
+ def clean_caches_for_db(cls, dbname):
+ for c in cls.__caches:
+ c.clear(dbname)
def __call__(self, fn):
- arg_names = inspect.getargspec(fn)[0][2:]
- def cached_result(self2, cr=None, *args, **kwargs):
- if cr is None:
- self.cache = {}
- return True
-
- # Update named arguments with positional argument values
- kwargs.update(dict(zip(arg_names, args)))
- for k in kwargs:
- if isinstance(kwargs[k], (list, dict, set)):
- kwargs[k] = tuple(kwargs[k])
- elif not is_hashable(kwargs[k]):
- kwargs[k] = repr(kwargs[k])
- kwargs = kwargs.items()
- kwargs.sort()
-
- # Work out key as a tuple of ('argname', value) pairs
- key = (('dbname', cr.dbname),) + tuple(kwargs)
-
- # Check cache and return cached value if possible
- if key in self.cache:
- (value, last_time) = self.cache[key]
- mintime = time.time() - self.timeout
- if self.timeout <= 0 or mintime <= last_time:
- return value
-
- # Work out new value, cache it and return it
- # FIXME Should copy() this value to avoid futur modifications of the cache ?
- # FIXME What about exceptions ?
- result = fn(self2,cr,**dict(kwargs))
-
- self.cache[key] = (result, time.time())
+ if self.fun is not None:
+ raise Exception("Can not use a cache instance on more than one function")
+ self.fun = fn
+
+ argspec = inspect.getargspec(fn)
+ self.fun_arg_names = argspec[0][self.skiparg:]
+ self.fun_default_values = {}
+ if argspec[3]:
+ self.fun_default_values = dict(zip(self.fun_arg_names[-len(argspec[3]):], argspec[3]))
+
+ def cached_result(self2, cr, *args, **kwargs):
+ if time.time()-self.timeout > self.lasttime:
+ self.lasttime = time.time()
+ t = time.time()-self.timeout
+ for key in self.cache.keys():
+ if self.cache[key][1]<t:
+ del self.cache[key]
+
+ kwargs2 = self._unify_args(*args, **kwargs)
+
+ result = {}
+ notincache = {}
+ for key, id in self._generate_keys(cr.dbname, kwargs2):
+ if key in self.cache:
+ result[id] = self.cache[key][0]
+ else:
+ notincache[id] = key
+
+ if notincache:
+ if self.multi:
+ kwargs2[self.multi] = notincache.keys()
+
+ result2 = fn(self2, cr, *args[2:self.skiparg], **kwargs2)
+ if not self.multi:
+ key = notincache[None]
+ self.cache[key] = (result2, time.time())
+ result[None] = result2
+ else:
+ for id in result2:
+ key = notincache[id]
+ self.cache[key] = (result2[id], time.time())
+ result.update(result2)
+
+ if not self.multi:
+ return result[None]
return result
+
+ cached_result.clear_cache = self.clear
return cached_result
def to_xml(s):
if not isinstance(value, str):
value = str(value)
- return unicode(value, 'utf-8')
+ try: # first try utf-8
+ return unicode(value, 'utf-8')
+ except:
+ pass
+
+ try: # then extened iso-8858
+ return unicode(value, 'iso-8859-15')
+ except:
+ pass
+
+ # else use default system locale
+ from locale import getlocale
+ return unicode(value, getlocale()[1])
+
+def exception_to_unicode(e):
+ if hasattr(e, 'message'):
+ return ustr(e.message)
+ if hasattr(e, 'args'):
+ return "\n".join((ustr(a) for a in e.args))
+ try:
+ return ustr(e)
+ except:
+ return u"Unknow message"
+
+
+# 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
+
def get_languages():
languages={
+ 'ar_AR': u'Arabic / الْعَرَبيّة',
'bg_BG': u'Bulgarian / български',
+ 'bs_BS': u'Bosnian / bosanski jezik',
'ca_ES': u'Catalan / Català',
'cs_CZ': u'Czech / Čeština',
+ 'da_DK': u'Danish / Dansk',
'de_DE': u'German / Deutsch',
+ 'el_EL': u'Greek / Ελληνικά',
'en_CA': u'English (CA)',
'en_EN': u'English (default)',
'en_GB': u'English (UK)',
'en_US': u'English (US)',
'es_AR': u'Spanish (AR) / Español (AR)',
'es_ES': u'Spanish / Español',
- 'et_ET': u'Estonian / Eesti keel',
+ 'et_EE': u'Estonian / Eesti keel',
'fr_BE': u'French (BE) / Français (BE)',
'fr_CH': u'French (CH) / Français (CH)',
'fr_FR': u'French / Français',
'hr_HR': u'Croatian / hrvatski jezik',
'hu_HU': u'Hungarian / Magyar',
+ 'id_ID': u'Indonesian / Bahasa Indonesia',
'it_IT': u'Italian / Italiano',
'lt_LT': u'Lithuanian / Lietuvių kalba',
'nl_NL': u'Dutch / Nederlands',
+ 'nl_BE': u'Dutch (Belgium) / Nederlands (Belgïe)',
+ 'pl_PL': u'Polish / Język polski',
'pt_BR': u'Portugese (BR) / português (BR)',
'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',
+ 'tr_TR': u'Turkish / Türkçe',
'uk_UK': u'Ukrainian / украї́нська мо́ва',
'zh_CN': u'Chinese (CN) / 简体中文' ,
'zh_TW': u'Chinese (TW) / 正體字',
i = i + 1
return "%0.2f %s" % (s, units[i])
-def logged(when):
- import netsvc
- def log(f, res, *args, **kwargs):
- vector = ['Call -> function: %s' % f]
+def logged(f):
+ from tools.func import wraps
+
+ @wraps(f)
+ def wrapper(*args, **kwargs):
+ import netsvc
+ from pprint import pformat
+
+ vector = ['Call -> function: %r' % f]
for i, arg in enumerate(args):
- vector.append( ' arg %02d: %r' % ( i, arg ) )
+ vector.append(' arg %02d: %s' % (i, pformat(arg)))
for key, value in kwargs.items():
- vector.append( ' kwarg %10s: %r' % ( key, value ) )
- vector.append( ' result: %r' % res )
- netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, vector)
+ 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))
+ netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, '\n'.join(vector))
+ return res
- def pre_logged(f):
- def wrapper(*args, **kwargs):
- res = f(*args, **kwargs)
- log(f, res, *args, **kwargs)
- return res
- return wrapper
+ return wrapper
- def post_logged(f):
+class profile(object):
+ def __init__(self, fname=None):
+ self.fname = fname
+
+ def __call__(self, f):
+ from tools.func import wraps
+
+ @wraps(f)
def wrapper(*args, **kwargs):
- now = time.time()
- res = None
- try:
- res = f(*args, **kwargs)
- return res
- finally:
- log(f, res, *args, **kwargs)
- netsvc.Logger().notifyChannel('logged', netsvc.LOG_DEBUG, "time delta: %s" % (time.time() - now))
+ class profile_wrapper(object):
+ def __init__(self):
+ self.result = None
+ def __call__(self):
+ self.result = f(*args, **kwargs)
+ pw = profile_wrapper()
+ import cProfile
+ fname = self.fname or ("%s.cprof" % (f.func_name,))
+ cProfile.runctx('pw()', globals(), locals(), filename=fname)
+ return pw.result
+
return wrapper
- try:
- return { "pre" : pre_logged, "post" : post_logged}[when]
- except KeyError, e:
- raise ValueError(e), "must to be 'pre' or 'post'"
+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(')')]
+ what = pformat(what)
+ if param != what:
+ what = "%s = %s" % (param, what)
+ netsvc.Logger().notifyChannel(st[3], netsvc.LOG_DEBUG, what)
+
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',
'terp-project', 'terp-report', 'terp-stock', 'terp-calendar', 'terp-graph',
])
+def extract_zip_file(zip_file, outdirectory):
+ import zipfile
+ import os
+
+ zf = zipfile.ZipFile(zip_file, 'r')
+ out = outdirectory
+ for path in zf.namelist():
+ tgt = os.path.join(out, path)
+ tgtdir = os.path.dirname(tgt)
+ if not os.path.exists(tgtdir):
+ os.makedirs(tgtdir)
+
+ if not tgt.endswith(os.sep):
+ fp = open(tgt, 'wb')
+ fp.write(zf.read(path))
+ fp.close()
+ zf.close()
+
+
+
if __name__ == '__main__':