From 38ad910755e4a673ffd07f01eacbbfbef35d3e9d Mon Sep 17 00:00:00 2001 From: Eu Pin Tien Date: Fri, 10 Oct 2025 14:14:18 +0100 Subject: [PATCH 1/3] Streamlined logic for 'secure_path', and added logic to preserve trailing underscores in file path parts --- src/murfey/util/__init__.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/murfey/util/__init__.py b/src/murfey/util/__init__.py index 27aabfb22..fac3ed907 100644 --- a/src/murfey/util/__init__.py +++ b/src/murfey/util/__init__.py @@ -27,24 +27,21 @@ def sanitise_nonpath(in_string: str) -> str: def secure_path(in_path: Path, keep_spaces: bool = False) -> Path: - if keep_spaces: - secured_parts = [] - for p, part in enumerate(in_path.parts): + secured_parts = [] + for p, part in enumerate(in_path.parts): + if p == 0 and ":" in part: + secured_parts.append(secure_filename(part) + ":") + continue # Skip subsequent conditions and move to next part + if keep_spaces: if " " in part: secured_parts.append(part) - elif ":" in part and not p: - secured_parts.append(secure_filename(part) + ":") - else: - secured_parts.append(secure_filename(part)) - else: - secured_parts = [ - ( - secure_filename(part) + ":" - if p == 0 and ":" in part - else secure_filename(part) - ) - for p, part in enumerate(in_path.parts) - ] + continue # Skip subsequent conditions and move to next part + if part.endswith("_"): + # Preserve all trailing underscores + num_underscores = len(part) - len(part.rstrip("_")) + secured_parts.append(secure_filename(part) + (num_underscores * "_")) + else: + secured_parts.append(secure_filename(part)) return Path("/".join(secured_parts)) From 329c0d66076d07c6e3cb57a7b9c1b39bd8c58433 Mon Sep 17 00:00:00 2001 From: Eu Pin Tien Date: Fri, 10 Oct 2025 14:14:37 +0100 Subject: [PATCH 2/3] Added unit tests for 'secure_path' --- tests/util/test_init.py | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tests/util/test_init.py diff --git a/tests/util/test_init.py b/tests/util/test_init.py new file mode 100644 index 000000000..9741154fe --- /dev/null +++ b/tests/util/test_init.py @@ -0,0 +1,63 @@ +""" +Test module for the functions located in murfey.util.__init__ +""" + +from pathlib import Path + +import pytest + +from murfey.util import secure_path + +secure_path_test_matrix = ( + # Keep spaces? | Input path | Expected output + # Tomo workflow examples + ( + False, + "D:/User_22220202_090000_cm40000-1/Position_1_1_001_0.00_22220202_090000_EER.eer", + "D:/User_22220202_090000_cm40000-1/Position_1_1_001_0.00_22220202_090000_EER.eer", + ), + ( + False, + "D:/User_22220202_090000_cm40000-1_/Position_1_1_001_0.00_22220202_090000_EER.eer", + "D:/User_22220202_090000_cm40000-1_/Position_1_1_001_0.00_22220202_090000_EER.eer", + ), + # CLEM workflow examples + ( + True, + "D:/Session/cm40000-1/images/My Sample/TileScan 1/Position 1--Stage00--Z00--C00.tif", + "D:/Session/cm40000-1/images/My Sample/TileScan 1/Position 1--Stage00--Z00--C00.tif", + ), + ( + True, + "D:/Session/cm40000-1/images/My Sample_/TileScan 1/Position 1--Stage00--Z00--C00.tif", + "D:/Session/cm40000-1/images/My Sample_/TileScan 1/Position 1--Stage00--Z00--C00.tif", + ), + ( + True, + "D:/Session/cm40000-1/images/My_Sample_/TileScan 1/Position 1--Stage00--Z00--C00.tif", + "D:/Session/cm40000-1/images/My_Sample_/TileScan 1/Position 1--Stage00--Z00--C00.tif", + ), + # Go wild + ( + True, + "D:/some path/to_/this/repo!/my_file.txt", + "D:/some path/to_/this/repo/my_file.txt", + ), + ( + True, + "D:/some path__/to_/this/repo/my file.txt", + "D:/some path__/to_/this/repo/my file.txt", + ), + ( + False, + "D:/some path__/to_/this/repo/my file.txt", + "D:/some_path__/to_/this/repo/my_file.txt", + ), +) + + +@pytest.mark.parametrize("test_params", secure_path_test_matrix) +def test_secure_path(test_params: tuple[bool, str, str]): + # Unpack test params + keep_spaces, input_path, expected_output = test_params + assert secure_path(Path(input_path), keep_spaces) == Path(expected_output) From 738c1872559365b17905fbff9612533740f7a0bb Mon Sep 17 00:00:00 2001 From: Eu Pin Tien Date: Fri, 10 Oct 2025 14:36:17 +0100 Subject: [PATCH 3/3] Further streamlined 'secure_path' logic --- src/murfey/util/__init__.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/murfey/util/__init__.py b/src/murfey/util/__init__.py index fac3ed907..98370e5d0 100644 --- a/src/murfey/util/__init__.py +++ b/src/murfey/util/__init__.py @@ -31,12 +31,9 @@ def secure_path(in_path: Path, keep_spaces: bool = False) -> Path: for p, part in enumerate(in_path.parts): if p == 0 and ":" in part: secured_parts.append(secure_filename(part) + ":") - continue # Skip subsequent conditions and move to next part - if keep_spaces: - if " " in part: - secured_parts.append(part) - continue # Skip subsequent conditions and move to next part - if part.endswith("_"): + elif " " in part and keep_spaces: + secured_parts.append(part) + elif part.endswith("_"): # Preserve all trailing underscores num_underscores = len(part) - len(part.rstrip("_")) secured_parts.append(secure_filename(part) + (num_underscores * "_"))