Skip to content

Commit

Permalink
Merge pull request #107 from Json-To-String/master
Browse files Browse the repository at this point in the history
adding logic to handle KeyError: "Unable to open object (object 'connection table' doesn't exist)" on initial run
  • Loading branch information
dihm authored Oct 21, 2024
2 parents 7a84e38 + 9858c9c commit 511975b
Showing 1 changed file with 74 additions and 65 deletions.
139 changes: 74 additions & 65 deletions blacs/front_panel_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from labscript_utils.connections import ConnectionTable

logger = logging.getLogger('BLACS.FrontPanelSettings')
logger = logging.getLogger('BLACS.FrontPanelSettings')

def _ensure_str(s):
"""convert bytestrings and numpy strings to python strings"""
Expand All @@ -36,7 +36,7 @@ def __init__(self,settings_path,connection_table):
self.connection_table = connection_table
with h5py.File(settings_path,'a') as h5file:
pass

def setup(self,blacs):
self.tablist = blacs.tablist
self.attached_devices = blacs.attached_devices
Expand All @@ -46,7 +46,7 @@ def setup(self,blacs):
self.blacs = blacs

def restore(self):

# Get list of DO/AO
# Does the object have a name?
# yes: Then, find the device in the BLACS connection table that matches that name
Expand All @@ -63,31 +63,40 @@ def restore(self):
# no: Restore as is
#
# Display errors, give option to cancel starting of BLACS so that the connection table can be edited

# Create saved connection table
settings = {}
question = {}
error = {}
tab_data = {'BLACS settings':{}}

# See if connection table exists in apparatus h5 file
with h5py.File(self.settings_path, 'r') as h5file:
if 'connection table' not in h5file:
logger.info('Front panel settings connection table not found!')

# TODO: tab_data will be passed into restore_window next, populate this
return settings, question, error, tab_data

try:
saved_ct = ConnectionTable(self.settings_path, logging_prefix='BLACS', exceptions_in_thread=True)
ct_match,error = self.connection_table.compare_to(saved_ct)

with h5py.File(self.settings_path,'r') as hdf5_file:
# Get Tab Data
dataset = hdf5_file['/front_panel'].get('_notebook_data',[])

for row in dataset:
tab_name = _ensure_str(row['tab_name'])
tab_data.setdefault(tab_name,{})
try:
tab_data[tab_name] = {'notebook':row['notebook'], 'page':row['page'], 'visible':row['visible'], 'data':eval(_ensure_str(row['data']))}
except Exception:
logger.info("Could not load tab data for %s"%tab_name)

#now get dataset attributes
tab_data['BLACS settings'] = dict(dataset.attrs)

# Get the front panel values
if 'front_panel' in hdf5_file["/front_panel"]:
dataset = hdf5_file["/front_panel"].get('front_panel', [])
Expand All @@ -101,7 +110,7 @@ def restore(self):
else:
data_dict[columns[i]] = row[i]
settings,question,error = self.handle_return_code(data_dict,result,settings,question,error)

# Else Legacy restore from GTK save data!
else:
# open Datasets
Expand All @@ -119,7 +128,7 @@ def restore(self):
logger.info("Could not load saved settings")
logger.info(str(e))
return settings,question,error,tab_data

def handle_return_code(self,row,result,settings,question,error):
# 1: Restore to existing device
# 2: Send to new device
Expand All @@ -131,7 +140,7 @@ def handle_return_code(self,row,result,settings,question,error):
if type(result) == tuple:
connection = result[1]
result = result[0]

if result == 1:
settings.setdefault(row['device_name'],{})
settings[row['device_name']][row['channel']] = row
Expand All @@ -145,10 +154,10 @@ def handle_return_code(self,row,result,settings,question,error):
error[row['device_name']+'_'+row['channel']] = row,"missing"
elif result == -2:
error[row['device_name']+'_'+row['channel']] = row,"changed"

return settings,question,error
def check_row(self,row,ct_match,blacs_ct,saved_ct):

def check_row(self,row,ct_match,blacs_ct,saved_ct):
# If it has a name
if row[0] != "-":
if ct_match:
Expand All @@ -158,21 +167,21 @@ def check_row(self,row,ct_match,blacs_ct,saved_ct):
# Find if this device is in the connection table
connection = blacs_ct.find_by_name(row[0])
connection2 = saved_ct.find_by_name(row[0])

