When using pytest
, I get nice pretty printing when two objects are not equivalent:
Expected :Foo(id='red', other_thing='green')
Actual :Foo(id='red', other_thing='blue')
<Click to see difference>
def test_baz():
oneFoo = Foo(id="red", other_thing="blue")
twoFoo = Foo(id="red", other_thing="green")
> assert oneFoo == twoFoo
E AssertionError: assert Foo(id='red', other_thing='blue') == Foo(id='red', other_thing='green')
E
E Full diff:
E - Foo(id='red', other_thing='green')
E ? ^^ --
E + Foo(id='red', other_thing='blue')
E ? ^^^
baz.py:22: AssertionError
If I use an assert directly in my code, I just get an AssertionError
and a stacktrace.
I am writing some integration tests right now that are NOT driven by pytest but would like to pretty print when two items (specifically Pydantic dataclasses) are not equal.
This works pretty well:
from difflib import Differ
import structlog
from colorama import Fore
from pydantic import BaseModel
logger = structlog.getLogger(__name__)
def check_equals(expected: BaseModel, actual: BaseModel) -> None:
if not expected == actual:
logger.error("Objects are not equal", expected=expected, actual=actual)
diff_output = Differ().compare(
_get_lines(expected),
_get_lines(actual)
)
color_diff_output = _color_diff(diff_output)
print("\n".join(color_diff_output))
raise ValueError("Objects not equal")
def _get_lines(item: BaseModel) -> str:
item_json = item.model_dump_json(indent=4)
lines = item_json.splitlines()
return lines
def _color_diff(diff):
"""
Found this nice function here: https://chezsoi.org/lucas/blog/colored-diff-output-with-python.html
"""
for line in diff:
if line.startswith('+'):
yield Fore.GREEN + line + Fore.RESET
elif line.startswith('-'):
yield Fore.RED + line + Fore.RESET
elif line.startswith('^'):
yield Fore.BLUE + line + Fore.RESET
else:
yield line
Prints:
When you run this code:
from pydantic import BaseModel
from util.integration_test_validation.check_equals import check_equals
class Bar(BaseModel):
beaches: int
oranges: int
class Foo(BaseModel):
id: str
other_thing: str
count: int
bar: Bar
oneFoo = Foo(id="red", other_thing="blue", count=3, bar=Bar(beaches=5, oranges=7))
twoFoo = Foo(id="red", other_thing="green", count=3, bar=Bar(beaches=5, oranges=7))
check_equals(oneFoo, twoFoo)