Skip to content

Commit e6333ea

Browse files
committed
Update version to 2.11.14 in version.py and add RegistrySnapshot class in registry.py for improved registry management, including methods for querying, setting, deleting, and exporting nested dictionary data.
1 parent f8a1504 commit e6333ea

2 files changed

Lines changed: 127 additions & 1 deletion

File tree

qulab/executor/registry.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import copy
12
import importlib
23
import os
34
import 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+
160283
class 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())

qulab/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.11.13"
1+
__version__ = "2.11.14"

0 commit comments

Comments
 (0)