From 81e51053590d46caa0e4e26f30e5e824e73f3324 Mon Sep 17 00:00:00 2001 From: Lea Waller Date: Tue, 24 Feb 2026 10:07:00 +0100 Subject: [PATCH 1/4] Detect duplicates in participant_id column And add unit test --- wonkyconn/tests/test_workflow.py | 35 ++++++++++++++++++++++++++++++++ wonkyconn/workflow.py | 6 ++++-- 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 wonkyconn/tests/test_workflow.py diff --git a/wonkyconn/tests/test_workflow.py b/wonkyconn/tests/test_workflow.py new file mode 100644 index 00000000..8743199e --- /dev/null +++ b/wonkyconn/tests/test_workflow.py @@ -0,0 +1,35 @@ +from argparse import Namespace +from pathlib import Path + +import pandas as pd +import pytest + +from wonkyconn.workflow import load_data_frame + + +def test_load_data_frame(tmp_path: Path) -> None: + # Create a sample phenotypes file + phenotypes_path = tmp_path / "phenotypes.tsv" + phenotypes_path.write_text("participant_id\tage\tgender\nsub-01\t25\tM\nsub-02\t30\tF\nsub-03\t35\tM\n") + + # Load the data frame + data_frame = load_data_frame(Namespace(phenotypes=str(phenotypes_path))) + + # Check that the data frame has the expected shape and columns + row_count, _ = data_frame.shape + assert row_count == 3 + assert list(data_frame.reset_index().columns) == ["participant_id", "age", "gender"] + + full_data_frame = data_frame.reset_index() + + # Check that we throw an error for missing columns + for missing_column in data_frame.reset_index().columns: + data_frame.reset_index().drop(columns=missing_column).to_csv(phenotypes_path, sep="\t", index=False) + with pytest.raises(ValueError): + load_data_frame(Namespace(phenotypes=str(phenotypes_path))) + + # Check that we throw an error for duplicate participant_id entries + data_frame = pd.concat([full_data_frame, full_data_frame.iloc[0:1]]) # Add a duplicate row + data_frame.to_csv(phenotypes_path, sep="\t", index=False) + with pytest.raises(ValueError): + load_data_frame(Namespace(phenotypes=str(phenotypes_path))) diff --git a/wonkyconn/workflow.py b/wonkyconn/workflow.py index ef556225..f58ddfa1 100644 --- a/wonkyconn/workflow.py +++ b/wonkyconn/workflow.py @@ -239,8 +239,8 @@ def make_record( # age / sex predictability metrics try: - ages = seg_data_frame["age"].to_numpy() - genders = seg_data_frame["gender"].to_numpy() + ages: npt.NDArray[np.float64] = seg_data_frame["age"].to_numpy() + genders: npt.NDArray[np.str_] = seg_data_frame["gender"].to_numpy() scores = age_sex_scores( connectivity_matrices, @@ -292,6 +292,8 @@ def load_data_frame(args: argparse.Namespace) -> pd.DataFrame: index_col="participant_id", dtype={"participant_id": str}, ) + if data_frame.index.has_duplicates: + raise ValueError("Phenotypes file has duplicate participant_id entries") if "gender" not in data_frame.columns: raise ValueError('Phenotypes file is missing the "gender" column') if "age" not in data_frame.columns: From 0c9f2b9c600f5a68d8fda247e46222df30edbde5 Mon Sep 17 00:00:00 2001 From: Lea Waller Date: Tue, 24 Feb 2026 10:12:13 +0100 Subject: [PATCH 2/4] Update wonkyconn/tests/test_workflow.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- wonkyconn/tests/test_workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wonkyconn/tests/test_workflow.py b/wonkyconn/tests/test_workflow.py index 8743199e..3265afd6 100644 --- a/wonkyconn/tests/test_workflow.py +++ b/wonkyconn/tests/test_workflow.py @@ -31,5 +31,5 @@ def test_load_data_frame(tmp_path: Path) -> None: # Check that we throw an error for duplicate participant_id entries data_frame = pd.concat([full_data_frame, full_data_frame.iloc[0:1]]) # Add a duplicate row data_frame.to_csv(phenotypes_path, sep="\t", index=False) - with pytest.raises(ValueError): + with pytest.raises(ValueError, match="duplicate participant_id"): load_data_frame(Namespace(phenotypes=str(phenotypes_path))) From ebdf38bd4e3c49a782b2ccc687e55979f6e27b9f Mon Sep 17 00:00:00 2001 From: Lea Waller Date: Tue, 24 Feb 2026 13:53:51 +0100 Subject: [PATCH 3/4] Update wonkyconn/tests/test_workflow.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- wonkyconn/tests/test_workflow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wonkyconn/tests/test_workflow.py b/wonkyconn/tests/test_workflow.py index 3265afd6..e12485a0 100644 --- a/wonkyconn/tests/test_workflow.py +++ b/wonkyconn/tests/test_workflow.py @@ -23,8 +23,8 @@ def test_load_data_frame(tmp_path: Path) -> None: full_data_frame = data_frame.reset_index() # Check that we throw an error for missing columns - for missing_column in data_frame.reset_index().columns: - data_frame.reset_index().drop(columns=missing_column).to_csv(phenotypes_path, sep="\t", index=False) + for missing_column in full_data_frame.columns: + full_data_frame.drop(columns=missing_column).to_csv(phenotypes_path, sep="\t", index=False) with pytest.raises(ValueError): load_data_frame(Namespace(phenotypes=str(phenotypes_path))) From 919d623cd730b82d12484717b9ee23e0158e04ce Mon Sep 17 00:00:00 2001 From: Lea Waller Date: Tue, 24 Feb 2026 13:57:34 +0100 Subject: [PATCH 4/4] Edits after automated code review --- wonkyconn/tests/test_workflow.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wonkyconn/tests/test_workflow.py b/wonkyconn/tests/test_workflow.py index e12485a0..06a646bf 100644 --- a/wonkyconn/tests/test_workflow.py +++ b/wonkyconn/tests/test_workflow.py @@ -20,16 +20,16 @@ def test_load_data_frame(tmp_path: Path) -> None: assert row_count == 3 assert list(data_frame.reset_index().columns) == ["participant_id", "age", "gender"] - full_data_frame = data_frame.reset_index() + data_frame = data_frame.reset_index() # Check that we throw an error for missing columns - for missing_column in full_data_frame.columns: - full_data_frame.drop(columns=missing_column).to_csv(phenotypes_path, sep="\t", index=False) - with pytest.raises(ValueError): + for missing_column in data_frame.columns: + data_frame.drop(columns=missing_column).to_csv(phenotypes_path, sep="\t", index=False) + with pytest.raises(ValueError, match=missing_column): load_data_frame(Namespace(phenotypes=str(phenotypes_path))) # Check that we throw an error for duplicate participant_id entries - data_frame = pd.concat([full_data_frame, full_data_frame.iloc[0:1]]) # Add a duplicate row + data_frame = pd.concat([data_frame, data_frame.iloc[0:1]]) # Add a duplicate row data_frame.to_csv(phenotypes_path, sep="\t", index=False) - with pytest.raises(ValueError, match="duplicate participant_id"): + with pytest.raises(ValueError, match="duplicate"): load_data_frame(Namespace(phenotypes=str(phenotypes_path)))