From ee2c0bdb82b4885dc2bc9b3fa78d1d461c40f963 Mon Sep 17 00:00:00 2001 From: garciadavid2000 Date: Tue, 4 Nov 2025 17:30:37 -0500 Subject: [PATCH 1/3] Add make_sample_data function --- src/RESPFlow/access_files.py | 43 +++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/RESPFlow/access_files.py b/src/RESPFlow/access_files.py index e01c896..a5fa856 100644 --- a/src/RESPFlow/access_files.py +++ b/src/RESPFlow/access_files.py @@ -1,4 +1,5 @@ import os, re +import pandas as pd # # ============================================================================= @@ -130,4 +131,44 @@ def map_files(in_path: str, elif (directory.endswith(file_ext)) and ((expression is None) or (re.match(expression, fileName)!=None)): file_dirs[fileName] = new_path - return file_dirs \ No newline at end of file + return file_dirs + +# +# ============================================================================= +# + +from pathlib import Path +from importlib import resources as ir +import shutil + +def make_sample_data(path_names: dict[str, str]) -> None: + """ + Copies sample data files from the RESPFlow package to the raw data folder + specified in `path_names`. + + Parameters + ---------- + path_names : dict[str, str] + A dictionary of file locations with keys for stage in the processing + pipeline. Must contain a 'raw' key specifying the destination folder + for the sample data. + + Raises + ------ + ValueError + If 'raw' key is not found in `path_names`. + + Returns + ------- + None + The function performs file operations only; it does not return a value. + """ + if "raw" not in path_names: + raise ValueError("Raw path not detected in path_names.") + + dest = Path(path_names["raw"]) + dest.mkdir(parents=True, exist_ok=True) + + with ir.as_file(ir.files("RESPFlow").joinpath("data")) as src: + shutil.copytree(src, dest, dirs_exist_ok=True) + From 9333e3a894b68771a00bc3eec2ff6e7184dcd4bd Mon Sep 17 00:00:00 2001 From: garciadavid2000 Date: Tue, 4 Nov 2025 17:50:09 -0500 Subject: [PATCH 2/3] Make some tests for make_sample_data function --- tests/test_access_files.py | 57 +++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/tests/test_access_files.py b/tests/test_access_files.py index 2ce4d5c..a0901b8 100644 --- a/tests/test_access_files.py +++ b/tests/test_access_files.py @@ -1,6 +1,21 @@ +# ============================================================================ +# Imports +# ============================================================================ + +# --- Standard library --- import os +from pathlib import Path +from importlib import resources as ir + +# --- Third-party packages --- import pytest -import RESPFlow + +# --- Local application / package imports --- +from RESPFlow.access_files import make_paths, map_files, make_sample_data + +# ============================================================================ +# Tests +# =========================================================================== # ============================================================================ # Test make_paths function @@ -23,7 +38,7 @@ def fake_makedirs(path, exist_ok=True): def test_make_paths_defaults(mock_filesystem): - paths = RESPFlow.make_paths() + paths = make_paths() expected_keys = { 'raw', 'notch', 'bandpass', 'fwr', @@ -45,7 +60,7 @@ def test_make_paths_custom_root_raw(mock_filesystem): custom_root = "my_root" custom_raw = "my_raw" - paths = RESPFlow.make_paths(root=custom_root, raw=custom_raw) + paths = make_paths(root=custom_root, raw=custom_raw) # Assert custom raw should be absolute and point to my_raw assert paths['raw'] == "/abs/my_raw" @@ -62,9 +77,43 @@ def test_make_paths_custom_root_raw(mock_filesystem): # ============================================================================ # ============================================================================ -# Tests for map_files +# Tests for make_sample_data function # ============================================================================ +def _fake_pkg_with_data(tmp_path: Path) -> Path: + """Create a fake RESPFlow/data tree with a few files.""" + root = tmp_path / "RESPFlow_fake" + (root / "data" / "10").mkdir(parents=True, exist_ok=True) + (root / "data" / "10" / "file1.csv").write_text("a,b\n1,2\n", encoding="utf-8") + (root / "data" / "10" / "nested").mkdir(parents=True, exist_ok=True) + (root / "data" / "10" / "nested" / "info.txt").write_text("hello\n", encoding="utf-8") + (root / "data" / "23").mkdir(parents=True, exist_ok=True) + (root / "data" / "23" / "file2.csv").write_text("x,y\n3,4\n", encoding="utf-8") + return root + + +def test_copies_all_and_preserves_structure(tmp_path: Path, monkeypatch): + fake_pkg = _fake_pkg_with_data(tmp_path) + # Make ir.files("RESPFlow") point to our fake package root + monkeypatch.setattr(ir, "files", lambda _pkg: fake_pkg) + + dest = tmp_path / "raw" + make_sample_data({"raw": str(dest)}) + + assert (dest / "10" / "file1.csv").is_file() + assert (dest / "10" / "nested" / "info.txt").is_file() + assert (dest / "23" / "file2.csv").is_file() + # spot-check contents + assert (dest / "10" / "file1.csv").read_text(encoding="utf-8").startswith("a,b\n") + + +def test_missing_raw_raises(monkeypatch, tmp_path: Path): + fake_pkg = _fake_pkg_with_data(tmp_path) + monkeypatch.setattr(ir, "files", lambda _pkg: fake_pkg) + + with pytest.raises(ValueError, match="Raw path not detected"): + make_sample_data({}) + # ============================================================================ # End of tests # ============================================================================ \ No newline at end of file From 3748086bcbfbb758e5bb27937e5d132a4e3c1a1f Mon Sep 17 00:00:00 2001 From: garciadavid2000 Date: Tue, 4 Nov 2025 18:01:05 -0500 Subject: [PATCH 3/3] Add tests for map_files --- tests/test_access_files.py | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/test_access_files.py b/tests/test_access_files.py index a0901b8..2b29ae6 100644 --- a/tests/test_access_files.py +++ b/tests/test_access_files.py @@ -76,6 +76,76 @@ def test_make_paths_custom_root_raw(mock_filesystem): # Test map_files function # ============================================================================ +def _touch(p: str, text: str = "") -> None: + os.makedirs(os.path.dirname(p), exist_ok=True) + with open(p, "w", encoding="utf-8") as f: + f.write(text) + + +def test_map_files_basic_recursive(tmp_path): + # data/ + # 10/file1.csv + # 10/nested/info.txt + # 23/file2.csv + root = tmp_path / "data" + f1 = root / "10" / "file1.csv" + f_txt = root / "10" / "nested" / "info.txt" + f2 = root / "23" / "file2.csv" + _touch(str(f1), "a,b\n1,2\n") + _touch(str(f_txt), "hello\n") + _touch(str(f2), "x,y\n3,4\n") + + result = map_files(str(root)) # default file_ext='csv' + + # Only CSVs should appear + keys = set(result.keys()) + assert os.path.join("10", "file1.csv") in keys + assert os.path.join("23", "file2.csv") in keys + + # Non-csv shouldn't be included + assert not any("info.txt" in k for k in keys) + + # Values should be absolute paths pointing to the files + assert os.path.isabs(result[os.path.join("10", "file1.csv")]) + assert os.path.exists(result[os.path.join("23", "file2.csv")]) + + +def test_map_files_extension_filter(tmp_path): + root = tmp_path / "data" + _touch(str(root / "a.csv"), "csv\n") + _touch(str(root / "b.txt"), "txt\n") + + only_txt = map_files(str(root), file_ext="txt") + + assert set(only_txt.keys()) == {"b.txt"} + + only_csv = map_files(str(root), file_ext="csv") + + assert set(only_csv.keys()) == {"a.csv"} + + +def test_map_files_regex_filter_on_filename(tmp_path): + root = tmp_path / "data" + _touch(str(root / "10" / "keep_this.csv"), "ok\n") + _touch(str(root / "10" / "skip_this.csv"), "no\n") + _touch(str(root / "23" / "also_skip.csv"), "no\n") + + # Match only files whose name ends with 'keep_this.csv' + expr = r".*keep_this\.csv$" + + result = map_files(str(root), expression=expr) + + keys = set(result.keys()) + assert any(k.endswith(os.path.join("10", "keep_this.csv")) for k in keys) + assert not any(k.endswith("skip_this.csv") for k in keys) + +def test_map_files_invalid_regex_raises(tmp_path): + root = tmp_path / "data" + _touch(str(root / "a.csv"), "a\n") + + with pytest.raises(Exception, match="Invalid regex expression"): + map_files(str(root), expression="(") # invalid regex + # ============================================================================ # Tests for make_sample_data function # ============================================================================