[docs]classScorecardValidator(ABC):"""Abstract base class for scorecard validators"""name:str
[docs]@classmethod@abstractmethoddefvalidate(cls,scorecard:ExpertScorecard)->None:"""Validate the scorecard. Raise ValidationError if invalid."""pass
[docs]classFeatureWeightValidator(ScorecardValidator):""" When assigning weights to features, the goal is that the sum of the weights of all features is 100. This is a common requirement in expert scorecard design to ensure that the importance of each feature is correctly proportioned. """name:str="feature_weight"
[docs]@classmethoddefvalidate(cls,scorecard:ExpertScorecard)->None:total_weight=sum(feature.weightforfeatureinscorecard.features)ifabs(total_weight-100.0)>0.001:# Allow for floating point precisionraiseValidationError.from_exception_data("Weight validation failed",[{"type":"value_error","input":total_weight,"ctx":{"error":f"Feature weights must sum to 100, got {total_weight}"},}],)
[docs]classOverlapValidator(ScorecardValidator):""" When defining a scorecard, it is important to ensure that the buckets of a feature do not overlap with each other. This validator will ensure that the buckets of a feature do not overlap with each other. """name:str="overlap"
[docs]@classmethoddefvalidate(cls,scorecard:ExpertScorecard)->None:forfeatureinscorecard.features:iffeature.has_overlapping_buckets():overlapping_pairs=feature.get_overlapping_buckets()error_messages=[]forbucket1,bucket2inoverlapping_pairs:error_messages.append(f"Buckets overlap in feature '{feature.name}': "f"{bucket1.definition} and {bucket2.definition}")raiseValidationError.from_exception_data("Bucket overlap validation failed",[{"type":"value_error","input":feature.name,"ctx":{"error":msg}}formsginerror_messages],)