Closed
Description
$ grep -r "[^_]exec(" pandas
pandas/compat/__init__.py: exec("""
pandas/core/groupby.py: exec(_def_str)
pandas/core/groupby.py: exec(_def_str)
The usage in compat
is for raise_with_traceback
where the py2 version is a syntax error in py3. This is pretty straightforward to de-exec by putting the py2-specific code in a module that only gets imported in py2.
The usage in core.groupby
is tougher. The string being exec'ed defines a method in some cases and property in others. The property version I think I've got a working fix, but the method version has me stumped.
These _def_str
s are constructed in core.groupby._whitelist_method_generator
:
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