Skip to content

Commit 2d8a80e

Browse files
committed
Run.get_* methods should open the HDF5 file in read-only mode
Fixes #42 Also addressed labscript-suite/labscript-utils#47 (removing h5py deprecation warnings) for this module Also fixed an issue where calling `set_group` on a `Run` inside a `Sequence` could disable the read-only mode of the `Run` object. Added `no_write` support to `Sequence`.
1 parent 74dfc19 commit 2d8a80e

File tree

1 file changed

+46
-32
lines changed

1 file changed

+46
-32
lines changed

lyse/__init__.py

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,10 @@ def globals_diff(run1, run2, group=None):
104104
class Run(object):
105105
def __init__(self,h5_path,no_write=False):
106106
self.no_write = no_write
107+
self._no_group = None
107108
self.h5_path = h5_path
108109
if not self.no_write:
109-
with h5py.File(h5_path) as h5_file:
110-
if not 'results' in h5_file:
111-
h5_file.create_group('results')
110+
self._create_group_if_not_exists(h5_path, '/', 'results')
112111

113112
try:
114113
if not self.no_write:
@@ -118,48 +117,65 @@ def __init__(self,h5_path,no_write=False):
118117
frame = inspect.currentframe()
119118
__file__ = frame.f_back.f_globals['__file__']
120119
self.group = os.path.basename(__file__).split('.py')[0]
121-
with h5py.File(h5_path) as h5_file:
122-
if not self.group in h5_file['results']:
123-
h5_file['results'].create_group(self.group)
120+
self._create_group_if_not_exists(h5_path, 'results', self.group)
124121
except KeyError:
125122
# sys.stderr.write('Warning: to write results, call '
126123
# 'Run.set_group(groupname), specifying the name of the group '
127124
# 'you would like to save results to. This normally comes from '
128125
# 'the filename of your script, but since you\'re in interactive '
129126
# 'mode, there is no scipt name. Opening in read only mode for '
130127
# 'the moment.\n')
128+
129+
# Backup the value of self.no_write for restoration once the group
130+
# is set
131+
self._no_group = (True, self.no_write)
131132
self.no_write = True
132133

134+
def _create_group_if_not_exists(self, h5_path, location, groupname):
135+
"""Creates a group in the HDF5 file at `location` if it does not exist.
136+
137+
Only opens the h5 file in write mode if a group must be created.
138+
This ensures the last modified time of the file is only updated if
139+
the file is actually written to."""
140+
create_group = False
141+
with h5py.File(h5_path, 'r') as h5_file:
142+
if not groupname in h5_file[location]:
143+
create_group = True
144+
if create_group:
145+
with h5py.File(h5_path, 'r+') as h5_file:
146+
h5_file[location].create_group(groupname)
147+
133148
def set_group(self, groupname):
134149
self.group = groupname
135-
with h5py.File(self.h5_path) as h5_file:
136-
if not self.group in h5_file['results']:
137-
h5_file['results'].create_group(self.group)
138-
self.no_write = False
150+
self._create_group_if_not_exists(self.h5_path, '/', 'results')
151+
# restore no_write attribute now we have set the group
152+
if self._no_group is not None and self._no_group[0]:
153+
self.no_write = self._no_group[1]
154+
self._no_group = None
139155

140156
def trace_names(self):
141-
with h5py.File(self.h5_path) as h5_file:
157+
with h5py.File(self.h5_path, 'r') as h5_file:
142158
try:
143159
return list(h5_file['data']['traces'].keys())
144160
except KeyError:
145161
return []
146162

147163
def get_attrs(self, group):
148164
"""Returns all attributes of the specified group as a dictionary."""
149-
with h5py.File(self.h5_path) as h5_file:
165+
with h5py.File(self.h5_path, 'r') as h5_file:
150166
if not group in h5_file:
151167
raise Exception('The group \'%s\' does not exist'%group)
152168
return get_attributes(h5_file[group])
153169

154170
def get_trace(self,name):
155-
with h5py.File(self.h5_path) as h5_file:
171+
with h5py.File(self.h5_path, 'r') as h5_file:
156172
if not name in h5_file['data']['traces']:
157173
raise Exception('The trace \'%s\' doesn not exist'%name)
158174
trace = h5_file['data']['traces'][name]
159175
return array(trace['t'],dtype=float),array(trace['values'],dtype=float)
160176

161177
def get_result_array(self,group,name):
162-
with h5py.File(self.h5_path) as h5_file:
178+
with h5py.File(self.h5_path, 'r') as h5_file:
163179
if not group in h5_file['results']:
164180
raise Exception('The result group \'%s\' doesn not exist'%group)
165181
if not name in h5_file['results'][group]:
@@ -169,7 +185,7 @@ def get_result_array(self,group,name):
169185
def get_result(self, group, name):
170186
"""Return 'result' in 'results/group' that was saved by
171187
the save_result() method."""
172-
with h5py.File(self.h5_path) as h5_file:
188+
with h5py.File(self.h5_path, 'r') as h5_file:
173189
if not group in h5_file['results']:
174190
raise Exception('The result group \'%s\' does not exist'%group)
175191
if not name in h5_file['results'][group].attrs.keys():
@@ -288,7 +304,7 @@ def save_result_arrays(self, *args, **kwargs):
288304
self.save_result_array(name, value, **kwargs)
289305

