From f6cf94d4bdb1722f49d56ef2c54ecba30dd334e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Voet=20=28ryv=29?= Date: Wed, 11 Jan 2023 11:57:16 +0000 Subject: [PATCH] [FIX] *: ormcache works with annotation The `ormcache` decorator fails to create the key method (`determine_key`) when the method signature contains any annotation. Fix it by removing annotation of the signature. closes odoo/odoo#109777 Signed-off-by: Raphael Collet --- odoo/addons/base/models/ir_model.py | 2 +- odoo/tools/cache.py | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/odoo/addons/base/models/ir_model.py b/odoo/addons/base/models/ir_model.py index 8e84e64a605..1ec765f41f0 100644 --- a/odoo/addons/base/models/ir_model.py +++ b/odoo/addons/base/models/ir_model.py @@ -1999,7 +1999,7 @@ class IrModelData(models.Model): # NEW V8 API @api.model @tools.ormcache('xmlid') - def _xmlid_lookup(self, xmlid): + def _xmlid_lookup(self, xmlid: str) -> tuple: """Low level xmlid lookup Return (id, res_model, res_id) or raise ValueError if not found """ diff --git a/odoo/tools/cache.py b/odoo/tools/cache.py index 662cd0d0653..912affbba6d 100644 --- a/odoo/tools/cache.py +++ b/odoo/tools/cache.py @@ -4,7 +4,7 @@ # decorator makes wrappers that have the same API as their wrapped function from collections import Counter, defaultdict from decorator import decorator -from inspect import signature +from inspect import signature, Parameter import logging unsafe_eval = eval @@ -64,7 +64,13 @@ class ormcache(object): """ 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 = str(signature(self.method))[1:-1] + args = ', '.join( + # remove annotations because lambdas can't be type-annotated, + # and defaults because they are redundant (defaults are present + # in the wrapper function itself) + str(params.replace(annotation=Parameter.empty, default=Parameter.empty)) + for params in signature(self.method).parameters.values() + ) if self.args: code = "lambda %s: (%s,)" % (args, ", ".join(self.args)) else: @@ -114,7 +120,10 @@ class ormcache_context(ormcache): assert self.skiparg is None, "ormcache_context() no longer supports skiparg" # build a string that represents function code and evaluate it sign = signature(self.method) - args = str(sign)[1:-1] + args = ', '.join( + str(params.replace(annotation=Parameter.empty, default=Parameter.empty)) + for params in sign.parameters.values() + ) cont_expr = "(context or {})" if 'context' in sign.parameters else "self._context" keys_expr = "tuple(%s.get(k) for k in %r)" % (cont_expr, self.keys) if self.args: @@ -143,7 +152,10 @@ class ormcache_multi(ormcache): # key_multi computes the extra element added to the key sign = signature(self.method) - args = str(sign)[1:-1] + args = ', '.join( + str(params.replace(annotation=Parameter.empty, default=Parameter.empty)) + for params in sign.parameters.values() + ) code_multi = "lambda %s: %s" % (args, self.multi) self.key_multi = unsafe_eval(code_multi)