Skip to content

CLN: generate groupby method wrapper code #16959

Closed
@jbrockmendel

Description

@jbrockmendel
$ 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_strs 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions