Repository: nilearn/nilearn

Issue:
Multiple definitions of `basic_paradigm`
The function `basic_paradigm` is defined in `nilearn._utils.data_gen.py`:

https://github.com/nilearn/nilearn/blob/00d3873fb6cf23d09f8eba6d0d20e905f26d22dd/nilearn/_utils/data_gen.py#L505-L510

But, it is re-defined in other files (with a duration) for testing:

- `nilearn/glm/tests/test_first_level.py`:
https://github.com/nilearn/nilearn/blob/a36c0442fc8eebe401b310dd9799c0f071080e90/nilearn/glm/tests/test_first_level.py#L353-L360

- `nilearn/glm/tests/test_paradigm.py`:
https://github.com/nilearn/nilearn/blob/a36c0442fc8eebe401b310dd9799c0f071080e90/nilearn/glm/tests/test_paradigm.py#L16-L23

- `nilearn/glm/tests/test_dmtx.py`:
https://github.com/nilearn/nilearn/blob/a36c0442fc8eebe401b310dd9799c0f071080e90/nilearn/glm/tests/test_dmtx.py#L48-L55

It would be better to remove those and import `basic_paradigm` from `_utils.data_gen.py`.
update: issue #2763
Replaced rewritten functions in multiple files by importing the original function.

<!---
This is a suggested pull request template for nilearn.
It's designed to capture information we've found to be useful in reviewing pull requests.

If there is other information that would be helpful to include, please don't hesitate to add it!

See here for more information on what is expected for pull requests:
https://github.com/nilearn/nilearn/blob/master/CONTRIBUTING.rst#pull-requests
-->

<!-- Please indicate after the # which issue you're closing with this PR.
This is helpful for the maintainers AND will magically close the issue when this
pull request is merged!
If the PR closes multiple issues, includes "closes" before each one is listed.
https://help.github.com/articles/closing-issues-using-keywords -->
Closes #2763.

<!-- Please give a brief overview of what has changed in the PR.
If you're not sure what to write, consider it a note to the maintainers to indicate
what they should be looking for when they review the pull request. -->
Changes proposed in this pull request:

- Import `basic_paradigm` function from original file to applicable files 
- Delete rewritten functions in applicable files



Discussion:
Good first issue indeed ! thx for spotting it.


Resolving patch:
diff --git a/nilearn/_utils/data_gen.py b/nilearn/_utils/data_gen.py
--- a/nilearn/_utils/data_gen.py
+++ b/nilearn/_utils/data_gen.py
@@ -501,11 +501,32 @@ def generate_group_sparse_gaussian_graphs(
     return signals, precisions, topology
 
 
-def basic_paradigm():
-    conditions = ['c0', 'c0', 'c0', 'c1', 'c1', 'c1', 'c2', 'c2', 'c2']
+def basic_paradigm(condition_names_have_spaces=False):
+    """Generate basic paradigm
+
+    Parameters
+    ----------
+    condition_names_have_spaces : :obj:`bool`, optional
+        Check for spaces in condition names.
+        Default=False.
+
+    Returns
+    -------
+    events : pd.DataFrame
+        Basic experimental paradigm with events data.
+
+    """
+    conditions = ['c 0', 'c 0', 'c 0',
+                  'c 1', 'c 1', 'c 1',
+                  'c 2', 'c 2', 'c 2']
+
+    if not condition_names_have_spaces:
+        conditions = [c.replace(' ', '') for c in conditions]
     onsets = [30, 70, 100, 10, 30, 90, 30, 40, 60]
+    durations = 1 * np.ones(9)
     events = pd.DataFrame({'trial_type': conditions,
-                           'onset': onsets})
+                           'onset': onsets,
+                           'duration': durations})
     return events
 
 


Test patch:
diff --git a/nilearn/glm/tests/test_dmtx.py b/nilearn/glm/tests/test_dmtx.py
--- a/nilearn/glm/tests/test_dmtx.py
+++ b/nilearn/glm/tests/test_dmtx.py
@@ -22,6 +22,8 @@
     make_second_level_design_matrix
 )
 
