2008-08-16 23:26:59 +08:00
|
|
|
"""Defines a safe repr function. This will always return a string of "reasonable" length
|
|
|
|
no matter what the object does in it's own repr function. Let's examine what can go wrong
|
|
|
|
in an arbitrary repr function.
|
|
|
|
The default repr will return something like (on Win32 anyway):
|
|
|
|
<foo.bar object at 0x008D5650>. Well behaved user-defined repr() methods will do similar.
|
|
|
|
The usual expectation is that repr will return a single line string.
|
|
|
|
|
|
|
|
1. However, the repr method can raise an exception of an arbitrary type.
|
|
|
|
|
|
|
|
Also, the return value may not be as expected:
|
|
|
|
2. The return value may not be a string!
|
|
|
|
3. The return value may not be a single line string, it may contain line breaks.
|
|
|
|
4. The method may enter a loop and never return.
|
|
|
|
5. The return value may be enormous, eg range(100000)
|
|
|
|
|
|
|
|
The standard library has a nice implementation in the repr module that will do the job,
|
|
|
|
but the exception
|
|
|
|
handling is silent, so the the output contains no clue that repr() call raised an
|
|
|
|
exception. I would like to be told if repr raises an exception, it's a serious error, so
|
|
|
|
a sublass of repr overrides the method that does repr for class instances."""
|
|
|
|
|
|
|
|
|
|
|
|
import repr
|
|
|
|
import __builtin__
|
|
|
|
|
|
|
|
|
|
|
|
class SafeRepr(repr.Repr):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
repr.Repr.__init__(self, *args, **kwargs)
|
|
|
|
# Do we need a commandline switch for this?
|
|
|
|
self.maxstring = 240 # 3 * 80 chars
|
|
|
|
self.maxother = 160 # 2 * 80 chars
|
2008-08-21 17:48:46 +08:00
|
|
|
|
|
|
|
def repr(self, x):
|
|
|
|
return self._callhelper(repr.Repr.repr, self, x)
|
|
|
|
|
2008-08-16 23:26:59 +08:00
|
|
|
def repr_instance(self, x, level):
|
2008-08-21 17:48:46 +08:00
|
|
|
return self._callhelper(__builtin__.repr, x)
|
|
|
|
|
|
|
|
def _callhelper(self, call, x, *args):
|
2008-08-16 23:26:59 +08:00
|
|
|
try:
|
|
|
|
# Try the vanilla repr and make sure that the result is a string
|
2008-08-21 17:48:46 +08:00
|
|
|
s = call(x, *args)
|
2008-08-16 23:26:59 +08:00
|
|
|
except (KeyboardInterrupt, MemoryError, SystemExit):
|
|
|
|
raise
|
|
|
|
except Exception ,e:
|
|
|
|
try:
|
|
|
|
exc_name = e.__class__.__name__
|
|
|
|
except:
|
|
|
|
exc_name = 'unknown'
|
|
|
|
try:
|
|
|
|
exc_info = str(e)
|
|
|
|
except:
|
|
|
|
exc_info = 'unknown'
|
|
|
|
return '<[%s("%s") raised in repr()] %s object at 0x%x>' % \
|
|
|
|
(exc_name, exc_info, x.__class__.__name__, id(x))
|
|
|
|
except:
|
|
|
|
try:
|
|
|
|
name = x.__class__.__name__
|
|
|
|
except:
|
|
|
|
name = 'unknown'
|
|
|
|
return '<[unknown exception raised in repr()] %s object at 0x%x>' % \
|
|
|
|
(name, id(x))
|
|
|
|
if len(s) > self.maxstring:
|
|
|
|
i = max(0, (self.maxstring-3)//2)
|
|
|
|
j = max(0, self.maxstring-3-i)
|
|
|
|
s = s[:i] + '...' + s[len(s)-j:]
|
|
|
|
return s
|
|
|
|
|
2008-08-21 17:48:46 +08:00
|
|
|
|
2008-08-16 23:26:59 +08:00
|
|
|
_repr = SafeRepr().repr
|