I want to be able to override the __repr__ function in my dataclasses to include all class variables from self.dict, not just fields, but still omitting fields with repr=False
, including in nested dataclasses.
Simplified version of my code:
from dataclasses import dataclass, field, fields
import utils
@dataclass
class Bar:
_data: dict = field(repr=False)
bar: int = 0
def __post_init__(self):
"""more nested dataclasses"""
@dataclass
class Foo:
_data: dict = field(repr=False)
foo: int = 0
def __post_init__(self):
self.bar = Bar(**utils.clean(_data, 'bar'))
foo = Foo(**data)
print(foo)
What I want (this or something similar):
Foo(foo=0, bar=Bar(...))
but still keep the same formatting when asked print(foo.bar)
: Bar(bar=0)
What I get with the default repr (the code is functional so things like foo.bar.bar
work as intended, I want the repr to display everything omitting fields where repr=False):
Foo(foo=0)
Solutions I've tried:
# works, kinda, but doesn't omit fields where repr=False
def __repr__(self):
return f'{self.__class__.__qualname__}({self.__dict__!r})'
# modified solution from a similar question on stack overflow, but doesn't return !r formatting
# for every recursion depth when copied to every dataclass and I'm not sure how I would change it
# to format nested dataclasses with '...'
def dict_without_repr_field(self) -> dict:
dict_to_show = self.__dict__.copy()
for key in self.__dict__.keys():
try:
if not self.__dataclass_fields__[key].repr:
dict_to_show.pop(key)
except KeyError:
pass
return dict_to_show
def __repr__(self):
updated_dict = self.dict_without_repr_field()
return f'{self.__class__.__qualname__}({updated_dict!r})'
Any help would be appreciated, thanks!
You have to declare the type of bar and disable its initialisation.
from dataclasses import field
@dataclass
class Foo:
_data: dict = field(repr=False)
foo: int = 0
bar: Bar = field(init=False) # <-
def __post_init__(self):
self.bar = Bar(**utils.clean(_data, 'bar'))