Skip to content

Commit 74c671e

Browse files
committed
Open files with a context manager in client to avoid file locks after crashes
1 parent df0ad99 commit 74c671e

1 file changed

Lines changed: 137 additions & 142 deletions

File tree

client.py

Lines changed: 137 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -85,58 +85,55 @@ def main(args):
8585
localConfigAdditionalText = fid.read()
8686
fid.close()
8787

88-
dset = h5py.File(args.filename, 'r')
89-
if not dset:
90-
logging.error("Not a valid dataset: %s" % args.filename)
91-
return
92-
93-
dsetNames = dset.keys()
94-
logging.info("File %s contains %d groups:", args.filename, len(dset.keys()))
95-
print(" ", "\n ".join(dsetNames))
96-
97-
if not args.in_group:
98-
if len(dset.keys()) == 1:
99-
args.in_group = list(dset.keys())[0]
100-
else:
101-
logging.error("Input group not specified and multiple groups are present")
88+
with h5py.File(args.filename, 'r') as dset:
89+
if not dset:
90+
logging.error("Not a valid dataset: %s" % args.filename)
10291
return
92+
dsetNames = dset.keys()
93+
logging.info("File %s contains %d groups:", args.filename, len(dset.keys()))
94+
print(" ", "\n ".join(dsetNames))
10395

96+
if not args.in_group:
97+
if len(dset.keys()) == 1:
98+
args.in_group = list(dset.keys())[0]
99+
else:
100+
logging.error("Input group not specified and multiple groups are present")
101+
return
104102

105-
if args.in_group not in dset:
106-
logging.error("Could not find group %s", args.in_group)
107-
return
108103

109-
group = dset.get(args.in_group)
104+
if args.in_group not in dset:
105+
logging.error("Could not find group %s", args.in_group)
106+
return
110107

111-
logging.info("Reading data from group '%s' in file '%s'", args.in_group, args.filename)
108+
group = dset.get(args.in_group)
112109

113-
# ----- Determine type of data stored --------------------------------------
114-
# Raw data is stored as:
115-
# /group/config text of recon config parameters (optional)
116-
# /group/xml text of ISMRMRD flexible data header
117-
# /group/data array of IsmsmrdAcquisition data + header
118-
# /group/waveforms array of waveform (e.g. PMU) data
110+
logging.info("Reading data from group '%s' in file '%s'", args.in_group, args.filename)
119111

120-
# Image data is stored as:
121-
# /group/config text of recon config parameters (optional)
122-
# /group/xml text of ISMRMRD flexible data header (optional)
123-
# /group/image_0/data array of IsmrmrdImage data
124-
# /group/image_0/header array of ImageHeader
125-
# /group/image_0/attributes text of image MetaAttributes
126-
hasRaw = False
127-
hasImage = False
128-
hasWaveforms = False
112+
# ----- Determine type of data stored --------------------------------------
113+
# Raw data is stored as:
114+
# /group/config text of recon config parameters (optional)
115+
# /group/xml text of ISMRMRD flexible data header
116+
# /group/data array of IsmsmrdAcquisition data + header
117+
# /group/waveforms array of waveform (e.g. PMU) data
129118

130-
if ('data' in group):
131-
hasRaw = True
132-
133-
if len([key for key in group.keys() if (key.startswith('image_') or key.startswith('images_'))]) > 0:
134-
hasImage = True
119+
# Image data is stored as:
120+
# /group/config text of recon config parameters (optional)
121+
# /group/xml text of ISMRMRD flexible data header (optional)
122+
# /group/image_0/data array of IsmrmrdImage data
123+
# /group/image_0/header array of ImageHeader
124+
# /group/image_0/attributes text of image MetaAttributes
125+
hasRaw = False
126+
hasImage = False
127+
hasWaveforms = False
135128

136-
if ('waveforms' in group):
137-
hasWaveforms = True
129+
if ('data' in group):
130+
hasRaw = True
131+
132+
if len([key for key in group.keys() if (key.startswith('image_') or key.startswith('images_'))]) > 0:
133+
hasImage = True
138134

139-
dset.close()
135+
if ('waveforms' in group):
136+
hasWaveforms = True
140137

141138
if ((hasRaw is False) and (hasImage is False)):
142139
logging.error("File does not contain properly formatted MRD raw or image data")
@@ -189,117 +186,115 @@ def main(args):
189186
logging.info("Sending remote config file name '%s'", args.config)
190187
connection.send_config_file(args.config)
191188

