Show More
@@ -202,7 +202,7 b' class FormatterABC(with_metaclass(abc.ABCMeta, object)):' | |||||
202 | """ |
|
202 | """ | |
203 | try: |
|
203 | try: | |
204 | return repr(obj) |
|
204 | return repr(obj) | |
205 |
except |
|
205 | except Exception: | |
206 | return None |
|
206 | return None | |
207 |
|
207 | |||
208 |
|
208 | |||
@@ -465,10 +465,7 b' class PlainTextFormatter(BaseFormatter):' | |||||
465 | def __call__(self, obj): |
|
465 | def __call__(self, obj): | |
466 | """Compute the pretty representation of the object.""" |
|
466 | """Compute the pretty representation of the object.""" | |
467 | if not self.pprint: |
|
467 | if not self.pprint: | |
468 | try: |
|
468 | return pretty._safe_repr(obj) | |
469 | return repr(obj) |
|
|||
470 | except TypeError: |
|
|||
471 | return '' |
|
|||
472 | else: |
|
469 | else: | |
473 | # This uses use StringIO, as cStringIO doesn't handle unicode. |
|
470 | # This uses use StringIO, as cStringIO doesn't handle unicode. | |
474 | stream = StringIO() |
|
471 | stream = StringIO() |
@@ -125,6 +125,60 b" __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter'," | |||||
125 |
|
125 | |||
126 | _re_pattern_type = type(re.compile('')) |
|
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 | def pretty(obj, verbose=False, max_width=79, newline='\n'): |
|
183 | def pretty(obj, verbose=False, max_width=79, newline='\n'): | |
130 | """ |
|
184 | """ | |
@@ -346,7 +400,7 b' class RepresentationPrinter(PrettyPrinter):' | |||||
346 | self.stack.append(obj_id) |
|
400 | self.stack.append(obj_id) | |
347 | self.begin_group() |
|
401 | self.begin_group() | |
348 | try: |
|
402 | try: | |
349 | obj_class = getattr(obj, '__class__', None) or type(obj) |
|
403 | obj_class = _safe_getattr(obj, '__class__', None) or type(obj) | |
350 | # First try to find registered singleton printers for the type. |
|
404 | # First try to find registered singleton printers for the type. | |
351 | try: |
|
405 | try: | |
352 | printer = self.singleton_pprinters[obj_id] |
|
406 | printer = self.singleton_pprinters[obj_id] | |
@@ -388,8 +442,8 b' class RepresentationPrinter(PrettyPrinter):' | |||||
388 | class is not in the registry. Successful matches will be moved to the |
|
442 | class is not in the registry. Successful matches will be moved to the | |
389 | regular type registry for future use. |
|
443 | regular type registry for future use. | |
390 | """ |
|
444 | """ | |
391 | mod = getattr(cls, '__module__', None) |
|
445 | mod = _safe_getattr(cls, '__module__', None) | |
392 | name = getattr(cls, '__name__', None) |
|
446 | name = _safe_getattr(cls, '__name__', None) | |
393 | key = (mod, name) |
|
447 | key = (mod, name) | |
394 | printer = None |
|
448 | printer = None | |
395 | if key in self.deferred_pprinters: |
|
449 | if key in self.deferred_pprinters: | |
@@ -492,10 +546,10 b' def _default_pprint(obj, p, cycle):' | |||||
492 | The default print function. Used if an object does not provide one and |
|
546 | The default print function. Used if an object does not provide one and | |
493 | it's none of the builtin objects. |
|
547 | it's none of the builtin objects. | |
494 | """ |
|
548 | """ | |
495 | klass = getattr(obj, '__class__', None) or type(obj) |
|
549 | klass = _safe_getattr(obj, '__class__', None) or type(obj) | |
496 | if getattr(klass, '__repr__', None) not in _baseclass_reprs: |
|
550 | if _safe_getattr(klass, '__repr__', None) not in _baseclass_reprs: | |
497 | # A user-provided repr. Find newlines and replace them with p.break_() |
|
551 | # A user-provided repr. Find newlines and replace them with p.break_() | |
498 | output = repr(obj) |
|
552 | output = _safe_repr(obj) | |
499 | for idx,output_line in enumerate(output.splitlines()): |
|
553 | for idx,output_line in enumerate(output.splitlines()): | |
500 | if idx: |
|
554 | if idx: | |
501 | p.break_() |
|
555 | p.break_() | |
@@ -658,7 +712,7 b' def _re_pattern_pprint(obj, p, cycle):' | |||||
658 |
|
712 | |||
659 | def _type_pprint(obj, p, cycle): |
|
713 | def _type_pprint(obj, p, cycle): | |
660 | """The pprint for classes and types.""" |
|
714 | """The pprint for classes and types.""" | |
661 | mod = getattr(obj, '__module__', None) |
|
715 | mod = _safe_getattr(obj, '__module__', None) | |
662 | if mod is None: |
|
716 | if mod is None: | |
663 | # Heap allocated types might not have the module attribute, |
|
717 | # Heap allocated types might not have the module attribute, | |
664 | # and others may set it to None. |
|
718 | # and others may set it to None. | |
@@ -673,7 +727,7 b' def _type_pprint(obj, p, cycle):' | |||||
673 |
|
727 | |||
674 | def _repr_pprint(obj, p, cycle): |
|
728 | def _repr_pprint(obj, p, cycle): | |
675 | """A pprint that just redirects to the normal repr function.""" |
|
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 | def _function_pprint(obj, p, cycle): |
|
733 | def _function_pprint(obj, p, cycle): |
@@ -74,6 +74,10 b' class BreakingReprParent(object):' | |||||
74 | with p.group(4,"TG: ",":"): |
|
74 | with p.group(4,"TG: ",":"): | |
75 | p.pretty(BreakingRepr()) |
|
75 | p.pretty(BreakingRepr()) | |
76 |
|
76 | |||
|
77 | class BadRepr(object): | |||
|
78 | ||||
|
79 | def __repr__(self): | |||
|
80 | return 1/0 | |||
77 |
|
81 | |||
78 |
|
82 | |||
79 | def test_indentation(): |
|
83 | def test_indentation(): | |
@@ -150,4 +154,31 b' def test_pprint_break_repr():' | |||||
150 | """ |
|
154 | """ | |
151 | output = pretty.pretty(BreakingReprParent()) |
|
155 | output = pretty.pretty(BreakingReprParent()) | |
152 | expected = "TG: Breaking(\n ):" |
|
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