Use always the immutable value from the cache

This prevents issues like #14433 from being missed.
This commit is contained in:
Cédric Krier
2025-12-19 09:39:32 +01:00
parent d9b73072df
commit aefd12642a
29 changed files with 63 additions and 90 deletions
+1 -2
View File
@@ -1170,8 +1170,7 @@ class PaymentBraintreeCustomer(
for payment_method in customer.payment_methods:
name = self._payment_method_name(payment_method)
methods.append((payment_method.token, name))
self._payment_methods_cache.set(self.id, methods)
return methods
return self._payment_methods_cache.set(self.id, methods)
def _payment_method_name(cls, payment_method):
name = payment_method.token
+2 -4
View File
@@ -1712,8 +1712,7 @@ class Customer(CheckoutMixin, DeactivableMixin, ModelSQL, ModelView):
else:
continue
sources.append((source.id, name))
self._sources_cache.set(self.id, sources)
return sources
return self._sources_cache.set(self.id, sources)
@classmethod
def _source_name(cls, source):
@@ -1779,8 +1778,7 @@ class Customer(CheckoutMixin, DeactivableMixin, ModelSQL, ModelView):
for payment_method in payment_methods:
name = self._payment_method_name(payment_method)
methods.append((payment_method.id, name))
self._payment_methods_cache.set(self.id, methods)
return methods
return self._payment_methods_cache.set(self.id, methods)
@classmethod
def _payment_method_name(cls, payment_method):
+1 -1
View File
@@ -210,7 +210,7 @@ class Period(Workflow, ModelSQL, ModelView):
result = record.ends_at
else:
result = None
cls._last_period_cache.set(key, result)
result = cls._last_period_cache.set(key, result)
return result
@classmethod
+2 -5
View File
@@ -174,9 +174,7 @@ class User(metaclass=PoolMeta):
companies = [c.id for c in user.companies]
else:
companies = []
companies = tuple(companies)
cls._get_companies_cache.set(user_id, companies)
return companies
return cls._get_companies_cache.set(user_id, companies)
@classmethod
def get_employees(cls):
@@ -196,8 +194,7 @@ class User(metaclass=PoolMeta):
else:
employees = []
employees = tuple(employees)
cls._get_employees_cache.set(user_id, employees)
return employees
return cls._get_employees_cache.set(user_id, employees)
@classmethod
def read(cls, ids, fields_names):
+2 -4
View File
@@ -625,8 +625,7 @@ ${COUNTRY}"""
else:
format_ = getattr(cls, f'default_{field}', lambda: '')()
cls._get_format_cache.set(key, format_)
return format_
return cls._get_format_cache.set(key, format_)
class SubdivisionType(DeactivableMixin, ModelSQL, ModelView):
@@ -670,8 +669,7 @@ class SubdivisionType(DeactivableMixin, ModelSQL, ModelView):
else:
types = []
cls._get_types_cache.set(key, types)
return types
return cls._get_types_cache.set(key, types)
@classmethod
def on_modification(cls, mode, types, field_names=None):
+2 -1
View File
@@ -119,7 +119,8 @@ class PriceListCache(ModelSQL):
unit_prices = self._unit_prices_cache.get(self.raw_unit_prices)
if unit_prices is None:
unit_prices = loads(self.raw_unit_prices)
self._unit_prices_cache.set(self.raw_unit_prices, unit_prices)
unit_prices = self._unit_prices_cache.set(
self.raw_unit_prices, unit_prices)
return unit_prices
@classmethod
@@ -73,7 +73,7 @@ class ProductPriceListCacheTestCase(ModuleTestCase):
self.assertEqual(cache.product, product)
self.assertEqual(cache.uom, kilogram)
self.assertEqual(
cache.unit_prices, [[0, Decimal(10)], [10, Decimal(9)]])
cache.unit_prices, ((0, Decimal(10)), (10, Decimal(9))))
self.assertEqual(cache.pattern, None)
# Test cached compute
+2 -4
View File
@@ -64,8 +64,7 @@ class WorkStatus(DeactivableMixin, sequence_ordered(), ModelSQL, ModelView):
status = records[0].id
else:
status = None
cls._get_default_status_cache.set(type, status)
return status
return cls._get_default_status_cache.set(type, status)
@classmethod
def on_modification(cls, mode, records, field_names=None):
@@ -100,8 +99,7 @@ class WorkStatus(DeactivableMixin, sequence_ordered(), ModelSQL, ModelView):
if domains:
domains.append(
(gettext('project.msg_domain_all'), '[]', False))
cls._get_window_domains_cache.set(key, domains)
return domains
return cls._get_window_domains_cache.set(key, domains)
class Work(
+1 -1
View File
@@ -369,7 +369,7 @@ class Location(DeactivableMixin, tree(), ModelSQL, ModelView):
warehouse = warehouses[0].id
else:
warehouse = None
cls._default_warehouse_cache.set(None, warehouse)
warehouse = cls._default_warehouse_cache.set(None, warehouse)
return warehouse
@property
@@ -94,8 +94,7 @@ class CredentialSendcloud(sequence_ordered(), ModelSQL, ModelView, MatchMixin):
auth=self.auth, timeout=timeout, headers=HEADERS)
response.raise_for_status()
addresses = response.json()['sender_addresses']
self._addresses_sender_cache.set(self.id, addresses)
return addresses
return self._addresses_sender_cache.set(self.id, addresses)
def get_sender_address(self, shipment_or_warehouse, pattern=None):
pattern = pattern.copy() if pattern is not None else {}
@@ -131,8 +130,7 @@ class CredentialSendcloud(sequence_ordered(), ModelSQL, ModelView, MatchMixin):
auth=self.auth, timeout=timeout, headers=HEADERS)
response.raise_for_status()
methods = response.json()['shipping_methods']
self._shiping_methods_cache.set(key, methods)
return methods
return self._shiping_methods_cache.set(key, methods)
def get_shipping_method(self, shipment, package=None):
pattern = self._get_shipping_method_pattern(shipment, package=package)
+2 -1
View File
@@ -46,7 +46,8 @@ class Employee(metaclass=PoolMeta):
for cost_price in cost_prices:
employee_costs.append(
(cost_price.date, cost_price.cost_price))
self._cost_prices_cache.set(self.id, employee_costs)
employee_costs = self._cost_prices_cache.set(
self.id, employee_costs)
return employee_costs
def compute_cost_price(self, date=None):
+2 -1
View File
@@ -1027,7 +1027,8 @@ class Shop_Warehouse(ModelView, metaclass=PoolMeta):
QUERY_LOCATIONS, {}, 'locations'):
locations.append(
(str(gid2id(location['id'])), location['name']))
self._shopify_locations_cache.set(self.shop.id, locations)
locations = self._shopify_locations_cache.set(
self.shop.id, locations)
except GraphQLException:
pass
return locations
+1 -1
View File
@@ -54,7 +54,7 @@ Cache
.. method:: Cache.set(key, value)
Set the ``value`` of the ``key`` in the cache.
Set and return the ``value`` of the ``key`` in the cache.
.. method:: Cache.clear()
+2 -1
View File
@@ -224,7 +224,8 @@ class MemoryCache(BaseCache):
else:
expire = None
try:
cache[key] = (expire, immutable(value))
value = immutable(value)
cache[key] = (expire, value)
except TypeError:
pass
return value
+7 -11
View File
@@ -336,8 +336,7 @@ class ActionKeyword(ModelSQL, ModelView):
value['name'] = (
parent.rec_name + ' / ' + value['name'])
keywords.sort(key=itemgetter('name'))
cls._get_keyword_cache.set(key, keywords)
return keywords
return cls._get_keyword_cache.set(key, keywords)
class ActionMixin(ModelSQL):
@@ -421,7 +420,7 @@ class ActionMixin(ModelSQL):
key = (name, action_id)
groups = Action._groups_cache.get(key)
if groups is not None:
return set(groups)
return groups
domain = [
(cls._action_name, '=', name),
@@ -430,8 +429,7 @@ class ActionMixin(ModelSQL):
domain.append(('id', '=', action_id))
actions = cls.search(domain)
groups = {g.id for a in actions for g in a.groups}
Action._groups_cache.set(key, list(groups))
return groups
return Action._groups_cache.set(key, groups)
@classmethod
def on_modification(cls, mode, records, field_names=None):
@@ -749,7 +747,7 @@ class ActionReport(
return template
def set_template_cached(self, template):
self._template_cache.set(self.id, template)
return self._template_cache.set(self.id, template)
@classmethod
def validate_fields(cls, reports, field_names):
@@ -1096,7 +1094,7 @@ class ActionWizard(
key = (name, action_id)
models = cls._get_models_cache.get(key)
if models is not None:
return set(models)
return models
domain = [
(cls._action_name, '=', name),
@@ -1105,8 +1103,7 @@ class ActionWizard(
domain.append(('id', '=', action_id))
actions = cls.search(domain)
models = {a.model for a in actions if a.model}
cls._get_models_cache.set(key, models)
return models
return cls._get_models_cache.set(key, models)
@classmethod
def get_name(cls, name, model):
@@ -1129,8 +1126,7 @@ class ActionWizard(
if actions:
action, = actions
wiz_name = action.name
cls._get_name_cache.set(key, wiz_name)
return wiz_name
return cls._get_name_cache.set(key, wiz_name)
@classmethod
def on_modification(cls, mode, keywords, field_names=None):
+1 -2
View File
@@ -25,8 +25,7 @@ class Configuration(ModelSingleton, ModelSQL):
language = cls(1).language
if not language:
language = config.get('database', 'language')
cls._get_language_cache.set(None, language)
return language
return cls._get_language_cache.set(None, language)
def check(self):
"Check configuration coherence on pool initialisation"
+6 -5
View File
@@ -387,14 +387,15 @@ class Lang(DeactivableMixin, ModelSQL, ModelView):
exception=exception)) from exception
def get_translatable_languages(cls):
res = cls._lang_cache.get('translatable_languages')
if res is None:
languages = cls._lang_cache.get('translatable_languages')
if languages is None:
langs = cls.search([
('translatable', '=', True),
])
res = [x.code for x in langs]
cls._lang_cache.set('translatable_languages', res)
return res
languages = [x.code for x in langs]
languages = cls._lang_cache.set(
'translatable_languages', languages)
return languages
@classmethod
def check_modification(cls, mode, languages, values=None, external=False):
+2 -2
View File
@@ -37,7 +37,7 @@ class Message(ModelSQL, ModelView):
text = translation.value or message.text
else:
text = message.text
cls._message_cache.set(key, text)
text = cls._message_cache.set(key, text)
return text if not variables else text % variables
@classmethod
@@ -68,7 +68,7 @@ class Message(ModelSQL, ModelView):
text = values[index] or fallback
else:
text = fallback
cls._message_cache.set(key, text)
text = cls._message_cache.set(key, text)
return text if not variables else text % variables
def _get_translation(self, language, fuzzy=False):
+10 -17
View File
@@ -185,11 +185,8 @@ class Model(
items = (
(m, n) for m, n in items
if issubclass(pool_get(m), classes))
items = list(items)
cls._get_names_cache.set(key, items)
else:
items = list(items)
return items
items = cls._get_names_cache.set(key, list(items))
return list(items)
@classmethod
def get_names(cls, classes=None):
@@ -198,7 +195,7 @@ class Model(
dict_ = cls._get_names_cache.get(key)
if dict_ is None:
dict_ = dict(cls.get_name_items())
cls._get_names_cache.set(key, dict_)
dict_ = cls._get_names_cache.set(key, dict_)
return dict_
@classmethod
@@ -476,7 +473,7 @@ class ModelField(
if fields:
field, = fields
name = field.string
cls._get_name_cache.set((model, field), name)
name = cls._get_name_cache.set((model, field), name)
else:
name = field
return name
@@ -1078,8 +1075,7 @@ class ModelButton(
else:
button, = buttons
reset = [b.name for b in button.reset]
cls._reset_cache.set(key, reset)
return reset
return cls._reset_cache.set(key, reset)
@classmethod
def get_groups(cls, model, name):
@@ -1099,8 +1095,7 @@ class ModelButton(
else:
button, = buttons
groups = set(g.id for g in button.groups)
cls._groups_cache.set(key, groups)
return groups
return cls._groups_cache.set(key, groups)
@classmethod
def get_view_attributes(cls, model, name):
@@ -1122,8 +1117,7 @@ class ModelButton(
'help': button.help,
'confirm': button.confirm,
}
cls._view_attributes_cache.set(key, attributes)
return attributes
return cls._view_attributes_cache.set(key, attributes)
class ModelButtonGroup(DeactivableMixin, ModelSQL):
@@ -1374,8 +1368,8 @@ class ModelData(
cursor = Transaction().connection.cursor()
cursor.execute(*table.select(table.model, group_by=[table.model]))
models = [m for m, in cursor]
cls._has_model_cache.set(None, models)
models = set(m for m, in cursor)
models = cls._has_model_cache.set(None, models)
return model in models
@classmethod
@@ -1446,8 +1440,7 @@ class ModelData(
except ValueError:
raise KeyError(f"Reference to '{module}.{fs_id}' not found")
cls._get_id_cache.set(key, data.db_id)
return data.db_id
return cls._get_id_cache.set(key, data.db_id)
@classmethod
def dump_values(cls, values):
+1 -2
View File
@@ -326,8 +326,7 @@ class Rule(ModelSQL, ModelView):
elif clause_global:
clause = clause_global
cls._domain_get_cache.set(key, clause)
return clause
return cls._domain_get_cache.set(key, clause)
@classmethod
def query_get(cls, model_name, mode='read'):
+1 -2
View File
@@ -319,8 +319,7 @@ class Translation(
Lang = pool.get('ir.lang')
langs = Lang.search([])
result = [(lang.code, lang.name) for lang in langs]
cls._get_language_cache.set(language, result)
return result
return cls._get_language_cache.set(language, result)
@classmethod
def view_attributes(cls):
+2 -3
View File
@@ -197,7 +197,7 @@ class View(
rng_name = os.path.join(os.path.dirname(__file__), type_ + '.rng')
with open(rng_name, 'rb') as fp:
rng = etree.fromstring(fp.read())
cls._get_rng_cache.set(key, rng)
rng = cls._get_rng_cache.set(key, rng)
return rng
@property
@@ -333,8 +333,7 @@ class View(
'arch': arch,
'field_childs': self.field_childs,
}
self._view_get_cache.set(key, result)
return result
return self._view_get_cache.set(key, result)
@classmethod
def inherit_apply(cls, tree, inherit):
+1 -2
View File
@@ -207,8 +207,7 @@ class DictSchemaMixin(object):
return fields
keys = cls.get_keys(cls.search([]))
fields = {k['name']: k for k in keys}
cls._relation_fields_cache.set(cls.__name__, fields)
return fields
return cls._relation_fields_cache.set(cls.__name__, fields)
@classmethod
def on_modification(cls, mode, records, field_names=None):
+1 -2
View File
@@ -22,8 +22,7 @@ class DigitsMixin:
if digits is not None:
return digits
digits = self._get_digits()
self._digits_cache.set(key, digits)
return digits
return self._digits_cache.set(key, digits)
def _get_digits(self):
return (None, self.digits)
+1 -1
View File
@@ -736,7 +736,7 @@ class ModelSQL(ModelStorage):
if count is None:
count = transaction.database.estimated_count(
transaction.connection, cls.__table__())
cls._count_cache.set(cls.__name__, count)
count = cls._count_cache.set(cls.__name__, count)
return count
@classmethod
+1 -1
View File
@@ -783,7 +783,7 @@ class ModelStorage(Model):
count = cls._count_cache.get(cls.__name__)
if count is None:
count = cls.search([], count=True)
cls._count_cache.set(cls.__name__, count)
count = cls._count_cache.set(cls.__name__, count)
return count
def resources(self):
+4 -6
View File
@@ -273,7 +273,6 @@ class ModelView(Model):
result = cls._fields_view_get_cache.get(key)
if result:
return result
result = {'model': cls.__name__}
pool = Pool()
View = pool.get('ir.ui.view')
@@ -297,10 +296,11 @@ class ModelView(Model):
# if a view was found
if view:
result = view.view_get(model=cls.__name__)
result = dict(view.view_get(model=cls.__name__))
# otherwise, build some kind of default view
else:
result = {}
if view_type == 'form':
res = cls.fields_get()
xml = '''<?xml version="1.0"?>''' \
@@ -348,8 +348,7 @@ class ModelView(Model):
tree, result['type'], view_id=view_id,
field_children=result['field_childs'], level=level)
cls._fields_view_get_cache.set(key, result)
return result
return cls._fields_view_get_cache.set(key, result)
@classmethod
def view_toolbar_get(cls):
@@ -389,8 +388,7 @@ class ModelView(Model):
'exports': exports,
'emails': emails,
}
cls._view_toolbar_get_cache.set(key, result)
return result
return cls._view_toolbar_get_cache.set(key, result)
@classmethod
def view_attributes(cls):
+1 -1
View File
@@ -392,7 +392,7 @@ class Report(URLMixin, PoolBase):
loader = relatorio.reporting.MIMETemplateLoader()
klass = loader.factories[loader.get_type(mimetype)]
template = klass(BytesIO(report.report_content))
report.set_template_cached(template)
template = report.set_template_cached(template)
translate = cls._callback_loader(report, template)
if translate:
report_context = report_context.copy()
+1 -2
View File
@@ -634,8 +634,7 @@ class User(avatar_mixin(100, 'login'), DeactivableMixin, ModelSQL, ModelView):
& (group.active == Literal(True))),
order_by=[user_group.group.asc]))
groups = tuple(g for g, in cursor)
cls._get_groups_cache.set(user, groups)
return groups
return cls._get_groups_cache.set(user, groups)
@classmethod
def _get_login(cls, login):