66
77import dataclasses
88
9+ from .. import exceptions
10+ from ..decorator import error_info_collector
911from . import score_statistics , test_result
1012from .metrics import score_result
1113
@@ -33,21 +35,61 @@ def _sanitize_error_reason(exception: Exception, context: str) -> str:
3335 return f"{ context } failed with { exc_type } ."
3436
3537
38+ _FABRICATED_SCORE_ATTRIBUTE = "_opik_fabricated"
39+
40+
41+ def _mark_fabricated (score : score_result .ScoreResult ) -> score_result .ScoreResult :
42+ setattr (score , _FABRICATED_SCORE_ATTRIBUTE , True )
43+ return score
44+
45+
46+ def _is_fabricated_score (score : score_result .ScoreResult ) -> bool :
47+ return bool (getattr (score , _FABRICATED_SCORE_ATTRIBUTE , False ))
48+
49+
50+ def _build_failed_score_result (
51+ name : str ,
52+ exception : Exception ,
53+ * ,
54+ reason : Optional [str ] = None ,
55+ category_name : Optional [str ] = None ,
56+ fabricated : bool = False ,
57+ ) -> score_result .ScoreResult :
58+ """Build a failed score with structured exception details."""
59+ metadata : Dict [str , object ] = {
60+ "error_info" : error_info_collector .collect (exception )
61+ }
62+ if fabricated :
63+ metadata ["_fabricated" ] = True
64+
65+ result = score_result .ScoreResult (
66+ name = name ,
67+ value = 0.0 ,
68+ reason = _safe_str (exception ) if reason is None else reason ,
69+ category_name = category_name ,
70+ metadata = metadata ,
71+ scoring_failed = True ,
72+ )
73+ return _mark_fabricated (result ) if fabricated else result
74+
75+
3676def normalize_experiment_score (
3777 score : object ,
3878 default_name : str ,
3979) -> score_result .ScoreResult :
4080 """Normalize raw values or malformed ScoreResult instances into a valid ScoreResult."""
4181 if not isinstance (score , score_result .ScoreResult ):
42- return score_result .ScoreResult (
43- name = default_name ,
44- value = 0.0 ,
45- reason = (
46- "Experiment scoring function returned "
47- f"{ type (score ).__name__ } ; expected ScoreResult."
48- ),
49- scoring_failed = True ,
50- metadata = {"_fabricated" : True },
82+ return _mark_fabricated (
83+ score_result .ScoreResult (
84+ name = default_name ,
85+ value = 0.0 ,
86+ reason = (
87+ "Experiment scoring function returned "
88+ f"{ type (score ).__name__ } ; expected ScoreResult."
89+ ),
90+ scoring_failed = True ,
91+ metadata = {"_fabricated" : True },
92+ )
5193 )
5294
5395 base_metadata : Optional [Dict [str , object ]] = (
@@ -60,7 +102,7 @@ def normalize_experiment_score(
60102
61103 if not isinstance (score .scoring_failed , bool ):
62104 meta = {** (base_metadata or {}), "_fabricated" : not is_valid_name }
63- return score_result .ScoreResult (
105+ result = score_result .ScoreResult (
64106 name = effective_name ,
65107 value = 0.0 ,
66108 reason = (
@@ -71,31 +113,39 @@ def normalize_experiment_score(
71113 category_name = score .category_name ,
72114 metadata = meta ,
73115 )
116+ return _mark_fabricated (result ) if not is_valid_name else result
74117
75118 if not is_valid_name :
76- return score_result .ScoreResult (
77- name = default_name ,
78- value = 0.0 ,
79- reason = (
80- "Expected non-empty string score name, got "
81- f"{ type (name ).__name__ if not isinstance (name , str ) else 'empty string' } ."
82- ),
83- scoring_failed = True ,
84- category_name = score .category_name ,
85- metadata = {** (base_metadata or {}), "_fabricated" : True },
119+ return _mark_fabricated (
120+ score_result .ScoreResult (
121+ name = default_name ,
122+ value = 0.0 ,
123+ reason = (
124+ "Expected non-empty string score name, got "
125+ f"{ type (name ).__name__ if not isinstance (name , str ) else 'empty string' } ."
126+ ),
127+ scoring_failed = True ,
128+ category_name = score .category_name ,
129+ metadata = {** (base_metadata or {}), "_fabricated" : True },
130+ )
86131 )
87132
88133 if score .metadata is not None and not isinstance (score .metadata , Mapping ):
89- return score_result .ScoreResult (
90- name = effective_name ,
91- value = 0.0 ,
92- reason = (
93- "ScoreResult.metadata must be a mapping or None, got "
94- f"{ type (score .metadata ).__name__ } ."
95- ),
96- scoring_failed = True ,
134+ metadata_error = exceptions .EvaluationError (
135+ "ScoreResult.metadata must be a mapping or None, got "
136+ f"{ type (score .metadata ).__name__ } ."
137+ )
138+ LOGGER .warning (
139+ "Failed to normalize score result from %s: %s" ,
140+ effective_name ,
141+ _safe_str (metadata_error ),
142+ )
143+ return _build_failed_score_result (
144+ effective_name ,
145+ metadata_error ,
146+ reason = _safe_str (metadata_error ),
97147 category_name = score .category_name ,
98- metadata = { "_fabricated" : True } ,
148+ fabricated = True ,
99149 )
100150
101151 if score .scoring_failed :
@@ -170,15 +220,17 @@ def compute_experiment_scores(
170220 exc_info = True ,
171221 )
172222 all_scores .append (
173- score_result .ScoreResult (
174- name = default_name ,
175- value = 0.0 ,
176- reason = _sanitize_error_reason (
177- elem_err ,
178- f"Scoring function '{ default_name } ' item" ,
179- ),
180- scoring_failed = True ,
181- metadata = {"_fabricated" : True },
223+ _mark_fabricated (
224+ score_result .ScoreResult (
225+ name = default_name ,
226+ value = 0.0 ,
227+ reason = _sanitize_error_reason (
228+ elem_err ,
229+ f"Scoring function '{ default_name } ' item" ,
230+ ),
231+ scoring_failed = True ,
232+ metadata = {"_fabricated" : True },
233+ )
182234 )
183235 )
184236 else :
@@ -192,15 +244,17 @@ def compute_experiment_scores(
192244 exc_info = True ,
193245 )
194246 all_scores .append (
195- score_result .ScoreResult (
196- name = default_name ,
197- value = 0.0 ,
198- reason = _sanitize_error_reason (
199- e ,
200- f"Experiment scoring function '{ default_name } '" ,
201- ),
202- scoring_failed = True ,
203- metadata = {"_fabricated" : True },
247+ _mark_fabricated (
248+ score_result .ScoreResult (
249+ name = default_name ,
250+ value = 0.0 ,
251+ reason = _sanitize_error_reason (
252+ e ,
253+ f"Experiment scoring function '{ default_name } '" ,
254+ ),
255+ scoring_failed = True ,
256+ metadata = {"_fabricated" : True },
257+ )
204258 )
205259 )
206260
0 commit comments