Merge pull request #5603 from bluetech/saferepr-simplify
Simplify SafeRepr a bit
This commit is contained in:
		
						commit
						9258fd1296
					
				|  | @ -0,0 +1 @@ | ||||||
|  | Simplified internal ``SafeRepr`` class and removed some dead code. | ||||||
|  | @ -2,57 +2,48 @@ import pprint | ||||||
| import reprlib | import reprlib | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _call_and_format_exception(call, x, *args): | def _format_repr_exception(exc, obj): | ||||||
|     try: |  | ||||||
|         # Try the vanilla repr and make sure that the result is a string |  | ||||||
|         return call(x, *args) |  | ||||||
|     except Exception as exc: |  | ||||||
|     exc_name = type(exc).__name__ |     exc_name = type(exc).__name__ | ||||||
|     try: |     try: | ||||||
|         exc_info = str(exc) |         exc_info = str(exc) | ||||||
|     except Exception: |     except Exception: | ||||||
|         exc_info = "unknown" |         exc_info = "unknown" | ||||||
|     return '<[{}("{}") raised in repr()] {} object at 0x{:x}>'.format( |     return '<[{}("{}") raised in repr()] {} object at 0x{:x}>'.format( | ||||||
|             exc_name, exc_info, x.__class__.__name__, id(x) |         exc_name, exc_info, obj.__class__.__name__, id(obj) | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def _ellipsize(s, maxsize): | ||||||
|  |     if len(s) > maxsize: | ||||||
|  |         i = max(0, (maxsize - 3) // 2) | ||||||
|  |         j = max(0, maxsize - 3 - i) | ||||||
|  |         return s[:i] + "..." + s[len(s) - j :] | ||||||
|  |     return s | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class SafeRepr(reprlib.Repr): | class SafeRepr(reprlib.Repr): | ||||||
|     """subclass of repr.Repr that limits the resulting size of repr() |     """subclass of repr.Repr that limits the resulting size of repr() | ||||||
|     and includes information on exceptions raised during the call. |     and includes information on exceptions raised during the call. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|  |     def __init__(self, maxsize): | ||||||
|  |         super().__init__() | ||||||
|  |         self.maxstring = maxsize | ||||||
|  |         self.maxsize = maxsize | ||||||
|  | 
 | ||||||
|     def repr(self, x): |     def repr(self, x): | ||||||
|         return self._callhelper(reprlib.Repr.repr, self, x) |         try: | ||||||
| 
 |             s = super().repr(x) | ||||||
|     def repr_unicode(self, x, level): |         except Exception as exc: | ||||||
|         # Strictly speaking wrong on narrow builds |             s = _format_repr_exception(exc, x) | ||||||
|         def repr(u): |         return _ellipsize(s, self.maxsize) | ||||||
|             if "'" not in u: |  | ||||||
|                 return "'%s'" % u |  | ||||||
|             elif '"' not in u: |  | ||||||
|                 return '"%s"' % u |  | ||||||
|             else: |  | ||||||
|                 return "'%s'" % u.replace("'", r"\'") |  | ||||||
| 
 |  | ||||||
|         s = repr(x[: self.maxstring]) |  | ||||||
|         if len(s) > self.maxstring: |  | ||||||
|             i = max(0, (self.maxstring - 3) // 2) |  | ||||||
|             j = max(0, self.maxstring - 3 - i) |  | ||||||
|             s = repr(x[:i] + x[len(x) - j :]) |  | ||||||
|             s = s[:i] + "..." + s[len(s) - j :] |  | ||||||
|         return s |  | ||||||
| 
 | 
 | ||||||
|     def repr_instance(self, x, level): |     def repr_instance(self, x, level): | ||||||
|         return self._callhelper(repr, x) |         try: | ||||||
| 
 |             s = repr(x) | ||||||
|     def _callhelper(self, call, x, *args): |         except Exception as exc: | ||||||
|         s = _call_and_format_exception(call, x, *args) |             s = _format_repr_exception(exc, x) | ||||||
|         if len(s) > self.maxsize: |         return _ellipsize(s, self.maxsize) | ||||||
|             i = max(0, (self.maxsize - 3) // 2) |  | ||||||
|             j = max(0, self.maxsize - 3 - i) |  | ||||||
|             s = s[:i] + "..." + s[len(s) - j :] |  | ||||||
|         return s |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def safeformat(obj): | def safeformat(obj): | ||||||
|  | @ -60,7 +51,10 @@ def safeformat(obj): | ||||||
|     Failing __repr__ functions of user instances will be represented |     Failing __repr__ functions of user instances will be represented | ||||||
|     with a short exception info. |     with a short exception info. | ||||||
|     """ |     """ | ||||||
|     return _call_and_format_exception(pprint.pformat, obj) |     try: | ||||||
|  |         return pprint.pformat(obj) | ||||||
|  |     except Exception as exc: | ||||||
|  |         return _format_repr_exception(exc, obj) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def saferepr(obj, maxsize=240): | def saferepr(obj, maxsize=240): | ||||||
|  | @ -70,9 +64,4 @@ def saferepr(obj, maxsize=240): | ||||||
|     care to never raise exceptions itself.  This function is a wrapper |     care to never raise exceptions itself.  This function is a wrapper | ||||||
|     around the Repr/reprlib functionality of the standard 2.6 lib. |     around the Repr/reprlib functionality of the standard 2.6 lib. | ||||||
|     """ |     """ | ||||||
|     # review exception handling |     return SafeRepr(maxsize).repr(obj) | ||||||
|     srepr = SafeRepr() |  | ||||||
|     srepr.maxstring = maxsize |  | ||||||
|     srepr.maxsize = maxsize |  | ||||||
|     srepr.maxother = 160 |  | ||||||
|     return srepr.repr(obj) |  | ||||||
|  |  | ||||||
|  | @ -45,10 +45,21 @@ def test_exceptions(): | ||||||
|     assert "unknown" in s2 |     assert "unknown" in s2 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def test_buggy_builtin_repr(): | ||||||
|  |     # Simulate a case where a repr for a builtin raises. | ||||||
|  |     # reprlib dispatches by type name, so use "int". | ||||||
|  | 
 | ||||||
|  |     class int: | ||||||
|  |         def __repr__(self): | ||||||
|  |             raise ValueError("Buggy repr!") | ||||||
|  | 
 | ||||||
|  |     assert "Buggy" in saferepr(int()) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def test_big_repr(): | def test_big_repr(): | ||||||
|     from _pytest._io.saferepr import SafeRepr |     from _pytest._io.saferepr import SafeRepr | ||||||
| 
 | 
 | ||||||
|     assert len(saferepr(range(1000))) <= len("[" + SafeRepr().maxlist * "1000" + "]") |     assert len(saferepr(range(1000))) <= len("[" + SafeRepr(0).maxlist * "1000" + "]") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def test_repr_on_newstyle(): | def test_repr_on_newstyle(): | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue