Skip to content

Commit

Permalink
Merge pull request #237 from PrimozGodec/fix-cachecontrol
Browse files Browse the repository at this point in the history
[FIX] ImageLoader - Avoid using http cache when no write/read permission
  • Loading branch information
lanzagar committed Oct 30, 2023
2 parents 02356b8 + 75db417 commit 9d56094
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 10 deletions.
35 changes: 26 additions & 9 deletions orangecontrib/imageanalytics/utils/embedder_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
from datetime import timedelta
from io import BytesIO
from os.path import join
from sqlite3 import OperationalError
from urllib.error import URLError
from urllib.parse import urlparse
from urllib.request import urlopen

import requests
from AnyQt.QtCore import QStandardPaths
from PIL import ImageFile
from PIL.Image import LANCZOS
Expand All @@ -19,16 +21,31 @@


class ImageLoader:
def __init__(self):
_session = None

@property
def session(self):
if self._session is not None:
return self._session

cache_dir = QStandardPaths.writableLocation(QStandardPaths.CacheLocation)
cache_path = join(cache_dir, "networkcache", "image_loader.sqlite")
self._session = CachedSession(
cache_path,
backend="sqlite",
cache_control=True,
expire_after=timedelta(days=1),
stale_if_error=True,
)
try:
self._session = CachedSession(
cache_path,
backend="sqlite",
cache_control=True,
expire_after=timedelta(days=1),
stale_if_error=True,
)
except OperationalError as ex:
# if no permission to write in dir or read cache file return regular session
log.info(
f"Cache file creation/opening failed with: '{str(ex)}'. "
"Using requests.Session instead of cached session."
)
self._session = requests.Session()
return self._session

def load_image_or_none(self, file_path, target_size=None):
if file_path is None:
Expand Down Expand Up @@ -66,7 +83,7 @@ def _load_image_from_url_or_local_path(self, file_path):
urlparts = urlparse(file_path)
if urlparts.scheme in ("http", "https"):
try:
file = BytesIO(self._session.get(file_path).content)
file = BytesIO(self.session.get(file_path).content)
except RequestException:
log.warning("Image skipped", exc_info=True)
return None
Expand Down
21 changes: 20 additions & 1 deletion orangecontrib/imageanalytics/utils/tests/test_embedder_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import unittest
from unittest.mock import patch
from sqlite3 import OperationalError
from unittest.mock import patch, MagicMock
from urllib.error import URLError

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

@patch("requests_cache.CachedSession.get")
def test_load_images_url_with_http_cache(self, mock) -> None:
with open(self.im_paths[0], "rb") as f:
mock.return_value = MagicMock(content=f.read())
self.assertIsNotNone(self.image_loader.load_image_or_none(self.im_url))
mock.assert_called_once()

@patch(
"orangecontrib.imageanalytics.utils.embedder_utils.CachedSession",
side_effect=OperationalError("test")
)
@patch("requests.Session.get")
def test_load_images_url_without_http_cache(self, mock, _) -> None:
with open(self.im_paths[0], "rb") as f:
mock.return_value = MagicMock(content=f.read())
self.assertIsNotNone(self.image_loader.load_image_or_none(self.im_url))
mock.assert_called_once()


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

0 comments on commit 9d56094

Please sign in to comment.