Define boxplot inside DataFrameGroupBy definition
State: closed

instead of pinning it on right after the definition; move the import of `plotting._core.boxplot_frame_groupby` to the top of the module.

Start getting rid of the `exec(...)` statements.  In particular, the ones that define
properties.  Still need to figure out the ones defining methods.

 - [ ] closes #xxxx
 - [ ] tests added / passed
 - [x] passes ``git diff upstream/master -u -- "*.py" | flake8 --diff``
 - [ ] whatsnew entry


Labels:
name: Clean

Comments:
I can't get CircleCI to load the error messages, so no idea why it's failing.
@gfyoung Can you see what the problem is with CircleCI?
@jbrockmendel : you can see for yourself in fact.  Under the test summary, for each failing test, there's a "more" button to the right-hand side that you can click.
As for why your tests are failing, they're failing because they aren't catching a `UserWarning` somewhere, at least according to `pytest`.
It was stuck in spinning-umbrella mode last time I checked, but I'm getting the error messages now.  Thanks.
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=h1) Report
> Merging [#17179](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/f165b90ed27487287e1c8a0a6c4e66344b2c731d?src=pr&el=desc) will **decrease** coverage by `0.02%`.
> The diff coverage is `89.28%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/17179/graphs/tree.svg?width=650&height=150&token=eZ4WkYLtcO&src=pr)](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #17179      +/-   ##
==========================================
- Coverage   91.02%      91%   -0.03%     
==========================================
  Files         162      162              
  Lines       49517    49523       +6     
==========================================
- Hits        45075    45068       -7     
- Misses       4442     4455      +13
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `88.78% <89.28%> (-0.01%)` | :arrow_down: |
| #single | `40.28% <85.71%> (-0.04%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/groupby.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ3JvdXBieS5weQ==) | `92.03% <89.28%> (-0.05%)` | :arrow_down: |
| [pandas/io/gbq.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2lvL2dicS5weQ==) | `25% <0%> (-58.34%)` | :arrow_down: |
| [pandas/core/indexes/accessors.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9hY2Nlc3NvcnMucHk=) | `88.09% <0%> (-0.67%)` | :arrow_down: |
| [pandas/core/internals.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW50ZXJuYWxzLnB5) | `94.04% <0%> (-0.17%)` | :arrow_down: |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.66% <0%> (-0.16%)` | :arrow_down: |
| [pandas/core/computation/eval.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvY29tcHV0YXRpb24vZXZhbC5weQ==) | `96.93% <0%> (-0.04%)` | :arrow_down: |
| [pandas/core/categorical.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvY2F0ZWdvcmljYWwucHk=) | `95.46% <0%> (-0.03%)` | :arrow_down: |
| [pandas/core/resample.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvcmVzYW1wbGUucHk=) | `96.13% <0%> (-0.03%)` | :arrow_down: |
| [pandas/core/computation/pytables.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvY29tcHV0YXRpb24vcHl0YWJsZXMucHk=) | `92.35% <0%> (-0.03%)` | :arrow_down: |
| [pandas/core/computation/align.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvY29tcHV0YXRpb24vYWxpZ24ucHk=) | `97.91% <0%> (-0.03%)` | :arrow_down: |
| ... and [17 more](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=footer). Last update [f165b90...1d59eff](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=h1) Report
> Merging [#17179](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/f165b90ed27487287e1c8a0a6c4e66344b2c731d?src=pr&el=desc) will **decrease** coverage by `0.03%`.
> The diff coverage is `84.21%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/17179/graphs/tree.svg?token=eZ4WkYLtcO&src=pr&height=150&width=650)](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #17179      +/-   ##
==========================================
- Coverage   91.02%   90.99%   -0.04%     
==========================================
  Files         162      162              
  Lines       49517    49655     +138     
==========================================
+ Hits        45075    45185     +110     
- Misses       4442     4470      +28
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `88.78% <84.21%> (-0.01%)` | :arrow_down: |
| #single | `40.27% <51.31%> (-0.05%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/groupby.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ3JvdXBieS5weQ==) | `91.63% <84.21%> (-0.44%)` | :arrow_down: |
| [pandas/io/gbq.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2lvL2dicS5weQ==) | `25% <0%> (-58.34%)` | :arrow_down: |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.72% <0%> (-0.1%)` | :arrow_down: |
| [pandas/core/tools/datetimes.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvdG9vbHMvZGF0ZXRpbWVzLnB5) | `66.85% <0%> (ø)` | :arrow_up: |
| [pandas/core/tools/numeric.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvdG9vbHMvbnVtZXJpYy5weQ==) | `100% <0%> (ø)` | :arrow_up: |
| [pandas/util/\_print\_versions.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL3V0aWwvX3ByaW50X3ZlcnNpb25zLnB5) | `15.71% <0%> (ø)` | :arrow_up: |
| [pandas/core/generic.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ2VuZXJpYy5weQ==) | `92.03% <0%> (ø)` | :arrow_up: |
| [pandas/core/tools/timedeltas.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvdG9vbHMvdGltZWRlbHRhcy5weQ==) | `98.33% <0%> (ø)` | :arrow_up: |
| [pandas/core/reshape/pivot.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvcmVzaGFwZS9waXZvdC5weQ==) | `95.4% <0%> (+0.1%)` | :arrow_up: |
| [pandas/util/\_decorators.py](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=tree#diff-cGFuZGFzL3V0aWwvX2RlY29yYXRvcnMucHk=) | `66% <0%> (+0.34%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=footer). Last update [f165b90...c3c0e0a](https://codecov.io/gh/pandas-dev/pandas/pull/17179?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

> actually generate the groupby whitelisted methods rather than using exec

That sounds great.  I'll try to put that together this afternoon.
Hello @jbrockmendel! Thanks for updating the PR.



Cheers ! There are no PEP8 issues in this Pull Request. :beers: 

##### Comment last updated on August 12, 2017 at 01:18 Hours UTC
Just pushed a commit that explicitly defines all of the inherited methods instead of generating them with `exec`.

closes #16959 

Aside from using `Appender` to inherit docstrings, the definitions here are identical to how they were in the `exec` version.  If we can reach a consensus, I'd like to go a step further and get rid of the `__getattr__` magic these methods use.  e.g.

```
    def __getattr__(self, attr):
        if attr in self._internal_names_set:
            return object.__getattribute__(self, attr)
        if attr in self.obj:
            return self[attr]
        if hasattr(self.obj, attr):
            return self._make_wrapper(attr)

        raise AttributeError("%r object has no attribute %r" %
                             (type(self).__name__, attr))

[...]
    @Appender(Series.idxmax.__doc__)
    def idxmax(self, axis=None, skipna=True, *args, **kwargs):
        f = self.__getattr__('idxmax')
        return f(axis=axis, skipna=skipna)

```

A casual reader could easily look at `f = self.__getattr__('idxmax')` and think it is equivalent to `self.idxmax` or `getattr(self, 'idxmax')`.  This confusion can be avoided by just writing `f = self._make_wrapper('idxmax')`.  Ideally we could take the `_make_wrapper` branch out of `__getattr__` altogether.

In fact, `gb.idxmax()` will raise a `TypeError` if there is ever a column named `idxmax`.  There was a related issue around not long ago but I can't seem to find it.

Side-note: Most of the inherited methods allow for `**kwargs`, but then ignore anything that is passed.  Is this intentional?
This PR has gotten stuck in the mud.  I propose swiss-cheesing the problem into smaller pieces.

1) A new PR that addresses the original issue by just taking `boxplot` out of `_dataframe_apply_whitelist`.

2) A PR that removes the whitelist _properties_ generated using `exec` (and the weird `__getattr__` redirection).  With properties we won't have to worry about the signatures being changed.

3) Remaining methods that don't have `*args, **kwargs`.

4) The rest.


@jbrockmendel : Given how the conversation has gone, I think that sounds like a good idea.  Keep this PR open until you're done dividing it up.