repr string for pd.Grouper
State: closed

- [ ] closes #xxxx
- [x ] tests added / passed
- [ x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [ ] whatsnew entry

**Edit: I've made a full proposal (sans some  discussion points below)**

Currently the repr for ``Grouper`` and ``TimeGrouper`` is not pretty:

```python
>>> pd.Grouper(key='key')
<pandas.core.groupby.Grouper at 0x248d5ebfd30>
>>> pd.Grouper(key='key', freq='50Min')
<pandas.core.resample.TimeGrouper at 0x248d68d95c0>
```

I propose adding a ``Grouper.__repr__``, so the repr will be like:

```python
>>> pd.Grouper(key='key')
Grouper(key='key')
>>> pd.Grouper(key='key', freq='50Min')
TimeGrouper(key='key', freq='50T')
>>> pd.Grouper(key='key', freq='50Min', label='right')
TimeGrouper(label='right', key='k', freq='50T')
```

The repr shows the instantiation form, so users could copy the repr and paste it in to use it, which is always nice.

See attached PR. Tests are still missing. Comments welcome.

Two points:
* The repr calculation is a bit heavy, so I've cached it. Don't know if that is going overboard?
* Is ``TimeGrouper`` deprecated?

Labels:
name: Enhancement
name: Groupby
name: Output-Formatting
description: __repr__ of pandas objects, to_string

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

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

```diff
@@            Coverage Diff             @@
##           master   #17727      +/-   ##
==========================================
- Coverage   91.25%   91.24%   -0.02%     
==========================================
  Files         163      163              
  Lines       50130    49876     -254     
==========================================
- Hits        45748    45509     -239     
+ Misses       4382     4367      -15
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `89.04% <100%> (-0.01%)` | :arrow_down: |
| #single | `40.27% <75%> (-0.12%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/groupby.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ3JvdXBieS5weQ==) | `92.04% <100%> (ø)` | :arrow_up: |
| [pandas/core/resample.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvcmVzYW1wbGUucHk=) | `96.18% <100%> (+0.02%)` | :arrow_up: |
| [pandas/io/gbq.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL2lvL2dicS5weQ==) | `25% <0%> (-58.34%)` | :arrow_down: |
| [pandas/compat/pickle\_compat.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL2NvbXBhdC9waWNrbGVfY29tcGF0LnB5) | `69.51% <0%> (-6.1%)` | :arrow_down: |
| [pandas/core/indexes/range.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9yYW5nZS5weQ==) | `92.83% <0%> (-2.83%)` | :arrow_down: |
| [pandas/util/\_decorators.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL3V0aWwvX2RlY29yYXRvcnMucHk=) | `78% <0%> (-2.71%)` | :arrow_down: |
| [pandas/util/\_validators.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL3V0aWwvX3ZhbGlkYXRvcnMucHk=) | `93.75% <0%> (-2.6%)` | :arrow_down: |
| [pandas/io/html.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL2lvL2h0bWwucHk=) | `84.85% <0%> (-1.13%)` | :arrow_down: |
| [pandas/core/dtypes/concat.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZHR5cGVzL2NvbmNhdC5weQ==) | `98.26% <0%> (-0.89%)` | :arrow_down: |
| [pandas/io/common.py](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree#diff-cGFuZGFzL2lvL2NvbW1vbi5weQ==) | `68.64% <0%> (-0.85%)` | :arrow_down: |
| ... and [52 more](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17727?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/17727?src=pr&el=footer). Last update [c176a3c...62f2de8](https://codecov.io/gh/pandas-dev/pandas/pull/17727?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

@topper-123 : The `__repr__` looks reasonable to me, though in the future, would have been good to create an issue first to get consensus before proceeding to a PR.
Yeah, I just started doing this for a personal use case and thought it could be nice to have in pandas itself. so I maybe took two steps when only one  was all that was needed. I felt silly to post a issue when the idea already was coded... My main concern was if you dislike caching the repr in pandas and/or the if the approach should be less complex.
why are you doing this?
if it actually is expensive to compute the repr we have the cache_readyonly decorator for that

this just makes the code confusing 
Timegrouper is deprecated
> I felt silly to post a issue when the idea already was coded

@topper-123 : The point of opening an issue is to get a consensus on whether we actually think it's a good idea to do this in the first place.
@topper-123 note that I DO like the idea of a nice repr for ``Grouper``, just don't think the caching is needed.
Hello @topper-123! Thanks for updating the PR.







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

##### Comment last updated on November 06, 2017 at 22:21 Hours UTC
I've changed the code:
* no more caching, always show current values
* the init default parameters are in a class attribute; improves subclassability (user can change them upon subclassing)
* default  ``closed`` and ``label`` for ``TimeGrouper`` are calculated at call time, so they will also always be correct now
``ènd_types`` have one location, which also is better.
* ``TimeGrouper`` still got a repr string: It looks to me that the top level location has been deprecated, but it will still be called through ``Grouper.__new__``?
Tests added. I've finished up, unless more comments .

EDIT: Moved the test for TimeGrouper to test_resample.py.
I've redone this.

It's almost impossible to set ``_attributes`` as a list before ``__init__`` for ``TimeGrouper`` because there's quite a lot of logic in ``TimeGrouper.__init__`` for what should count as a default value.

By setting ``_attributes`` right after ``__init__`` and setting it to an OrderedDict, the implementation works relatively simple, also for ``TimeGrouper``.
@topper-123 again, not sure why you want to repeat code for the default values. you simply need to introspect them, NOT redefine the default.
The travis error seems to be unrelated to my PR.

I've made some changes that I *think* correspond to your comments. Note that this makes ``TimeGrouper`` more verbose:

```python
>>> Grouper(key='key', freq='50Min', label='right')
TimeGrouper(key='key', freq=<50 * Minutes>, axis=0, sort=True, closed='left', label='right', how='mean', loffset=None)
```

I've made a version where only input is displayed, but is that code quite complex, because there are so many special cases in ``TimeGrouper.__init__``.

Is this ok?
superseded by #18203