Replace memoize with functools.lru_cache
issue9081 review286781002
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Replace memoize with functools.lru_cache
|
||||
* Add support for Python 3.8
|
||||
* Set all fields readonly for inactive record
|
||||
* Enable check_access context when checking wizard access (issue9108)
|
||||
|
||||
@@ -7,15 +7,14 @@ import csv
|
||||
|
||||
from decimal import Decimal
|
||||
from itertools import islice, chain
|
||||
from functools import wraps
|
||||
from functools import lru_cache, wraps
|
||||
from operator import itemgetter
|
||||
from collections import defaultdict
|
||||
|
||||
from trytond.exceptions import UserError
|
||||
from trytond.model import Model
|
||||
from trytond.model import fields
|
||||
from trytond.tools import reduce_domain, memoize, is_instance_method, \
|
||||
grouped_slice
|
||||
from trytond.tools import reduce_domain, is_instance_method, grouped_slice
|
||||
from trytond.tools.domain_inversion import (
|
||||
domain_inversion, parse as domain_parse)
|
||||
from trytond.pyson import PYSONEncoder, PYSONDecoder, PYSON
|
||||
@@ -696,7 +695,7 @@ class ModelStorage(Model):
|
||||
'''
|
||||
pool = Pool()
|
||||
|
||||
@memoize(1000)
|
||||
@lru_cache(maxsize=1000)
|
||||
def get_many2one(relation, value):
|
||||
if not value:
|
||||
return None
|
||||
@@ -718,7 +717,7 @@ class ModelStorage(Model):
|
||||
res = res[0].id
|
||||
return res
|
||||
|
||||
@memoize(1000)
|
||||
@lru_cache(maxsize=1000)
|
||||
def get_many2many(relation, value):
|
||||
if not value:
|
||||
return None
|
||||
@@ -748,7 +747,7 @@ class ModelStorage(Model):
|
||||
def get_one2one(relation, value):
|
||||
return ('add', get_many2one(relation, value))
|
||||
|
||||
@memoize(1000)
|
||||
@lru_cache(maxsize=1000)
|
||||
def get_reference(value, field):
|
||||
if not value:
|
||||
return None
|
||||
@@ -758,7 +757,7 @@ class ModelStorage(Model):
|
||||
raise ImportDataError(
|
||||
gettext('ir.msg_reference_syntax_error',
|
||||
value=value,
|
||||
field='/'.join(field)))
|
||||
field=field))
|
||||
Relation = pool.get(relation)
|
||||
res = Relation.search([
|
||||
('rec_name', '=', value),
|
||||
@@ -777,7 +776,7 @@ class ModelStorage(Model):
|
||||
res = '%s,%s' % (relation, res[0].id)
|
||||
return res
|
||||
|
||||
@memoize(1000)
|
||||
@lru_cache(maxsize=1000)
|
||||
def get_by_id(value, field, ftype):
|
||||
if not value:
|
||||
return None
|
||||
@@ -792,7 +791,7 @@ class ModelStorage(Model):
|
||||
raise ImportDataError(
|
||||
gettext('ir.msg_reference_syntax_error',
|
||||
value=value,
|
||||
field='/'.join(field)))
|
||||
field=field))
|
||||
value = [value]
|
||||
else:
|
||||
value = [value]
|
||||
@@ -804,7 +803,7 @@ class ModelStorage(Model):
|
||||
raise ImportDataError(
|
||||
gettext('ir.msg_xml_id_syntax_error',
|
||||
value=word,
|
||||
field='/'.join(field)))
|
||||
field=field))
|
||||
db_id = ModelData.get_id(module, xml_id)
|
||||
res_ids.append(db_id)
|
||||
if ftype == 'many2many' and res_ids:
|
||||
@@ -838,7 +837,8 @@ class ModelStorage(Model):
|
||||
value = line[i]
|
||||
if is_prefix_len and field[-1].endswith(':id'):
|
||||
ftype = fields_def[field[-1][:-3]]['type']
|
||||
row[field[0][:-3]] = get_by_id(value, field, ftype)
|
||||
row[field[0][:-3]] = get_by_id(
|
||||
value, '/'.join(field), ftype)
|
||||
elif is_prefix_len and ':lang=' in field[-1]:
|
||||
field_name, lang = field[-1].split(':lang=')
|
||||
translate.setdefault(lang, {})[field_name] = value or False
|
||||
@@ -904,7 +904,7 @@ class ModelStorage(Model):
|
||||
elif field_type == 'one2one':
|
||||
res = get_one2one(this_field_def['relation'], value)
|
||||
elif field_type == 'reference':
|
||||
res = get_reference(value, field)
|
||||
res = get_reference(value, '/'.join(field))
|
||||
else:
|
||||
res = value or None
|
||||
row[field[-1]] = res
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from .misc import (
|
||||
file_open, get_smtp_server, memoize, reduce_ids, reduce_domain,
|
||||
file_open, get_smtp_server, reduce_ids, reduce_domain,
|
||||
grouped_slice, is_instance_method, resolve, strip_wildcard,
|
||||
lstrip_wildcard, rstrip_wildcard, slugify)
|
||||
from .decimal_ import decistmt
|
||||
|
||||
__all__ = ['file_open', 'get_smtp_server', 'memoize', 'reduce_ids',
|
||||
__all__ = ['file_open', 'get_smtp_server', 'reduce_ids',
|
||||
'reduce_domain', 'grouped_slice', 'is_instance_method', 'resolve',
|
||||
'strip_wildcard', 'lstrip_wildcard', 'rstrip_wildcard', 'slugify',
|
||||
'decistmt', 'ClassProperty', 'cursor_dict']
|
||||
|
||||
@@ -90,69 +90,6 @@ def get_smtp_server():
|
||||
return get_smtp_server()
|
||||
|
||||
|
||||
def memoize(maxsize):
|
||||
"""
|
||||
Decorator to 'memoize' a function - caching its results with a
|
||||
near LRU implementation.
|
||||
|
||||
The cache keeps a list of keys logicaly separated in 4 segment :
|
||||
|
||||
segment 1 | ... | segment4
|
||||
[k,k,k,k,k,k,k, .. ,k,k,k,k,k,k,k]
|
||||
|
||||
For each segment there is a pointer that loops on it. When a key
|
||||
is accessed from the cache it is promoted to the first segment (at
|
||||
the pointer place of segment one), the key under the pointer is
|
||||
moved to the next segment, the pointer is then incremented and so
|
||||
on. A key that is removed from the last segment is removed from
|
||||
the cache.
|
||||
|
||||
:param: maxsize the size of the cache (must be greater than or
|
||||
equal to 4)
|
||||
"""
|
||||
assert maxsize >= 4, "Memoize cannot work if maxsize is less than 4"
|
||||
|
||||
def wrap(fct):
|
||||
cache = {}
|
||||
keys = [None for i in range(maxsize)]
|
||||
seg_size = maxsize // 4
|
||||
|
||||
pointers = [i * seg_size for i in range(4)]
|
||||
max_pointers = [(i + 1) * seg_size for i in range(3)] + [maxsize]
|
||||
|
||||
def wrapper(*args):
|
||||
key = repr(args)
|
||||
res = cache.get(key)
|
||||
if res:
|
||||
pos, res = res
|
||||
keys[pos] = None
|
||||
else:
|
||||
res = fct(*args)
|
||||
|
||||
value = res
|
||||
for segment, pointer in enumerate(pointers):
|
||||
newkey = keys[pointer]
|
||||
keys[pointer] = key
|
||||
cache[key] = (pointer, value)
|
||||
|
||||
pointers[segment] = pointer + 1
|
||||
if pointers[segment] == max_pointers[segment]:
|
||||
pointers[segment] = segment * seg_size
|
||||
|
||||
if newkey is None:
|
||||
break
|
||||
segment, value = cache.pop(newkey)
|
||||
key = newkey
|
||||
|
||||
return res
|
||||
|
||||
wrapper.__doc__ = fct.__doc__
|
||||
wrapper.__name__ = fct.__name__
|
||||
|
||||
return wrapper
|
||||
return wrap
|
||||
|
||||
|
||||
def reduce_ids(field, ids):
|
||||
'''
|
||||
Return a small SQL expression for the list of ids and the sql column
|
||||
|
||||
Reference in New Issue
Block a user