Source code for sherpa_ai.output_parsers.self_consistency.object_aggregator

from typing import Union, get_origin, get_args
from pydantic import BaseModel


[docs] class ObjectAggregator(BaseModel): """ Class representing an aggregation of objects by capture their attributes values as a list """ obj_schema: type[BaseModel] """ Schema of the object, used to validate the object. """ value_weight_map: dict[str, Union[dict, float]] = {} """ Dictionary mapping each field to a dictionary of values and their weights. If the field is a primitive type, it will be mapped to a dictionary with values as keys and their weights as values. If the field is a nested model, it will be mapped to a dictionary for storing object values. The default weight is 1.0. """ # noqa: E501 obj_dict: dict[str, Union[list, dict]] = {} """ Dictionary representing the object aggregator, where each field is mapped to a list or a dictionary. If the field is a primitive type, it will be mapped to a list for storing object values. If the field is a nested model, it will be mapped to a dictionary for storing object values. """ # noqa: E501 def __init__(self, obj_schema, **kwargs): """ Initialize the ObjectAggregator with a schema and additional keyword arguments. Args: obj_schema (type[BaseModel]): The Pydantic model class representing the schema of the object. """ # noqa: E501 super().__init__(obj_schema=obj_schema, **kwargs) self.obj_dict = flatten_model_schema(obj_schema)
[docs] def add_object(self, obj: BaseModel): """ Add an object to the aggregation of objects. Args: obj (BaseModel): The object to add, must conform to the schema defined by obj_schema. """ # noqa: E501 def add_to_dict(obj_dict: dict[str, Union[list, dict]], dict_to_add: dict): """ Recursively add the object dictionary to a dictionary. Args: obj_dict (dict[str, Union[list, dict]]): The abstract object's dictionary. dict_to_add (dict): The dictionary representation of the object to add. """ # noqa: E501 for key, value in dict_to_add.items(): if key in obj_dict: if isinstance(obj_dict[key], list): # If the field is a list, append the value obj_dict[key].append(value) else: # If the field is a dictionary, recursively add the value add_to_dict(obj_dict[key], value) else: # Honest this should not happen since the schema is checked raise KeyError( f"Field '{key}' not found in the abstract object's schema." ) if not isinstance(obj, self.obj_schema): raise ValueError(f"Object must be of type {self.obj_schema.__name__}") dict_to_add = obj.model_dump() add_to_dict(self.obj_dict, dict_to_add)
def flatten_model_schema(cls: type[BaseModel]) -> dict[str, Union[list, dict]]: """ Flatten the schema of a Pydantic model. Args: cls (type[BaseModel]): The Pydantic model class to flatten. Returns: dict[str, Union[list, dict]]: A dictionary representing the flattened schema. If the field is a primitive type, it will be map to a list for storing object values If the field is a nested model, it will be mapped to a dictionary for storing object values. """ # noqa: E501 fields = cls.model_fields result = {} for field_name, field in fields.items(): field_type = field.annotation # Check if it's a list type if get_origin(field_type) is list or field_type == list: # For list fields, we'll store lists of lists (each object's list becomes one item) result[field_name] = [] elif isinstance(field_type, type) and issubclass(field_type, BaseModel): # If the field is a nested model, map it to a dictionary recursively result[field_name] = flatten_model_schema(field_type) else: # If it's a primitive type, map it to a list for the abstract object result[field_name] = [] return result