Skip to content

Commit 873a5c9

Browse files
committed
👔 Look up REDCap indexes instead of relying on +1 heuristic
1 parent 045a54c commit 873a5c9

4 files changed

Lines changed: 396 additions & 5 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ extend-ignore = [
9191
]
9292

9393
[tool.ruff.lint.extend-per-file-ignores]
94+
"tests/test_redcap_format.py" = ["PLR2004"]
9495
"tests/**/*.py" = ["S101", "SLF001", "INP001", "D103", "ERA001"]
9596
"scripts/*.py" = ["T20", "D100", "N803", "B018", "ERA001", "PLR0913", "FBT003"]
9697
"scripts/*.ipynb" = [

src/mindlogger_data_export/outputs.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -444,20 +444,33 @@ def _parse_redcap_choice_mapping(self, field_name: str) -> dict[int, str] | None
444444
Parameters
445445
----------
446446
field_name
447-
The field name to look up in REDCap metadata
447+
The base field name (without suffix) to look up in REDCap metadata
448448
449449
Returns:
450450
-------
451451
dict[int, str] | None
452-
Mapping from Curious index to REDCap raw value, or None if not found
452+
Mapping from Mindlogger index to REDCap raw value, or None if not found
453453
"""
454454
if self._redcap_metadata is None or self._redcap_metadata.is_empty():
455455
return None
456456

457-
# Get choices for this field from metadata
458-
field_meta = self._redcap_metadata.filter(pl.col("field_name") == field_name)
457+
# The REDCap metadata contains field names with suffixes (_response, _index, etc.)
458+
# We need to try different variations to find the actual field
459+
possible_field_names = [
460+
field_name, # Try base name first
461+
f"{field_name}_response", # Try with _response suffix
462+
f"{field_name}_index", # Try with _index suffix
463+
]
464+
465+
field_meta = None
466+
for possible_name in possible_field_names:
467+
field_meta = self._redcap_metadata.filter(
468+
pl.col("field_name") == possible_name
469+
)
470+
if not field_meta.is_empty():
471+
break
459472

460-
if field_meta.is_empty():
473+
if field_meta is None or field_meta.is_empty():
461474
return None
462475

463476
choices_str = field_meta["select_choices_or_calculations"].item()

tests/test_mindlogger_data.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,38 @@ def test_expand_responses(report):
192192
def test_data_dictionary(report):
193193
_data = MindloggerData(report)
194194
assert len(list(_data.data_dictionary)) != 0
195+
196+
197+
@WITH_REPORT
198+
def test_redcap_format_integration_with_test_data(datafiles: Path):
199+
"""Integration test for RedcapImportFormat with actual test data."""
200+
from mindlogger_data_export.outputs import RedcapImportFormat
201+
202+
mindlogger_data = MindloggerData.create(datafiles)
203+
204+
# Create REDCap metadata with mixed suffix patterns
205+
redcap_metadata = pl.DataFrame(
206+
{
207+
"field_name": [
208+
"mood1_1_response", # Has _response suffix
209+
"mood2_1", # Base name
210+
"sleepquality_1_index", # Has _index suffix
211+
],
212+
"select_choices_or_calculations": [
213+
"0, 0-Very Cheerful | 6, 6-Very Sad",
214+
"0, 0-Very Relaxed | 6, 6-Very Anxious",
215+
"0, 0-Very Poor | 4, 4-Very Good",
216+
],
217+
}
218+
)
219+
220+
# Create RedcapImportFormat with metadata
221+
redcap_format = RedcapImportFormat(redcap_metadata=redcap_metadata)
222+
223+
# Use produce() instead of non-existent to_wide()
224+
outputs = redcap_format.produce(mindlogger_data)
225+
226+
# Should successfully process despite suffix pattern differences
227+
assert outputs is not None
228+
assert len(outputs) > 0
229+
assert all(isinstance(output.output, pl.DataFrame) for output in outputs)

0 commit comments

Comments
 (0)