From ad75d5014921b4b2b0ac34734da2adf60111b71b Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 26 Mar 2021 13:30:48 -0400 Subject: [PATCH] ENH+BF: consistent n/a for age/sex, also handle ?M for months Also initiated test_bids.py to finally start collecting testing of BIDS specific logic we add Closes #499 --- heudiconv/bids.py | 35 +++++++++++++++++++++++++++++++++-- heudiconv/tests/test_bids.py | 26 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 heudiconv/tests/test_bids.py diff --git a/heudiconv/bids.py b/heudiconv/bids.py index e07c347e..fc630aa5 100644 --- a/heudiconv/bids.py +++ b/heudiconv/bids.py @@ -47,6 +47,36 @@ class BIDSError(Exception): BIDS_VERSION = "1.4.1" +def maybe_na(val): + """Return 'n/a' if non-None value represented as str is not empty + + Primarily for the consistent use of lower case 'n/a' so 'N/A' and 'NA' + are also treated as 'n/a' + """ + if val is not None: + val = str(val) + val = val.strip() + return 'n/a' if (not val or val in ('N/A', 'NA')) else val + + +def treat_age(age): + """Age might encounter 'Y' suffix or be a float""" + age = str(age) + if age.endswith('M'): + age = age.rstrip('M') + age = float(age) / 12 + age = ('%.2f' if age != int(age) else '%d') % age + else: + age = age.rstrip('Y') + if age: + # strip all leading 0s but allow to scan a newborn (age 0Y) + age = '0' if not age.lstrip('0') else age.lstrip('0') + if age.startswith('.'): + # we had float point value, let's prepend 0 + age = '0' + age + return age + + def populate_bids_templates(path, defaults={}): """Premake BIDS text files with templates""" @@ -278,12 +308,13 @@ def add_participant_record(studydir, subject, age, sex): "control group)")])), ]), sort_keys=False) + # Add a new participant with open(participants_tsv, 'a') as f: f.write( '\t'.join(map(str, [participant_id, - age.lstrip('0').rstrip('Y') if age else 'N/A', - sex if sex else 'n/a', + maybe_na(treat_age(age)), + maybe_na(sex), 'control'])) + '\n') diff --git a/heudiconv/tests/test_bids.py b/heudiconv/tests/test_bids.py new file mode 100644 index 00000000..a980e359 --- /dev/null +++ b/heudiconv/tests/test_bids.py @@ -0,0 +1,26 @@ +"""Test functions in heudiconv.bids module. +""" + +from heudiconv.bids import ( + maybe_na, + treat_age, +) + + +def test_maybe_na(): + for na in '', ' ', None, 'n/a', 'N/A', 'NA': + assert maybe_na(na) == 'n/a' + for notna in 0, 1, False, True, 'value': + assert maybe_na(notna) == str(notna) + + +def test_treat_age(): + assert treat_age(0) == '0' + assert treat_age('0') == '0' + assert treat_age('0000') == '0' + assert treat_age('0000Y') == '0' + assert treat_age('000.1Y') == '0.1' + assert treat_age('1M') == '0.08' + assert treat_age('12M') == '1' + assert treat_age('0000.1') == '0.1' + assert treat_age(0000.1) == '0.1' \ No newline at end of file