"""Target utilities."""from__future__importannotationsimportinspectfromcollections.abcimportCallablefromfunctoolsimportwrapsfromtypingimportTYPE_CHECKING,Any,Concatenate,ParamSpecfromattrsimportevolve,fields,fields_dictfrombaybe.transformations.basicimportIdentityTransformationifTYPE_CHECKING:frombaybe.targets.numericalimportNumericalTargetP=ParamSpec("P")def_validate_numerical_target_combination(t1:NumericalTarget,t2:NumericalTarget,/)->None:"""Validate if two numerical targets can be combined."""frombaybe.targets.numericalimportNumericalTargett1_=evolve(t1,transformation=IdentityTransformation())# type: ignore[call-arg]t2_=evolve(t2,transformation=IdentityTransformation())# type: ignore[call-arg]ift1_!=t2_:raiseValueError(f"Two objects of type '{NumericalTarget.__name__}' can only be "f"combined if they are identical in all attributes except for the "f"'{fields(NumericalTarget).transformation.name}'. "f"Given: {t1_!r} and {t2_!r}.")
[docs]defcombine_numerical_targets(t1:NumericalTarget,t2:NumericalTarget,/,operator)->NumericalTarget:"""Combine two numerical targets using a binary operator."""_validate_numerical_target_combination(t1,t2)returnevolve(t1,transformation=operator(t1.transformation,t2.transformation))# type: ignore[call-arg]
[docs]defcapture_constructor_info(constructor:Callable[Concatenate[type[NumericalTarget],P],NumericalTarget],)->Callable[Concatenate[type[NumericalTarget],P],NumericalTarget]:"""Capture constructor history upon object creation. To be used as decorator with classmethods. """@wraps(constructor)defwrapper(cls:type[NumericalTarget],*args:P.args,**kwargs:P.kwargs)->NumericalTarget:frombaybe.targets.numericalimportNumericalTargettarget=constructor(cls,*args,**kwargs)# Reconstruct argumentssig=inspect.signature(constructor)bound=sig.bind(cls,*args,**kwargs)bound.apply_defaults()# To make it consistent with results for __init__bound.arguments.pop("cls")# Ignore "cls"# Store argument historyconstructor_info:dict[str,Any]={"constructor":constructor.__name__,**{k:vfork,vinbound.arguments.items()ifknotinfields_dict(target.__class__)# Ignore persistent attributes},}object.__setattr__(target,fields(NumericalTarget)._constructor_info.name,constructor_info)returntargetreturnwrapper