# 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"