1+ import copy
12import importlib
23import os
34import sys
@@ -157,6 +158,128 @@ def _init():
157158_init ()
158159
159160
161+ class RegistrySnapshot :
162+
163+ def __init__ (self , data : dict [str , Any ]):
164+ self .data = copy .deepcopy (data )
165+
166+ def query (self , key : str , default = ...) -> Any :
167+ """
168+ Query a value from the nested dictionary using dot-separated keys.
169+
170+ Args:
171+ key: Dot-separated key path (e.g., 'level1.level2.level3')
172+ default: Default value to return if key not found.
173+ If not provided and key is missing, raises KeyError.
174+
175+ Returns:
176+ The value at the specified path, default value, or raises KeyError
177+ """
178+ keys = key .split ('.' )
179+ current = self .data
180+
181+ # Track which level we're at for error reporting
182+ for i , k in enumerate (keys ):
183+ if isinstance (current , dict ) and k in current :
184+ current = current [k ]
185+ else :
186+ # Key not found at this level
187+ missing_path = '.' .join (keys [:i + 1 ])
188+ if default is ...:
189+ raise KeyError (
190+ f"Key '{ missing_path } ' not found in registry (failed at level { i + 1 } )"
191+ )
192+ return default
193+
194+ return current
195+
196+ def get (self , key : str , default = ...) -> Any :
197+ """
198+ Query a value from the nested dictionary using dot-separated keys.
199+
200+ Args:
201+ key: Dot-separated key path (e.g., 'level1.level2.level3')
202+ default: Default value to return if key not found.
203+ If not provided and key is missing, raises KeyError.
204+
205+ Returns:
206+ The value at the specified path, default value, or raises KeyError
207+ """
208+ return self .query (key , default )
209+
210+ def export (self ) -> dict [str , Any ]:
211+ return self .data
212+
213+ def set (self , key : str , value : Any ):
214+ """
215+ Set a value in the nested dictionary using dot-separated keys.
216+ Creates intermediate dictionaries if they don't exist.
217+
218+ Args:
219+ key: Dot-separated key path (e.g., 'level1.level2.level3')
220+ value: Value to set
221+ """
222+ keys = key .split ('.' )
223+ current = self .data
224+
225+ # Navigate to the parent of the target key, creating dicts as needed
226+ for k in keys [:- 1 ]:
227+ if k not in current :
228+ current [k ] = {}
229+ elif not isinstance (current [k ], dict ):
230+ # If existing value is not a dict, replace it with a dict
231+ current [k ] = {}
232+ current = current [k ]
233+
234+ # Set the final value
235+ current [keys [- 1 ]] = value
236+
237+ def delete (self , key : str ):
238+ """
239+ Delete a value from the nested dictionary using dot-separated keys.
240+ Also cleans up empty parent dictionaries after deletion.
241+
242+ Args:
243+ key: Dot-separated key path (e.g., 'level1.level2.level3')
244+ """
245+ keys = key .split ('.' )
246+
247+ # First check if the path exists
248+ try :
249+ self .query (key )
250+ except KeyError :
251+ return # Path doesn't exist, nothing to delete
252+
253+ # Navigate and collect references to all parent dictionaries
254+ path_refs = []
255+ current = self .data
256+
257+ for k in keys [:- 1 ]:
258+ path_refs .append ((current , k ))
259+ current = current [k ]
260+
261+ # Delete the final key
262+ if isinstance (current , dict ) and keys [- 1 ] in current :
263+ del current [keys [- 1 ]]
264+
265+ # Clean up empty dictionaries from leaf to root
266+ for parent_dict , parent_key in reversed (path_refs ):
267+ # Check if the current dictionary is empty
268+ if isinstance (current , dict ) and len (current ) == 0 :
269+ del parent_dict [parent_key ]
270+ current = parent_dict
271+ else :
272+ # Stop if we encounter a non-empty dictionary
273+ break
274+
275+ def clear (self ):
276+ self .data .clear ()
277+
278+ def update (self , parameters : dict [str , Any ]):
279+ for k , v in parameters .items ():
280+ self .set (k , v )
281+
282+
160283class Registry ():
161284
162285 def __init__ (self ):
@@ -183,3 +306,6 @@ def clear(self):
183306
184307 def update (self , parameters : dict [str , Any ]):
185308 return self .api [1 ](parameters )
309+
310+ def snapshot (self ) -> RegistrySnapshot :
311+ return RegistrySnapshot (self .export ())
0 commit comments