Skip to content

Commit 5acc6f8

Browse files
committed
EmbedderCache - Handle cache persisting when no permissions
1 parent 219852d commit 5acc6f8

File tree

2 files changed

+81
-9
lines changed

2 files changed

+81
-9
lines changed

Orange/misc/tests/test_embedder_utils.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import os
2+
import shutil
3+
import stat
4+
import tempfile
25
import unittest
6+
from unittest.mock import patch
37

4-
from Orange.misc.utils.embedder_utils import get_proxies
8+
from Orange.misc.utils.embedder_utils import get_proxies, EmbedderCache
59

610

711
class TestProxies(unittest.TestCase):
@@ -63,5 +67,69 @@ def test_none(self):
6367
self.assertIsNone(get_proxies())
6468

6569

70+
class TestEmbedderCache(unittest.TestCase):
71+
# pylint: disable=protected-access
72+
def setUp(self):
73+
self.temp_dir = tempfile.mkdtemp()
74+
patcher = patch(
75+
"Orange.misc.utils.embedder_utils.cache_dir", return_value=self.temp_dir
76+
)
77+
patcher.start()
78+
self.addCleanup(patch.stopall)
79+
80+
def tearDown(self):
81+
shutil.rmtree(self.temp_dir)
82+
83+
def test_save_load_cache(self):
84+
# open when cache file doesn't exist yet
85+
cache = EmbedderCache("TestModel")
86+
self.assertDictEqual({}, cache._cache_dict)
87+
88+
# add values and save to test opening with existing file
89+
cache.add("abc", [1, 2, 3])
90+
cache.persist_cache()
91+
92+
cache = EmbedderCache("TestModel")
93+
self.assertDictEqual({"abc": [1, 2, 3]}, cache._cache_dict)
94+
95+
def test_save_cache_no_permission(self):
96+
# prepare a file
97+
cache = EmbedderCache("TestModel")
98+
self.assertDictEqual({}, cache._cache_dict)
99+
cache.add("abc", [1, 2, 3])
100+
cache.persist_cache()
101+
102+
# set file to read-only and try to write
103+
curr_permission = os.stat(cache._cache_file_path).st_mode
104+
os.chmod(cache._cache_file_path, stat.S_IRUSR)
105+
cache.add("abcd", [1, 2, 3])
106+
# new values should be cached since file is readonly
107+
cache.persist_cache()
108+
cache = EmbedderCache("TestModel")
109+
self.assertDictEqual({"abc": [1, 2, 3]}, cache._cache_dict)
110+
os.chmod(cache._cache_file_path, curr_permission)
111+
112+
def test_load_cache_no_permission(self):
113+
# prepare a file
114+
cache = EmbedderCache("TestModel")
115+
self.assertDictEqual({}, cache._cache_dict)
116+
cache.add("abc", [1, 2, 3])
117+
cache.persist_cache()
118+
119+
# no read permission - load no cache
120+
if os.name == "nt":
121+
with patch(
122+
"Orange.misc.utils.embedder_utils.pickle.load",
123+
side_effect=PermissionError,
124+
):
125+
# it is difficult to change write permission on Windows using
126+
# patch instead
127+
cache = EmbedderCache("TestModel")
128+
else:
129+
os.chmod(cache._cache_file_path, stat.S_IWUSR)
130+
cache = EmbedderCache("TestModel")
131+
self.assertDictEqual({}, cache._cache_dict)
132+
133+
66134
if __name__ == "__main__":
67135
unittest.main()

Orange/misc/utils/embedder_utils.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,25 @@ def __init__(self, model):
3838

3939
def _init_cache(self):
4040
if isfile(self._cache_file_path):
41-
try:
42-
return self.load_pickle(self._cache_file_path)
43-
except EOFError:
44-
return {}
41+
return self.load_pickle(self._cache_file_path)
4542
return {}
4643

4744
@staticmethod
4845
def save_pickle(obj, file_name):
49-
with open(file_name, 'wb') as f:
50-
pickle.dump(obj, f)
46+
try:
47+
with open(file_name, 'wb') as f:
48+
pickle.dump(obj, f)
49+
except PermissionError:
50+
# do not save cache if no right permission
51+
pass
5152

5253
@staticmethod
5354
def load_pickle(file_name):
54-
with open(file_name, 'rb') as f:
55-
return pickle.load(f)
55+
try:
56+
with open(file_name, 'rb') as f:
57+
return pickle.load(f)
58+
except (EOFError, PermissionError):
59+
return {}
5660

5761
@staticmethod
5862
def md5_hash(bytes_):

0 commit comments

Comments
 (0)