# HG changeset patch # User Nicolas Évrard <nicoe@b2ck.com> # Date 1675705200 -3600 # Mon Feb 06 18:40:00 2023 +0100 # Node ID 8616fb62c5e94e83eb6fc8c908917a45e35e7d38 # Parent 08779343f15d8d37b859218172796e01692ac1db Add global and local set of ignored context keys Closes #11234 diff --git a/trytond/CHANGELOG b/trytond/CHANGELOG --- 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 --- 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 @@ 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 --- a/trytond/trytond/cache.py +++ b/trytond/trytond/cache.py @@ -64,11 +64,23 @@ 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 @@ 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 --- a/trytond/trytond/tests/test_cache.py +++ b/trytond/trytond/tests/test_cache.py @@ -15,6 +15,9 @@ 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 @@ 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"