Last active
December 15, 2015 17:09
-
-
Save sharow/5293945 to your computer and use it in GitHub Desktop.
another repr() implementation. readable JSON(or some object) formatter.
multibyte string, cut long string.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; coding: utf-8; -*- | |
""" prettyrepr.py - another repr() implementation | |
""" | |
import sys | |
version_major = sys.version_info[0] | |
if version_major == 3: | |
# python3.x | |
from functools import reduce | |
xrange = list | |
unicode = str | |
__all__ = ['BaseRepr', 'BasicRepr', 'NestedPrettyRepr', | |
'basic_repr', 'pretty_repr'] | |
def basic_repr(obj, **kwargs): | |
return repr(BasicRepr(obj, **kwargs)) | |
def pretty_repr(obj, **kwargs): | |
return repr(NestedPrettyRepr(obj, **kwargs)) | |
class BaseRepr(object): | |
def __init__(self, obj, iterate_all=False, **kwargs): | |
self.level = 0 | |
self._obj = obj | |
self._iterate_all = iterate_all | |
self._derived_path = '' | |
self._cur_path = '' | |
if 'derived_path' in kwargs: | |
self._derived_path = kwargs['derived_path'] | |
if 'level' in kwargs: | |
self.level = kwargs['level'] | |
def __iter__(self): | |
obj = self._obj | |
if isinstance(obj, (str, unicode, int, float, bool)): | |
yield self.handle_atom_before() | |
if isinstance(obj, str): | |
yield self.handle_str(obj) | |
elif isinstance(obj, unicode): | |
yield self.handle_unicode(obj) | |
elif isinstance(obj, int): | |
yield self.handle_int(obj) | |
elif isinstance(obj, float): | |
yield self.handle_float(obj) | |
elif isinstance(obj, bool): | |
yield self.handle_bool(obj) | |
else: | |
assert False | |
yield self.handle_atom_after() | |
elif self._is_iterable(obj, self._iterate_all): | |
block_handler = self._determine_block_handler(obj) | |
yield block_handler(self, open_block=True) | |
self.level += 1 | |
writeback = '' # writeback for remove tail object's ', ' | |
if isinstance(obj, dict): | |
for k, v in obj.items(): | |
self._cur_path = "['%s']" % (k) | |
yield writeback | |
writeback = self.handle_atom_before() | |
yield writeback | |
writeback = self.handle_dict_key(k) | |
yield writeback | |
writeback = self.handle_atom_after() | |
yield writeback | |
writeback = self.handle_dict_separator() | |
for dict_item in self.handle_dict_item_it(v): | |
yield writeback | |
writeback = dict_item | |
yield writeback | |
writeback = self.handle_collection_separator() | |
else: | |
counter = 0 | |
for i in iter(obj): | |
self._cur_path = "[%d]" % (counter) | |
for item in self._sub_iterator_context(i): | |
yield writeback | |
writeback = item | |
yield writeback | |
writeback = self.handle_collection_separator() | |
counter += 1 | |
yield block_handler(self, open_block=False) | |
self.level -= 1 | |
else: | |
yield self.handle_atom_before() | |
yield self.handle_unknown_atom(obj) | |
yield self.handle_atom_after() | |
def __repr__(self): | |
return ''.join(self) | |
__str__ = __repr__ | |
__unicode__ = __repr__ | |
def _sub_iterator_context(self, obj): | |
kwargs = self.generate_kwargs() | |
return self.__class__(obj, iterate_all=self._iterate_all, **kwargs) | |
@staticmethod | |
def _is_iterable(obj, iterate_all): | |
if iterate_all: | |
if hasattr(obj, '__iter__'): | |
return True | |
else: | |
return False | |
else: | |
if isinstance(obj, (list, dict, tuple, set, xrange)): #xrange | |
return True | |
else: | |
return False | |
@classmethod | |
def _determine_block_handler(cls, obj): | |
if isinstance(obj, list): return cls.handle_list | |
if isinstance(obj, xrange): return cls.handle_xrange | |
elif isinstance(obj, tuple):return cls.handle_tuple | |
elif isinstance(obj, set): return cls.handle_set | |
elif isinstance(obj, dict): return cls.handle_dict | |
else: return cls.handle_unknown_iterable | |
# for sub-instance args (derive current context(arg)) | |
def generate_kwargs(self): | |
return {'derived_path': self.get_cur_path(), | |
'level': self.level} | |
@staticmethod | |
def super_generate_kwargs(baseclass, obj): | |
return super(baseclass, obj).__thisclass__.generate_kwargs(obj) | |
def get_cur_path(self): | |
return self._derived_path + self._cur_path | |
# need override | |
def handle_str(self, obj): pass | |
def handle_unicode(self, obj): pass | |
def handle_int(self, obj): pass | |
def handle_float(self, obj): pass | |
def handle_bool(self, obj): pass | |
def handle_unknown_atom(self, obj): pass | |
def handle_atom_before(self): pass | |
def handle_atom_after(self): pass | |
def handle_dict_key(self, obj): pass | |
def handle_dict_separator(self): pass | |
def handle_dict_item_it(self, obj): pass | |
def handle_collection_separator(self): pass | |
def handle_list(self, open_block): pass | |
def handle_xrange(self, open_block): pass | |
def handle_tuple(self, open_block): pass | |
def handle_set(self, open_block): pass | |
def handle_dict(self, open_block): pass | |
def handle_unknown_iterable(self, open_block): pass | |
# looks like default repr() | |
class BasicRepr(BaseRepr): | |
def __init__(self, obj, **kwargs): | |
""" | |
ex: obj = {'key': StringIO('abc')} | |
iterate_all=False => "{'key': <StringIO.StringIO instance at ??>}" | |
iterate_all=True => "{'key': <'abc'>}" | |
""" | |
BaseRepr.__init__(self, obj, **kwargs) | |
def handle_atom_before(self): | |
return '' | |
def handle_atom_after(self): | |
return '' | |
# atom handlers | |
def handle_str(self, obj): | |
return "'" + obj + "'" | |
def handle_unicode(self, obj): | |
return "u'" + obj.encode('utf-8') + "'" | |
def handle_int(self, obj): | |
return str(obj) | |
def handle_float(self, obj): | |
return str(obj) | |
def handle_bool(self, obj): | |
return str(obj) | |
def handle_unknown_atom(self, obj): | |
return repr(obj) | |
# other handlers | |
def handle_dict_key(self, obj): | |
return "'" + obj + "'" | |
def handle_dict_separator(self): | |
return ': ' | |
def handle_dict_item_it(self, obj): | |
return self._sub_iterator_context(obj) | |
def handle_collection_separator(self): | |
return ', ' | |
# block handlers | |
def handle_list(self, open_block): | |
return '[' if open_block else ']' | |
def handle_xrange(self, open_block): | |
return '[' if open_block else ']' | |
def handle_tuple(self, open_block): | |
return '(' if open_block else ')' | |
def handle_set(self, open_block): | |
if version_major == 2: | |
return 'set([' if open_block else '])' | |
elif version_major == 3: | |
return 'set(' if open_block else ')' | |
else: | |
assert False | |
def handle_dict(self, open_block): | |
return '{' if open_block else '}' | |
def handle_unknown_iterable(self, open_block): | |
return "'<" if open_block else ">'" | |
class NestedPrettyRepr(BaseRepr): | |
def __init__(self, obj, iterate_all=False, | |
indent=2, print_path=True, object_name='', | |
str_limit_len=48, str_replace_crlf=True, | |
dict_key_fmt="'%s'", comment_fmt='# %s', **kwargs): | |
self.indent = indent | |
self.cur_nest = 0 | |
self.dict_key_fmt = dict_key_fmt | |
self.str_limit_len = str_limit_len | |
self.str_replace_crlf = str_replace_crlf | |
self.comment_fmt = comment_fmt | |
self.print_path = print_path | |
self.object_name = object_name | |
self._one_time_nest_stop = False | |
if 'cur_nested' in kwargs: | |
self.cur_nest = kwargs['cur_nested'] | |
if 'one_time_nest_stop' in kwargs: | |
self._one_time_nest_stop = kwargs['one_time_nest_stop'] | |
BaseRepr.__init__(self, obj, iterate_all, **kwargs) | |
def nest(self): | |
if self._one_time_nest_stop: | |
self._one_time_nest_stop = False | |
return '' | |
return ' ' * self.cur_nest | |
def generate_kwargs(self): | |
kwargs = self.super_generate_kwargs(BaseRepr, self) | |
kwargs.update({ | |
'indent': self.indent, | |
'cur_nested': self.cur_nest, | |
'object_name': self.object_name, | |
'print_path': self.print_path, | |
'str_limit_len': self.str_limit_len, | |
'str_replace_crlf': self.str_replace_crlf, | |
'dict_key_fmt': self.dict_key_fmt, | |
'comment_fmt': self.comment_fmt, | |
'one_time_nest_stop': self._one_time_nest_stop | |
}) | |
return kwargs | |
# atom handlers | |
def handle_atom_before(self): | |
return self.nest() | |
def handle_atom_after(self): | |
return '' | |
def handle_str(self, obj): | |
s = obj | |
limi = 0 | |
cut = False | |
if self.str_limit_len > 0: | |
limit = self.str_limit_len - 3 # for '...' | |
if limit <= 0: | |
limit = self.str_limit_len | |
if limit > 0: | |
if len(s) > limit: | |
s = s[:limit] | |
cut = True | |
if self.str_replace_crlf: | |
s = s.replace('\r', '\\r') | |
s = s.replace('\n', '\\n') | |
if limit > 0: | |
if len(s) > limit: | |
s = s[:limit] | |
cut = True | |
if cut: | |
return "'%s...'" % (s) | |
else: | |
return "'%s'" % (s) | |
handle_unicode = handle_str | |
def handle_int(self, obj): | |
return str(obj) | |
def handle_float(self, obj): | |
return str(obj) | |
def handle_bool(self, obj): | |
return "'" + str(obj) + "'" | |
def handle_unknown_atom(self, obj): | |
return repr(obj) | |
# other handlers | |
def handle_dict_key(self, obj): | |
return self.dict_key_fmt % (obj) | |
def handle_dict_separator(self): | |
self._one_time_nest_stop = True | |
return ': ' | |
def handle_dict_item_it(self, obj): | |
return filter(lambda x: self.nest() + x, | |
self._sub_iterator_context(obj)) | |
def handle_collection_separator(self): | |
return ',\n' | |
# block handlers | |
def _handle_collection(self, open_block, outputs): | |
if open_block: | |
v = self.nest() + outputs[0] | |
if self.print_path: | |
path = self.get_cur_path() | |
if path != '': | |
path_str = '%s%s' % (self.object_name, path) | |
v += ' ' + self.comment_fmt % (path_str) | |
self.cur_nest += self.indent | |
return v + '\n' | |
else: | |
self.cur_nest -= self.indent | |
return '\n' + self.nest() + outputs[1] | |
def handle_list(self, open_block): | |
return self._handle_collection(open_block, ('[', ']')) | |
def handle_xrange(self, open_block): | |
return self._handle_collection(open_block, ('[', ']')) | |
def handle_tuple(self, open_block): | |
return self._handle_collection(open_block, ('(', ')')) | |
def handle_set(self, open_block): | |
if version_major == 2: | |
return self._handle_collection(open_block, ('set([', '])')) | |
elif version_major == 3: | |
return self._handle_collection(open_block, ('(', ')')) | |
def handle_dict(self, open_block): | |
return self._handle_collection(open_block, ('{', '}')) | |
def handle_unknown_iterable(self, open_block): | |
return self._handle_collection(open_block, ("'<", ">'")) | |
if __name__ == '__main__': | |
import sys | |
import json | |
print pretty_repr(json.load(sys.stdin)) |
Author
sharow
commented
Apr 2, 2013
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment