Closed
Description
in core.groupby._whitelist_method_generator
(https://github.com/pandas-dev/pandas/blob/master/pandas/core/groupby.py#L2801)
method_wrapper_template = \
"""def %(name)s(%(sig)s) :
\"""
%(doc)s
\"""
f = %(self)s.__getattr__('%(name)s')
return f(%(args)s)"""
property_wrapper_template = \
"""@property
def %(name)s(self) :
\"""
%(doc)s
\"""
return self.__getattr__('%(name)s')"""
for name in whitelist:
# don't override anything that was explicitly defined
# in the base class
if hasattr(GroupBy, name):
continue
# ugly, but we need the name string itself in the method.
f = getattr(klass, name)
doc = f.__doc__
doc = doc if type(doc) == str else ''
if isinstance(f, types.MethodType):
wrapper_template = method_wrapper_template
decl, args = make_signature(f)
# pass args by name to f because otherwise
# GroupBy._make_wrapper won't know whether
# we passed in an axis parameter.
args_by_name = ['{0}={0}'.format(arg) for arg in args[1:]]
params = {'name': name,
'doc': doc,
'sig': ','.join(decl),
'self': args[0],
'args': ','.join(args_by_name)}
else:
wrapper_template = property_wrapper_template
params = {'name': name, 'doc': doc}
yield wrapper_template % params
It looks like isinstance(f, types.MethodType)
is never evaluating True in py3, so these are all coming out as properties.
PY2:
In [1]: import pandas as pd
In [2]: gb = pd.Series(range(10)).groupby(lambda x: x % 2)
In [3]: gb.mad
Out[3]: <bound method SeriesGroupBy.mad of <pandas.core.groupby.SeriesGroupBy object at 0x10f394f10>>
In [4]: gb.mad.__doc__
Out[4]: '\n \n\nReturn the mean absolute deviation of the values for the requested axis\n\nParameters\n----------\naxis : {index (0)}\nskipna : boolean, default True\n Exclude NA/null values. If an entire row/column is NA, the result\n will be NA\nlevel : int or level name, default None\n If the axis is a MultiIndex (hierarchical), count along a\n particular level, collapsing into a scalar\nnumeric_only : boolean, default None\n Include only float, int, boolean columns. If None, will attempt to use\n everything, then use only numeric data. Not implemented for Series.\n\nReturns\n-------\nmad : scalar or Series (if level specified)\n\n '
PY3:
In [1]: import pandas as pd
In [2]: gb = pd.Series(range(10)).groupby(lambda x: x % 2)
In [3]: gb.mad
Out[3]: <function pandas.core.groupby._GroupBy._make_wrapper.<locals>.wrapper>
In [4]: gb.mad.__doc__
In [5]:
If we change the condition from isinstance(f, types.MethodType)
to not isinstance(f, property)
, a TypeError
is raised (py3 only):
File "[...]/pandas/core/groupby.py", line 2796, in _whitelist_method_generator
decl, args = make_signature(f)
File "[...]/pandas/util/_decorators.py", line 245, in make_signature
defaults = ('',) * n_wo_defaults + spec.defaults
TypeError: can only concatenate tuple (not "list") to tuple
#17600 should make this problem irrelevant eventually, but someone might want to look at it more short-term.
Metadata
Metadata
Assignees
Labels
No labels