Source code for biogeme.tools.checks

"""Utilities to perform various checks

Michel Bierlaire
Fri Apr 5 11:09:39 2024
"""

from typing import Any


[docs] def check_consistency_of_named_dicts( named_dicts: dict[str, dict[Any, Any]] ) -> tuple[bool, str | None]: """Verify that all dictionaries have the same set of keys. If not, report the inconsistencies. :param named_dicts: A dictionary where each key is a name (str) and each value is a dictionary to check. :return: True if keys are consistent across all dictionaries, False otherwise. If not consistent, returns a report detailing the inconsistencies. """ # Initialize variables dict_names = list(named_dicts.keys()) keys = [set(d.keys()) for d in named_dicts.values()] consistent = True inconsistencies = [] # Reference keys for comparison reference_keys = keys[0] reference_name = dict_names[0] # Compare each set of keys with the first to check for consistency for i, (name, key_set) in enumerate(zip(dict_names[1:], keys[1:]), start=1): if key_set != reference_keys: consistent = False missing_in_ref = reference_keys - key_set extra_in_ref = key_set - reference_keys if missing_in_ref: inconsistencies.append( f'{name} missing keys compared to {reference_name}: {missing_in_ref}.' ) if extra_in_ref: inconsistencies.append( f'{name} has extra keys compared to {reference_name}: {extra_in_ref}.' ) # Compile the report if there are inconsistencies report = None if not consistent: report = "Inconsistencies found among dictionaries:\n" + "\n".join( inconsistencies ) return consistent, report
[docs] def validate_dict_types( parameter: dict, name: str, value_type: type, key_type: type = int ) -> None: """Validate the types of keys and values in a dictionary. :param parameter: The dictionary parameter to validate. :param name: The name of the parameter for error messages. :param value_type: The expected type of the dictionary values. :param key_type: The expected type of the dictionary keys. Default is int. :raises TypeError: If key or value types do not match expectations. """ if not isinstance(parameter, dict): raise TypeError( f"{name} must be a dict, got {type(parameter).__name__} instead." ) for key, value in parameter.items(): if not isinstance(key, key_type): raise TypeError( f"Keys in {name} must be of type {key_type.__name__}, found type {type(key).__name__}." ) if not (isinstance(value, value_type) or value is None): raise TypeError( f"Values in {name} must be of type {value_type.__name__} or None, found type {type(value).__name__}." )