Replace memoize with functools.lru_cache

issue9081
review286781002
This commit is contained in:
David Harper
2020-03-25 17:34:35 +01:00
parent 6b3eb52d17
commit ba776f36a5
4 changed files with 15 additions and 77 deletions
+1
View File
@@ -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)
+12 -12
View File
@@ -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 -2
View File
@@ -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']
-63
View File
@@ -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