@@ -147,16 +147,72 @@ def validate_software_versions(cls, v: dict[str, Any]) -> dict[str, str]:
147147 return v
148148
149149
150+ @lru_cache (maxsize = 1 )
150151def machine_config_from_file (
151- config_file_path : Path , instrument : str = ""
152+ config_file_path : Path ,
153+ instrument_name : str ,
152154) -> dict [str , MachineConfig ]:
155+ """
156+ Loads the machine config YAML file and constructs instrument-specific configs from
157+ a hierarchical set of dictionary key-value pairs. It will populate the keys listed
158+ in the general dictionary, then update the keys specified in the shared instrument
159+ dictionary, before finally updating the keys for that specific instrument.
160+ """
161+
162+ def _update_nested_values (base : dict [str , Any ], new : dict [str , Any ]):
163+ """
164+ Helper function to recursively update nested dictioanry values.
165+ If the old and new values are both dicts, it will add the new keys and values
166+ to the existing dictionary recursively without overwriting entries.
167+ If the old and new values are both lists, it will extend the existing list.
168+ For all other values, it will overwrite the existing value with the new one.
169+ """
170+ for key , value in new .items ():
171+ # If new values are dicts and dict values already exist, do recursive update
172+ if key in base and isinstance (base [key ], dict ) and isinstance (value , dict ):
173+ base [key ] = _update_nested_values (base [key ], value )
174+ # If new values are lists and a list already exists, extend the list
175+ if key in base and isinstance (base [key ], list ) and isinstance (value , list ):
176+ base [key ].extend (value )
177+ # Otherwise, overwrite values as normal
178+ else :
179+ base [key ] = value
180+ return base
181+
182+ # Load the dict from the file
153183 with open (config_file_path , "r" ) as config_stream :
154- config = yaml .safe_load (config_stream )
155- return {
156- i : MachineConfig (** config [i ])
157- for i in config .keys ()
158- if not instrument or i == instrument
159- }
184+ master_config : dict [str , Any ] = yaml .safe_load (config_stream )
185+
186+ # Construct requested machine configs from the YAML file
187+ all_machine_configs : dict [str , MachineConfig ] = {}
188+ for i in sorted (master_config .keys ()):
189+ # Skip reserved top-level keys
190+ if i in ("general" , "clem" , "fib" , "tem" ):
191+ continue
192+ # If instrument name is set, skip irrelevant configs
193+ if instrument_name and i != instrument_name :
194+ continue
195+ print (f"Parsing key { i } " )
196+ # Construct instrument config hierarchically
197+ config : dict [str , Any ] = {}
198+
199+ # Populate with general values
200+ general_config : dict [str , Any ] = master_config .get ("general" , {})
201+ config = _update_nested_values (config , general_config )
202+
203+ # Populate with shared instrument values
204+ instrument_config : dict [str , Any ] = master_config .get (i , {})
205+ instrument_shared_config : dict [str , Any ] = master_config .get (
206+ str (instrument_config .get ("instrument_type" , "" )).lower (), {}
207+ )
208+ config = _update_nested_values (config , instrument_shared_config )
209+
210+ # Insert instrument-specific values
211+ config = _update_nested_values (config , instrument_config )
212+
213+ all_machine_configs [i ] = MachineConfig (** config )
214+
215+ return all_machine_configs
160216
161217
162218class Security (BaseModel ):
@@ -250,22 +306,13 @@ def get_security_config() -> Security:
250306
251307@lru_cache (maxsize = 1 )
252308def get_machine_config (instrument_name : str = "" ) -> dict [str , MachineConfig ]:
253- machine_config = {
254- "" : MachineConfig (
255- acquisition_software = [],
256- calibrations = {},
257- data_directories = [],
258- rsync_basepath = Path ("dls/tmp" ),
259- murfey_db_credentials = "" ,
260- default_model = "/tmp/weights.h5" ,
261- )
262- }
309+ # Create an empty machine config as a placeholder
310+ machine_configs = {instrument_name : MachineConfig ()}
263311 if settings .murfey_machine_configuration :
264- microscope = instrument_name
265- machine_config = machine_config_from_file (
266- Path (settings .murfey_machine_configuration ), microscope
312+ machine_configs = machine_config_from_file (
313+ Path (settings .murfey_machine_configuration ), instrument_name
267314 )
268- return machine_config
315+ return machine_configs
269316
270317
271318def get_extended_machine_config (
0 commit comments