192-
dset = ismrmrd.Dataset(args.filename, args.in_group, False)
193-
194-
# --------------- Send MRD metadata -----------------------
195-
groups = dset.list()
196-
if ('xml' in groups):
197-
xml_header = dset.read_xml_header()
198-
xml_header = xml_header.decode("utf-8")
199-
else:
200-
logging.warning("Could not find MRD metadata xml in file")
201-
xml_header = "Dummy XML header"
202-
connection.send_metadata(xml_header)
203-
204-
# --------------- Send additional config -----------------------
205-
groups = dset.list()
206-
if localConfigAdditionalText is None:
207-
if ('configAdditional' in groups):
208-
configAdditionalText = dset._dataset['configAdditional'][0]
209-
configAdditionalText = configAdditionalText.decode("utf-8")
189+
with ismrmrd.Dataset(args.filename, args.in_group, create_if_needed=False) as dset:
190+
# --------------- Send MRD metadata -----------------------
191+
groups = dset.list()
192+
if ('xml' in groups):
193+
xml_header = dset.read_xml_header()
194+
xml_header = xml_header.decode("utf-8")
195+
else:
196+
logging.warning("Could not find MRD metadata xml in file")
197+
xml_header = "Dummy XML header"
198+
connection.send_metadata(xml_header)
199+
200+
# --------------- Send additional config -----------------------
201+
groups = dset.list()
202+
if localConfigAdditionalText is None:
203+
if ('configAdditional' in groups):
204+
configAdditionalText = dset._dataset['configAdditional'][0]
205+
configAdditionalText = configAdditionalText.decode("utf-8")
206+
207+
if args.ignore_json_config:
208+
# Remove the config specified in the JSON, allowing the config passed via command line to the client to be used
209+
configAdditional = json.loads(configAdditionalText)
210+
if ('parameters' in configAdditional):
211+
if ('config' in configAdditional['parameters']):
212+
logging.warning(f"Input file contains JSON configAdditional that specifies config '{configAdditional['parameters']['config']}', but will be ignored because '--ignore-json-config' was specified!")
213+
del configAdditional['parameters']['config']
214+
215+
if ('customconfig' in configAdditional['parameters']):
216+
if configAdditional['parameters']['customconfig'] != '':
217+
logging.warning(f"Input file contains JSON configAdditional that specifies customconfig '{configAdditional['parameters']['customconfig']}', but will be ignored because '--ignore-json-config' was specified!")
218+
del configAdditional['parameters']['customconfig']
219+
220+
configAdditionalText = json.dumps(configAdditional, indent=2)
221+
222+
logging.info("Sending configAdditional found in file %s:\n%s", args.filename, configAdditionalText)
223+
connection.send_text(configAdditionalText)
224+
else:
225+
# Do nothing -- no additional config in local .json file or in MRD file
226+
pass
227+
else:
228+
if ('configAdditional' in groups):
229+
logging.warning("configAdditional found in file %s, but is overriden by local file %s!", args.filename, configAdditionalFile)
210230