290306
def get_image(self,orientation,label,image):
291-
with h5py.File(self.h5_path) as h5_file:
307+
with h5py.File(self.h5_path, 'r') as h5_file:
292308
if not 'images' in h5_file:
293309
raise Exception('File does not contain any images')
294310
if not orientation in h5_file['images']:
@@ -307,13 +323,13 @@ def get_images(self,orientation,label, *images):
307323

308324
def get_all_image_labels(self):
309325
images_list = {}
310-
with h5py.File(self.h5_path) as h5_file:
326+
with h5py.File(self.h5_path, 'r') as h5_file:
311327
for orientation in h5_file['/images'].keys():
312328
images_list[orientation] = list(h5_file['/images'][orientation].keys())
313329
return images_list
314330

315331
def get_image_attributes(self, orientation):
316-
with h5py.File(self.h5_path) as h5_file:
332+
with h5py.File(self.h5_path, 'r') as h5_file:
317333
if not 'images' in h5_file:
318334
raise Exception('File does not contain any images')
319335
if not orientation in h5_file['images']:
@@ -322,18 +338,18 @@ def get_image_attributes(self, orientation):
322338

323339
def get_globals(self,group=None):
324340
if not group:
325-
with h5py.File(self.h5_path) as h5_file:
341+
with h5py.File(self.h5_path, 'r') as h5_file:
326342
return dict(h5_file['globals'].attrs)
327343
else:
328344
try:
329-
with h5py.File(self.h5_path) as h5_file:
345+
with h5py.File(self.h5_path, 'r') as h5_file:
330346
return dict(h5_file['globals'][group].attrs)
331347
except KeyError:
332348
return {}
333349

334350
def get_globals_raw(self, group=None):
335351
globals_dict = {}
336-
with h5py.File(self.h5_path) as h5_file:
352+
with h5py.File(self.h5_path, 'r') as h5_file:
337353
if group == None:
338354
for obj in h5_file['globals'].values():
339355
temp_dict = dict(obj.attrs)
@@ -374,7 +390,7 @@ def append_expansion(name, obj):
374390
for key, val in temp_dict.items():
375391
if val:
376392
expansion_dict[key] = val
377-
with h5py.File(self.h5_path) as h5_file:
393+
with h5py.File(self.h5_path, 'r') as h5_file:
378394
h5_file['globals'].visititems(append_expansion)
379395
return expansion_dict
380396

@@ -385,12 +401,12 @@ def append_units(name, obj):
385401
temp_dict = dict(obj.attrs)
386402
for key, val in temp_dict.items():
387403
units_dict[key] = val
388-
with h5py.File(self.h5_path) as h5_file:
404+
with h5py.File(self.h5_path, 'r') as h5_file:
389405
h5_file['globals'].visititems(append_units)
390406
return units_dict
391407

392408
def globals_groups(self):
393-
with h5py.File(self.h5_path) as h5_file:
409+
with h5py.File(self.h5_path, 'r') as h5_file:
394410
try:
395411
return list(h5_file['globals'].keys())
396412
except KeyError:
@@ -401,14 +417,13 @@ def globals_diff(self, other_run, group=None):
401417

402418

403419
class Sequence(Run):
404-
def __init__(self,h5_path,run_paths):
420+
def __init__(self, h5_path, run_paths, no_write=False):
405421
if isinstance(run_paths, pandas.DataFrame):
406422
run_paths = run_paths['filepath']
407423
self.h5_path = h5_path
408-
self.no_write = False
409-
with h5py.File(h5_path) as h5_file:
410-
if not 'results' in h5_file:
411-
h5_file.create_group('results')
424+
self.no_write = no_write
425+
if not self.no_write:
426+
self._create_group_if_not_exists(h5_path, '/', 'results')
412427

413428
self.runs = {path: Run(path,no_write=True) for path in run_paths}
414429

@@ -419,9 +434,8 @@ def __init__(self,h5_path,run_paths):
419434
try:
420435
__file__ = frame.f_back.f_locals['__file__']
421436
self.group = os.path.basename(__file__).split('.py')[0]
422-
with h5py.File(h5_path) as h5_file:
423-
if not self.group in h5_file['results']:
424-
h5_file['results'].create_group(self.group)
437+
if not self.no_write:
438+
self._create_group_if_not_exists(h5_path, 'results', self.group)
425439
except KeyError:
426440
sys.stderr.write('Warning: to write results, call '
427441
'Sequence.set_group(groupname), specifying the name of the group '

0 commit comments

Comments
 (0)