import logging
logger = logging.getLogger(__name__)
import types
from types import NoneType, FunctionType, MethodType, ClassType, InstanceType
name_counter = 0
def common_prefix(s1,s2):
if type(s1) is str and type(s2) is str:
prefix = ''
strings = True
else:
prefix = []
strings = False
for c1, c2 in map(None, s1, s2):
if c1 == c2:
if strings:
prefix += c1
else:
prefix.append(c1)
else:
break
return prefix
def postfix_difference(s1, s2):
if type(s1) is str and type(s2) is str:
a, b = '', ''
strings = True
else:
a, b = [], []
strings = False
i = 0
while i < len(s1) and i < len(s2):
if s1[i] != s2[i]:
break
i += 1
while i < len(s1) or i < len(s2):
if i < len(s1):
if strings:
a += s1[i]
else:
a.append(s1[i])
if i < len(s2):
if strings:
b += s2[i]
else:
b.append(s2[i])
i += 1
return a, b
def getindentation(text):
lines = text.splitlines()
smallest = 1000
for line in lines:
i = 0
while i < len(line) and line[i].isspace():
i += 1
if i < smallest:
smallest = i
return smallest
def indent(text, n=4):
lines = text.splitlines()
lines = [' ' * n + line for line in lines]
return '\n'.join(lines)
def indent_but_first(text, n=4):
lines = text.splitlines()
lines = [lines[0]] + [' ' * n + line for line in lines[1:]]
return '\n'.join(lines)
def dedent(text, n=4):
lines = text.splitlines()
n = getindentation(text)
lines = [line[n:] for line in lines]
return '\n'.join(lines)
[docs]def fit(s, n, filler=' ', lpad=0, rpad=0):
"""
This is equivalent to
filler * lpad + s.ljust(n,filler)[:n] + filler * rpad
"""
s = str(s)
ns = ''
if len(s) < n:
ns = s + filler * (n - len(s))
else:
ns = s[:n]
return filler * lpad + ns + filler * rpad
def rfit(s, n, filler=' ', lpad=0, rpad=0):
s = str(s)
ns = ''
if len(s) < n:
ns = filler * (n - len(s)) + s
else:
ns = s[:n]
return filler * lpad + ns + filler * rpad
[docs]def make_hashable(val):
"""Returns a hashable value of the given value.
Warning: it will not terminate on recursive data structures."""
if type(val) in (int,float,bool,str,long,complex,unicode,frozenset,NoneType,FunctionType,MethodType,ClassType):
return val
elif type(val) in (tuple,list,set):
return (type(val), tuple(make_hashable(item) for item in val))
elif type(val) is dict:
return (type(val), tuple((key, make_hashable(item)) for key, item in val.items()))
elif type(val) in InstanceType:
return (type(val), tuple((attr, make_hashable(getattr(val, attr))) for attr in val.__dict__))
def new_name(base='x',existing=[],upper=False):
global name_counter
if upper:
base = base.upper()
new = base + '_' + str(name_counter)
name_counter += 1
while new in existing:
new = base + '_' + str(name_counter)
name_counter += 1
return new
def print_dict(d,indentation=0, key_width=15, type_width=15, value_width=20, value_delim='"', items='ktv'):
for k in d:
s = ''
if k is not '__builtins__':
if 'k' in items:
s += fit(k,key_width,' ')+' : '
if 't' in items:
if type(d[k]) is types.InstanceType:
s += fit(d[k].__class__.__name__ + ' instance', type_width)
elif type(d[k]) is types.ClassType:
s += fit('class ' + d[k].__name__, type_width)
else:
s += fit(str(type(d[k]).__name__), type_width)
if 'v' in items:
s += " |-> " + value_delim + short_str(d[k], value_width) + value_delim
s = indent(s, indentation)
else:
if 'k' in items:
s += fit(k,key_width,' ')+' : '
if 't' in items:
s += fit('module', type_width)
if 'v' in items:
s += ' |-> ...'
print s
def short_class_name(class_obj):
full_name = str(class_obj)
path = full_name.split('.')
return path[len(path) - 1]
def short_str(obj, max_size=10):
if type(obj) is types.ClassType:
return short_class_name(obj)
return str(obj)[:max_size]
def unzip(list_of_pairs):
if list_of_pairs == [] or list_of_pairs == ():
return ([],[])
r = unzip(list_of_pairs[1:])
return ([list_of_pairs[0][0]] + r[0], [list_of_pairs[0][1]] + r[1])
def raise_exn(e):
raise e
class NameGenerator:
def __init__(self, base_name='x', names_to_avoid=None, upper=False):
if names_to_avoid is None:
names_to_avoid = {}
self.names_to_avoid = dict([(name, None) for name in names_to_avoid])
self.base_name = str(base_name)
if upper:
self.base_name = self.base_name.upper()
self.last_index = 0
def get_new_name(self, base=None, names_to_avoid=None, upper=False):
if base is None:
base = self.base_name
if names_to_avoid is not None:
for key in names_to_avoid:
self.names_to_avoid[key] = None
if upper:
base = str(base).upper()
new_index = self.last_index
new_name = base + '_' + str(new_index)
while new_name in self.names_to_avoid:
new_index += 1
new_name = base + '_' + str(new_index)
self.last_index = new_index + 1
return new_name
def reset(self):
self.last_index = 0
def __call__(self, base=None, names_to_avoid=None, upper=False):
return self.get_new_name(base, names_to_avoid, upper)
class IndexedNameGenerator:
def __init__(self, base_name='x', names_to_avoid=None, upper=False):
if names_to_avoid is None:
names_to_avoid = {}
self.names_to_avoid = dict([(name, None) for name in names_to_avoid])
self.base_name = str(base_name)
if upper:
self.base_name = self.base_name.upper()
self.last_index = 0
def get_new_name(self, base=None, names_to_avoid=None, upper=False):
if base is None:
base = self.base_name
if names_to_avoid is not None:
for key in names_to_avoid:
self.names_to_avoid[key] = None
if upper:
base = str(base).upper()
# new_index = self.last_index
parts = base.split('_')
try:
last = int(parts[len(parts) - 1])
base = '_'.join(parts[:len(parts)-1])
except ValueError:
last = 0
new_index = last + 1
new_name = base + '_' + str(new_index)
while new_name in self.names_to_avoid:
new_index += 1
new_name = base + '_' + str(new_index)
self.last_index = new_index + 1
return new_name
def is_of_atomic_type(obj):
return type(obj) in [types.NoneType, bool, int, float, str]
def is_of_visible_type(obj):
logger.debug("obj = %10s, type(obj) = %s", obj, type(obj))
return is_of_atomic_type(obj) or isinstance(obj, Obj) or type(obj) in [list, tuple, dict]
[docs]def get_attributes(obj):
"""Returns the list of 'visible' attributes of obj."""
if type(obj) in [list, tuple]:
return range(len(obj))
if type(obj) is dict:
return obj.keys()
if isinstance(obj, Obj):
logger.debug("obj %10s is an instance of Obj", obj)
return obj.get_attributes()
logger.debug("obj %10s is neither a list nor a tuple nor a dictionady nor an instance of Obj", obj)
return []
class Obj(object):
__counter = 0
def __init__(self):
Obj.__counter += 1
self.__id = Obj.__counter
def get_attributes(self):
if hasattr(self, '__dir__'):
keys = self.__dir__()
logger.debug("obj.__dir__() = %s", keys)
else:
keys = dir(self)
logger.debug("dir(obj) = %s", keys)
logger.debug("key/visibility = %s", dict((key, is_of_visible_type(getattr(self, key))) for key in keys))
return [key for key in keys
if is_of_visible_type(getattr(self, key)) and key[:2] != '__' and key[:4] != '_Obj']
def __repr__(self):
return "%s_%s" % (self.__class__.__name__, self.__id)
class KeyValuePair:
def __init__(self, key, value):
self.key = key
self.value = value
class GenericPrettyPrinter:
def __init__(self, indent=2, depth=10, white_space=' '):
self.indent = indent
self.depth = depth
self.white_space = white_space
self.delimiters = \
{
list: ('[', ']'),
tuple: ('(', ')'),
set: ('set([', '])'),
frozenset: ('frozenset([', '])'),
dict: ('{', '}')
}
def pprint(self, obj):
print self.pformat(obj)
def pformat(self, obj):
def add_spaces_up_to(s, n):
return s + self.white_space * (n - len(s))
def recursive_pformat(obj, current_indent=0, inhibit_prefix=False, recursion_depth=0, seen_set=None):
if seen_set is None:
seen_set = []
logger.debug("obj = %10s, seen set = %s", obj, seen_set)
if inhibit_prefix:
prefix = ''
else:
prefix = self.white_space * current_indent
if recursion_depth >= self.depth:
return prefix + '...'
logger.debug("type(obj) = %s", str(type(obj)))
if type(obj) in [types.NoneType, bool, int, float]:
return prefix + str(obj)
elif type(obj) is str:
return prefix + "'" + str(obj) + "'"
else:
if obj in seen_set:
logger.debug("obj = %10s, recursion detected", obj)
return prefix + '<rec ref to obj ' + repr(obj) + '>'
item_list = []
first_line_cont = ''
cont_inhibit_prefix = True
if type(obj) in [tuple, list, set, frozenset]:
logger.debug("obj = %10s, is a %s", obj, type(obj))
start_delimiter, end_delimiter = self.delimiters[type(obj)]
item_list = list(obj)
if len(item_list) > 1:
start_delimiter = add_spaces_up_to(start_delimiter, self.indent)
elif type(obj) is dict:
logger.debug("obj = %10s, is a dictionary", obj)
start_delimiter, end_delimiter = self.delimiters[type(obj)]
item_list = [KeyValuePair(key, obj[key]) for key in obj]
if len(item_list) > 1:
start_delimiter = add_spaces_up_to(start_delimiter, self.indent)
elif isinstance(obj, KeyValuePair):
logger.debug("obj = %10s, is a KeyValuePair", obj)
start_delimiter = add_spaces_up_to("'%s':" % obj.key, self.indent)
end_delimiter = ''
item_list = [obj.value]
if len(start_delimiter) > self.indent and not is_of_atomic_type(obj.value):
first_line_cont = '\n'
cont_inhibit_prefix = False
else:
logger.debug("obj = %10s, is an object of class '%s'", obj, obj.__class__.__name__)
start_delimiter = obj.__class__.__name__ + '('
end_delimiter = ')'
item_list = [getattr(obj, attr) for attr in get_attributes(obj)]
logger.debug("dir(obj) = %s" % get_attributes(obj))
if len(start_delimiter) <= self.indent:
if len(item_list) > 1:
start_delimiter = add_spaces_up_to(obj.__class__.__name__ + '(', self.indent)
elif len(item_list) > 1 \
or len(item_list) == 1 \
and not is_of_atomic_type(item_list[0]):
first_line_cont = '\n'
cont_inhibit_prefix = False
lines = prefix + start_delimiter + first_line_cont
i = 0
for item in item_list:
cont_separator = ''
if i < len(item_list) - 1:
cont_separator = ',\n'
lines += recursive_pformat(item,
current_indent + self.indent,
cont_inhibit_prefix and i==0,
recursion_depth + 1,
seen_set + [obj]) + cont_separator
i += 1
lines += end_delimiter
return lines
return recursive_pformat(obj, 0, True)
def old_pformat(self, obj):
def add_spaces_up_to(s, n):
return s + self.white_space * (n - len(s))
def recursive_pformat(obj, current_indent=0, inhibit_prefix=False, recursion_depth=0, seen_set=None):
if seen_set is None:
seen_set = []
logger.debug("obj = %10s, seen set = %s", obj, seen_set)
if inhibit_prefix:
prefix = ''
else:
prefix = self.white_space * current_indent
if recursion_depth >= self.depth:
return prefix + '...'
logger.debug("type(obj) = %s", str(type(obj)))
if type(obj) in [types.NoneType, bool, int, float]:
return prefix + str(obj)
elif type(obj) is str:
return prefix + "'" + str(obj) + "'"
else:
if obj in seen_set:
logger.debug("obj = %10s, recursion detected", obj)
return prefix + '<rec ref to obj ' + repr(obj) + '>'
attr_list = get_attributes(obj)
logger.debug("obj = %10s, attr list = %s", obj, attr_list)
first_line_cont = ''
cont_inhibit_prefix = True
get = lambda o, i: o[i]
if type(obj) is list:
logger.debug("obj = %10s, is a list", obj)
start_delimiter = '['
end_delimiter = ']'
if len(attr_list) > 1:
start_delimiter = add_spaces_up_to('[', self.indent)
elif type(obj) is tuple:
logger.debug("obj = %10s, is a tuple", obj)
start_delimiter = '('
end_delimiter = ')'
if len(attr_list) > 1:
start_delimiter = add_spaces_up_to('(', self.indent)
elif type(obj) is set:
logger.debug("obj = %10s, is a set", obj)
start_delimiter = 'set(['
end_delimiter = '])'
if len(attr_list) > 1:
start_delimiter = add_spaces_up_to('set([', self.indent)
elif type(obj) is dict:
logger.debug("obj = %10s, is a dictionary", obj)
start_delimiter = '{'
end_delimiter = '}'
get = lambda o, k: KeyValuePair(k, o[k])
if len(attr_list) > 1:
start_delimiter = add_spaces_up_to('{', self.indent)
elif isinstance(obj, KeyValuePair):
logger.debug("obj = %10s, is a KeyValuePair", obj)
start_delimiter = add_spaces_up_to("'%s':" % obj.key, self.indent)
end_delimiter = ''
attr_list = ['value']
get = lambda o, k: o.value
if len(start_delimiter) > self.indent and not is_of_atomic_type(obj.value):
first_line_cont = '\n'
cont_inhibit_prefix = False
else:
logger.debug("obj = %10s, is an object of class '%s'", obj, obj.__class__.__name__)
start_delimiter = obj.__class__.__name__ + '('
end_delimiter = ')'
get = lambda o, a: getattr(o, a)
if len(start_delimiter) <= self.indent:
if len(attr_list) > 1:
start_delimiter = add_spaces_up_to(obj.__class__.__name__ + '(', self.indent)
elif len(attr_list) > 1 \
or len(attr_list) == 1 \
and not is_of_atomic_type(getattr(obj,attr_list[0])):
first_line_cont = '\n'
cont_inhibit_prefix = False
lines = prefix + start_delimiter + first_line_cont
i = 0
for attr in attr_list:
cont_separator = ''
if i < len(attr_list) - 1:
cont_separator = ',\n'
lines += recursive_pformat(get(obj, attr),
current_indent + self.indent,
cont_inhibit_prefix and i==0,
recursion_depth + 1,
seen_set + [obj]) + cont_separator
i += 1
lines += end_delimiter
return lines
return recursive_pformat(obj, 0, True)