2020-07-03 13:28:36 -04:00
"""
Utilities for turning objects into human - readable strings .
This module has been ported to Python 3.
"""
2020-07-02 14:26:35 -04:00
from __future__ import division
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
2020-07-06 14:00:02 -04:00
from future . utils import PY2
if PY2 :
from builtins import filter , map , zip , ascii , chr , hex , input , next , oct , open , pow , round , super , bytes , dict , int , list , object , range , str , max , min # noqa: F401
2020-07-02 14:26:35 -04:00
import os
from reprlib import Repr
2006-11-30 15:22:25 -07:00
2019-08-13 16:55:40 -04:00
class BetterRepr ( Repr , object ) :
2006-11-30 15:22:25 -07:00
def __init__ ( self ) :
Repr . __init__ ( self )
2007-05-25 15:49:57 -07:00
# Note: These levels can get adjusted dynamically! My goal is to get more info when printing important debug stuff like exceptions and stack traces and less info when logging normal events. --Zooko 2000-10-14
self . maxlevel = 6
self . maxdict = 6
self . maxlist = 6
self . maxtuple = 6
self . maxstring = 300
self . maxother = 300
2006-11-30 15:22:25 -07:00
def repr_function ( self , obj , level ) :
2020-07-02 14:26:35 -04:00
if hasattr ( obj , ' __code__ ' ) :
return ' < ' + obj . __name__ + ' () at ' + os . path . basename ( obj . __code__ . co_filename ) + ' : ' + str ( obj . __code__ . co_firstlineno ) + ' > '
2006-11-30 15:22:25 -07:00
else :
2020-07-02 14:26:35 -04:00
return ' < ' + obj . __name__ + ' () at (builtin) '
2006-11-30 15:22:25 -07:00
def repr_instance_method ( self , obj , level ) :
2020-07-02 14:26:35 -04:00
if hasattr ( obj , ' __code__ ' ) :
return ' < ' + obj . __self__ . __class__ . __name__ + ' . ' + obj . __func__ . __name__ + ' () at ' + os . path . basename ( obj . __func__ . __code__ . co_filename ) + ' : ' + str ( obj . __func__ . __code__ . co_firstlineno ) + ' > '
2006-11-30 15:22:25 -07:00
else :
2020-07-02 14:26:35 -04:00
return ' < ' + obj . __self__ . __class__ . __name__ + ' . ' + obj . __func__ . __name__ + ' () at (builtin) '
2006-11-30 15:22:25 -07:00
def repr_long ( self , obj , level ) :
2019-04-18 13:50:21 +02:00
s = repr ( obj ) # XXX Hope this isn't too slow...
2006-11-30 15:22:25 -07:00
if len ( s ) > self . maxlong :
2020-07-02 14:26:35 -04:00
i = max ( 0 , ( self . maxlong - 3 ) / / 2 )
2006-11-30 15:22:25 -07:00
j = max ( 0 , self . maxlong - 3 - i )
s = s [ : i ] + ' ... ' + s [ len ( s ) - j : ]
if s [ - 1 ] == ' L ' :
return s [ : - 1 ]
return s
def repr_instance ( self , obj , level ) :
"""
If it is an instance of Exception , format it nicely ( trying to emulate
the format that you see when an exception is actually raised , plus
bracketing ' < ' ' s). If it is an instance of dict call self.repr_dict()
on it . If it is an instance of list call self . repr_list ( ) on it . Else
call Repr . repr_instance ( ) .
"""
2020-07-02 14:26:35 -04:00
if isinstance ( obj , Exception ) :
2006-11-30 15:22:25 -07:00
# Don't cut down exception strings so much.
tms = self . maxstring
self . maxstring = max ( 512 , tms * 4 )
tml = self . maxlist
self . maxlist = max ( 12 , tml * 4 )
try :
if hasattr ( obj , ' args ' ) :
if len ( obj . args ) == 1 :
return ' < ' + obj . __class__ . __name__ + ' : ' + self . repr1 ( obj . args [ 0 ] , level - 1 ) + ' > '
else :
return ' < ' + obj . __class__ . __name__ + ' : ' + self . repr1 ( obj . args , level - 1 ) + ' > '
else :
return ' < ' + obj . __class__ . __name__ + ' > '
finally :
self . maxstring = tms
self . maxlist = tml
if isinstance ( obj , dict ) :
return self . repr_dict ( obj , level )
if isinstance ( obj , list ) :
return self . repr_list ( obj , level )
return Repr . repr_instance ( self , obj , level )
def repr_list ( self , obj , level ) :
"""
copied from standard repr . py and fixed to work on multithreadedly mutating lists .
"""
if level < = 0 : return ' [...] '
n = len ( obj )
myl = obj [ : min ( n , self . maxlist ) ]
s = ' '
for item in myl :
entry = self . repr1 ( item , level - 1 )
if s : s = s + ' , '
s = s + entry
if n > self . maxlist : s = s + ' , ... '
return ' [ ' + s + ' ] '
def repr_dict ( self , obj , level ) :
"""
copied from standard repr . py and fixed to work on multithreadedly mutating dicts .
"""
if level < = 0 : return ' { ...} '
s = ' '
n = len ( obj )
2020-07-02 14:26:35 -04:00
items = list ( obj . items ( ) ) [ : min ( n , self . maxdict ) ]
2006-11-30 15:22:25 -07:00
items . sort ( )
for key , val in items :
entry = self . repr1 ( key , level - 1 ) + ' : ' + self . repr1 ( val , level - 1 )
if s : s = s + ' , '
s = s + entry
if n > self . maxdict : s = s + ' , ... '
return ' { ' + s + ' } '
# This object can be changed by other code updating this module's "brepr"
# variables. This is so that (a) code can use humanreadable with
# "from humanreadable import hr; hr(mything)", and (b) code can override
# humanreadable to provide application-specific human readable output
# (e.g. libbase32's base32id.AbbrevRepr).
brepr = BetterRepr ( )
def hr ( x ) :
return brepr . repr ( x )