[IMP] ormcache: improve API to enable the decoration of new-api methods

The new signature of ormcache() is way more intuitive: simply list the names of
the method arguments that compose the cache key (see documentation and existing
code).  A backward-compatible mode is available by using the keyword argument
`skiparg`.
This commit is contained in:
Raphael Collet
2015-05-19 09:59:42 +02:00
parent baca220bb7
commit 0ae59c779f
9 changed files with 47 additions and 21 deletions
+1 -1
View File
@@ -913,7 +913,7 @@ class ir_model_data(osv.osv):
cr.execute('CREATE INDEX ir_model_data_module_name_index ON ir_model_data (module, name)')
# NEW V8 API
@tools.ormcache(skiparg=3)
@tools.ormcache('xmlid')
def xmlid_lookup(self, cr, uid, xmlid):
"""Low level xmlid lookup
Return (id, res_model, res_id) or raise ValueError if not found
+1 -1
View File
@@ -103,7 +103,7 @@ class ir_rule(osv.osv):
(_check_model_name, 'Rules can not be applied on the Record Rules model.', ['model_id']),
]
@tools.ormcache()
@tools.ormcache('uid', 'model_name', 'mode')
def _compute_domain(self, cr, uid, model_name, mode="read"):
if mode not in self._MODES:
raise ValueError('Invalid mode: %r' % (mode,))
+1 -1
View File
@@ -333,7 +333,7 @@ class ir_translation(osv.osv):
return (query, params)
@tools.ormcache(skiparg=3)
@tools.ormcache('name', 'types', 'lang', 'source', 'res_id')
def __get_source(self, cr, uid, name, types, lang, source, res_id):
# res_id is a tuple or None, otherwise ormcache cannot cache it!
query, params = self._get_source_query(cr, uid, name, types, lang, source, res_id)
+1 -1
View File
@@ -1070,7 +1070,7 @@ class view(osv.osv):
self._translate_qweb(cr, uid, arch, translate_func, context=context)
return arch
@openerp.tools.ormcache()
@openerp.tools.ormcache('uid', 'id')
def get_view_xmlid(self, cr, uid, id):
imd = self.pool['ir.model.data']
domain = [('model', '=', 'ir.ui.view'), ('res_id', '=', id)]
+1 -1
View File
@@ -337,7 +337,7 @@ class ir_values(osv.osv):
return defaults.values()
# use ormcache: this is called a lot by BaseModel.default_get()!
@tools.ormcache(skiparg=2)
@tools.ormcache('uid', 'model', 'condition')
def get_defaults_dict(self, cr, uid, model, condition=False):
""" Returns a dictionary mapping field names with their corresponding
default value. This method simply improves the returned value of
+1 -1
View File
@@ -240,7 +240,7 @@ class res_company(osv.osv):
return rule.company_dest_id.id
return user.company_id.id
@tools.ormcache()
@tools.ormcache('uid', 'company')
def _get_company_children(self, cr, uid=None, company=None):
if not company:
return []
+2 -2
View File
@@ -176,13 +176,13 @@ class lang(osv.osv):
(_check_grouping, "The Separator Format should be like [,n] where 0 < n :starting from Unit digit.-1 will end the separation. e.g. [3,2,-1] will represent 106500 to be 1,06,500;[1,2,-1] will represent it to be 106,50,0;[3] will represent it as 106,500. Provided ',' as the thousand separator in each case.", ['grouping'])
]
@tools.ormcache(skiparg=3)
@tools.ormcache('lang')
def _lang_get(self, cr, uid, lang):
lang_ids = self.search(cr, uid, [('code', '=', lang)]) or \
self.search(cr, uid, [('code', '=', 'en_US')])
return lang_ids[0]
@tools.ormcache(skiparg=3)
@tools.ormcache('lang', 'monetary')
def _lang_data_get(self, cr, uid, lang, monetary=False):
if type(lang) in (str, unicode):
lang = self._lang_get(cr, uid, lang)
+5 -8
View File
@@ -344,7 +344,7 @@ class res_users(osv.osv):
for id in ids:
if id in self._uid_cache[db]:
del self._uid_cache[db][id]
self._context_get.clear_cache(self)
self.context_get.clear_cache(self)
self.has_group.clear_cache(self)
return res
@@ -379,9 +379,9 @@ class res_users(osv.osv):
default['login'] = _("%s (copy)") % user2copy['login']
return super(res_users, self).copy(cr, uid, id, default, context)
@tools.ormcache(skiparg=2)
def _context_get(self, cr, uid):
user = self.browse(cr, SUPERUSER_ID, uid)
@tools.ormcache('uid')
def context_get(self, cr, uid, context=None):
user = self.browse(cr, SUPERUSER_ID, uid, context)
result = {}
for k in self._fields:
if k.startswith('context_'):
@@ -397,9 +397,6 @@ class res_users(osv.osv):
result[context_key] = res or False
return result
def context_get(self, cr, uid, context=None):
return self._context_get(cr, uid)
def action_get(self, cr, uid, context=None):
dataobj = self.pool['ir.model.data']
data_id = dataobj._get_id(cr, SUPERUSER_ID, 'base', 'action_res_users_my')
@@ -533,7 +530,7 @@ class res_users(osv.osv):
'target': 'new',
}
@tools.ormcache(skiparg=2)
@tools.ormcache('uid', 'group_ext_id')
def has_group(self, cr, uid, group_ext_id):
"""Checks whether user belongs to given group.
+34 -5
View File
@@ -23,7 +23,7 @@
# this is important for the openerp.api.guess() that relies on signatures
from collections import defaultdict
from decorator import decorator
from inspect import getargspec
from inspect import formatargspec, getargspec
import logging
_logger = logging.getLogger(__name__)
@@ -47,24 +47,53 @@ STAT = defaultdict(ormcache_counter)
class ormcache(object):
""" LRU cache decorator for orm methods. """
""" LRU cache decorator for model methods.
The parameters are strings that represent expressions referring to the
signature of the decorated method, and are used to compute a cache key::
def __init__(self, skiparg=2, size=8192, multi=None, timeout=None):
self.skiparg = skiparg
@ormcache('model_name', 'mode')
def _compute_domain(self, cr, uid, model_name, mode="read"):
...
For the sake of backward compatibility, the decorator supports the named
parameter `skiparg`::
@ormcache(skiparg=3)
def _compute_domain(self, cr, uid, model_name, mode="read"):
...
"""
def __init__(self, *args, **kwargs):
self.args = args
self.skiparg = kwargs.get('skiparg')
def __call__(self, method):
self.method = method
self.determine_key()
lookup = decorator(self.lookup, method)
lookup.clear_cache = self.clear
return lookup
def determine_key(self):
""" Determine the function that computes a cache key from arguments. """
if self.skiparg is None:
# build a string that represents function code and evaluate it
args = formatargspec(*getargspec(self.method))[1:-1]
if self.args:
code = "lambda %s: (%s,)" % (args, ", ".join(self.args))
else:
code = "lambda %s: ()" % (args,)
self.key = eval(code)
else:
# backward-compatible function that uses self.skiparg
self.key = lambda *args, **kwargs: args[self.skiparg:]
def lru(self, model):
counter = STAT[(model.pool.db_name, model._name, self.method)]
return model.pool.cache, (model._name, self.method), counter
def lookup(self, method, *args, **kwargs):
d, key0, counter = self.lru(args[0])
key = key0 + args[self.skiparg:]
key = key0 + self.key(*args, **kwargs)
try:
r = d[key]
counter.hit += 1