@@ -392,6 +392,73 @@ def _from_sequence_of_strings(
392392 )
393393 return cls ._from_sequence (scalars , dtype = pa_type , copy = copy )
394394
395+ def _cast_pointwise_result (self , values ) -> ArrayLike :
396+ if len (values ) == 0 :
397+ # Retain our dtype
398+ return self [:0 ].copy ()
399+
400+ try :
401+ arr = pa .array (values , from_pandas = True )
402+ except (ValueError , TypeError ):
403+ # e.g. test_by_column_values_with_same_starting_value with nested
404+ # values, one entry of which is an ArrowStringArray
405+ # or test_agg_lambda_complex128_dtype_conversion for complex values
406+ return super ()._cast_pointwise_result (values )
407+
408+ if pa .types .is_duration (arr .type ):
409+ # workaround for https://github.com/apache/arrow/issues/40620
410+ result = ArrowExtensionArray ._from_sequence (values )
411+ if pa .types .is_duration (self ._pa_array .type ):
412+ result = result .astype (self .dtype ) # type: ignore[assignment]
413+ elif pa .types .is_timestamp (self ._pa_array .type ):
414+ # Try to retain original unit
415+ new_dtype = ArrowDtype (pa .duration (self ._pa_array .type .unit ))
416+ try :
417+ result = result .astype (new_dtype ) # type: ignore[assignment]
418+ except ValueError :
419+ pass
420+ elif pa .types .is_date64 (self ._pa_array .type ):
421+ # Try to match unit we get on non-pointwise op
422+ dtype = ArrowDtype (pa .duration ("ms" ))
423+ result = result .astype (dtype ) # type: ignore[assignment]
424+ elif pa .types .is_date (self ._pa_array .type ):
425+ # Try to match unit we get on non-pointwise op
426+ dtype = ArrowDtype (pa .duration ("s" ))
427+ result = result .astype (dtype ) # type: ignore[assignment]
428+ return result
429+
430+ elif pa .types .is_date (arr .type ) and pa .types .is_date (self ._pa_array .type ):
431+ arr = arr .cast (self ._pa_array .type )
432+ elif pa .types .is_time (arr .type ) and pa .types .is_time (self ._pa_array .type ):
433+ arr = arr .cast (self ._pa_array .type )
434+ elif pa .types .is_decimal (arr .type ) and pa .types .is_decimal (self ._pa_array .type ):
435+ arr = arr .cast (self ._pa_array .type )
436+ elif pa .types .is_integer (arr .type ) and pa .types .is_integer (self ._pa_array .type ):
437+ try :
438+ arr = arr .cast (self ._pa_array .type )
439+ except pa .lib .ArrowInvalid :
440+ # e.g. test_combine_add if we can't cast
441+ pass
442+ elif pa .types .is_floating (arr .type ) and pa .types .is_floating (
443+ self ._pa_array .type
444+ ):
445+ try :
446+ arr = arr .cast (self ._pa_array .type )
447+ except pa .lib .ArrowInvalid :
448+ # e.g. test_combine_add if we can't cast
449+ pass
450+
451+ if isinstance (self .dtype , StringDtype ):
452+ if pa .types .is_string (arr .type ) or pa .types .is_large_string (arr .type ):
453+ # ArrowStringArrayNumpySemantics
454+ return type (self )(arr ).astype (self .dtype )
455+ if self .dtype .na_value is np .nan :
456+ # ArrowEA has different semantics, so we return numpy-based
457+ # result instead
458+ return super ()._cast_pointwise_result (values )
459+ return ArrowExtensionArray (arr )
460+ return type (self )(arr )
461+
395462 @classmethod
396463 def _box_pa (
397464 cls , value , pa_type : pa .DataType | None = None
0 commit comments