Show More
@@ -202,7 +202,7 b' class FormatterABC(with_metaclass(abc.ABCMeta, object)):' | |||
|
202 | 202 | """ |
|
203 | 203 | try: |
|
204 | 204 | return repr(obj) |
|
205 |
except |
|
|
205 | except Exception: | |
|
206 | 206 | return None |
|
207 | 207 | |
|
208 | 208 | |
@@ -465,10 +465,7 b' class PlainTextFormatter(BaseFormatter):' | |||
|
465 | 465 | def __call__(self, obj): |
|
466 | 466 | """Compute the pretty representation of the object.""" |
|
467 | 467 | if not self.pprint: |
|
468 | try: | |
|
469 | return repr(obj) | |
|
470 | except TypeError: | |
|
471 | return '' | |
|
468 | return pretty._safe_repr(obj) | |
|
472 | 469 | else: |
|
473 | 470 | # This uses use StringIO, as cStringIO doesn't handle unicode. |
|
474 | 471 | stream = StringIO() |
@@ -125,6 +125,60 b" __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter'," | |||
|
125 | 125 | |
|
126 | 126 | _re_pattern_type = type(re.compile('')) |
|
127 | 127 | |
|
128 | def _failed_repr(obj, e): | |
|
129 | """Render a failed repr, including the exception. | |
|
130 | ||
|
131 | Tries to get exception and type info | |
|
132 | """ | |
|
133 | # get exception name | |
|
134 | if e.__class__.__module__ in ('exceptions', 'builtins'): | |
|
135 | ename = e.__class__.__name__ | |
|
136 | else: | |
|
137 | ename = '{}.{}'.format( | |
|
138 | e.__class__.__module__, | |
|
139 | e.__class__.__name__, | |
|
140 | ) | |
|
141 | # and exception string, which sometimes fails | |
|
142 | # (usually due to unicode error message) | |
|
143 | try: | |
|
144 | estr = str(e) | |
|
145 | except Exception: | |
|
146 | estr = "unknown" | |
|
147 | ||
|
148 | # and class name | |
|
149 | try: | |
|
150 | klass = _safe_getattr(obj, '__class__', None) or type(obj) | |
|
151 | mod = _safe_getattr(klass, '__module__', None) | |
|
152 | if mod in (None, '__builtin__', 'builtins', 'exceptions'): | |
|
153 | classname = klass.__name__ | |
|
154 | else: | |
|
155 | classname = mod + '.' + klass.__name__ | |
|
156 | except Exception: | |
|
157 | # this may be paranoid, but we already know repr is broken | |
|
158 | classname = "unknown type" | |
|
159 | ||
|
160 | # the informative repr | |
|
161 | return "<repr(<{} at 0x{:x}>) failed: {}: {}>".format( | |
|
162 | classname, id(obj), ename, estr, | |
|
163 | ) | |
|
164 | ||
|
165 | def _safe_repr(obj): | |
|
166 | """Don't assume repr is not broken.""" | |
|
167 | try: | |
|
168 | return repr(obj) | |
|
169 | except Exception as e: | |
|
170 | return _failed_repr(obj, e) | |
|
171 | ||
|
172 | def _safe_getattr(obj, attr, default=None): | |
|
173 | """Safe version of getattr. | |
|
174 | ||
|
175 | Same as getattr, but will return ``default`` on any Exception, | |
|
176 | rather than raising. | |
|
177 | """ | |
|
178 | try: | |
|
179 | return getattr(obj, attr, default) | |
|
180 | except Exception: | |
|
181 | return default | |
|
128 | 182 | |
|
129 | 183 | def pretty(obj, verbose=False, max_width=79, newline='\n'): |
|
130 | 184 | """ |
@@ -346,7 +400,7 b' class RepresentationPrinter(PrettyPrinter):' | |||
|
346 | 400 | self.stack.append(obj_id) |
|
347 | 401 | self.begin_group() |
|
348 | 402 | try: |
|
349 | obj_class = getattr(obj, '__class__', None) or type(obj) | |
|
403 | obj_class = _safe_getattr(obj, '__class__', None) or type(obj) | |
|
350 | 404 | # First try to find registered singleton printers for the type. |
|
351 | 405 | try: |
|
352 | 406 | printer = self.singleton_pprinters[obj_id] |
@@ -388,8 +442,8 b' class RepresentationPrinter(PrettyPrinter):' | |||
|
388 | 442 | class is not in the registry. Successful matches will be moved to the |
|
389 | 443 | regular type registry for future use. |
|
390 | 444 | """ |
|
391 | mod = getattr(cls, '__module__', None) | |
|
392 | name = getattr(cls, '__name__', None) | |
|
445 | mod = _safe_getattr(cls, '__module__', None) | |
|
446 | name = _safe_getattr(cls, '__name__', None) | |
|
393 | 447 | key = (mod, name) |
|
394 | 448 | printer = None |
|
395 | 449 | if key in self.deferred_pprinters: |
@@ -492,10 +546,10 b' def _default_pprint(obj, p, cycle):' | |||
|
492 | 546 | The default print function. Used if an object does not provide one and |
|
493 | 547 | it's none of the builtin objects. |
|
494 | 548 | """ |
|
495 | klass = getattr(obj, '__class__', None) or type(obj) | |
|
496 | if getattr(klass, '__repr__', None) not in _baseclass_reprs: | |
|
549 | klass = _safe_getattr(obj, '__class__', None) or type(obj) | |
|
550 | if _safe_getattr(klass, '__repr__', None) not in _baseclass_reprs: | |
|
497 | 551 | # A user-provided repr. Find newlines and replace them with p.break_() |
|
498 | output = repr(obj) | |
|
552 | output = _safe_repr(obj) | |
|
499 | 553 | for idx,output_line in enumerate(output.splitlines()): |
|
500 | 554 | if idx: |
|
501 | 555 | p.break_() |
@@ -658,7 +712,7 b' def _re_pattern_pprint(obj, p, cycle):' | |||
|
658 | 712 | |
|
659 | 713 | def _type_pprint(obj, p, cycle): |
|
660 | 714 | """The pprint for classes and types.""" |
|
661 | mod = getattr(obj, '__module__', None) | |
|
715 | mod = _safe_getattr(obj, '__module__', None) | |
|
662 | 716 | if mod is None: |
|
663 | 717 | # Heap allocated types might not have the module attribute, |
|
664 | 718 | # and others may set it to None. |
@@ -673,7 +727,7 b' def _type_pprint(obj, p, cycle):' | |||
|
673 | 727 | |
|
674 | 728 | def _repr_pprint(obj, p, cycle): |
|
675 | 729 | """A pprint that just redirects to the normal repr function.""" |
|
676 | p.text(repr(obj)) | |
|
730 | p.text(_safe_repr(obj)) | |
|
677 | 731 | |
|
678 | 732 | |
|
679 | 733 | def _function_pprint(obj, p, cycle): |
@@ -74,6 +74,10 b' class BreakingReprParent(object):' | |||
|
74 | 74 | with p.group(4,"TG: ",":"): |
|
75 | 75 | p.pretty(BreakingRepr()) |
|
76 | 76 | |
|
77 | class BadRepr(object): | |
|
78 | ||
|
79 | def __repr__(self): | |
|
80 | return 1/0 | |
|
77 | 81 | |
|
78 | 82 | |
|
79 | 83 | def test_indentation(): |
@@ -150,4 +154,31 b' def test_pprint_break_repr():' | |||
|
150 | 154 | """ |
|
151 | 155 | output = pretty.pretty(BreakingReprParent()) |
|
152 | 156 | expected = "TG: Breaking(\n ):" |
|
153 | nt.assert_equal(output, expected) No newline at end of file | |
|
157 | nt.assert_equal(output, expected) | |
|
158 | ||
|
159 | def test_bad_repr(): | |
|
160 | """Don't raise, even when repr fails""" | |
|
161 | output = pretty.pretty(BadRepr()) | |
|
162 | nt.assert_in("failed", output) | |
|
163 | nt.assert_in("at 0x", output) | |
|
164 | nt.assert_in("test_pretty", output) | |
|
165 | ||
|
166 | class BadException(Exception): | |
|
167 | def __str__(self): | |
|
168 | return -1 | |
|
169 | ||
|
170 | class ReallyBadRepr(object): | |
|
171 | __module__ = 1 | |
|
172 | @property | |
|
173 | def __class__(self): | |
|
174 | raise ValueError("I am horrible") | |
|
175 | ||
|
176 | def __repr__(self): | |
|
177 | raise BadException() | |
|
178 | ||
|
179 | def test_really_bad_repr(): | |
|
180 | output = pretty.pretty(ReallyBadRepr()) | |
|
181 | nt.assert_in("failed", output) | |
|
182 | nt.assert_in("BadException: unknown", output) | |
|
183 | nt.assert_in("unknown type", output) | |
|
184 | No newline at end of file |
General Comments 0
You need to be logged in to leave comments.
Login now