python-devtools
python-devtools copied to clipboard
`inspect` / `vars` function
(I thought this was already an issue, but I checked and it seems it only existed in my head)
I want a way to pretty-print pertinent attributes of an object, like vars(...)
but more intelligent - in particular it should try to inspect __slots__
if __dict__
is not available.
This might be as simple as sugar around the following POC, but there are probably edge cases I haven't thought about.
I guess we should expose this via debug.inspect()
.
Rough demo code of what I mean
from __future__ import annotations
from devtools import debug
ignored_attributes = {
'__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '__slots__',
}
class DebugInspect:
__slots__ = ('obj',)
def __init__(self, obj: Any):
self.obj = obj
def __pretty__(self, fmt: Callable[[Any], Any], **kwargs: Any) -> Generator[Any, None, None]:
yield self.obj.__class__.__name__ + '('
yield 1
# use __dict__ if possible to maintain order, also should be slightly faster
obj_dict = getattr(self.obj, '__dict__', None)
if obj_dict is not None:
for name, value in obj_dict.items():
yield name + '='
yield fmt(value)
yield ','
yield 0
else:
for name in dir(self.obj):
if name not in ignored_attributes:
yield name + '='
yield fmt(getattr(self.obj, name))
yield ','
yield 0
yield -1
# closing bracket to keep it looking a bit like python
yield ')'
class Foo:
def __init__(self):
self.x = 1
self.y = 2
self._private = 3
self.__custom_dunder__ = 4
class Bar:
__slots__ = 'x', 'y', '_private', '__custom_dunder__'
def __init__(self):
self.x = 1
self.y = 2
self._private = 3
self.__custom_dunder__ = 4
f = Foo()
debug(DebugInspect(f))
b = Bar()
debug(DebugInspect(b))
prints:
foobar.py:61 <module>
DebugInspect(f): Foo(
x=1,
y=2,
_private=3,
__custom_dunder__=4,
) (DebugInspect)
foobar.py:64 <module>
DebugInspect(b): Bar(
__custom_dunder__=4,
_private=3,
x=1,
y=2,
) (DebugInspect)