From f433751a3c6d1bd764cee81e468beca360487de3 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Tue, 2 Apr 2024 14:43:52 -0400 Subject: [PATCH] fix: Be able to clear the process_cache manually in Python 3.11 Given code like the following ``` class Foo: @process_cached def bar(self): pass ``` In Python 3.8 referencing `bar` would not call its `__get__` method. ``` x = Foo().bar ``` However in Python 3.11, making the same call would call the `__get__` method, permanently replacing the underlying `process_cached` object with the partial function that references it. This meant that code to clear the cache would work in Python 3.8 but would break in 3.11 ``` Foo().bar.cache.clear() # Works in 3.8 but not in 3.11 ``` In 3.11 this results in the following error: ``` E AttributeError: 'functools.partial' object has no attribute 'cache' ``` To make this compatible in both version, we just add the cache as an accessible attribute on the partial we generate for our wrapped function. --- openedx/core/lib/cache_utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openedx/core/lib/cache_utils.py b/openedx/core/lib/cache_utils.py index ecbfb9b94883..c379ab2d961a 100644 --- a/openedx/core/lib/cache_utils.py +++ b/openedx/core/lib/cache_utils.py @@ -147,7 +147,10 @@ def __get__(self, obj, objtype): """ Support instance methods. """ - return functools.partial(self.__call__, obj) + partial = functools.partial(self.__call__, obj) + # Make the cache accessible on the wrapped object so it can be cleared if needed. + partial.cache = self.cache + return partial class CacheInvalidationManager: