|
11 | 11 | from functools import partial
|
12 | 12 | from textwrap import dedent
|
13 | 13 | import typing
|
14 |
| -from typing import Any, Callable, List, Union |
| 14 | +from typing import Any, Callable, FrozenSet, Iterator, List, Type, Union |
15 | 15 | import warnings
|
16 | 16 |
|
17 | 17 | import numpy as np
|
|
27 | 27 | is_integer_dtype, is_interval_dtype, is_numeric_dtype, is_scalar)
|
28 | 28 | from pandas.core.dtypes.missing import isna, notna
|
29 | 29 |
|
| 30 | +from pandas._typing import FrameOrSeries |
30 | 31 | import pandas.core.algorithms as algorithms
|
31 | 32 | from pandas.core.base import DataError, SpecificationError
|
32 | 33 | import pandas.core.common as com
|
|
48 | 49 | AggScalar = Union[str, Callable[..., Any]]
|
49 | 50 |
|
50 | 51 |
|
| 52 | +def whitelist_method_generator(base_class: Type[GroupBy], |
| 53 | + klass: Type[FrameOrSeries], |
| 54 | + whitelist: FrozenSet[str], |
| 55 | + ) -> Iterator[str]: |
| 56 | + """ |
| 57 | + Yields all GroupBy member defs for DataFrame/Series names in whitelist. |
| 58 | +
|
| 59 | + Parameters |
| 60 | + ---------- |
| 61 | + base_class : Groupby class |
| 62 | + base class |
| 63 | + klass : DataFrame or Series class |
| 64 | + class where members are defined. |
| 65 | + whitelist : frozenset |
| 66 | + Set of names of klass methods to be constructed |
| 67 | +
|
| 68 | + Returns |
| 69 | + ------- |
| 70 | + The generator yields a sequence of strings, each suitable for exec'ing, |
| 71 | + that define implementations of the named methods for DataFrameGroupBy |
| 72 | + or SeriesGroupBy. |
| 73 | +
|
| 74 | + Since we don't want to override methods explicitly defined in the |
| 75 | + base class, any such name is skipped. |
| 76 | + """ |
| 77 | + property_wrapper_template = \ |
| 78 | + """@property |
| 79 | +def %(name)s(self) : |
| 80 | + \"""%(doc)s\""" |
| 81 | + return self.__getattr__('%(name)s')""" |
| 82 | + |
| 83 | + for name in whitelist: |
| 84 | + # don't override anything that was explicitly defined |
| 85 | + # in the base class |
| 86 | + if hasattr(base_class, name): |
| 87 | + continue |
| 88 | + # ugly, but we need the name string itself in the method. |
| 89 | + f = getattr(klass, name) |
| 90 | + doc = f.__doc__ |
| 91 | + doc = doc if type(doc) == str else '' |
| 92 | + wrapper_template = property_wrapper_template |
| 93 | + params = {'name': name, 'doc': doc} |
| 94 | + yield wrapper_template % params |
| 95 | + |
| 96 | + |
51 | 97 | class NDFrameGroupBy(GroupBy):
|
52 | 98 |
|
53 | 99 | def _iterate_slices(self):
|
@@ -685,7 +731,7 @@ class SeriesGroupBy(GroupBy):
|
685 | 731 | # Make class defs of attributes on SeriesGroupBy whitelist
|
686 | 732 |
|
687 | 733 | _apply_whitelist = base.series_apply_whitelist
|
688 |
| - for _def_str in base.whitelist_method_generator( |
| 734 | + for _def_str in whitelist_method_generator( |
689 | 735 | GroupBy, Series, _apply_whitelist):
|
690 | 736 | exec(_def_str)
|
691 | 737 |
|
@@ -1289,7 +1335,7 @@ class DataFrameGroupBy(NDFrameGroupBy):
|
1289 | 1335 |
|
1290 | 1336 | #
|
1291 | 1337 | # Make class defs of attributes on DataFrameGroupBy whitelist.
|
1292 |
| - for _def_str in base.whitelist_method_generator( |
| 1338 | + for _def_str in whitelist_method_generator( |
1293 | 1339 | GroupBy, DataFrame, _apply_whitelist):
|
1294 | 1340 | exec(_def_str)
|
1295 | 1341 |
|
|
0 commit comments