72 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			72 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Python
		
	
	
	
| """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
 | |
| 
 | |
|     def repr(self, x):
 | |
|         return self._callhelper(repr.Repr.repr, self, x)
 | |
| 
 | |
|     def repr_instance(self, x, level):
 | |
|         return self._callhelper(__builtin__.repr, x)
 | |
|         
 | |
|     def _callhelper(self, call, x, *args):
 | |
|         try:
 | |
|             # Try the vanilla repr and make sure that the result is a string
 | |
|             s = call(x, *args)
 | |
|         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
 | |
| 
 | |
| 
 | |
| _repr = SafeRepr().repr
 |