Source code for fastcfg.config.utils

from typing import TYPE_CHECKING, Any, Union

# Import modules directly to avoid circular imports
from fastcfg.config import cfg, items, value_wrapper

if TYPE_CHECKING:
    from fastcfg.config.cfg import Config
else:
    Config = None


[docs] def create_config_dict(item: dict) -> Config: """ Converts a dictionary (including a ValueWrapped dictionary) into a `Config` object. This is abstracted into this module as it's used in multiple places. Args: item (dict): The dictionary to be converted. Returns: Config: A `Config` object initialized with the dictionary's key-value pairs. """ if isinstance(item, value_wrapper.ValueWrapper): # Unwrap ValueWrapper item = value_wrapper.ValueWrapper.unwrap(item) return cfg.Config(**item)
[docs] def potentially_has_children(obj: Any) -> bool: """ Checks if the given object is potentially has children. Currently dict and `Config` instances are considered to have children. Args: obj (Any): The object to check. Returns: bool: True if the object type is in `POTENTIALLY_HAS_CHILDREN`, False otherwise. """ POTENTIALLY_HAS_CHILDREN = (dict, cfg.Config) return isinstance(obj, POTENTIALLY_HAS_CHILDREN)
[docs] def resolve_all_values(obj: Union[dict, Config]) -> dict: """ Recursively resolves all values in a dictionary or `Config` object. This function traverses the given object, resolving any nested dictionaries or `Config` objects, and extracting the values of `IConfigItem` instances. Args: obj (Union[dict, Config]): The object to resolve. Returns: dict: A dictionary with all values resolved. Raises: ValueError: If the object is not a dictionary or `Config` object. """ if isinstance(obj, dict): obj_dict = obj elif isinstance(obj, cfg.Config): # Convert Config to dict obj_dict = obj.to_dict() else: raise ValueError( "Resolve all values requires obj type to be dict or Config!" ) values = {} for k, v in obj_dict.items(): if potentially_has_children(v): v = resolve_all_values(v) # Recursively resolve values if isinstance(v, items.AbstractConfigItem): v = v.value values[k] = v return values
[docs] def deep_merge_config(target, updates): """ Recursively merge updates into target, preserving existing nested values. This function performs a deep merge where: - Existing nested Config objects are recursively updated - New keys are added - Existing non-Config values are replaced - Dictionaries are automatically converted to Config objects Args: target: The target Config object to update updates: Dictionary of updates to apply """ for key, value in updates.items(): # Check if the key already exists in the target if hasattr(target, key): existing = getattr(target, key) # If both existing and new value are dict-like, merge recursively if isinstance(existing, cfg.Config) and isinstance(value, dict): deep_merge_config(existing, value) else: # Otherwise, replace the value (convert dict to Config if needed) if isinstance(value, dict): value = create_config_dict(value) setattr(target, key, value) else: # New key, just set it (convert dict to Config if needed) if isinstance(value, dict): value = create_config_dict(value) setattr(target, key, value)