Skip to content

Commit 8866cc5

Browse files
authored
Merge pull request #507 from dbic/enh-bids-meta
RF/ENH: populate a singular scans.json at the top level of the bids dataset
2 parents a5e6718 + 6ff5a96 commit 8866cc5

File tree

3 files changed

+23
-25
lines changed

3 files changed

+23
-25
lines changed

heudiconv/bids.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
load_json,
1919
save_json,
2020
create_file_if_missing,
21-
json_dumps_pretty,
21+
json_dumps,
2222
set_readonly,
2323
is_readonly,
2424
get_datetime,
@@ -120,6 +120,9 @@ def populate_bids_templates(path, defaults={}):
120120
create_file_if_missing(op.join(path, 'README'),
121121
"TODO: Provide description for the dataset -- basic details about the "
122122
"study, possibly pointing to pre-registration (if public or embargoed)")
123+
create_file_if_missing(op.join(path, 'scans.json'),
124+
json_dumps(SCANS_FILE_FIELDS, sort_keys=False)
125+
)
123126

124127
populate_aggregated_jsons(path)
125128

@@ -404,11 +407,6 @@ def add_rows_to_scans_keys_file(fn, newrows):
404407
os.unlink(fn)
405408
else:
406409
fnames2info = newrows
407-
# Populate _scans.json (an optional file to describe column names in
408-
# _scans.tsv). This auto generation will make BIDS-validator happy.
409-
scans_json = '.'.join(fn.split('.')[:-1] + ['json'])
410-
if not op.lexists(scans_json):
411-
save_json(scans_json, SCANS_FILE_FIELDS, sort_keys=False)
412410

413411
header = SCANS_FILE_FIELDS
414412
# prepare all the data rows

heudiconv/tests/test_main.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
from heudiconv.main import workflow
55
from heudiconv import __version__
66
from heudiconv.utils import (create_file_if_missing,
7+
load_json,
78
set_readonly,
89
is_readonly)
910
from heudiconv.bids import (populate_bids_templates,
1011
add_participant_record,
1112
get_formatted_scans_key_row,
1213
add_rows_to_scans_keys_file,
13-
find_subj_ses)
14+
find_subj_ses,
15+
SCANS_FILE_FIELDS,
16+
)
1417
from heudiconv.external.dlad import MIN_VERSION, add_to_datalad
1518

1619
from .utils import TESTS_DATA_PATH
@@ -81,6 +84,9 @@ def test_populate_bids_templates(tmpdir):
8184
assert "something" not in description_file.read()
8285
assert "TODO" in description_file.read()
8386

87+
# Explicit str() is needed for py 3.5. TODO: remove when dropping 3.5
88+
assert load_json(str(tmpdir / "scans.json")) == SCANS_FILE_FIELDS
89+
8490

8591
def test_add_participant_record(tmpdir):
8692
tf = tmpdir.join('participants.tsv')
@@ -127,6 +133,7 @@ def test_prepare_for_datalad(tmpdir):
127133
'.gitattributes',
128134
'.datalad/config', '.datalad/.gitattributes',
129135
'dataset_description.json',
136+
'scans.json',
130137
'CHANGES', 'README'}
131138
assert set(ds.repo.get_indexed_files()) == target_files
132139
# and all are under git
@@ -217,7 +224,9 @@ def _check_rows(fn, rows):
217224
assert dates == sorted(dates)
218225

219226
_check_rows(fn, rows)
220-
assert op.exists(opj(tmpdir.strpath, 'file.json'))
227+
# we no longer produce a sidecar .json file there and only generate
228+
# it while populating templates for BIDS
229+
assert not op.exists(opj(tmpdir.strpath, 'file.json'))
221230
# add a new one
222231
extra_rows = {
223232
'a_new_file.nii.gz': ['2016adsfasd23', '', 'fasadfasdf'],

heudiconv/utils.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -147,21 +147,6 @@ def write_config(outfile, info):
147147
fp.writelines(PrettyPrinter().pformat(info))
148148

149149

150-
def _canonical_dumps(json_obj, **kwargs):
151-
""" Dump `json_obj` to string, allowing for Python newline bug
152-
153-
Runs ``json.dumps(json_obj, \*\*kwargs), then removes trailing whitespaces
154-
added when doing indent in some Python versions. See
155-
https://bugs.python.org/issue16333. Bug seems to be fixed in 3.4, for now
156-
fixing manually not only for aestetics but also to guarantee the same
157-
result across versions of Python.
158-
"""
159-
out = json.dumps(json_obj, **kwargs)
160-
if 'indent' in kwargs:
161-
out = out.replace(' \n', '\n')
162-
return out
163-
164-
165150
def load_json(filename):
166151
"""Load data from a json file
167152
@@ -220,19 +205,25 @@ def save_json(filename, data, indent=2, sort_keys=True, pretty=False):
220205
% (str(exc), filename)
221206
)
222207
if not pretty:
223-
j = _canonical_dumps(data, **dumps_kw)
208+
j = json_dumps(data, **dumps_kw)
224209
assert j is not None # one way or another it should have been set to a str
225210
with open(filename, 'w') as fp:
226211
fp.write(j)
227212

228213

214+
def json_dumps(json_obj, indent=2, sort_keys=True):
215+
"""Unified (default indent and sort_keys) invocation of json.dumps
216+
"""
217+
return json.dumps(json_obj, indent=indent, sort_keys=sort_keys)
218+
219+
229220
def json_dumps_pretty(j, indent=2, sort_keys=True):
230221
"""Given a json structure, pretty print it by colliding numeric arrays
231222
into a line.
232223
233224
If resultant structure differs from original -- throws exception
234225
"""
235-
js = _canonical_dumps(j, indent=indent, sort_keys=sort_keys)
226+
js = json_dumps(j, indent=indent, sort_keys=sort_keys)
236227
# trim away \n and spaces between entries of numbers
237228
js_ = re.sub(
238229
'[\n ]+("?[-+.0-9e]+"?,?) *\n(?= *"?[-+.0-9e]+"?)', r' \1',

0 commit comments

Comments
 (0)