11import re
2- from typing import Any , Dict , List , Optional , Union , get_args , get_origin
2+ from typing import Any , Dict , List , Optional , Union , cast , get_args , get_origin
33
44from haystack import Document , component
55from haystack .dataclasses import ChatMessage
6- from pydantic import ValidationError # type: ignore
6+ from pydantic import ValidationError
77
8- from ragas import evaluate # type: ignore
8+ from ragas import evaluate
99from ragas .dataset_schema import (
1010 EvaluationDataset ,
1111 EvaluationResult ,
@@ -135,7 +135,7 @@ def run(
135135 )
136136
137137 except (ValueError , ValidationError ) as e :
138- raise self ._handle_conversion_error (e ) from None
138+ self ._handle_conversion_error (e )
139139
140140 dataset = EvaluationDataset ([sample ])
141141
@@ -147,7 +147,7 @@ def run(
147147 embeddings = self .embedding ,
148148 )
149149 except (ValueError , ValidationError ) as e :
150- raise self ._handle_evaluation_error (e ) from None
150+ self ._handle_evaluation_error (e )
151151
152152 return {"result" : result }
153153
@@ -157,22 +157,19 @@ def _process_documents(self, documents: Union[List[Union[Document, str]], None])
157157 :param documents: List of Documents or strings to process
158158 :return: List of document contents as strings or None
159159 """
160- if documents :
161- first_type = type (documents [0 ])
162- if first_type is Document :
163- if not all (isinstance (doc , Document ) for doc in documents ):
164- error_message = "All elements in documents list must be of type Document."
165- raise ValueError (error_message )
166- return [doc .content for doc in documents ] # type: ignore[union-attr]
167-
168- if first_type is str :
169- if not all (isinstance (doc , str ) for doc in documents ):
170- error_message = "All elements in documents list must be strings."
171- raise ValueError (error_message )
172- return documents
173- error_message = "Unsupported type in documents list."
174- raise ValueError (error_message )
175- return documents
160+ if documents is None :
161+ return None
162+
163+ if isinstance (documents , list ) and all (isinstance (doc , str ) for doc in documents ):
164+ # we need to check types again in the list comprehension to make mypy happy
165+ return [doc for doc in documents if isinstance (doc , str )]
166+
167+ if isinstance (documents , list ) and all (isinstance (doc , Document ) for doc in documents ):
168+ # we need to check types again in the list comprehension to make mypy happy
169+ return [doc .content for doc in documents if isinstance (doc , Document ) and doc .content ]
170+
171+ error_message = "'documents' must be a list of either Documents or strings."
172+ raise ValueError (error_message )
176173
177174 def _process_response (self , response : Optional [Union [List [ChatMessage ], str ]]) -> Union [str , None ]:
178175 """Process response into expected format.
@@ -181,14 +178,14 @@ def _process_response(self, response: Optional[Union[List[ChatMessage], str]]) -
181178 :return: None or Processed response string
182179 """
183180 if isinstance (response , list ): # Check if response is a list
184- if all (isinstance (item , ChatMessage ) for item in response ):
185- return response [0 ]._content [ 0 ]. text
181+ if all (isinstance (item , ChatMessage ) and item . text for item in response ):
182+ return response [0 ].text
186183 return None
187184 elif isinstance (response , str ):
188185 return response
189186 return response
190187
191- def _handle_conversion_error (self , error : Exception ):
188+ def _handle_conversion_error (self , error : Exception ) -> None :
192189 """Handle evaluation errors with improved messages.
193190
194191 :params error: Original error
@@ -199,7 +196,9 @@ def _handle_conversion_error(self, error: Exception):
199196 "retrieved_contexts" : "documents" ,
200197 }
201198 for err in error .errors ():
202- field = err ["loc" ][0 ]
199+ # loc is a tuple of strings and ints but according to pydantic docs, the first element is a string
200+ # https://docs.pydantic.dev/latest/errors/errors/
201+ field = cast (str , err ["loc" ][0 ])
203202 haystack_field = field_mapping .get (field , field )
204203 expected_type = self .run .__annotations__ .get (haystack_field )
205204 type_desc = self ._get_expected_type_description (expected_type )
@@ -213,7 +212,7 @@ def _handle_conversion_error(self, error: Exception):
213212 )
214213 raise ValueError (error_message )
215214
216- def _handle_evaluation_error (self , error : Exception ):
215+ def _handle_evaluation_error (self , error : Exception ) -> None :
217216 error_message = str (error )
218217 columns_match = re .search (r"additional columns \[(.*?)\]" , error_message )
219218 field_mapping = {
@@ -233,7 +232,7 @@ def _handle_evaluation_error(self, error: Exception):
233232 )
234233 raise ValueError (updated_error_message )
235234
236- def _get_expected_type_description (self , expected_type ) -> str :
235+ def _get_expected_type_description (self , expected_type : Any ) -> str :
237236 """Helper method to get a description of the expected type."""
238237 if get_origin (expected_type ) is Union :
239238 expected_types = [getattr (t , "__name__" , str (t )) for t in get_args (expected_type )]
0 commit comments