Source code for ash_model.classes.node_profile

import json
from typing import Any, Dict, List, Optional, Tuple, Union


[docs]class NProfile: """ A profile holding attributes and computed statistics for a node. """
[docs] def __init__(self, node_id: Optional[int] = None, **kwargs: Any) -> None: """ Initialize a new NProfile. :param node_id: Optional identifier for the node. :param kwargs: Initial attributes to set on the profile. """ self.__attrs: Dict[str, Any] = {} self.__stats: Dict[str, Dict[str, float]] = {} self.node_id: Optional[int] = node_id self.add_attributes(**kwargs)
[docs] def add_attribute(self, key: str, value: Any) -> None: """ Add or update a single attribute in the profile. :param key: Name of the attribute to add. :param value: Value of the attribute. """ self.__attrs[key] = value
[docs] def add_attributes(self, **kwargs: Any) -> None: """ Add or update multiple attributes in the profile. :param kwargs: Key-value pairs of attributes to add. """ for key, value in kwargs.items(): self.add_attribute(key, value)
[docs] def get_attribute(self, key: str) -> Union[str, int, float]: """ Retrieve the value of a given attribute. :param key: Name of the attribute to retrieve. :return: The attribute's value. :raises ValueError: If the attribute is not present. """ if key in self.__attrs: return self.__attrs[key] # type: ignore raise ValueError(f"Attribute '{key}' not present in the profile.")
[docs] def get_attributes(self) -> Dict[str, Any]: """ Retrieve all attributes in the profile. :return: Dictionary of attribute names to values. """ return dict(self.__attrs)
[docs] def has_attribute(self, key: str) -> bool: """ Check if an attribute exists in the profile. :param key: Name of the attribute to check. :return: True if the attribute exists, False otherwise. """ return key in self.__attrs
[docs] def add_statistic(self, attr_name: str, stat_name: str, value: float) -> None: """ Add or update a computed statistic for a given attribute. :param attr_name: The attribute to which the statistic applies. :param stat_name: Name of the statistic (e.g., 'mean', 'max'). :param value: Numeric value of the statistic. :raises ValueError: If the attribute is not present in the profile. """ if attr_name not in self.__attrs: raise ValueError(f"Attribute '{attr_name}' not present in the profile.") self.__stats.setdefault(attr_name, {})[stat_name] = value
[docs] def get_statistic( self, attr_name: str, stats_name: Optional[str] = None ) -> Dict[str, float]: """ Retrieve computed statistics for a given attribute. :param attr_name: The attribute whose statistics to retrieve. :param stats_name: Specific statistic name to retrieve (optional). :return: Dictionary of statistic names to their values. :raises ValueError: If the attribute or statistic is not present. """ if attr_name not in self.__attrs: raise ValueError(f"Attribute '{attr_name}' not present in the profile.") if attr_name not in self.__stats: raise ValueError(f"No statistics computed for attribute '{attr_name}'.") if stats_name is None: return dict(self.__stats[attr_name]) if stats_name in self.__stats[attr_name]: return {stats_name: self.__stats[attr_name][stats_name]} raise ValueError( f"Statistic '{stats_name}' not computed for attribute '{attr_name}'." )
[docs] def has_statistic(self, attr_name: str, stats_name: str) -> bool: """ Check if a specific statistic exists for a given attribute. :param attr_name: The attribute to check. :param stats_name: The statistic name to check. :return: True if the statistic exists, False otherwise. :raises ValueError: If the attribute is not present. """ if attr_name not in self.__attrs: raise ValueError(f"Attribute '{attr_name}' not present in the profile.") return stats_name in self.__stats.get(attr_name, {})
[docs] def attribute_computed_statistics(self, attr_name: str) -> List[str]: """ List all computed statistic names for a given attribute. :param attr_name: The attribute to query. :return: List of statistic names. :raises ValueError: If the attribute is not present or has no statistics. """ if attr_name not in self.__attrs: raise ValueError(f"Attribute '{attr_name}' not present in the profile.") if attr_name not in self.__stats: raise ValueError(f"No statistics computed for attribute '{attr_name}'.") return list(self.__stats[attr_name].keys())
[docs] def items(self) -> List[Tuple[str, Any]]: """ Get all attribute key-value pairs as a list. :return: List of tuples (key, value). """ return list(self.__attrs.items())
def __eq__(self, other: object) -> bool: """ Check equality of two profiles based on their attributes. :param other: Another object to compare against. :return: True if the other object is an NProfile with identical attributes. """ if not isinstance(other, NProfile): return NotImplemented for key, value in self.__attrs.items(): if not other.has_attribute(key) or other.get_attribute(key) != value: return False return True def __ge__(self, other: object) -> bool: """ Compare if all numeric attributes of this profile are greater than or equal to those of another. :param other: Another NProfile to compare to. :return: True if for every non-string attribute, this value >= other's value. """ if not isinstance(other, NProfile): return NotImplemented for key, value in self.__attrs.items(): if isinstance(value, (int, float)): if not other.has_attribute(key) or value < other.get_attribute(key): return False return True def __le__(self, other: object) -> bool: """ Compare if all numeric attributes of this profile are less than or equal to those of another. :param other: Another NProfile to compare to. :return: True if for every non-string attribute, this value <= other's value. """ if not isinstance(other, NProfile): return NotImplemented for key, value in self.__attrs.items(): if isinstance(value, (int, float)): if not other.has_attribute(key) or value > other.get_attribute(key): return False return True def __str__(self) -> str: """ Return a JSON-formatted string of all attributes. :return: Pretty-printed JSON string of attributes. """ return json.dumps(self.__attrs, indent=2)
[docs] def to_dict(self) -> Dict[str, Any]: """ Convert the profile to a dictionary representation. :return: Dictionary with 'node_id' and 'attrs' keys. """ return {"node_id": self.node_id, "attrs": dict(self.__attrs)}