diff --git a/lyse/__init__.py b/lyse/__init__.py index a00d8d5..6163b8a 100644 --- a/lyse/__init__.py +++ b/lyse/__init__.py @@ -104,11 +104,10 @@ def globals_diff(run1, run2, group=None): class Run(object): def __init__(self,h5_path,no_write=False): self.no_write = no_write + self._no_group = None self.h5_path = h5_path if not self.no_write: - with h5py.File(h5_path) as h5_file: - if not 'results' in h5_file: - h5_file.create_group('results') + self._create_group_if_not_exists(h5_path, '/', 'results') try: if not self.no_write: @@ -118,9 +117,7 @@ def __init__(self,h5_path,no_write=False): frame = inspect.currentframe() __file__ = frame.f_back.f_globals['__file__'] self.group = os.path.basename(__file__).split('.py')[0] - with h5py.File(h5_path) as h5_file: - if not self.group in h5_file['results']: - h5_file['results'].create_group(self.group) + self._create_group_if_not_exists(h5_path, 'results', self.group) except KeyError: # sys.stderr.write('Warning: to write results, call ' # 'Run.set_group(groupname), specifying the name of the group ' @@ -128,17 +125,36 @@ def __init__(self,h5_path,no_write=False): # 'the filename of your script, but since you\'re in interactive ' # 'mode, there is no scipt name. Opening in read only mode for ' # 'the moment.\n') + + # Backup the value of self.no_write for restoration once the group + # is set + self._no_group = (True, self.no_write) self.no_write = True + def _create_group_if_not_exists(self, h5_path, location, groupname): + """Creates a group in the HDF5 file at `location` if it does not exist. + + Only opens the h5 file in write mode if a group must be created. + This ensures the last modified time of the file is only updated if + the file is actually written to.""" + create_group = False + with h5py.File(h5_path, 'r') as h5_file: + if not groupname in h5_file[location]: + create_group = True + if create_group: + with h5py.File(h5_path, 'r+') as h5_file: + h5_file[location].create_group(groupname) + def set_group(self, groupname): self.group = groupname - with h5py.File(self.h5_path) as h5_file: - if not self.group in h5_file['results']: - h5_file['results'].create_group(self.group) - self.no_write = False + self._create_group_if_not_exists(self.h5_path, '/', 'results') + # restore no_write attribute now we have set the group + if self._no_group is not None and self._no_group[0]: + self.no_write = self._no_group[1] + self._no_group = None def trace_names(self): - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: try: return list(h5_file['data']['traces'].keys()) except KeyError: @@ -146,20 +162,20 @@ def trace_names(self): def get_attrs(self, group): """Returns all attributes of the specified group as a dictionary.""" - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: if not group in h5_file: raise Exception('The group \'%s\' does not exist'%group) return get_attributes(h5_file[group]) def get_trace(self,name): - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: if not name in h5_file['data']['traces']: raise Exception('The trace \'%s\' doesn not exist'%name) trace = h5_file['data']['traces'][name] return array(trace['t'],dtype=float),array(trace['values'],dtype=float) def get_result_array(self,group,name): - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: if not group in h5_file['results']: raise Exception('The result group \'%s\' doesn not exist'%group) if not name in h5_file['results'][group]: @@ -169,7 +185,7 @@ def get_result_array(self,group,name): def get_result(self, group, name): """Return 'result' in 'results/group' that was saved by the save_result() method.""" - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: if not group in h5_file['results']: raise Exception('The result group \'%s\' does not exist'%group) if not name in h5_file['results'][group].attrs.keys(): @@ -288,7 +304,7 @@ def save_result_arrays(self, *args, **kwargs): self.save_result_array(name, value, **kwargs) def get_image(self,orientation,label,image): - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: if not 'images' in h5_file: raise Exception('File does not contain any images') if not orientation in h5_file['images']: @@ -307,13 +323,13 @@ def get_images(self,orientation,label, *images): def get_all_image_labels(self): images_list = {} - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: for orientation in h5_file['/images'].keys(): images_list[orientation] = list(h5_file['/images'][orientation].keys()) return images_list def get_image_attributes(self, orientation): - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: if not 'images' in h5_file: raise Exception('File does not contain any images') if not orientation in h5_file['images']: @@ -322,18 +338,18 @@ def get_image_attributes(self, orientation): def get_globals(self,group=None): if not group: - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: return dict(h5_file['globals'].attrs) else: try: - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: return dict(h5_file['globals'][group].attrs) except KeyError: return {} def get_globals_raw(self, group=None): globals_dict = {} - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: if group == None: for obj in h5_file['globals'].values(): temp_dict = dict(obj.attrs) @@ -374,7 +390,7 @@ def append_expansion(name, obj): for key, val in temp_dict.items(): if val: expansion_dict[key] = val - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: h5_file['globals'].visititems(append_expansion) return expansion_dict @@ -385,12 +401,12 @@ def append_units(name, obj): temp_dict = dict(obj.attrs) for key, val in temp_dict.items(): units_dict[key] = val - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: h5_file['globals'].visititems(append_units) return units_dict def globals_groups(self): - with h5py.File(self.h5_path) as h5_file: + with h5py.File(self.h5_path, 'r') as h5_file: try: return list(h5_file['globals'].keys()) except KeyError: @@ -401,14 +417,13 @@ def globals_diff(self, other_run, group=None): class Sequence(Run): - def __init__(self,h5_path,run_paths): + def __init__(self, h5_path, run_paths, no_write=False): if isinstance(run_paths, pandas.DataFrame): run_paths = run_paths['filepath'] self.h5_path = h5_path - self.no_write = False - with h5py.File(h5_path) as h5_file: - if not 'results' in h5_file: - h5_file.create_group('results') + self.no_write = no_write + if not self.no_write: + self._create_group_if_not_exists(h5_path, '/', 'results') self.runs = {path: Run(path,no_write=True) for path in run_paths} @@ -419,9 +434,8 @@ def __init__(self,h5_path,run_paths): try: __file__ = frame.f_back.f_locals['__file__'] self.group = os.path.basename(__file__).split('.py')[0] - with h5py.File(h5_path) as h5_file: - if not self.group in h5_file['results']: - h5_file['results'].create_group(self.group) + if not self.no_write: + self._create_group_if_not_exists(h5_path, 'results', self.group) except KeyError: sys.stderr.write('Warning: to write results, call ' 'Sequence.set_group(groupname), specifying the name of the group '