Skip to content

Commit 7dcb0d5

Browse files
authored
fix __pretty__ get (#52)
* fix __pretty__ get needs tests * catch errors in pretty print
1 parent 7482e87 commit 7dcb0d5

File tree

4 files changed

+53
-7
lines changed

4 files changed

+53
-7
lines changed

devtools/debug.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,22 @@ def str(self, highlight=False) -> str:
4242
s = ''
4343
if self.name:
4444
s = sformat(self.name, sformat.blue, apply=highlight) + ': '
45-
s += pformat(self.value, indent=4, highlight=highlight)
46-
suffix = (
47-
' ({0.value.__class__.__name__}) {1}'
48-
.format(self, ' '.join('{}={}'.format(k, v) for k, v in self.extra))
49-
.rstrip(' ') # trailing space if extra is empty
45+
46+
suffix = sformat(
47+
' ({.value.__class__.__name__}){}'.format(self, ''.join(' {}={}'.format(k, v) for k, v in self.extra)),
48+
sformat.dim,
49+
apply=highlight
5050
)
51-
s += sformat(suffix, sformat.dim, apply=highlight)
51+
try:
52+
s += pformat(self.value, indent=4, highlight=highlight)
53+
except Exception as exc:
54+
s += '{!r}{}\n {}'.format(
55+
self.value,
56+
suffix,
57+
sformat('!!! error pretty printing value: {!r}'.format(exc), sformat.yellow, apply=highlight),
58+
)
59+
else:
60+
s += suffix
5261
return s
5362

5463
def __str__(self) -> str:

devtools/prettier.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import io
22
import os
33
import textwrap
4+
import warnings
45
from collections import OrderedDict
56
from collections.abc import Generator
67
from typing import Any, Union
@@ -89,10 +90,13 @@ def _format(self, value: Any, indent_current: int, indent_first: bool):
8990
self._stream.write(indent_current * self._c)
9091

9192
pretty_func = getattr(value, '__pretty__', None)
92-
if pretty_func and not isinstance(value, MockCall):
93+
if pretty_func and callable(pretty_func) and not isinstance(value, MockCall):
9394
try:
9495
gen = pretty_func(fmt=fmt, skip_exc=SkipPretty)
9596
self._render_pretty(gen, indent_current)
97+
except TypeError as e:
98+
if e.args != ("__pretty__() missing 1 required positional argument: 'self'",):
99+
raise
96100
except SkipPretty:
97101
pass
98102
else:

tests/test_custom_pretty.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,19 @@ def __pretty__(self, fmt, **kwargs):
4747
my_cls = CustomCls()
4848
v = pformat(my_cls)
4949
assert v == "'xxx'123"
50+
51+
52+
def test_pretty_not_func():
53+
class Foobar:
54+
__pretty__ = 1
55+
56+
assert '<locals>.Foobar object' in pformat(Foobar())
57+
58+
59+
def test_pretty_class():
60+
class Foobar:
61+
def __pretty__(self, fmt, **kwargs):
62+
yield 'xxx'
63+
64+
assert pformat(Foobar()) == 'xxx'
65+
assert pformat(Foobar).endswith(".test_pretty_class.<locals>.Foobar'>")

tests/test_main.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ def test_small_call_frame_warning():
9595
2,
9696
3,
9797
)
98+
print(str(v))
9899
assert re.sub(r':\d{2,}', ':<line no>', str(v)) == (
99100
"tests/test_main.py:<line no> test_small_call_frame_warning "
100101
"(error passing code, found <class '_ast.Tuple'> not Call)\n"
@@ -239,3 +240,19 @@ def test_starred_kwargs():
239240
' foo: 1 (int)',
240241
' bar: 2 (int)',
241242
}
243+
244+
245+
def test_pretty_error():
246+
class BadPretty:
247+
def __getattr__(self, item):
248+
raise RuntimeError('this is an error')
249+
250+
b = BadPretty()
251+
v = debug.format(b)
252+
s = re.sub(r':\d{2,}', ':<line no>', str(v))
253+
s = re.sub(r'0x[0-9a-f]+', '0x000', s)
254+
assert s == (
255+
"tests/test_main.py:<line no> test_pretty_error\n"
256+
" b: <tests.test_main.test_pretty_error.<locals>.BadPretty object at 0x000> (BadPretty)\n"
257+
" !!! error pretty printing value: RuntimeError('this is an error')"
258+
)

0 commit comments

Comments
 (0)