Skip to content

Commit c94dee0

Browse files
matt-bernsteinrobot-ci-heartex
authored andcommitted
fix: FIT-1654: Exporting YOLO with Images using local storage results in no images
GitOrigin-RevId: d1ff9fb4d8f01ed8b17855b8142288c49b76b592
1 parent d2ba58a commit c94dee0

2 files changed

Lines changed: 51 additions & 9 deletions

File tree

src/label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
import base64
12
import hashlib
23
import io
34
import logging
45
import os
56
import shutil
6-
import base64
77
from contextlib import contextmanager
88
from tempfile import mkdtemp
99
from urllib.parse import parse_qs, urlparse
10-
import jwt
1110

11+
import jwt
1212
import requests
1313
from appdirs import user_cache_dir, user_data_dir
1414

@@ -71,6 +71,10 @@ def _build_headers(target_url, hostname, access_token):
7171
return headers
7272

7373

74+
def _build_cache_path(cache_dir, target_url, filename):
75+
return os.path.join(cache_dir, hashlib.md5(target_url.encode(), usedforsecurity=False).hexdigest()[:8] + "__" + filename)
76+
77+
7478
def get_local_path(
7579
url,
7680
cache_dir=None,
@@ -178,6 +182,12 @@ def get_local_path(
178182
logger.debug(
179183
f"Local Storage file path exists locally, use it as a local file: {filepath}"
180184
)
185+
if cache_dir and download_resources:
186+
os.makedirs(cache_dir, exist_ok=True)
187+
cache_path = _build_cache_path(cache_dir, url, os.path.basename(filepath))
188+
if not os.path.exists(cache_path):
189+
shutil.copy(filepath, cache_path)
190+
return cache_path
181191
return filepath
182192

183193
# try to get local directories
@@ -310,7 +320,7 @@ def _filename_for(target_url, storage_fp=None):
310320
return os.path.basename(parsed.path)
311321

312322
def _cache_path(target_url, fname):
313-
return os.path.join(cache_dir, hashlib.md5(target_url.encode(), usedforsecurity=False).hexdigest()[:8] + "__" + fname)
323+
return _build_cache_path(cache_dir, target_url, fname)
314324

315325
cache_dir = cache_dir or get_cache_dir()
316326
current_filename = _filename_for(url, storage_filepath)

tests/custom/label_studio_tools/test_get_local_path.py

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
import base64
22
import hashlib
3-
import os
4-
import tempfile
5-
import requests
63
from types import SimpleNamespace
7-
from unittest.mock import patch, MagicMock
4+
from unittest.mock import MagicMock, patch
85

96
import pytest
7+
import requests
108

119
from label_studio_sdk._extensions.label_studio_tools.core.utils.io import (
12-
get_local_path,
13-
get_base64_content,
1410
_DIR_APP_NAME,
11+
get_base64_content,
12+
get_local_path,
1513
)
1614

1715

@@ -105,6 +103,40 @@ def test_get_local_path_safe_build(mock_data_dir, mock_cache_dir, url, raises_er
105103
assert "my_dir/1.jpg" in local_path
106104

107105

106+
@patch("label_studio_sdk._extensions.label_studio_tools.core.utils.io.LOCAL_FILES_DOCUMENT_ROOT", "")
107+
def test_get_local_path_local_storage_downloads_to_cache(tmp_path):
108+
"""Ensure local storage files are copied into cache when download_resources is enabled."""
109+
local_root = tmp_path / "local-storage-root"
110+
image_dir = local_root / "my_dir"
111+
image_dir.mkdir(parents=True)
112+
source_file = image_dir / "1.jpg"
113+
source_content = b"local-image-bytes"
114+
source_file.write_bytes(source_content)
115+
116+
cache_dir = tmp_path / "cache"
117+
cache_dir.mkdir()
118+
local_url = "/data/local-files?d=my_dir/1.jpg"
119+
120+
with patch(
121+
"label_studio_sdk._extensions.label_studio_tools.core.utils.io.LOCAL_FILES_DOCUMENT_ROOT", str(local_root)
122+
):
123+
cached_path = get_local_path(
124+
url=local_url,
125+
cache_dir=str(cache_dir),
126+
hostname="http://app.heartex.com",
127+
access_token="secret",
128+
download_resources=True,
129+
task_id=1,
130+
)
131+
132+
expected_hash = hashlib.md5(local_url.encode(), usedforsecurity=False).hexdigest()[:8]
133+
expected_path = cache_dir / f"{expected_hash}__1.jpg"
134+
135+
assert cached_path == str(expected_path)
136+
assert expected_path.exists()
137+
assert expected_path.read_bytes() == source_content
138+
139+
108140
def test_get_local_path_storage_proxy_filename_and_auth(monkeypatch, tmp_path):
109141
"""
110142
Ensure storage proxy URLs use `filepath` for filename, rewrite to hostname,

0 commit comments

Comments
 (0)