From 967a41f4674aba65e82fe32bb2bfbc160234c674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Mon, 6 Feb 2023 18:40:00 +0100 Subject: [PATCH] Add global and local set of ignored context keys Closes #11234 --- trytond/CHANGELOG | 1 + trytond/doc/ref/cache.rst | 3 ++- trytond/trytond/cache.py | 21 ++++++++++++++++----- trytond/trytond/tests/test_cache.py | 25 +++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/trytond/CHANGELOG b/trytond/CHANGELOG index 8a93195a44..26e2e0aa21 100644 --- a/trytond/CHANGELOG +++ b/trytond/CHANGELOG @@ -1,3 +1,4 @@ +* Add local and global list of ignore context keys * Add functions in transaction for check access and active record * Add check_access and active_records attribute to Transaction * Add searchable and sortable methods on Field diff --git a/trytond/doc/ref/cache.rst b/trytond/doc/ref/cache.rst index 3b94e10ebb..076cae3628 100644 --- a/trytond/doc/ref/cache.rst +++ b/trytond/doc/ref/cache.rst @@ -4,7 +4,7 @@ Cache ===== -.. class:: Cache(name[, size_limit[, duration[, context]]]) +.. class:: Cache(name[, size_limit[, duration[, context[, context_ignored_keys]]]]) Use to cache values between server requests. @@ -19,6 +19,7 @@ Cache And the ``context`` parameter is used to indicate if the cache depends on the user context and is ``True`` by default. + Keys specified in ``context_ignored_keys`` are ignored. The cache is cleaned on :class:`~trytond.transaction.Transaction` starts and resets on :class:`~trytond.transaction.Transaction` commit or rollback. diff --git a/trytond/trytond/cache.py b/trytond/trytond/cache.py index d1c670ecc8..4a4ec71a3c 100644 --- a/trytond/trytond/cache.py +++ b/trytond/trytond/cache.py @@ -64,11 +64,23 @@ def _get_modules(cursor): class BaseCache(object): _instances = {} + context_ignored_keys = { + 'client', '_request', '_check_access', '_skip_warnings', + } - def __init__(self, name, size_limit=1024, duration=None, context=True): + def __init__( + self, name, size_limit=1024, duration=None, context=True, + context_ignored_keys=None): + assert ((context_ignored_keys is not None and context) + or (context_ignored_keys is None)), ( + f"context_ignored_keys ({context_ignored_keys}) is not valid" + f" in regards to context ({context}).") self._name = name self.size_limit = size_limit self.context = context + self.context_ignored_keys = set() + if context and context_ignored_keys: + self.context_ignored_keys.update(context_ignored_keys) self.hit = self.miss = 0 if isinstance(duration, dt.timedelta): self.duration = duration @@ -93,10 +105,9 @@ class BaseCache(object): def _key(self, key): if self.context: context = Transaction().context.copy() - context.pop('client', None) - context.pop('_request', None) - context.pop('_check_access', None) - context.pop('_skip_warnings', None) + for k in (self.__class__.context_ignored_keys + | self.context_ignored_keys): + context.pop(k, None) return (key, Transaction().user, freeze(context)) return key diff --git a/trytond/trytond/tests/test_cache.py b/trytond/trytond/tests/test_cache.py index a30801a26d..42dce5fd99 100644 --- a/trytond/trytond/tests/test_cache.py +++ b/trytond/trytond/tests/test_cache.py @@ -15,6 +15,9 @@ from trytond.transaction import Transaction cache = MemoryCache('test.cache') cache_expire = MemoryCache('test.cache_expire', duration=1) +cache_ignored_local_context = MemoryCache( + 'test.cache.ignored.local', context_ignored_keys={'ignored'}) +cache_ignored_global_context = MemoryCache('test.cache.ignored.global') class CacheTestCase(unittest.TestCase): @@ -64,6 +67,28 @@ class CacheTestCase(unittest.TestCase): with self.subTest(value=value): self.assertEqual(unfreeze(value), result) + @with_transaction() + def test_ignored_context_key_global(self): + "Test global keys are ignored from context" + with Transaction().set_context(client='foo'): + cache_ignored_global_context.set('key', 0) + + with Transaction().set_context(client='bar'): + value = cache_ignored_global_context.get('key') + + self.assertEqual(value, 0) + + @with_transaction() + def test_ignored_context_key_local(self): + "Test local keys are ignored from context" + with Transaction().set_context(ignored='foo'): + cache_ignored_local_context.set('key', 1) + + with Transaction().set_context(ignored='bar'): + value = cache_ignored_local_context.get('key') + + self.assertEqual(value, 1) + class MemoryCacheTestCase(unittest.TestCase): "Test Cache"