""" A perl Data.Dumper clone for Python Author: simon@log4think.com 2011-07-08 """ #!/bin/env python import sys from types import * def DEBUG(msg, level=None): pass magin_space = ' ' break_base = False break_string = False break_before_list_item = True break_before_list_begin = False break_after_list_begin = False break_before_list_end = True break_after_list_end = False break_before_tuple_item = True break_before_tuple_begin = False break_after_tuple_begin = False break_before_tuple_end = True break_after_tuple_end = False break_before_dict_key = True break_before_dict_value = False break_before_dict_begin = False break_after_dict_begin = False break_before_dict_end = True break_after_dict_end = False DICT_TYPES = {DictionaryType: 1} def atomic_type (t): return t in (NoneType, StringType, IntType, LongType, FloatType, ComplexType) def simple_value (val): t = type(val) if atomic_type (val): return True if (not DICT_TYPES.has_key(t) and t not in (ListType, TupleType) and not is_instance(val)): return True elif t in (ListType, TupleType) and len (val) <= 10: for x in val: if not atomic_type (type (x)): return False return True elif DICT_TYPES.has_key(t) and len (val) <= 5: for (k,v) in val.items(): if not (atomic_type (type (k)) and atomic_type (type (v))): return False return True else: return False def is_instance (val): if type(val) is InstanceType: return True # instance of extension class, but not an actual extension class elif (hasattr(val, '__class__') and hasattr(val, '__dict__') and not hasattr(val, '__bases__')): return True else: return False def is_class (val): return hasattr(val, '__bases__') def indent(level=0, nextline=True): if nextline: return "\n" + magin_space*level else: return "" class Dumper(): def __init__(self, max_depth=999): self.max_depth = max_depth self.seen = {} def reset(self): self.seen = {} def dump_default(self, obj, level=0, nextline=True): DEBUG('; dump_default') if level + 1 > self.max_depth: return " <%s...>" % type(obj).__class__ else: result = "%s::%s <<" % (type(obj).__name__, obj.__class__) if hasattr(obj, '__dict__'): result = "%s%s__dict__ :: %s" % ( result, indent(level+1), self.dump_dict(obj.__dict__, level+1) ) if isinstance(obj, dict): result = "%s%sas_dict :: %s" % ( result, indent(level+1), self.dump_dict(obj, level+1) ) elif isinstance(obj, list): result = "%s%sas_list :: %s" % ( result, indent(level+1), self.dump_list(obj, level+1) ) result = result = "%s%s>>" % (result, indent(level)) return result def dump_base(self, obj, level=0, nextline=True): DEBUG("; dump_%s", type(obj).__name__) return "%s%s" % (indent(level, break_base), obj) dump_NoneType = dump_base dump_int = dump_base dump_long = dump_base dump_float = dump_base def dump_str(self, obj, level=0, nextline=True): DEBUG('; dump_str') return "%s'%s'" % (indent(level, break_string), obj) def dump_tuple(self, obj, level=0, nextline=True): DEBUG('; dump_tuple') if level + 1 > self.max_depth: return "%s(...)%s" % ( indent(level, break_before_tuple_begin), indent(level, break_after_tuple_end) ) else: items = ["%s%s" % ( indent(level + 1, break_before_tuple_item), self.dump(x, level + 1) ) for x in obj ] return "%s(%s%s%s)%s" % ( indent(level, nextline and break_before_tuple_begin), indent(level + 1, break_after_tuple_begin), ' '.join(items), indent(level, break_before_tuple_end), indent(level, break_after_tuple_end) ) def dump_list(self, obj, level=0, nextline=True): DEBUG('; dump_list') if level + 1 > self.max_depth: return "%s[...]%s" % ( indent(level, break_before_list_begin), indent(level, break_after_list_end) ) else: items = ["%s%s" % ( indent(level + 1, break_before_list_item), self.dump(x, level + 1) ) for x in obj ] return "%s[%s%s%s]%s" % ( indent(level, nextline and break_before_list_begin), indent(level + 1, break_after_list_begin), ' '.join(items), indent(level, break_before_list_end), indent(level, break_after_list_end) ) def dump_dict(self, obj, level=0, nextline=True): DEBUG('; dump_dict') if level + 1 > self.max_depth: return "%s{...}%s" % ( indent(level, break_before_dict_begin), indent(level, break_after_dict_end) ) else: items = ["%s%s: %s%s" % ( indent(level + 1, break_before_dict_key), self.dump(k, level + 1), indent(level + 2, break_before_dict_value), self.dump(v, level + 1) ) for k, v in obj.items() ] return "%s{%s%s%s}%s" % ( indent(level, nextline and break_before_dict_begin), indent(level + 1, break_after_dict_begin), ' '.join(items), indent(level, break_before_dict_end), indent(level, break_after_dict_end) ) def dump(self, obj, level=0, nextline=True): DEBUG('; dump') if not simple_value(obj): if self.seen.has_key(id(obj)): return "%s::%s <<...>>" % (type(obj).__name__, obj.__class__) else: self.seen[id(obj)] = 1 name = type(obj).__name__ dump_func = getattr(self, "dump_%s" % name, self.dump_default) return dump_func(obj, level, nextline) def dump(obj, max_depth=999): d = Dumper(max_depth) return d.dump(obj) if __name__ == '__main__': l1 = [3, 5, 'hello'] t1 = ('uh', 'oh') l2 = ['foo', t1] d1 = {'k1': 'val1', 'k2': l1, 'k2': l2} print dump (l1) print dump (t1) print dump (l2) print dump (d1) dumper = Dumper (max_depth=1) l = { 'author': 'joe', 'created' : '03/28/2009', 'title' : 'Yet another blog post', 'text' : 'Here is the text...', 'tags' : [ 'example', 'joe' ], 'comments' : [ { 'author': 'jim', 'comment': 'I disagree' }, { 'author': 'nancy', 'comment': 'Good post' } ], } print dumper.dump (l) dumper.reset() dumper.max_depth = 2 print dumper.dump (l) dumper.reset() dumper.max_depth = None print "max_depth: %s" % dumper.max_depth class Foo(list): pass class Bar(dict): pass f = Foo () b = Bar () f.a1 = 35 f.a2 = l1 f.a3 = 'foo' f.b = b f.a4 = l2 b.a1 = f b.a2 = None b.a3 = 'bar' print dump (f) print dump (Dumper())