if connection:
# compare the two connections, see what differs
# if compare fails only on parent, connected to:
# send to new parent
# else:
# show error, device parameters not compatible with saved data
result,error = connection.compare_to(connection2)

allowed_length = 0
if "parent_port" in error:
allowed_length += 1

if len(error) > allowed_length:
return -2 # failure, device parameters not compatible
return -2 # failure, device parameters not compatible
elif error == {} and connection.parent.name == connection2.parent.name:
return 1 # All details about this device match
else:
Expand All @@ -190,46 +199,46 @@ def check_row(self,row,ct_match,blacs_ct,saved_ct):
else:
# restore to device
return 1
@inmain_decorator(wait_for_return=True)

@inmain_decorator(wait_for_return=True)
def get_save_data(self):
tab_data = {}
notebook_data = {}
window_data = {}
plugin_data = {}

# iterate over all tabs
for device_name,tab in self.tablist.items():
tab_data[device_name] = {'front_panel':tab.settings['front_panel_settings'], 'save_data': tab.get_all_save_data()}

# Find the notebook the tab is in
#
# By default we assume it is in notebook0, on page 0. This way, if a tab gets lost somewhere,
# and isn't found to be a child of any notebook we know about,
#
# By default we assume it is in notebook0, on page 0. This way, if a tab gets lost somewhere,
# and isn't found to be a child of any notebook we know about,
# it will revert back to notebook 1 when the file is loaded upon program restart!
current_notebook_name = 0
current_notebook_name = 0
page = 0
visible = False

for notebook_name,notebook in self.notebook.items():
if notebook.indexOf(tab._ui) != -1:
current_notebook_name = notebook_name
page = notebook.indexOf(tab._ui)
visible = True if notebook.currentIndex() == page else False
if notebook.indexOf(tab._ui) != -1:
current_notebook_name = notebook_name
page = notebook.indexOf(tab._ui)
visible = True if notebook.currentIndex() == page else False
break

notebook_data[device_name] = {"notebook":current_notebook_name,"page":page, "visible":visible}

# iterate over all plugins
for module_name, plugin in self.blacs.plugins.items():
try:
plugin_data[module_name] = plugin.get_save_data()
except Exception as e:
logger.error('Could not save data for plugin %s. Error was: %s'%(module_name,str(e)))

# save window data
# Size of window
window_data["_main_window"] = {"width":self.window.normalGeometry().width(),
# Size of window
window_data["_main_window"] = {"width":self.window.normalGeometry().width(),
"height":self.window.normalGeometry().height(),
"xpos":self.window.normalGeometry().x(),
"ypos":self.window.normalGeometry().y(),
Expand All @@ -242,24 +251,24 @@ def get_save_data(self):
# Pane positions
for name,pane in self.panes.items():
window_data[name] = pane.sizes()

return tab_data,notebook_data,window_data,plugin_data

@inmain_decorator(wait_for_return=True)
def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,plugin_data,silent = {}, force_new_conn_table = False):
def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,plugin_data,silent = {}, force_new_conn_table = False):
# Save the front panel!

# Does the file exist?
# Does the file exist?
# Yes: Check connection table inside matches current connection table. Does it match?
# Yes: Does the file have a front panel already saved in it?
# Yes: Can we overwrite?
# Yes: Delete front_panel group, save new front panel
# No: Create error dialog!
# No: Save front panel in here
#
#
# No: Return
# No: Create new file, place inside the connection table and front panel

if os.path.isfile(current_file):
save_conn_table = True if force_new_conn_table else False
result = False
Expand All @@ -270,10 +279,10 @@ def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,pl
except Exception:
# no connection table is present, so also save the connection table!
save_conn_table = True

# if save_conn_table is True, we don't bother checking to see if the connection tables match, because save_conn_table is only true when the connection table doesn't exist in the current file
# As a result, if save_conn_table is True, we ignore connection table checking, and save the connection table in the h5file.

if save_conn_table or result:
with h5py.File(current_file,'r+') as hdf5_file:
if hdf5_file['/'].get('front_panel') != None:
Expand All @@ -288,18 +297,18 @@ def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,pl
message.setIcon(QMessageBox.Question)
message.setWindowTitle("BLACS")
resp = message.exec_()

if resp == QMessageBox.Yes :
overwrite = True
overwrite = True
else:
overwrite = silent["overwrite"]

