[IMP] ir.translation,tools.translate._(): cleanup and speedup if translations via _()

- Removed expensive inspect.stack() (courtesy of xrg)
- Improved heuristics for detection of context/lang and cursor
- Switch to using ir.translation when possible instead of direct DB hit to benefit from cache
- Cleanup

lp bug: https://launchpad.net/bugs/624114 fixed

bzr revid: odo@openerp.com-20101215114019-psrsu998inw6cksu
This commit is contained in:
Olivier Dony 2010-12-15 12:40:19 +01:00
parent 516dc572c4
commit 650490d61d
2 changed files with 77 additions and 41 deletions

View File

@ -138,7 +138,7 @@ class ir_translation(osv.osv):
and source. All values passed to this method should be unicode (not byte strings),
especially ``source``.
:param name: identification of the term to translate, such as field name
:param name: identification of the term to translate, such as field name (optional if source is passed)
:param types: single string defining type of term to translate (see ``type`` field on ir.translation), or sequence of allowed types (strings)
:param lang: language code of the desired translation
:param source: optional source term to translate (should be unicode)
@ -153,19 +153,22 @@ class ir_translation(osv.osv):
if isinstance(types, basestring):
types = (types,)
if source:
cr.execute('select value ' \
'from ir_translation ' \
'where lang=%s ' \
'and type in %s ' \
'and name=%s ' \
'and src=%s',
(lang or '', types, tools.ustr(name), source))
query = """SELECT value
FROM ir_translation
WHERE lang=%s
AND type in %s
AND src=%s"""
params = (lang or '', types, source)
if name:
query += " AND name=%s"
params += (tools.ustr(name),)
cr.execute(query, params)
else:
cr.execute('select value ' \
'from ir_translation ' \
'where lang=%s ' \
'and type in %s ' \
'and name=%s',
cr.execute("""SELECT value
FROM ir_translation
WHERE lang=%s
AND type in %s
AND name=%s"""
(lang or '', types, tools.ustr(name)))
res = cr.fetchone()
trad = res and res[0] or u''

View File

@ -26,10 +26,12 @@ import inspect
import itertools
import locale
import os
import pooler
import re
import logging
import tarfile
import tempfile
import threading
from os.path import join
import logging
@ -153,48 +155,79 @@ logger = logging.getLogger('translate')
class GettextAlias(object):
def _get_db_pool(self):
# find current DB based on thread/worker db name (see netsvc)
db_name = getattr(threading.currentThread(), 'dbname', None)
if db_name:
dbname = getattr(threading.currentThread(), 'dbname')
return pooler.get_db_and_pool(dbname)
return (None, None)
def _get_cr(self, frame):
is_new_cr = False
cr = frame.f_locals.get('cr')
new_cr = False
cr = frame.f_locals.get('cr', frame.f_locals.get('cursor'))
if not cr:
s = frame.f_locals.get('self', {})
cr = getattr(s, 'cr', False)
if not cr:
if frame.f_globals.get('pooler', False):
# TODO: we should probably get rid of the 'is_new_cr' case: no cr in locals -> no translation for you
dbs = frame.f_globals['pooler'].pool_dic.keys()
if len(dbs) == 1:
cr = pooler.get_db(dbs[0]).cursor()
is_new_cr = True
return cr, is_new_cr
cr = getattr(s, 'cr', None)
if not cr:
db, _ = self._get_db_pool()
if db:
cr = db.cursor()
new_cr = True
return cr, new_cr
def _get_lang(self, frame):
lang = frame.f_locals.get('context', {}).get('lang', False)
lang = None
ctx = frame.f_locals.get('context')
if not ctx:
kwargs = frame.f_locals.get('kwargs')
if kwargs is None:
args = frame.f_locals.get('args')
if args and isinstance(args, (list, tuple)) \
and isinstance(args[-1], dict):
ctx = args[-1]
elif isinstance(kwargs, dict):
ctx = kwargs.get('context')
if ctx:
lang = ctx.get('lang')
if not lang:
args = frame.f_locals.get('args', False)
if args:
lang = args[-1].get('lang', False)
if not lang:
s = frame.f_locals.get('self', {})
c = getattr(s, 'localcontext', {})
lang = c.get('lang', False)
s = frame.f_locals.get('self', {})
c = getattr(s, 'localcontext', None)
if c:
lang = c.get('lang')
return lang
def __call__(self, source):
is_new_cr = False
res = source
cr = None
new_cr = False
try:
frame = inspect.stack()[1][0]
cr, is_new_cr = self._get_cr(frame)
frame = inspect.currentframe()
if frame is None:
return source
frame = frame.f_back
if not frame:
return source
lang = self._get_lang(frame)
if lang and cr:
cr.execute('SELECT value FROM ir_translation WHERE lang=%s AND type IN (%s, %s) AND src=%s', (lang, 'code','sql_constraint', source))
res_trans = cr.fetchone()
res = res_trans and res_trans[0] or source
if lang:
cr, new_cr = self._get_cr(frame)
if cr:
# Try to use ir.translation to benefit from global cache if possible
_, pool = self._get_db_pool()
if pool:
res = pool.get('ir.translation')._get_source(cr, 1, None, ('code','sql_constraint'), lang, source)
else:
cr.execute('SELECT value FROM ir_translation WHERE lang=%s AND type IN (%s, %s) AND src=%s', (lang, 'code','sql_constraint', source))
res_trans = cr.fetchone()
res = res_trans and res_trans[0] or source
else:
logger.debug('no context cursor detected, skipping translation for "%r"', source)
else:
logger.debug('no translation language detected, skipping translation for "%r" ', source)
except Exception:
logger.debug('translation went wrong for string %s', repr(source))
logger.debug('translation went wrong for "%r", skipped', source)
finally:
if is_new_cr:
if cr and new_cr:
cr.close()
return res