Repository: nilearn/nilearn

Issue:
check_paradigm should check for invalid keys in passed dict
Using the old `nipy` user logic, I passed `amplitude=somethx` instead of `modulation=somethx` in the `make_design_matrix`. I didn't crash but the values where ignored (e.g Error: unknown param, etc.). A default value of 1 was forced...



Discussion:
We could have warning when unexpected keys are given in events files.

Resolving patch:
diff --git a/nilearn/glm/first_level/experimental_paradigm.py b/nilearn/glm/first_level/experimental_paradigm.py
--- a/nilearn/glm/first_level/experimental_paradigm.py
+++ b/nilearn/glm/first_level/experimental_paradigm.py
@@ -17,6 +17,11 @@
 
 import numpy as np
 
+VALID_FIELDS = set(["onset",
+                    "duration",
+                    "trial_type",
+                    "modulation",
+                    ])
 
 def check_events(events):
     """Test that the events data describes a valid experimental paradigm
@@ -54,13 +59,19 @@ def check_events(events):
     onset = np.array(events['onset'])
     duration = np.array(events['duration']).astype(np.float)
     n_events = len(onset)
-    trial_type = np.array(events['trial_type'])
     modulation = np.ones(n_events)
     if 'trial_type' not in events.keys():
         warnings.warn("'trial_type' column not found "
                       "in the given events data.")
         trial_type = np.repeat('dummy', n_events)
+    else:
+        trial_type = np.array(events['trial_type'])
     if 'modulation' in events.keys():
         warnings.warn("'modulation' column found in the given events data.")
         modulation = np.array(events['modulation']).astype(np.float)
+    for event,_ in events.items():
+        if event not in VALID_FIELDS:
+            warnings.warn("Unexpected key `{}` in events "
+                          "will be ignored.".format(
+                              event))
     return trial_type, onset, duration, modulation


Test patch:
diff --git a/nilearn/glm/tests/test_paradigm.py b/nilearn/glm/tests/test_paradigm.py
--- a/nilearn/glm/tests/test_paradigm.py
+++ b/nilearn/glm/tests/test_paradigm.py
@@ -6,9 +6,11 @@
 """
 
 import os
-
+import pytest
 import numpy as np
 import pandas as pd
+from numpy.testing import assert_array_equal
+from nilearn.glm.first_level import check_events
 
 
 def basic_paradigm():
@@ -66,6 +68,48 @@ def write_events(events, tmpdir):
     return tsvfile
 
 
+def test_check_events():
+    """Test the function which tests that the events
+    data describes a valid experimental paradigm.
+    """
+    events = basic_paradigm()
+    # Errors checkins
+    # Missing onset
+    missing_onset = events.drop(columns=['onset'])
+    with pytest.raises(ValueError,
+                       match='The provided events data has no onset column.'):
+        check_events(missing_onset)
+    # Missing duration
+    missing_duration = events.drop(columns=['duration'])
+    with pytest.raises(ValueError,
+                       match='The provided events data has no duration column.'):
+        check_events(missing_duration)
+    # Warnings checkins
+    # Missing trial type
+    with pytest.warns(UserWarning,
+                      match="'trial_type' column not found"):
+        ttype, onset, duration, modulation = check_events(events)
+    # Check that missing trial type yields a 'dummy' array
+    assert_array_equal(ttype, np.repeat('dummy', len(events)))
+    # Check that missing modulation yields an array one ones
+    assert_array_equal(modulation, np.ones(len(events)))
+    # Modulation is provided
+    events['modulation'] = np.ones(len(events))
+    with pytest.warns(UserWarning,
+                      match="'modulation' column found in the given events data."):
+        check_events(events)
+    # An unexpected field is provided
+    events = events.drop(columns=['modulation'])
+    events['foo'] = np.zeros(len(events))
+    with pytest.warns(UserWarning,
+                      match="Unexpected key `foo` in events will be ignored."):
+        ttype2, onset2, duration2, modulation2 = check_events(events)
+    assert_array_equal(ttype, ttype2)
+    assert_array_equal(onset, onset2)
+    assert_array_equal(duration, duration2)
+    assert_array_equal(modulation, modulation2)
+
+
 def test_read_events():
     """ test that a events for an experimental paradigm are correctly read.
     """