-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Python wrapper entry cache adjustment #354
Python wrapper entry cache adjustment #354
Conversation
d502f4a
to
3f99844
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's very much worthwhile to add a unit test that asserts caching works as expected.
GPT helped me generate the following -- maybe it's helpful inspiration, but obviously just auto-generated and requires more attention to detail:
import unittest
from unittest.mock import patch, MagicMock
from aries_askar.bindings.handle import EntryListHandle
class TestEntryCache(unittest.TestCase):
@patch('aries_askar.bindings.lib.Lib')
def test_get_category_caching(self, mock_lib):
# Setup the mock for Lib().invoke
mock_invoke = MagicMock()
# Define return values for different indices
mock_invoke.side_effect = [
'Category1', # For index 0
'Category2', # For index 1
]
mock_lib_instance = mock_lib.return_value
mock_lib_instance.invoke.return_value = None # Assuming invoke modifies the StrBuffer in place
# Initialize EntryListHandle
handle = EntryListHandle(value=123)
with patch('aries_askar.bindings.lib.StrBuffer') as MockStrBuffer:
# Mock StrBuffer to return the desired string
mock_str_buffer_instance = MockStrBuffer.return_value
mock_str_buffer_instance.__str__.return_value = mock_invoke()
# First call with index 0
category1_first = handle.get_category(0)
self.assertEqual(category1_first, 'Category1')
mock_lib_instance.invoke.assert_called_with(
"askar_entry_list_get_category",
(EntryListHandle, int, unittest.mock.ANY),
handle,
0,
unittest.mock.ANY,
)
# Reset mock to track subsequent calls
mock_lib_instance.invoke.reset_mock()
# Second call with index 0 (should use cache)
category1_second = handle.get_category(0)
self.assertEqual(category1_second, 'Category1')
mock_lib_instance.invoke.assert_not_called()
# Call with a new index 1
mock_str_buffer_instance.__str__.return_value = mock_invoke() # Update return value
category2 = handle.get_category(1)
self.assertEqual(category2, 'Category2')
mock_lib_instance.invoke.assert_called_with(
"askar_entry_list_get_category",
(EntryListHandle, int, unittest.mock.ANY),
handle,
1,
unittest.mock.ANY,
)
# Reset mock to track subsequent calls
mock_lib_instance.invoke.reset_mock()
# Call again with index 1 (should use cache)
category2_second = handle.get_category(1)
self.assertEqual(category2_second, 'Category2')
mock_lib_instance.invoke.assert_not_called()
if __name__ == '__main__':
unittest.main()
cache[ckey] = res | ||
if isinstance(res, dict): | ||
# make sure the cached copy is not mutated | ||
res = dict(res) | ||
return res |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct? If res is a dict, it's cast to a dict?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dict
constructor creates a new instance by iterating through the old instance's entries, but I changed it to a deep copy anyway in case there's nested structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aah I see now -- that modifying res
downstream would modify the same object stored in cache. Was a lil confusing at first
…evel Signed-off-by: Andrew Whitehead <[email protected]>
Signed-off-by: Andrew Whitehead <[email protected]>
Signed-off-by: Andrew Whitehead <[email protected]>
3f99844
to
aa554a1
Compare
I've added a unit test that should cover the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice 👍
From the Python library documentation it appears that the native
lru_cache
decorator could result in caching of Entry instances longer than necessary. This PR switches to a custom cache implementation at the EntryList level which should avoid any undesired behaviour.@ff137