Repository: mne-tools/mne-bids

Issue:
write_raw_bids overwrites dataset_description.json, participants.json
When the files are modified (i.e. when someone puts the authors in instead of the placeholder) it gets overwritten in the next write_raw_bids. 

I can do this PR later but I don't have time today.


Discussion:
PR is welcome! Thanks @alexrockhill 

I need some support from north american contributors to balance the European crew ;-)

Resolving patch:
diff --git a/mne_bids/write.py b/mne_bids/write.py
--- a/mne_bids/write.py
+++ b/mne_bids/write.py
@@ -777,14 +777,14 @@ def get_anonymization_daysback(raws):
             daysback_min_list.append(daysback_min)
             daysback_max_list.append(daysback_max)
     if not daysback_min_list or not daysback_max_list:
-        raise ValueError('All measurement dates are None, ' +
+        raise ValueError('All measurement dates are None, '
                          'pass any `daysback` value to anonymize.')
     daysback_min = max(daysback_min_list)
     daysback_max = min(daysback_max_list)
     if daysback_min > daysback_max:
-        raise ValueError('The dataset spans more time than can be ' +
-                         'accomodated by MNE, you may have to ' +
-                         'not follow BIDS recommendations and use' +
+        raise ValueError('The dataset spans more time than can be '
+                         'accomodated by MNE, you may have to '
+                         'not follow BIDS recommendations and use'
                          'anonymized dates after 1925')
     return daysback_min, daysback_max
 
@@ -794,7 +794,7 @@ def make_dataset_description(path, name, data_license=None,
                              how_to_acknowledge=None, funding=None,
                              references_and_links=None, doi=None,
                              dataset_type='raw',
-                             verbose=False):
+                             overwrite=False, verbose=False):
     """Create json for a dataset description.
 
     BIDS datasets may have one or more fields, this function allows you to
@@ -831,6 +831,12 @@ def make_dataset_description(path, name, data_license=None,
         The DOI for the dataset.
     dataset_type : str
         Must be either "raw" or "derivative". Defaults to "raw".
+    overwrite : bool
+        Whether to overwrite existing files or data in files.
+        Defaults to False.
+        If overwrite is True, provided fields will overwrite previous data.
+        If overwrite is False, no existing data will be overwritten or
+        replaced.
     verbose : bool
         Set verbose output to True or False.
 
@@ -839,11 +845,6 @@ def make_dataset_description(path, name, data_license=None,
     The required field BIDSVersion will be automatically filled by mne_bids.
 
     """
-    # default author to make dataset description BIDS compliant
-    if authors is None:
-        authors = ("Please cite MNE-BIDS in your publication before removing "
-                   "this (citations in README)")
-
     # Put potential string input into list of strings
     if isinstance(authors, str):
         authors = authors.split(', ')
@@ -866,6 +867,24 @@ def make_dataset_description(path, name, data_license=None,
                                ('Funding', funding),
                                ('ReferencesAndLinks', references_and_links),
                                ('DatasetDOI', doi)])
+    if op.isfile(fname):
+        with open(fname, 'r') as fin:
+            orig_cols = json.load(fin)
+        if 'BIDSVersion' in orig_cols and \
+                orig_cols['BIDSVersion'] != BIDS_VERSION:
+            raise ValueError('Previous BIDS version used, please redo the '
+                             'conversion to BIDS in a new directory '
+                             'after ensuring all software is updated')
+        for key, val in description.items():
+            if description[key] is None or not overwrite:
+                description[key] = orig_cols.get(key, None)
+    # default author to make dataset description BIDS compliant
+    # if the user passed an author don't overwrite,
+    # if there was an author there, only overwrite if `overwrite=True`
+    if authors is None and (description['Authors'] is None or overwrite):
+        description['Authors'] = ["Please cite MNE-BIDS in your publication "
+                                  "before removing this (citations in README)"]
+
     pop_keys = [key for key, val in description.items() if val is None]
     for key in pop_keys:
         description.pop(key)
