Draft a (pretty)`Struct.fields_diff()`

For comparing a `msgspec.Struct` against an input `dict` presumably to
be used as input for struct instantiation. The main diff with
`.__sub__()` is that non-existing fields on either are reported
(loudly).
aio_abandons
Tyler Goodlet 2024-12-10 13:50:35 -05:00
parent aa1f6fa4b5
commit fb04f74605
1 changed files with 70 additions and 20 deletions

View File

@ -30,9 +30,9 @@ from msgspec import (
Struct as _Struct, Struct as _Struct,
structs, structs,
) )
from pprint import ( # from pprint import (
saferepr, # saferepr,
) # )
from tractor.log import get_logger from tractor.log import get_logger
@ -75,8 +75,8 @@ class DiffDump(UserList):
for k, left, right in self: for k, left, right in self:
repstr += ( repstr += (
f'({k},\n' f'({k},\n'
f'\t{repr(left)},\n' f' |_{repr(left)},\n'
f'\t{repr(right)},\n' f' |_{repr(right)},\n'
')\n' ')\n'
) )
repstr += ']\n' repstr += ']\n'
@ -144,15 +144,22 @@ def pformat(
field_indent=indent + field_indent, field_indent=indent + field_indent,
) )
else: # the `pprint` recursion-safe format: else:
val_str: str = repr(v)
# XXX LOL, below just seems to be f#$%in causing
# recursion errs..
#
# the `pprint` recursion-safe format:
# https://docs.python.org/3.11/library/pprint.html#pprint.saferepr # https://docs.python.org/3.11/library/pprint.html#pprint.saferepr
try: # try:
val_str: str = saferepr(v) # val_str: str = saferepr(v)
except Exception: # except Exception:
log.exception( # log.exception(
'Failed to `saferepr({type(struct)})` !?\n' # 'Failed to `saferepr({type(struct)})` !?\n'
) # )
return _Struct.__repr__(struct) # raise
# return _Struct.__repr__(struct)
# TODO: LOLOL use `textwrap.indent()` instead dawwwwwg! # TODO: LOLOL use `textwrap.indent()` instead dawwwwwg!
obj_str += (field_ws + f'{k}: {typ_name} = {val_str},\n') obj_str += (field_ws + f'{k}: {typ_name} = {val_str},\n')
@ -203,12 +210,7 @@ class Struct(
return sin_props return sin_props
pformat = pformat pformat = pformat
# __repr__ = pformat
# __str__ = __repr__ = pformat
# TODO: use a pprint.PrettyPrinter instance around ONLY rendering
# inside a known tty?
# def __repr__(self) -> str:
# ...
def __repr__(self) -> str: def __repr__(self) -> str:
try: try:
return pformat(self) return pformat(self)
@ -218,6 +220,13 @@ class Struct(
) )
return _Struct.__repr__(self) return _Struct.__repr__(self)
# __repr__ = pformat
# __str__ = __repr__ = pformat
# TODO: use a pprint.PrettyPrinter instance around ONLY rendering
# inside a known tty?
# def __repr__(self) -> str:
# ...
def copy( def copy(
self, self,
update: dict | None = None, update: dict | None = None,
@ -267,13 +276,15 @@ class Struct(
fi.type(getattr(self, fi.name)), fi.type(getattr(self, fi.name)),
) )
# TODO: make a mod func instead and just point to it here for
# method impl?
def __sub__( def __sub__(
self, self,
other: Struct, other: Struct,
) -> DiffDump[tuple[str, Any, Any]]: ) -> DiffDump[tuple[str, Any, Any]]:
''' '''
Compare fields/items key-wise and return a ``DiffDump`` Compare fields/items key-wise and return a `DiffDump`
for easy visual REPL comparison B) for easy visual REPL comparison B)
''' '''
@ -290,3 +301,42 @@ class Struct(
)) ))
return diffs return diffs
@classmethod
def fields_diff(
cls,
other: dict|Struct,
) -> DiffDump[tuple[str, Any, Any]]:
'''
Very similar to `PrettyStruct.__sub__()` except accepts an
input `other: dict` (presumably that would normally be called
like `Struct(**other)`) which returns a `DiffDump` of the
fields of the struct and the `dict`'s fields.
'''
nullish = object()
consumed: dict = other.copy()
diffs: DiffDump[tuple[str, Any, Any]] = DiffDump()
for fi in structs.fields(cls):
field_name: str = fi.name
# ours: Any = getattr(self, field_name)
theirs: Any = consumed.pop(field_name, nullish)
if theirs is nullish:
diffs.append((
field_name,
f'{fi.type!r}',
'NOT-DEFINED in `other: dict`',
))
# when there are lingering fields in `other` that this struct
# DOES NOT define we also append those.
if consumed:
for k, v in consumed.items():
diffs.append((
k,
f'NOT-DEFINED for `{cls.__name__}`',
f'`other: dict` has value = {v!r}',
))
return diffs