[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:
@@ -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
|
||||
|
||||
@@ -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,))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 []
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user