blob: 53d2771d294b5e058eff2db604072e2985a68c27 [file] [log] [blame]
# vim: set fileencoding=utf-8
# Copyright (c) 2009 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Simplifies live debugging, like buildbot's manhole.
Similar to pprint except that:
- It is really to print objects and the code is 100% recursive.
- Prefers str() over repr() since it's only for debugging.
- Indent is not configurable by design and locked to 2.
Usage:
class MyClass(Printable):
(...)
from printable import AutoString as A
print A(master)
"""
# Hack to quickly display 'set'.
CONTROL_CHARS = {tuple: '()', list: '[]', set: '«»'}
SIMPLE_TYPES = (basestring, bool, buffer, xrange, int, float, long, complex,
None.__class__)
def StrippedStr(obj, maxlen=80):
"""Strings too long are useless anyway."""
if isinstance(obj, str):
# Quote strings.
b = "'%s'" % obj
else:
b = str(obj)
if len(b) > maxlen:
b = b[0:maxlen] + '...'
return b
def AutoString(obj, depth=3, maxlen=80):
"""Returns a textual representation the members of an object for debugging.
List member variables but not functions.
"""
out = []
if isinstance(obj, SIMPLE_TYPES):
return StrippedStr(obj, maxlen)
elif isinstance(obj, (tuple, list, set)):
# Print each item.
chars = CONTROL_CHARS[obj.__class__]
if not len(obj):
return chars
out.append(chars[0])
for v in obj:
if depth > 0:
out.extend([' %s' % l
for l in AutoString(v, depth-1, maxlen).split('\n')])
out[-1] = '%s,' % out[-1]
else:
out.append(' %s,' % StrippedStr(v, maxlen))
out.append(chars[1])
if len(out) == 3:
out = ['%s%s%s' % (out[0], out[1].lstrip(' '), out[2])]
elif isinstance(obj, dict):
if not len(obj):
return '{}'
out.append('{')
for (k, v) in obj.iteritems():
if depth > 0:
k_lines = AutoString(k, depth-1, maxlen).split('\n')
v_lines = AutoString(v, depth-1, maxlen).split('\n')
out.extend([' %s' % k for k in k_lines])
out[-1] = '%s:' % out[-1]
if len(v_lines) > 1:
out.extend([' %s' % l for l in v_lines])
out[-1] = '%s,' % out[-1]
else:
out[-1] = '%s %s,' % (out[-1], v_lines[0])
else:
out.append(' %s: %s,' % (
StrippedStr(k, maxlen), StrippedStr(v, maxlen)))
out.append('}')
if len(out) == 3:
out = ['%s%s%s' % (out[0], out[1].lstrip(' '), out[2])]
else:
# Standard object. Skips over __.* and callable members.
out.append('<%s>:' % obj.__class__)
for member_name in dir(obj):
member_obj = getattr(obj, member_name)
if not callable(member_obj) and not member_name.startswith('__'):
if depth > 0:
out.append(' %s:' % member_name)
v_lines = AutoString(member_obj, depth-1, maxlen).split('\n')
if len(v_lines) > 1:
out.extend([' %s' % l for l in v_lines])
else:
out[-1] = '%s %s' % (out[-1], v_lines[0])
else:
out.append(' %s: %s' % (
member_name, StrippedStr(member_obj, maxlen)))
return '\n'.join(out)
class Printable(object):
def __str__(self):
return AutoString(self)