@@ -1164,9 +1183,8 @@ def write_raw_bids(raw, bids_basename, bids_root, events_data=None,
     if events is not None and len(events) > 0 and not emptyroom:
         _events_tsv(events, raw, events_fname, event_id, overwrite, verbose)
 
-    dataset_description_fpath = op.join(bids_root, "dataset_description.json")
-    if not op.exists(dataset_description_fpath) or overwrite:
-        make_dataset_description(bids_root, name=" ", verbose=verbose)
+    make_dataset_description(bids_root, name=" ", overwrite=overwrite,
+                             verbose=verbose)
 
     _sidecar_json(raw, task, manufacturer, sidecar_fname, kind, overwrite,
                   verbose)
@@ -1186,7 +1204,7 @@ def write_raw_bids(raw, bids_basename, bids_root, events_data=None,
     convert = ext not in ALLOWED_EXTENSIONS[kind]
 
     if kind == 'meg' and convert and not anonymize:
-        raise ValueError('Got file extension %s for MEG data, ' +
+        raise ValueError('Got file extension %s for MEG data, '
                          'expected one of %s' %
                          ALLOWED_EXTENSIONS['meg'])
 


Test patch:
diff --git a/mne_bids/tests/test_write.py b/mne_bids/tests/test_write.py
--- a/mne_bids/tests/test_write.py
+++ b/mne_bids/tests/test_write.py
@@ -123,13 +123,45 @@ def test_make_dataset_description():
                                          'or "derivative."'):
         make_dataset_description(path=tmp_dir, name='tst', dataset_type='src')
 
+    make_dataset_description(path=tmp_dir, name='tst')
+
+    with open(op.join(tmp_dir, 'dataset_description.json'), 'r') as fid:
+        dataset_description_json = json.load(fid)
+        assert dataset_description_json["Authors"] == \
+            ["Please cite MNE-BIDS in your publication before removing this "
+             "(citations in README)"]
+
     make_dataset_description(
         path=tmp_dir, name='tst', authors='MNE B., MNE P.',
         funding='GSOC2019, GSOC2021',
         references_and_links='https://doi.org/10.21105/joss.01896',
-        dataset_type='derivative', verbose=True
+        dataset_type='derivative', overwrite=False, verbose=True
+    )
+
+    with open(op.join(tmp_dir, 'dataset_description.json'), 'r') as fid:
+        dataset_description_json = json.load(fid)
+        assert dataset_description_json["Authors"] == \
+            ["Please cite MNE-BIDS in your publication before removing this "
+             "(citations in README)"]
+
+    make_dataset_description(
+        path=tmp_dir, name='tst2', authors='MNE B., MNE P.',
+        funding='GSOC2019, GSOC2021',
+        references_and_links='https://doi.org/10.21105/joss.01896',
+        dataset_type='derivative', overwrite=True, verbose=True
     )
 
+    with open(op.join(tmp_dir, 'dataset_description.json'), 'r') as fid:
+        dataset_description_json = json.load(fid)
+        assert dataset_description_json["Authors"] == ['MNE B.', 'MNE P.']
+
+    with pytest.raises(ValueError, match='Previous BIDS version used'):
+        version = make_dataset_description.__globals__['BIDS_VERSION']
+        make_dataset_description.__globals__['BIDS_VERSION'] = 'old'
+        make_dataset_description(path=tmp_dir, name='tst')
+        # put version back so that it doesn't cause issues down the road
+        make_dataset_description.__globals__['BIDS_VERSION'] = version
+
 
 def test_stamp_to_dt():
     """Test conversions of meas_date to datetime objects."""
@@ -775,8 +807,8 @@ def test_edf(_bids_validate):
     with open(dataset_description_fpath, 'r') as f:
         dataset_description_json = json.load(f)
         assert dataset_description_json["Authors"] == \
-            [("Please cite MNE-BIDS in your publication before removing this "
-              "(citations in README)")]
+            ["Please cite MNE-BIDS in your publication before removing this "
+             "(citations in README)"]
 
     # Reading the file back should raise an error, because we renamed channels
     # in `raw` and used that information to write a channels.tsv. Yet, we