+from nilearn._utils.data_gen import basic_paradigm
+
 # load the spm file to test cosine basis
 my_path = osp.dirname(osp.abspath(__file__))
 full_path_design_matrix_file = osp.join(my_path, 'spm_dmtx.npz')
@@ -44,16 +46,6 @@ def design_matrix_light(
     return matrix, names
 
 
-def basic_paradigm():
-    conditions = ['c0', 'c0', 'c0', 'c1', 'c1', 'c1', 'c2', 'c2', 'c2']
-    onsets = [30, 70, 100, 10, 30, 90, 30, 40, 60]
-    durations = 1 * np.ones(9)
-    events = pd.DataFrame({'trial_type': conditions,
-                           'onset': onsets,
-                           'duration': durations})
-    return events
-
-
 def modulated_block_paradigm():
     rng = np.random.RandomState(42)
     conditions = ['c0', 'c0', 'c0', 'c1', 'c1', 'c1', 'c2', 'c2', 'c2']
@@ -184,7 +176,7 @@ def test_convolve_regressors():
 
 
 def test_design_matrix1():
-    # basic test based on basic_paradigm and glover hrf
+    # basic test based on basic_paradigm() and glover hrf
     tr = 1.0
     frame_times = np.linspace(0, 127 * tr, 128)
     events = basic_paradigm()
diff --git a/nilearn/glm/tests/test_first_level.py b/nilearn/glm/tests/test_first_level.py
--- a/nilearn/glm/tests/test_first_level.py
+++ b/nilearn/glm/tests/test_first_level.py
@@ -14,7 +14,8 @@
 
 from nilearn._utils.data_gen import (create_fake_bids_dataset,
                                      generate_fake_fmri_data_and_design,
-                                     write_fake_fmri_data_and_design)
+                                     write_fake_fmri_data_and_design,
+                                     basic_paradigm)
 from nilearn.glm.contrasts import compute_fixed_effects
 from nilearn.glm.first_level import (FirstLevelModel, first_level_from_bids,
                                      mean_scaling, run_glm)
@@ -26,6 +27,7 @@
 from nilearn.glm.regression import ARModel, OLSModel
 from nilearn.maskers import NiftiMasker
 
+
 BASEDIR = os.path.dirname(os.path.abspath(__file__))
 FUNCFILE = os.path.join(BASEDIR, 'functional.nii.gz')
 
@@ -470,20 +472,6 @@ def test_fmri_inputs():
         del fi, func_img, mask, d, des, FUNCFILE, _
 
 
-def basic_paradigm(condition_names_have_spaces=False):
-    if condition_names_have_spaces:
-        conditions = ['c 0', 'c 0', 'c 0', 'c 1', 'c 1', 'c 1',
-                      'c 2', 'c 2', 'c 2']
-    else:
-        conditions = ['c0', 'c0', 'c0', 'c1', 'c1', 'c1', 'c2', 'c2', 'c2']
-    onsets = [30, 70, 100, 10, 30, 90, 30, 40, 60]
-    durations = 1 * np.ones(9)
-    events = pd.DataFrame({'trial_type': conditions,
-                           'onset': onsets,
-                           'duration': durations})
-    return events
-
-
 def test_first_level_design_creation():
     # Test processing of FMRI inputs
     with InTemporaryDirectory():
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
@@ -10,19 +10,10 @@
 import numpy as np
 import pandas as pd
 from numpy.testing import assert_array_equal
+from nilearn._utils.data_gen import basic_paradigm
 from nilearn.glm.first_level import check_events
 
 
-def basic_paradigm():
-    conditions = ['c0', 'c0', 'c0', 'c1', 'c1', 'c1', 'c2', 'c2', 'c2']
-    onsets = [30, 70, 100, 10, 30, 90, 30, 40, 60]
-    durations = 1 * np.ones(9)
-    events = pd.DataFrame({'trial_type': conditions,
-                           'onset': onsets,
-                           'duration': durations})
-    return events
-
-
 def duplicate_events_paradigm():
     conditions = ['c0', 'c0', 'c0', 'c0', 'c1', 'c1']
     onsets = [10, 30, 70, 70, 10, 30]