Skip to content

Conversation

@connorbrinton
Copy link
Contributor

Fix how IsDataclass handles nested dataclasses so they can be compared successfully. Previously something like the following would not work:

from dataclasses import dataclass
from dirty_equals import IsDataclass

@dataclass
class Address:
    street: str
    zip_code: str

@dataclass
class Person:
    name: str
    address: Address

person = Person(
    name='Alice',
    address=Address(street='123 Main St', zip_code='12345'),
)

assert person == IsDataclass(
    name='Alice',
    address=IsDataclass(street='123 Main St', zip_code='12345')
)

This is a result of IsDataclass converting dataclasses to a dictionary for comparison using dataclasses.asdict, which recursively converts dataclasses to plain dictionaries. Thus the inner IsDataclass fails, because the other side of the comparison is now a dictionary, not a dataclass.

These changes fix this by shallowly converting the dataclass to a dictionary using the approach recommended in the dataclasses documentation:

{field.name: getattr(obj, field.name) for field in fields(obj)}

These changes also include a test for nested dataclass comparisons to ensure this works as expected and continues to work in the future.

Fix how `IsDataclass` handles nested dataclasses so they can be compared
successfully. Previously something like the following would not work:
```python
from dataclasses import dataclass
from dirty_equals import IsDataclass

@DataClass
class Address:
    street: str
    zip_code: str

@DataClass
class Person:
    name: str
    address: Address

person = Person(
    name='Alice',
    address=Address(street='123 Main St', zip_code='12345'),
)

assert person == IsDataclass(
    name='Alice',
    address=IsDataclass(street='123 Main St', zip_code='12345')
)
```

This is a result of `IsDataclass` converting dataclasses to a dictionary
for comparison using `dataclasses.asdict`, which _recursively_ converts
dataclasses to plain dictionaries. Thus the inner `IsDataclass` fails,
because the other side of the comparison is now a dictionary, not a
dataclass.

These changes fix this by shallowly converting the dataclass to a
dictionary using [the approach recommended in the dataclasses
documentation](https://docs.python.org/3/library/dataclasses.html#dataclasses.asdict):
```python
{field.name: getattr(obj, field.name) for field in fields(obj)}
```

These changes also include a test for nested dataclass comparisons to
ensure this works as expected and continues to work in the future.
@connorbrinton connorbrinton marked this pull request as ready for review November 16, 2025 01:47
@samuelcolvin
Copy link
Owner

Looks good to me. Thanks for the contribution.

@samuelcolvin samuelcolvin merged commit f15a6de into samuelcolvin:main Nov 17, 2025
17 checks passed
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 this pull request may close these issues.

2 participants