Last active
September 6, 2019 13:40
-
-
Save gimbo/19f1fede170090fdf029a4f3f5c7fece to your computer and use it in GitHub Desktop.
An attrs extension giving fields more control over how they're rendered in an autogenerated __repr__
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def attrs_flexible_repr(cls): | |
""" | |
An [attrs](http://www.attrs.org/) extension giving attributes more | |
flexibility about how they appear in the autogenerated `__repr__`. | |
Out of the box, attrs gives your class a pretty decent `__repr__` method; | |
you can disable this at the class level to define your own, or you can | |
keep it but exclude attributes by setting their `repr` field to False. | |
This extension adds to that by giving the attributes more control over | |
how they're rendered, depending on the value of `repr` field; the new | |
possibilities are: | |
* `repr` a callable - pass the field's value to the callable and render | |
its result as the value in the repr string. | |
* `repr` a tuple - assumed to be a (str, callable) pair, where the str | |
is the label to use for the attribute (rather than its name), and the | |
callable is used as described above. | |
(Otherwise it will just behave as usual.) | |
Note that if you use this extension and also specify repr=False at the | |
class level, that will be ignored: you _will_ get a __repr__ and any | |
that you define for yourself will be ignored. | |
Example: | |
>>> @attrs_flexible_repr | |
>>> @attr.s(repr=False) # repr=False here ignored | |
>>> class Example: | |
>>> username = attr.ib() # Rendered as normal | |
>>> password = attr.ib(repr=False) # Excluded from repr as normal | |
>>> # Next field is assumed to be a datetime.datetime | |
>>> time = attr.ib(repr=lambda t: t.isoformat(timespec='seconds')) | |
>>> content = attr.ib(repr=('Length', lambda c: len(c))) # Title tweak | |
>>> weird = attr.ib(repr=lambda _: False) # Always renders 'False' | |
>>> | |
>>> e = Example('me', 'xxx', datetime.datetime.now(), 'Hello there', 'Blah') | |
>>> e | |
Example(username=me, time=2018-06-15T10:52:13, Length=11, weird=False) | |
""" | |
def flexible_repr(self): | |
parts = [] | |
for field in cls.__attrs_attrs__: | |
if not field.repr: | |
continue | |
field_name = field.name | |
field_repr_callable = None | |
field_value = getattr(self, field.name) | |
if callable(field.repr): | |
field_repr_callable = field.repr | |
elif isinstance(field.repr, tuple): | |
field_name, field_repr_callable = field.repr | |
if field_repr_callable: | |
field_value = field_repr_callable(field_value) | |
parts.append('{}={}'.format(field_name, field_value)) | |
return '{}({})'.format(self.__class__.__name__, ', '.join(parts)) | |
cls.__repr__ = flexible_repr | |
return cls |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note that attrs PR 568 makes this redundant, and is surely better implemented (see issue 212 there).