Skip to content

Commit

Permalink
Merge pull request #6611 from PrimozGodec/fix-embeder-cache
Browse files Browse the repository at this point in the history
[FIX] EmbedderCache - Handle cache persisting when no permissions
  • Loading branch information
VesnaT committed Oct 30, 2023
2 parents 219852d + 5acc6f8 commit dde4638
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 9 deletions.
70 changes: 69 additions & 1 deletion Orange/misc/tests/test_embedder_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import os
import shutil
import stat
import tempfile
import unittest
from unittest.mock import patch

from Orange.misc.utils.embedder_utils import get_proxies
from Orange.misc.utils.embedder_utils import get_proxies, EmbedderCache


class TestProxies(unittest.TestCase):
Expand Down Expand Up @@ -63,5 +67,69 @@ def test_none(self):
self.assertIsNone(get_proxies())


class TestEmbedderCache(unittest.TestCase):
# pylint: disable=protected-access
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
patcher = patch(
"Orange.misc.utils.embedder_utils.cache_dir", return_value=self.temp_dir
)
patcher.start()
self.addCleanup(patch.stopall)

def tearDown(self):
shutil.rmtree(self.temp_dir)

def test_save_load_cache(self):
# open when cache file doesn't exist yet
cache = EmbedderCache("TestModel")
self.assertDictEqual({}, cache._cache_dict)

# add values and save to test opening with existing file
cache.add("abc", [1, 2, 3])
cache.persist_cache()

cache = EmbedderCache("TestModel")
self.assertDictEqual({"abc": [1, 2, 3]}, cache._cache_dict)

def test_save_cache_no_permission(self):
# prepare a file
cache = EmbedderCache("TestModel")
self.assertDictEqual({}, cache._cache_dict)
cache.add("abc", [1, 2, 3])
cache.persist_cache()

# set file to read-only and try to write
curr_permission = os.stat(cache._cache_file_path).st_mode
os.chmod(cache._cache_file_path, stat.S_IRUSR)
cache.add("abcd", [1, 2, 3])
# new values should be cached since file is readonly
cache.persist_cache()
cache = EmbedderCache("TestModel")
self.assertDictEqual({"abc": [1, 2, 3]}, cache._cache_dict)
os.chmod(cache._cache_file_path, curr_permission)

def test_load_cache_no_permission(self):
# prepare a file
cache = EmbedderCache("TestModel")
self.assertDictEqual({}, cache._cache_dict)
cache.add("abc", [1, 2, 3])
cache.persist_cache()

# no read permission - load no cache
if os.name == "nt":
with patch(
"Orange.misc.utils.embedder_utils.pickle.load",
side_effect=PermissionError,
):
# it is difficult to change write permission on Windows using
# patch instead
cache = EmbedderCache("TestModel")
else:
os.chmod(cache._cache_file_path, stat.S_IWUSR)
cache = EmbedderCache("TestModel")
self.assertDictEqual({}, cache._cache_dict)


if __name__ == "__main__":
unittest.main()
20 changes: 12 additions & 8 deletions Orange/misc/utils/embedder_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,25 @@ def __init__(self, model):

def _init_cache(self):
if isfile(self._cache_file_path):
try:
return self.load_pickle(self._cache_file_path)
except EOFError:
return {}
return self.load_pickle(self._cache_file_path)
return {}

@staticmethod
def save_pickle(obj, file_name):
with open(file_name, 'wb') as f:
pickle.dump(obj, f)
try:
with open(file_name, 'wb') as f:
pickle.dump(obj, f)
except PermissionError:
# do not save cache if no right permission
pass

@staticmethod
def load_pickle(file_name):
with open(file_name, 'rb') as f:
return pickle.load(f)
try:
with open(file_name, 'rb') as f:
return pickle.load(f)
except (EOFError, PermissionError):
return {}

@staticmethod
def md5_hash(bytes_):
Expand Down

0 comments on commit dde4638

Please sign in to comment.