1
1
import abc
2
2
import inspect
3
- from typing import TYPE_CHECKING , Iterator , Type
3
+ from typing import TYPE_CHECKING , Any , Dict , Iterator , Optional , Type , Union
4
4
5
5
import numpy as np
6
6
18
18
if TYPE_CHECKING :
19
19
from pandas import DataFrame , Series , Index
20
20
21
+ ResType = Dict [int , Any ]
22
+
21
23
22
24
def frame_apply (
23
25
obj : "DataFrame" ,
@@ -64,10 +66,15 @@ def result_index(self) -> "Index":
64
66
def result_columns (self ) -> "Index" :
65
67
pass
66
68
69
+ @property
67
70
@abc .abstractmethod
68
71
def series_generator (self ) -> Iterator ["Series" ]:
69
72
pass
70
73
74
+ @abc .abstractmethod
75
+ def wrap_results_for_axis (self , results : ResType ) -> Union ["Series" , "DataFrame" ]:
76
+ pass
77
+
71
78
# ---------------------------------------------------------------
72
79
73
80
def __init__ (
@@ -107,8 +114,16 @@ def f(x):
107
114
108
115
# results
109
116
self .result = None
110
- self .res_index = None
111
- self .res_columns = None
117
+ self ._res_index : Optional ["Index" ] = None
118
+
119
+ @property
120
+ def res_index (self ) -> "Index" :
121
+ assert self ._res_index is not None
122
+ return self ._res_index
123
+
124
+ @property
125
+ def res_columns (self ) -> "Index" :
126
+ return self .result_columns
112
127
113
128
@property
114
129
def columns (self ) -> "Index" :
@@ -298,12 +313,12 @@ def apply_standard(self):
298
313
return self .obj ._constructor_sliced (result , index = labels )
299
314
300
315
# compute the result using the series generator
301
- self .apply_series_generator ()
316
+ results = self .apply_series_generator ()
302
317
303
318
# wrap results
304
- return self .wrap_results ()
319
+ return self .wrap_results (results )
305
320
306
- def apply_series_generator (self ):
321
+ def apply_series_generator (self ) -> ResType :
307
322
series_gen = self .series_generator
308
323
res_index = self .result_index
309
324
@@ -330,17 +345,15 @@ def apply_series_generator(self):
330
345
results [i ] = self .f (v )
331
346
keys .append (v .name )
332
347
333
- self .results = results
334
- self .res_index = res_index
335
- self .res_columns = self .result_columns
348
+ self ._res_index = res_index
349
+ return results
336
350
337
- def wrap_results (self ):
338
- results = self .results
351
+ def wrap_results (self , results : ResType ) -> Union ["Series" , "DataFrame" ]:
339
352
340
353
# see if we can infer the results
341
354
if len (results ) > 0 and 0 in results and is_sequence (results [0 ]):
342
355
343
- return self .wrap_results_for_axis ()
356
+ return self .wrap_results_for_axis (results )
344
357
345
358
# dict of scalars
346
359
result = self .obj ._constructor_sliced (results )
@@ -367,10 +380,9 @@ def result_index(self) -> "Index":
367
380
def result_columns (self ) -> "Index" :
368
381
return self .index
369
382
370
- def wrap_results_for_axis (self ) :
383
+ def wrap_results_for_axis (self , results : ResType ) -> "DataFrame" :
371
384
""" return the results for the rows """
372
385
373
- results = self .results
374
386
result = self .obj ._constructor (data = results )
375
387
376
388
if not isinstance (results [0 ], ABCSeries ):
@@ -406,13 +418,13 @@ def result_index(self) -> "Index":
406
418
def result_columns (self ) -> "Index" :
407
419
return self .columns
408
420
409
- def wrap_results_for_axis (self ) :
421
+ def wrap_results_for_axis (self , results : ResType ) -> Union [ "Series" , "DataFrame" ] :
410
422
""" return the results for the columns """
411
- results = self . results
423
+ result : Union [ "Series" , "DataFrame" ]
412
424
413
425
# we have requested to expand
414
426
if self .result_type == "expand" :
415
- result = self .infer_to_same_shape ()
427
+ result = self .infer_to_same_shape (results )
416
428
417
429
# we have a non-series and don't want inference
418
430
elif not isinstance (results [0 ], ABCSeries ):
@@ -423,13 +435,12 @@ def wrap_results_for_axis(self):
423
435
424
436
# we may want to infer results
425
437
else :
426
- result = self .infer_to_same_shape ()
438
+ result = self .infer_to_same_shape (results )
427
439
428
440
return result
429
441
430
- def infer_to_same_shape (self ) -> "DataFrame" :
442
+ def infer_to_same_shape (self , results : ResType ) -> "DataFrame" :
431
443
""" infer the results to the same shape as the input object """
432
- results = self .results
433
444
434
445
result = self .obj ._constructor (data = results )
435
446
result = result .T
0 commit comments