Skip to content

Commit 4ec5d43

Browse files
authored
Merge pull request #523 from dbic/bf-retry-load_json
BF(workaround): retry loading json multiple times
2 parents 21d5104 + c51a843 commit 4ec5d43

File tree

3 files changed

+52
-9
lines changed

3 files changed

+52
-9
lines changed

heudiconv/bids.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def populate_aggregated_jsons(path):
157157
# TODO: if we are to fix it, then old ones (without _acq) should be
158158
# removed first
159159
task = re.sub('.*_(task-[^_\.]*(_acq-[^_\.]*)?)_.*', r'\1', fpath)
160-
json_ = load_json(fpath)
160+
json_ = load_json(fpath, retry=100)
161161
if task not in tasks:
162162
tasks[task] = json_
163163
else:
@@ -212,7 +212,7 @@ def populate_aggregated_jsons(path):
212212
"CogAtlasID": "http://www.cognitiveatlas.org/task/id/TODO",
213213
}
214214
if op.lexists(task_file):
215-
j = load_json(task_file)
215+
j = load_json(task_file, retry=100)
216216
# Retain possibly modified placeholder fields
217217
for f in placeholders:
218218
if f in j:

heudiconv/tests/test_utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import os
33
import os.path as op
44

5+
import mock
6+
57
from heudiconv.utils import (
68
get_known_heuristics_with_descriptions,
79
get_heuristic_description,
@@ -77,6 +79,13 @@ def test_load_json(tmpdir, caplog):
7779
with pytest.raises(JSONDecodeError):
7880
load_json(str(invalid_json_file))
7981

82+
# and even if we ask to retry a few times -- should be the same
83+
with pytest.raises(JSONDecodeError):
84+
load_json(str(invalid_json_file), retry=3)
85+
86+
with pytest.raises(FileNotFoundError):
87+
load_json("absent123not.there", retry=3)
88+
8089
assert ifname in caplog.text
8190

8291
# test valid json
@@ -87,6 +96,23 @@ def test_load_json(tmpdir, caplog):
8796

8897
assert load_json(valid_json_file) == vcontent
8998

99+
calls = [0]
100+
json_load = json.load
101+
102+
def json_load_patched(fp):
103+
calls[0] += 1
104+
if calls[0] == 1:
105+
# just reuse bad file
106+
load_json(str(invalid_json_file))
107+
elif calls[0] == 2:
108+
raise FileNotFoundError()
109+
else:
110+
return json_load(fp)
111+
112+
with mock.patch.object(json, 'load', json_load_patched):
113+
assert load_json(valid_json_file, retry=3) == vcontent
114+
115+
90116

91117
def test_get_datetime():
92118
"""

heudiconv/utils.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from glob import glob
1515
from subprocess import check_output
1616
from datetime import datetime
17+
from time import sleep
1718

1819
from nipype.utils.filemanip import which
1920

@@ -147,24 +148,40 @@ def write_config(outfile, info):
147148
fp.writelines(PrettyPrinter().pformat(info))
148149

149150

150-
def load_json(filename):
151+
def load_json(filename, retry=0):
151152
"""Load data from a json file
152153
153154
Parameters
154155
----------
155156
filename : str
156157
Filename to load data from.
158+
retry: int, optional
159+
Number of times to retry opening/loading the file in case of
160+
failure. Code will sleep for 0.1 seconds between retries.
161+
Could be used in code which is not sensitive to order effects
162+
(e.g. like populating bids templates where the last one to
163+
do it, would make sure it would be the correct/final state).
157164
158165
Returns
159166
-------
160167
data : dict
161168
"""
162-
try:
163-
with open(filename, 'r') as fp:
164-
data = json.load(fp)
165-
except JSONDecodeError:
166-
lgr.error("{fname} is not a valid json file".format(fname=filename))
167-
raise
169+
assert retry >= 0
170+
for i in range(retry + 1): # >= 10 sec wait
171+
try:
172+
try:
173+
with open(filename, 'r') as fp:
174+
data = json.load(fp)
175+
break
176+
except JSONDecodeError:
177+
lgr.error("{fname} is not a valid json file".format(fname=filename))
178+
raise
179+
except (JSONDecodeError, FileNotFoundError) as exc:
180+
if i >= retry:
181+
raise
182+
lgr.warning("Caught %s. Will retry again", exc)
183+
sleep(0.1)
184+
continue
168185

169186
return data
170187

0 commit comments

Comments
 (0)