
import pandas as pd
import pandas
from pandas.core.groupby import GroupBy

from inspect import getmembers, isfunction

import bamboo, groups, frames, plotting


_bamboo_methods = {name:func  for name, func in getmembers(bamboo) if isfunction(func)}
_frames_methods = {name:func  for name, func in getmembers(frames) if isfunction(func)}
_groups_methods = {name:func  for name, func in getmembers(groups) if isfunction(func)}
_plot_methods = {name:func  for name, func in getmembers(plotting) if isfunction(func)}


def _wrap_with_bamboo(obj):

    if isinstance(obj, pandas.DataFrame):
        return BambooDataFrame(obj)

    elif isinstance(obj, pandas.core.groupby.SeriesGroupBy):
        return BambooSeriesGroupBy(obj)

    elif isinstance(obj, pandas.core.groupby.DataFrameGroupBy):
        return BambooDataFrameGroupBy(obj)

    else:
        return obj


def _create_bamboo_wrapper(obj, func):
    def callable(*args, **kwargs):
        res = func(obj, *args, **kwargs)
        return _wrap_with_bamboo(res)
    return callable


class BambooDataFrame(pandas.DataFrame):

    def __init__(self, *args, **kwargs):
        super(BambooDataFrame, self).__init__(*args, **kwargs)

    def groupby(self, *args, **kwargs):
        return _wrap_with_bamboo(super(BambooDataFrame, self).groupby(*args, **kwargs))

    def __getattr__(self, *args, **kwargs):

        name, pargs = args[0], args[1:]

        if name in _bamboo_methods:
            return _create_bamboo_wrapper(self, _bamboo_methods[name])

        if name in _plot_methods:
            return _create_bamboo_wrapper(self, _plot_methods[name])

        if name in _frames_methods:
            return _create_bamboo_wrapper(self, _frames_methods[name])

        return _create_bamboo_wrapper(self, super(BambooDataFrame, self).__getattribute__(*args, **kwargs))


class BambooDataFrameGroupBy(pandas.core.groupby.DataFrameGroupBy):

    def __init__(self, other):
        if not isinstance(other, pandas.core.groupby.DataFrameGroupBy):
            raise TypeError()

        super(BambooDataFrameGroupBy, self).__init__(
                                             other.obj,
                                             other.keys,
                                             other.axis,
                                             other.level,
                                             other.grouper,
                                             other.exclusions,
                                             other._selection,
                                             other.as_index,
                                             other.sort,
                                             other.group_keys,
                                             other.squeeze)

    def head(self, *args, **kwargs):
        return bamboo.head(self, *args, **kwargs)

    def __getattr__(self, *args, **kwargs):

        name, pargs = args[0], args[1:]

        if name in _bamboo_methods:
            return _create_bamboo_wrapper(self, _bamboo_methods[name])

        if name in _plot_methods:
            return _create_bamboo_wrapper(self, _plot_methods[name])

        if name in _groups_methods:
            return _create_bamboo_wrapper(self, _groups_methods[name])

        return _create_bamboo_wrapper(self, super(BambooDataFrameGroupBy, self).__getattribute__(*args, **kwargs))


class BambooSeriesGroupBy(pandas.core.groupby.SeriesGroupBy):

    def __init__(self, other):
        if not isinstance(other, pandas.core.groupby.SeriesGroupBy):
            raise TypeError()
        super(BambooSeriesGroupBy, self).__init__(
                                             other.obj,
                                             other.keys,
                                             other.axis,
                                             other.level,
                                             other.grouper,
                                             other.exclusions,
                                             other._selection,
                                             other.as_index,
                                             other.sort,
                                             other.group_keys,
                                             other.squeeze)

    def head(self, *args, **kwargs):
        return bamboo.head(self, *args, **kwargs)

    def __getattr__(self, *args, **kwargs):

        name, pargs = args[0], args[1:]

        if name in _bamboo_methods:
            return _create_bamboo_wrapper(self, _bamboo_methods[name])

        if name in _plot_methods:
            return _create_bamboo_wrapper(self, _plot_methods[name])

        if name in _groups_methods:
            return _create_bamboo_wrapper(self, _groups_methods[name])

        return _create_bamboo_wrapper(self, super(BambooSeriesGroupBy, self).__getattribute__(*args, **kwargs))


@@ -1715,32 +1715,143 @@
 name%5D)%0A%0A        
+res = super(BambooDataFrame, self).__getattr__(*args, **kwargs)%0A        return _wrap_with_bamboo(res)%0A        #
 return _create_b
@@ -1926,32 +1926,32 @@
 rgs, **kwargs))%0A
-
 %0A%0Aclass BambooDa
@@ -2841,32 +2841,33 @@
 other.squeeze)%0A%0A
+%0A
     def head(sel
@@ -2930,32 +2930,33 @@
 rgs, **kwargs)%0A%0A
+%0A
     def __getatt
@@ -3359,41 +3359,11 @@
   re
-turn _create_bamboo_wrapper(self,
+s =
  sup
@@ -3396,37 +3396,32 @@
  self).__getattr
-ibute
 __(*args, **kwar
@@ -3415,32 +3415,119 @@
 *args, **kwargs)
+%0A        return _wrap_with_bamboo(res)%0A        #return _create_bamboo_wrapper(self, res
 )%0A%0A%0Aclass Bamboo
@@ -4908,24 +4908,24 @@
 name%5D)%0A%0A
-
         
 return _
@@ -4908,32 +4908,147 @@
 name%5D)%0A%0A        
+res = super(BambooSeriesGroupBy, self).__getattr__(*args, **kwargs)%0A        return _wrap_with_bamboo(res)%0A        #
 return _create_b

Fix bamboo object method forwarding