2626import inspect
2727import itertools
2828import json
29- from typing import Any , Callable , Iterable , Iterator , Optional , Tuple , Union
29+ from typing import Any , Callable , Iterable , Iterator , Optional , Tuple , TYPE_CHECKING , Union
30+
31+ if TYPE_CHECKING :
32+ from pyspark .sql .pandas ._typing import GroupedBatch
3033
3134from pyspark .accumulators import (
3235 SpecialAccumulatorIds ,
@@ -2573,12 +2576,12 @@ def read_udfs(pickleSer, infile, eval_type, runner_conf, eval_conf):
25732576 assert num_udfs == 1 , "One MAP_ARROW_ITER UDF expected here."
25742577 udf_func : Callable [[Iterator [pa .RecordBatch ]], Iterator [pa .RecordBatch ]] = udfs [0 ][0 ]
25752578
2576- def func (split_index : int , batches : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
2579+ def func (split_index : int , data : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
25772580 """Apply mapInArrow UDF"""
25782581
25792582 # Pre-processing
25802583 input_batches : Iterator [pa .RecordBatch ] = map (
2581- ArrowBatchTransformer .flatten_struct , batches
2584+ ArrowBatchTransformer .flatten_struct , data
25822585 )
25832586
25842587 # invoke the UDF
@@ -2601,15 +2604,15 @@ def func(split_index: int, batches: Iterator[pa.RecordBatch]) -> Iterator[pa.Rec
26012604 prefers_large_types = runner_conf .use_large_var_types ,
26022605 )
26032606
2604- def func (split_index : int , batches : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
2607+ def func (split_index : int , data : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
26052608 """Apply scalar Arrow UDFs"""
26062609
2607- for input_batch in batches :
2610+ for batch in data :
26082611 output_batch = pa .RecordBatch .from_arrays (
26092612 [
26102613 udf_func (
2611- * [input_batch .column (o ) for o in args_offsets ],
2612- ** {k : input_batch .column (v ) for k , v in kwargs_offsets .items ()},
2614+ * [batch .column (o ) for o in args_offsets ],
2615+ ** {k : batch .column (v ) for k , v in kwargs_offsets .items ()},
26132616 )
26142617 for udf_func , args_offsets , kwargs_offsets , _ in udfs
26152618 ],
@@ -2618,7 +2621,7 @@ def func(split_index: int, batches: Iterator[pa.RecordBatch]) -> Iterator[pa.Rec
26182621 output_batch = ArrowBatchTransformer .enforce_schema (
26192622 output_batch , combined_arrow_schema
26202623 )
2621- verify_scalar_result (output_batch , input_batch .num_rows )
2624+ verify_scalar_result (output_batch , batch .num_rows )
26222625 yield output_batch
26232626
26242627 # profiling is not supported for UDF
@@ -2635,7 +2638,7 @@ def func(split_index: int, batches: Iterator[pa.RecordBatch]) -> Iterator[pa.Rec
26352638 return_type , timezone = "UTC" , prefers_large_types = runner_conf .use_large_var_types
26362639 )
26372640
2638- def func (split_index : int , batches : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
2641+ def func (split_index : int , data : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
26392642 """Apply scalar Arrow iterator UDF"""
26402643
26412644 num_input_rows = 0
@@ -2647,7 +2650,7 @@ def extract_args(batch: pa.RecordBatch):
26472650 return args [0 ] if len (args ) == 1 else args
26482651
26492652 # Extract args from input batches (streaming)
2650- args_iter = map (extract_args , batches )
2653+ args_iter = map (extract_args , data )
26512654
26522655 # Call UDF and verify result type (iterator of pa.Array)
26532656 verified_iter = verify_result (pa .Array )(udf_func (args_iter ))
@@ -2697,9 +2700,11 @@ def process_results():
26972700 prefers_large_types = runner_conf .use_large_var_types ,
26982701 )
26992702
2700- def func (split_index : int , batches : Iterator [Any ]) -> Iterator [pa .RecordBatch ]:
2701- for group_batches in batches :
2702- batch_list = list (group_batches )
2703+ def grouped_func (
2704+ split_index : int , data : Iterator ["GroupedBatch" ]
2705+ ) -> Iterator [pa .RecordBatch ]:
2706+ for group in data :
2707+ batch_list = list (group )
27032708 if not batch_list :
27042709 continue
27052710 if hasattr (pa , "concat_batches" ):
@@ -2722,7 +2727,7 @@ def func(split_index: int, batches: Iterator[Any]) -> Iterator[pa.RecordBatch]:
27222727 yield ArrowBatchTransformer .enforce_schema (batch , return_schema )
27232728
27242729 # profiling is not supported for UDF
2725- return func , None , ser , ser
2730+ return grouped_func , None , ser , ser
27262731
27272732 if eval_type == PythonEvalType .SQL_GROUPED_AGG_ARROW_ITER_UDF :
27282733 import pyarrow as pa
@@ -2740,9 +2745,11 @@ def extract_args(batch):
27402745 args = tuple (batch .column (o ) for o in args_offsets )
27412746 return args [0 ] if len (args ) == 1 else args
27422747
2743- def func (split_index : int , batches : Iterator [Any ]) -> Iterator [pa .RecordBatch ]:
2744- for group_batches in batches :
2745- batch_iter = map (extract_args , group_batches )
2748+ def grouped_func (
2749+ split_index : int , data : Iterator ["GroupedBatch" ]
2750+ ) -> Iterator [pa .RecordBatch ]:
2751+ for group in data :
2752+ batch_iter = map (extract_args , group )
27462753 result = udf_func (batch_iter )
27472754 # Drain remaining batches to maintain stream position
27482755 for _ in batch_iter :
@@ -2751,7 +2758,7 @@ def func(split_index: int, batches: Iterator[Any]) -> Iterator[pa.RecordBatch]:
27512758 yield ArrowBatchTransformer .enforce_schema (batch , return_schema )
27522759
27532760 # profiling is not supported for UDF
2754- return func , None , ser , ser
2761+ return grouped_func , None , ser , ser
27552762
27562763 if eval_type == PythonEvalType .SQL_WINDOW_AGG_ARROW_UDF :
27572764 import pyarrow as pa
@@ -2766,9 +2773,11 @@ def func(split_index: int, batches: Iterator[Any]) -> Iterator[pa.RecordBatch]:
27662773 prefers_large_types = runner_conf .use_large_var_types ,
27672774 )
27682775
2769- def func (split_index : int , batches : Iterator [Any ]) -> Iterator [pa .RecordBatch ]:
2770- for group_batches in batches :
2771- batch_list = list (group_batches )
2776+ def grouped_func (
2777+ split_index : int , data : Iterator ["GroupedBatch" ]
2778+ ) -> Iterator [pa .RecordBatch ]:
2779+ for group in data :
2780+ batch_list = list (group )
27722781 if not batch_list :
27732782 continue
27742783 if hasattr (pa , "concat_batches" ):
@@ -2817,7 +2826,7 @@ def func(split_index: int, batches: Iterator[Any]) -> Iterator[pa.RecordBatch]:
28172826 yield ArrowBatchTransformer .enforce_schema (batch , return_schema )
28182827
28192828 # profiling is not supported for UDF
2820- return func , None , ser , ser
2829+ return grouped_func , None , ser , ser
28212830
28222831 if (
28232832 eval_type == PythonEvalType .SQL_ARROW_BATCHED_UDF
@@ -2868,8 +2877,8 @@ def _evaluate_batch_udf(udf_func, rows):
28682877 with ThreadPoolExecutor (max_workers = runner_conf .arrow_concurrency_level ) as pool :
28692878 return list (pool .map (lambda row : udf_func (* row ), rows ))
28702879
2871- def func (split_index : int , batches : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
2872- for input_batch in batches :
2880+ def func (split_index : int , data : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
2881+ for input_batch in data :
28732882 num_rows = input_batch .num_rows
28742883
28752884 # --- Input: Arrow -> Python columns ---
@@ -2953,8 +2962,8 @@ def _evaluate_batch_udf_legacy(udf_func, rows):
29532962 with ThreadPoolExecutor (max_workers = runner_conf .arrow_concurrency_level ) as pool :
29542963 return list (pool .map (lambda row : udf_func (* row ), rows ))
29552964
2956- def func (split_index : int , batches : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
2957- for input_batch in batches :
2965+ def func (split_index : int , data : Iterator [pa .RecordBatch ]) -> Iterator [pa .RecordBatch ]:
2966+ for input_batch in data :
29582967 # --- Input: Arrow -> pandas columns ---
29592968 pandas_columns = ArrowBatchTransformer .to_pandas (
29602969 input_batch ,
0 commit comments