Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Custom __repr__ for particular attribute? #567

Closed
peteroconnor-bc opened this issue Sep 4, 2019 · 9 comments · Fixed by #568
Closed

Feature Request: Custom __repr__ for particular attribute? #567

peteroconnor-bc opened this issue Sep 4, 2019 · 9 comments · Fixed by #568

Comments

@peteroconnor-bc
Copy link

peteroconnor-bc commented Sep 4, 2019

Reading the docs, it seems that there's no ability to do a custom repr for a particular attribute. E.g., It would be nice to be able to specify a function for repr like:

@attr.s 
class Datapoint:
    image = attr.ib(type=np.ndarray, repr = lambda x: '<array of shape {} and dtype {}>'.format(x.shape, x.dtype))
    label = attr.ib(type=int)

so that when you print(Datapoint(img, lab)), it does not display numpy's awkward default formatting.

As far as I see you can currently only set a boolean flag repr=False to disable to whole attribute from being shown in the object's repr, which is not what I want. We could still maintain this behaviour if we just say repr: Optional[Union[bool, Callable[[Any], str]]]=True

@wbolster
Copy link
Member

wbolster commented Sep 5, 2019

wow. i've been using attrs for a long time, and i was searching the issue tracker to see whether this feature was considered before... only to find that exactly what i am also looking for has been posted only 10 hours before.

thanks for writing it up @peteroconnor-bc, this is exactly what i would like to have as well.

@wbolster
Copy link
Member

wbolster commented Sep 5, 2019

here's a preliminary pull request to explore what it could look like: #568

@hynek
Copy link
Member

hynek commented Sep 5, 2019

I have mixed feelings about this, but maybe we can sort this out. My plan is to make the whole creation of methods pluggable (I have to admit that I have been lazy or swamped – depending on how charitable you are). I.e. you pass a method-factory to @attr.s(repr=your_repr_factory) and then you do whatever the fuck you want. My first thought is to use singledispatch here too.

However that doesn't seem to preclude the need to modify the behavior of single attributes so I guess who could do both?

@wbolster
Copy link
Member

wbolster commented Sep 5, 2019

for class level custom repr, one can already pass repr=False and then you can implement your own __repr__ dunder method.

this means the main (only?) usefulness of custom repr callables is to have this on a per-attribute level, e.g. you don't want your np.ndarray or whatever weird object to clutter debugging output or turn your interactive python shell into a mess, while still having some useful info (unlike repr=False which will just omit it).

and as my preliminary pull request shows, this is mostly an extension of existing behaviour without any backward compatibility concerns. the repr attribute would simply change from bool to Union[bool, Callable[T]].

@peteroconnor-bc
Copy link
Author

@wbolster nice, was not expecting someone to implement this already

@gabbard
Copy link
Member

gabbard commented Sep 5, 2019

I also was just reviewing some code using attrs yesterday which would have been simplified by this feature (it was also a case of handling np.ndarray fields).

@Julian
Copy link
Member

Julian commented Sep 6, 2019

for class level custom repr, one can already pass repr=False and then you can implement your own __repr__ dunder method.

Yes, but then you need to know a bunch of attrs "internals" and write some loops.

E.g., take the use case in #41 itself, where the logic at the class level now needs to be "Ask all the attrs for their own reprs, then give me those, and I know how to assemble a class-whole one".

Still think there's a chance it might be nice to have some class-level help, but yeah possibly that can decouple from this since obviously the attr-specific stuff is even more important, can always come back for the other side if it continues to be annoying (I suspect for me it likely will be personally, since I essentially always want #41 as my repr, but yeah...).

@wbolster
Copy link
Member

wbolster commented Sep 6, 2019

yeah let's keep class repr separate. incidentally, it was me who opened #41 ;)

@wbolster
Copy link
Member

wbolster commented Sep 6, 2019

closing this issue because it is pretty much identical to #212.

@wbolster wbolster closed this as completed Sep 6, 2019
hynek pushed a commit that referenced this issue Sep 6, 2019
* wip: support custom repr() callable for attributes

see #567

* extend ‘repr=...’ arg type in .pyi stubs

* expand docstring for attr.ib()

* add changelog entry

* add docs with example

* improve my copy/paste skills 🙈

* fix grammar

* fix typo in changelog entry

* fix and improve attrib() docstring

* detect custom repr() once, not per call. be strict about bool.

* use rst syntax, not markdown

* apply hynek's suggestions for changelog entry

* add ‘versionchanged’ note in docstring

* add custom attribute repr= to typing example

* simplify comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants