Skip to content

Commit dbd4cd9

Browse files
GitHKAndrei Neagu
andauthored
🐛 More than 1 input port containing files can be safely pulled (#6286)
Co-authored-by: Andrei Neagu <[email protected]>
1 parent 986f663 commit dbd4cd9

File tree

6 files changed

+42
-27
lines changed

6 files changed

+42
-27
lines changed
Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import tempfile
2-
import threading
32
from pathlib import Path
4-
from typing import Optional
3+
from typing import Final
4+
from uuid import uuid4
55

66
from models_library.projects_nodes_io import SimcoreS3FileID
77

8+
_TMP_SIMCOREFILES: Final[Path] = Path(tempfile.gettempdir()) / "simcorefiles"
9+
810

911
def create_simcore_file_id(
1012
file_path: Path,
1113
project_id: str,
1214
node_id: str,
1315
*,
14-
file_base_path: Optional[Path] = None,
16+
file_base_path: Path | None = None,
1517
) -> SimcoreS3FileID:
1618
s3_file_name = file_path.name
1719
if file_base_path:
@@ -20,12 +22,9 @@ def create_simcore_file_id(
2022
return SimcoreS3FileID(f"{clean_path}")
2123

2224

23-
_INTERNAL_DIR = Path(tempfile.gettempdir(), "simcorefiles")
24-
25-
26-
def create_folder_path(key: str) -> Path:
27-
return Path(_INTERNAL_DIR, f"{threading.get_ident()}", key)
25+
def get_folder_path(key: str) -> Path:
26+
return _TMP_SIMCOREFILES / f"{uuid4()}" / key
2827

2928

30-
def create_file_path(key: str, name: str) -> Path:
31-
return Path(_INTERNAL_DIR, f"{threading.get_ident()}", key, name)
29+
def get_file_path(key: str, name: str) -> Path:
30+
return _TMP_SIMCOREFILES / f"{uuid4()}" / key / name

packages/simcore-sdk/src/simcore_sdk/node_ports_v2/port_utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ async def get_value_from_link(
6767
if file_to_key_map:
6868
file_name = next(iter(file_to_key_map))
6969

70-
file_path = data_items_utils.create_file_path(key, file_name)
70+
file_path = data_items_utils.get_file_path(key, file_name)
7171
if other_value == file_path:
7272
# this is a corner case: in case the output key of the other node has the same name as the input key
7373
return other_value
@@ -194,7 +194,7 @@ async def pull_file_from_store(
194194
) -> Path:
195195
log.debug("pulling file from storage %s", value)
196196
# do not make any assumption about s3_path, it is a str containing stuff that can be anything depending on the store
197-
local_path = data_items_utils.create_folder_path(key)
197+
local_path = data_items_utils.get_folder_path(key)
198198
downloaded_file = await filemanager.download_path_from_s3(
199199
user_id=user_id,
200200
store_id=value.store,
@@ -275,7 +275,7 @@ async def pull_file_from_download_link(
275275
value.label,
276276
)
277277

278-
local_path = data_items_utils.create_folder_path(key)
278+
local_path = data_items_utils.get_folder_path(key)
279279
downloaded_file = await filemanager.download_file_from_link(
280280
URL(f"{value.download_link}"),
281281
local_path,

packages/simcore-sdk/tests/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import pytest
1212
import simcore_sdk
13+
from helpers.utils_port_v2 import CONSTANT_UUID
14+
from pytest_mock.plugin import MockerFixture
1315
from pytest_simcore.helpers.postgres_tools import PostgresTestConfig
1416
from pytest_simcore.helpers.typing_env import EnvVarsDict
1517
from simcore_sdk.node_ports_common.file_io_utils import LogRedirectCB
@@ -74,3 +76,11 @@ async def _mocked_function(*args, **kwargs) -> None:
7476
pass
7577

7678
return _mocked_function
79+
80+
81+
@pytest.fixture
82+
def constant_uuid4(mocker: MockerFixture) -> None:
83+
mocker.patch(
84+
"simcore_sdk.node_ports_common.data_items_utils.uuid4",
85+
return_value=CONSTANT_UUID,
86+
)

packages/simcore-sdk/tests/helpers/utils_port_v2.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
from typing import Any
1+
from typing import Any, Final
2+
from uuid import UUID
23

34
from simcore_sdk.node_ports_v2.ports_mapping import InputsList, OutputsList
45

6+
CONSTANT_UUID: Final[UUID] = UUID(int=0)
7+
58

69
def create_valid_port_config(conf_type: str, **kwargs) -> dict[str, Any]:
710
valid_config = {

packages/simcore-sdk/tests/integration/test_node_ports_v2_nodeports2.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import filecmp
1010
import os
1111
import tempfile
12-
import threading
1312
from asyncio import gather
1413
from collections.abc import Awaitable, Callable, Iterable
1514
from pathlib import Path
@@ -37,6 +36,7 @@
3736
from simcore_sdk.node_ports_v2.links import ItemConcreteValue, PortLink
3837
from simcore_sdk.node_ports_v2.nodeports_v2 import Nodeports
3938
from simcore_sdk.node_ports_v2.port import Port
39+
from utils_port_v2 import CONSTANT_UUID
4040

4141
pytest_simcore_core_services_selection = [
4242
"migration",
@@ -273,6 +273,7 @@ async def test_port_file_accessors(
273273
e_tag: str,
274274
option_r_clone_settings: RCloneSettings | None,
275275
request: pytest.FixtureRequest,
276+
constant_uuid4: None,
276277
):
277278

278279
if item_value == "symlink_path":
@@ -307,7 +308,7 @@ async def test_port_file_accessors(
307308
await (await PORTS.outputs)[ServicePortKey("out_34")].set(item_value)
308309
# this is the link to S3 storage
309310
value = (await PORTS.outputs)[ServicePortKey("out_34")].value
310-
assert isinstance(value, (DownloadLink, PortLink, BaseFileLink))
311+
assert isinstance(value, DownloadLink | PortLink | BaseFileLink)
311312
received_file_link = value.dict(by_alias=True, exclude_unset=True)
312313
assert received_file_link["store"] == s3_simcore_location
313314
assert (
@@ -331,7 +332,7 @@ async def test_port_file_accessors(
331332
Path(
332333
tempfile.gettempdir(),
333334
"simcorefiles",
334-
f"{threading.get_ident()}",
335+
f"{CONSTANT_UUID}",
335336
"out_34",
336337
)
337338
)
@@ -495,6 +496,7 @@ async def test_get_file_from_previous_node(
495496
item_value: str,
496497
item_pytype: type,
497498
option_r_clone_settings: RCloneSettings | None,
499+
constant_uuid4: None,
498500
):
499501
config_dict, _, _ = create_2nodes_configuration(
500502
prev_node_inputs=None,
@@ -519,7 +521,7 @@ async def test_get_file_from_previous_node(
519521
assert file_path == Path(
520522
tempfile.gettempdir(),
521523
"simcorefiles",
522-
f"{threading.get_ident()}",
524+
f"{CONSTANT_UUID}",
523525
"in_15",
524526
Path(item_value).name,
525527
)
@@ -551,6 +553,7 @@ async def test_get_file_from_previous_node_with_mapping_of_same_key_name(
551553
item_alias: str,
552554
item_pytype: type,
553555
option_r_clone_settings: RCloneSettings | None,
556+
constant_uuid4: None,
554557
):
555558
config_dict, _, this_node_uuid = create_2nodes_configuration(
556559
prev_node_inputs=None,
@@ -579,7 +582,7 @@ async def test_get_file_from_previous_node_with_mapping_of_same_key_name(
579582
assert file_path == Path(
580583
tempfile.gettempdir(),
581584
"simcorefiles",
582-
f"{threading.get_ident()}",
585+
f"{CONSTANT_UUID}",
583586
"in_15",
584587
item_alias,
585588
)
@@ -612,6 +615,7 @@ async def test_file_mapping(
612615
item_pytype: type,
613616
option_r_clone_settings: RCloneSettings | None,
614617
create_valid_file_uuid: Callable[[str, Path], SimcoreS3FileID],
618+
constant_uuid4: None,
615619
):
616620
config_dict, project_id, node_uuid = create_special_configuration(
617621
inputs=[("in_1", item_type, await create_store_link(item_value))],
@@ -638,7 +642,7 @@ async def test_file_mapping(
638642
assert file_path == Path(
639643
tempfile.gettempdir(),
640644
"simcorefiles",
641-
f"{threading.get_ident()}",
645+
f"{CONSTANT_UUID}",
642646
"in_1",
643647
item_alias,
644648
)
@@ -649,7 +653,7 @@ async def test_file_mapping(
649653
assert file_path == Path(
650654
tempfile.gettempdir(),
651655
"simcorefiles",
652-
f"{threading.get_ident()}",
656+
f"{CONSTANT_UUID}",
653657
"in_1",
654658
item_alias,
655659
)
@@ -662,7 +666,7 @@ async def test_file_mapping(
662666
await PORTS.set_file_by_keymap(file_path)
663667
file_id = create_valid_file_uuid("out_1", file_path)
664668
value = (await PORTS.outputs)[ServicePortKey("out_1")].value
665-
assert isinstance(value, (DownloadLink, PortLink, BaseFileLink))
669+
assert isinstance(value, DownloadLink | PortLink | BaseFileLink)
666670
received_file_link = value.dict(by_alias=True, exclude_unset=True)
667671
assert received_file_link["store"] == s3_simcore_location
668672
assert received_file_link["path"] == file_id
@@ -734,7 +738,7 @@ async def _upload_create_task(item_key: str) -> None:
734738

735739
# since a race condition was created when uploading values in parallel
736740
# it is expected to find at least one mismatching value here
737-
with pytest.raises(AssertionError) as exc_info:
741+
with pytest.raises(AssertionError) as exc_info: # noqa: PT012
738742
for item_key, _, _ in outputs:
739743
assert (await PORTS.outputs)[
740744
ServicePortKey(item_key)

packages/simcore-sdk/tests/unit/test_node_ports_v2_port.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import re
1111
import shutil
1212
import tempfile
13-
import threading
1413
from collections.abc import Callable, Iterator
1514
from dataclasses import dataclass
1615
from pathlib import Path
@@ -39,7 +38,7 @@
3938
)
4039
from simcore_sdk.node_ports_v2.port import Port
4140
from simcore_sdk.node_ports_v2.ports_mapping import InputsList, OutputsList
42-
from utils_port_v2 import create_valid_port_config
41+
from utils_port_v2 import CONSTANT_UUID, create_valid_port_config
4342
from yarl import URL
4443

4544

@@ -57,7 +56,7 @@ def another_node_file_name() -> Path:
5756

5857

5958
def download_file_folder_name() -> Path:
60-
return Path(tempfile.gettempdir(), "simcorefiles", f"{threading.get_ident()}")
59+
return Path(tempfile.gettempdir()) / "simcorefiles" / f"{CONSTANT_UUID}"
6160

6261

6362
def project_id() -> str:
@@ -141,7 +140,7 @@ def another_node_file() -> Iterator[Path]:
141140

142141

143142
@pytest.fixture
144-
def download_file_folder() -> Iterator[Path]:
143+
def download_file_folder(constant_uuid4: None) -> Iterator[Path]:
145144
destination_path = download_file_folder_name()
146145
destination_path.mkdir(parents=True, exist_ok=True)
147146
yield destination_path

0 commit comments

Comments
 (0)