211231
if args.ignore_json_config:
212232
# Remove the config specified in the JSON, allowing the config passed via command line to the client to be used
213-
configAdditional = json.loads(configAdditionalText)
214-
if ('parameters' in configAdditional):
215-
if ('config' in configAdditional['parameters']):
216-
logging.warning(f"Input file contains JSON configAdditional that specifies config '{configAdditional['parameters']['config']}', but will be ignored because '--ignore-json-config' was specified!")
217-
del configAdditional['parameters']['config']
218-
219-
if ('customconfig' in configAdditional['parameters']):
220-
if configAdditional['parameters']['customconfig'] != '':
221-
logging.warning(f"Input file contains JSON configAdditional that specifies customconfig '{configAdditional['parameters']['customconfig']}', but will be ignored because '--ignore-json-config' was specified!")
222-
del configAdditional['parameters']['customconfig']
223-
224-
configAdditionalText = json.dumps(configAdditional, indent=2)
225-
226-
logging.info("Sending configAdditional found in file %s:\n%s", args.filename, configAdditionalText)
227-
connection.send_text(configAdditionalText)
228-
else:
229-
# Do nothing -- no additional config in local .json file or in MRD file
230-
pass
231-
else:
232-
if ('configAdditional' in groups):
233-
logging.warning("configAdditional found in file %s, but is overriden by local file %s!", args.filename, configAdditionalFile)
234-
235-
if args.ignore_json_config:
236-
# Remove the config specified in the JSON, allowing the config passed via command line to the client to be used
237-
localConfigAdditional = json.loads(localConfigAdditionalText)
238-
if ('parameters' in localConfigAdditional):
239-
if ('config' in localConfigAdditional['parameters']):
240-
logging.warning(f"configAdditional file '{configAdditionalFile}' specifies config '{localConfigAdditional['parameters']['config']}', but will be ignored because '--ignore-json-config' was specified!")
241-
del localConfigAdditional['parameters']['config']
242-
243-
if ('customconfig' in localConfigAdditional['parameters']):
244-
if localConfigAdditional['parameters']['customconfig'] != '':
245-
logging.warning(f"configAdditional file '{configAdditionalFile}' specifies customconfig '{localConfigAdditional['parameters']['customconfig']}', but will be ignored because '--ignore-json-config' was specified!")
246-
del localConfigAdditional['parameters']['customconfig']
247-
248-
localConfigAdditionalText = json.dumps(localConfigAdditional, indent=2)
249-
250-
logging.info("Sending configAdditional found in file %s:\n%s", configAdditionalFile, localConfigAdditionalText)
251-
connection.send_text(localConfigAdditionalText)
252-
253-
# --------------- Send waveform data ----------------------
254-
# TODO: Interleave waveform and other data so they arrive chronologically
255-
if hasWaveforms:
256-
if args.send_waveforms:
257-
logging.info("Sending waveform data")
258-
logging.info("Found %d waveforms", dset.number_of_waveforms())
259-
260-
for idx in range(0, dset.number_of_waveforms()):
261-
wav = dset.read_waveform(idx)
233+
localConfigAdditional = json.loads(localConfigAdditionalText)
234+
if ('parameters' in localConfigAdditional):
235+
if ('config' in localConfigAdditional['parameters']):
236+
logging.warning(f"configAdditional file '{configAdditionalFile}' specifies config '{localConfigAdditional['parameters']['config']}', but will be ignored because '--ignore-json-config' was specified!")
237+
del localConfigAdditional['parameters']['config']
238+
239+
if ('customconfig' in localConfigAdditional['parameters']):
240+
if localConfigAdditional['parameters']['customconfig'] != '':
241+
logging.warning(f"configAdditional file '{configAdditionalFile}' specifies customconfig '{localConfigAdditional['parameters']['customconfig']}', but will be ignored because '--ignore-json-config' was specified!")
242+
del localConfigAdditional['parameters']['customconfig']
243+
244+
localConfigAdditionalText = json.dumps(localConfigAdditional, indent=2)
245+
246+
logging.info("Sending configAdditional found in file %s:\n%s", configAdditionalFile, localConfigAdditionalText)
247+
connection.send_text(localConfigAdditionalText)
248+
249+
# --------------- Send waveform data ----------------------
250+
# TODO: Interleave waveform and other data so they arrive chronologically
251+
if hasWaveforms:
252+
if args.send_waveforms:
253+
logging.info("Sending waveform data")
254+
logging.info("Found %d waveforms", dset.number_of_waveforms())
255+
256+
for idx in range(0, dset.number_of_waveforms()):
257+
wav = dset.read_waveform(idx)
258+
try:
259+
connection.send_waveform(wav)
260+
except:
261+
logging.error('Failed to send waveform %d -- aborting!' % idx)
262+
break
263+
else:
264+
logging.info("Waveform data present, but send-waveforms option turned off")
265+
266+
# --------------- Send raw data ----------------------
267+
if hasRaw:
268+
logging.info("Starting raw data session")
269+
logging.info("Found %d raw data readouts", dset.number_of_acquisitions())
270+
271+
for idx in range(dset.number_of_acquisitions()):
272+
acq = dset.read_acquisition(idx)
262273
try:
263-
connection.send_waveform(wav)
274+
connection.send_acquisition(acq)
264275
except:
265-
logging.error('Failed to send waveform %d -- aborting!' % idx)
276+
logging.error('Failed to send acquisition %d -- aborting!' % idx)
266277
break
267-
else:
268-
logging.info("Waveform data present, but send-waveforms option turned off")
269-
270-
# --------------- Send raw data ----------------------
271-
if hasRaw:
272-
logging.info("Starting raw data session")
273-
logging.info("Found %d raw data readouts", dset.number_of_acquisitions())
274-
275-
for idx in range(dset.number_of_acquisitions()):
276-
acq = dset.read_acquisition(idx)
277-
try:
278-
connection.send_acquisition(acq)
279-
except:
280-
logging.error('Failed to send acquisition %d -- aborting!' % idx)
281-
break
282278

283-
# --------------- Send image data ----------------------
284-
if hasImage:
285-
logging.info("Starting image data session")
286-
for group in [key for key in groups if (key.startswith('image_') or key.startswith('images_'))]:
287-
logging.info("Reading images from '/" + args.in_group + "/" + group + "'")
279+
# --------------- Send image data ----------------------
280+
if hasImage:
281+
logging.info("Starting image data session")
282+
for group in [key for key in groups if (key.startswith('image_') or key.startswith('images_'))]:
283+
logging.info("Reading images from '/" + args.in_group + "/" + group + "'")
288284

289-
for imgNum in range(0, dset.number_of_images(group)):
290-
image = dset.read_image(group, imgNum)
285+
for imgNum in range(0, dset.number_of_images(group)):
286+
image = dset.read_image(group, imgNum)
291287

292-
if not isinstance(image.attribute_string, str):
293-
image.attribute_string = image.attribute_string.decode('utf-8')
288+
if not isinstance(image.attribute_string, str):
289+
image.attribute_string = image.attribute_string.decode('utf-8')
294290

295-
logging.debug("Sending image %d of %d", imgNum, dset.number_of_images(group)-1)
296-
try:
297-
connection.send_image(image)
298-
except:
299-
logging.error('Failed to send image %d -- aborting!' % imgNum)
300-
break
291+
logging.debug("Sending image %d of %d", imgNum, dset.number_of_images(group)-1)
292+
try:
293+
connection.send_image(image)
294+
except:
295+
logging.error('Failed to send image %d -- aborting!' % imgNum)
296+
break
301297

302-
dset.close()
303298
try:
304299
connection.send_close()
305300
except:

0 commit comments

Comments
 (0)