if overwrite:
# Delete Front panel group, save new front panel
del hdf5_file['/front_panel']
self.store_front_panel_in_h5(hdf5_file,states,tab_positions,window_data,plugin_data,save_conn_table)
else:
if not silent:
if not silent:
message = QMessageBox()
message.setText("Front Panel not saved.")
message.setIcon(QMessageBox.Information)
Expand All @@ -308,7 +317,7 @@ def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,pl
else:
logger.info("Front Panel not saved as it already existed in the h5 file '"+current_file+"'")
return
else:
else:
# Save Front Panel in here
self.store_front_panel_in_h5(hdf5_file,states,tab_positions,window_data,plugin_data,save_conn_table)
else:
Expand All @@ -318,32 +327,32 @@ def save_front_panel_to_h5(self,current_file,states,tab_positions,window_data,pl
message.setText("The Front Panel was not saved as the file selected contains a connection table which is not a subset of the BLACS connection table.")
message.setIcon(QMessageBox.Information)
message.setWindowTitle("BLACS")
message.exec_()
message.exec_()
else:
logger.info("Front Panel not saved as the connection table in the h5 file '"+current_file+"' didn't match the current connection table.")
return
else:
with h5py.File(current_file,'w') as hdf5_file:
# save connection table, save front panel
# save connection table, save front panel
self.store_front_panel_in_h5(hdf5_file,states,tab_positions,window_data,plugin_data,save_conn_table=True)

@inmain_decorator(wait_for_return=True)
def store_front_panel_in_h5(self, hdf5_file,tab_data,notebook_data,window_data,plugin_data,save_conn_table=False,save_queue_data=True):
if save_conn_table:
if 'connection table' in hdf5_file:
del hdf5_file['connection table']
hdf5_file.create_dataset('connection table', data=self.connection_table.raw_table)

data_group = hdf5_file['/'].create_group('front_panel')

front_panel_list = []
other_data_list = []
other_data_list = []
front_panel_dtype = [('name','a256'),('device_name','a256'),('channel','a256'),('base_value',float),('locked',bool),('base_step_size',float),('current_units','a256')]
max_od_length = 2 # empty dictionary

# Iterate over each device within a class
for device_name, device_state in tab_data.items():
logger.debug("saving front panel for device:" + device_name)
logger.debug("saving front panel for device:" + device_name)
# Insert front panel data into dataset
for hardware_name, data in device_state["front_panel"].items():
if data != {}:
Expand All @@ -359,29 +368,29 @@ def store_front_panel_in_h5(self, hdf5_file,tab_data,notebook_data,window_data,p
data['base_step_size'] if 'base_step_size' in data else 0,
data['current_units'] if 'current_units' in data else ''
)
)
)
else:
logger.warning('Could not save data for channel %s on device %s because the output value (in base units) was not a string or could not be coerced to a float without loss of precision'%(hardware_name, device_name))

# Save "other data"
od = repr(device_state["save_data"])
other_data_list.append(od)
max_od_length = len(od) if len(od) > max_od_length else max_od_length
other_data_list.append(od)
max_od_length = len(od) if len(od) > max_od_length else max_od_length

# Create datasets
if front_panel_list:
front_panel_array = numpy.empty(len(front_panel_list),dtype=front_panel_dtype)
for i, row in enumerate(front_panel_list):
front_panel_array[i] = row
data_group.create_dataset('front_panel',data=front_panel_array)

# Save tab data
i = 0
tab_data = numpy.empty(len(notebook_data),dtype=[('tab_name','a256'),('notebook','a2'),('page',int),('visible',bool),('data','a'+str(max_od_length))])
for device_name,data in notebook_data.items():
tab_data[i] = (device_name,data["notebook"],data["page"],data["visible"],other_data_list[i])
i += 1

# Save BLACS Main GUI Info
dataset = data_group.create_dataset("_notebook_data",data=tab_data)
dataset.attrs["window_width"] = window_data["_main_window"]["width"]
Expand All @@ -398,7 +407,7 @@ def store_front_panel_in_h5(self, hdf5_file,tab_data,notebook_data,window_data,p
for pane_name,pane_position in window_data.items():
if pane_name != "_main_window":
dataset.attrs[pane_name] = pane_position

# Save analysis server settings:
#dataset = data_group.create_group("analysis_server")
#dataset.attrs['send_for_analysis'] = self.blacs.analysis_submission.toggle_analysis.get_active()
Expand Down

0 comments on commit 511975b

Please sign in to comment.