Skip to content

Commit 9d56094

Browse files
authored
Merge pull request #237 from PrimozGodec/fix-cachecontrol
[FIX] ImageLoader - Avoid using http cache when no write/read permission
2 parents 02356b8 + 75db417 commit 9d56094

File tree

2 files changed

+46
-10
lines changed

2 files changed

+46
-10
lines changed

orangecontrib/imageanalytics/utils/embedder_utils.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
from datetime import timedelta
44
from io import BytesIO
55
from os.path import join
6+
from sqlite3 import OperationalError
67
from urllib.error import URLError
78
from urllib.parse import urlparse
89
from urllib.request import urlopen
910

11+
import requests
1012
from AnyQt.QtCore import QStandardPaths
1113
from PIL import ImageFile
1214
from PIL.Image import LANCZOS
@@ -19,16 +21,31 @@
1921

2022

2123
class ImageLoader:
22-
def __init__(self):
24+
_session = None
25+
26+
@property
27+
def session(self):
28+
if self._session is not None:
29+
return self._session
30+
2331
cache_dir = QStandardPaths.writableLocation(QStandardPaths.CacheLocation)
2432
cache_path = join(cache_dir, "networkcache", "image_loader.sqlite")
25-
self._session = CachedSession(
26-
cache_path,
27-
backend="sqlite",
28-
cache_control=True,
29-
expire_after=timedelta(days=1),
30-
stale_if_error=True,
31-
)
33+
try:
34+
self._session = CachedSession(
35+
cache_path,
36+
backend="sqlite",
37+
cache_control=True,
38+
expire_after=timedelta(days=1),
39+
stale_if_error=True,
40+
)
41+
except OperationalError as ex:
42+
# if no permission to write in dir or read cache file return regular session
43+
log.info(
44+
f"Cache file creation/opening failed with: '{str(ex)}'. "
45+
"Using requests.Session instead of cached session."
46+
)
47+
self._session = requests.Session()
48+
return self._session
3249

3350
def load_image_or_none(self, file_path, target_size=None):
3451
if file_path is None:
@@ -66,7 +83,7 @@ def _load_image_from_url_or_local_path(self, file_path):
6683
urlparts = urlparse(file_path)
6784
if urlparts.scheme in ("http", "https"):
6885
try:
69-
file = BytesIO(self._session.get(file_path).content)
86+
file = BytesIO(self.session.get(file_path).content)
7087
except RequestException:
7188
log.warning("Image skipped", exc_info=True)
7289
return None

orangecontrib/imageanalytics/utils/tests/test_embedder_utils.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import unittest
3-
from unittest.mock import patch
3+
from sqlite3 import OperationalError
4+
from unittest.mock import patch, MagicMock
45
from urllib.error import URLError
56

67
import numpy as np
@@ -115,6 +116,24 @@ def test_unsuccessful_convert_to_RGB(self, _) -> None:
115116
image = self.image_loader.load_image_or_none(self.im_paths[2])
116117
self.assertIsNone(image)
117118

119+
@patch("requests_cache.CachedSession.get")
120+
def test_load_images_url_with_http_cache(self, mock) -> None:
121+
with open(self.im_paths[0], "rb") as f:
122+
mock.return_value = MagicMock(content=f.read())
123+
self.assertIsNotNone(self.image_loader.load_image_or_none(self.im_url))
124+
mock.assert_called_once()
125+
126+
@patch(
127+
"orangecontrib.imageanalytics.utils.embedder_utils.CachedSession",
128+
side_effect=OperationalError("test")
129+
)
130+
@patch("requests.Session.get")
131+
def test_load_images_url_without_http_cache(self, mock, _) -> None:
132+
with open(self.im_paths[0], "rb") as f:
133+
mock.return_value = MagicMock(content=f.read())
134+
self.assertIsNotNone(self.image_loader.load_image_or_none(self.im_url))
135+
mock.assert_called_once()
136+
118137

119138
if __name__ == "__main__":
120139
unittest.main()

0 commit comments

Comments
 (0)