Source code for libutilitaspy.general.utils

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)