From 8eba104c402a4c431a5dc962c46ac772da3588b9 Mon Sep 17 00:00:00 2001 From: pyy <568397440@qq.com> Date: Wed, 8 Jun 2016 23:45:41 +0800 Subject: [PATCH] arrange structure, add test --- .gitignore | 1 + LICENSE.txt | 0 MANIFEST | 0 README.md | 63 --------------- README.txt | 12 +++ beeprint/__init__.py | 0 constants.py => beeprint/constants.py | 9 +++ beeprint/debug_kit.py | 22 ++++++ bprint.py => beeprint/printer.py | 107 ++++++++++++++------------ settings.py => beeprint/settings.py | 7 ++ makefile | 15 ++++ setup.cfg | 0 setup.py | 25 ++++++ tests/test_default_beeprint.py | 49 ++++++++++++ 14 files changed, 196 insertions(+), 114 deletions(-) create mode 100644 LICENSE.txt create mode 100644 MANIFEST delete mode 100644 README.md create mode 100644 README.txt create mode 100644 beeprint/__init__.py rename constants.py => beeprint/constants.py (64%) create mode 100644 beeprint/debug_kit.py rename bprint.py => beeprint/printer.py (84%) rename settings.py => beeprint/settings.py (73%) create mode 100644 makefile create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 tests/test_default_beeprint.py diff --git a/.gitignore b/.gitignore index d646835..32a9f6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +.* *.pyc __pycache__/ diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..e69de29 diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md deleted file mode 100644 index 4994372..0000000 --- a/README.md +++ /dev/null @@ -1,63 +0,0 @@ -dump.py 的作用 -======= - -var_dump() of python, format your output | python 中的 var_dump(),用于打印 Python 数据结构,类似于 pprint - -对于一个dict,它输出如下: - - { - 'a': 1 - 'c': - [ - 2, - 3, - ] - 'b': 2 - } -对于一个object,它输出如下: - - object(testcls): - 'a': 'aaaa' - 'b': 'bbbb' - 'c': '三三三' - 'p1': 'p1' - 'p2': 222 - 'p3': - object(testcls2): - 't1': 't1' - 't2': 't三' - 'p4': - { - 'a': 'va' - '键': '值' - 'obj': - object(testcls2): - 't1': 't1' - 't2': 't三' - 'tuple': - ( - '中文', - 3, - 3.4, - ) - 'i': 123 - 'list': - [ - '值值', - 1, - 1.3, - ] - 'u': u'unicode' - } -示例解释: - - object(testcls): - ... - 'p3': - object(testcls2): - 't1': 't1' - 't2': 't三' - ... -在这里 p3 是 testcls 类实例的一个属性,所以它比 testcls 要多缩进一格,表示从属于。 -而 p3 的值(testcls2类的实例)也是一个对象,而这个对象属于 p3,所以它比 p3 多缩进一格。 -若 p3 的值的结构仅仅是字符串、数字等单行结构,那么它就不用空行再缩进。而是直接跟在 p3 后面。例如 p2。 diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..9790e9a --- /dev/null +++ b/README.txt @@ -0,0 +1,12 @@ +beeprint: Beautiful Print +=== + +Features +=== + +Examples +=== + +Plain Variables +--- + diff --git a/beeprint/__init__.py b/beeprint/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/constants.py b/beeprint/constants.py similarity index 64% rename from constants.py rename to beeprint/constants.py index bfb9c90..ee6563c 100644 --- a/constants.py +++ b/beeprint/constants.py @@ -1,4 +1,8 @@ # -*- coding:utf-8 -*- +from __future__ import print_function +from __future__ import absolute_import +from __future__ import unicode_literals +from __future__ import division # >> 优先策略 # 正确性优先,尽量正确显示出所有字段,有无法解析的字段立即报错并退出 @@ -13,3 +17,8 @@ _AS_DICT_ELEMENT_ = \ _AS_TUPLE_ELEMENT_ = \ _AS_CLASS_ELEMENT_ = 4 + +# string type +ST_LITERAL = 1 # string literal depends on script's coding +ST_UNICODE = 2 +ST_BYTES = 4 diff --git a/beeprint/debug_kit.py b/beeprint/debug_kit.py new file mode 100644 index 0000000..0964d24 --- /dev/null +++ b/beeprint/debug_kit.py @@ -0,0 +1,22 @@ +# -*- coding:utf-8 -*- +from __future__ import print_function +from __future__ import absolute_import +from __future__ import unicode_literals +from __future__ import division +from . import settings as S +from . import constants as C + + +### global variables +G_leading_char = ' ' + +def add_leading(depth, text): + text = G_leading_char*depth + text + text = text.replace('\n', '\n' + G_leading_char*depth) + return text + +def debug(level, depth, text): + if S.debug is False: + return + text = add_leading(depth, text) + print(text) diff --git a/bprint.py b/beeprint/printer.py similarity index 84% rename from bprint.py rename to beeprint/printer.py index 001d9e1..7caafd6 100644 --- a/bprint.py +++ b/beeprint/printer.py @@ -1,5 +1,8 @@ # -*- coding:utf-8 -*- from __future__ import print_function +from __future__ import absolute_import +from __future__ import unicode_literals +from __future__ import division import sys import traceback import types @@ -11,8 +14,14 @@ reload(sys) sys.setdefaultencoding('utf-8') + pyv = 2 +else: + unicode = str + pyv = 3 + from . import settings as S from . import constants as C +from .debug_kit import debug def object_attr_default_filter(obj, name, val): @@ -49,18 +58,23 @@ def _b(s): return s def pstr(s): + '''convert all string to unicode + for unicode is python's built-in coding + ''' res = u'' if isinstance(s, unicode): res += s elif isinstance(s, str): + # in python 2/3, it's utf8 + # so decode to unicode res += s.decode(S.encoding) else: - res += str(s).decode(S.encoding) + res += str(s)#.decode(S.encoding) return res -def dump_obj(o, output=True): +def beeprint(o, output=True): res = build_single_block(o, 0) if output and not S.write_to_buffer_when_execute: @@ -126,6 +140,9 @@ def tail_symbol(position): def build_single_block(obj, leadCnt=0, position=C._AS_ELEMENT_): '遍历对象,判断对象内成员的类型,然后调用对应的 build_*_block() 处理' + + debug(0, leadCnt, 'ready to build %s:%s' % (type(obj), obj)) + ret = pstr('') tail = tail_symbol(position) @@ -140,15 +157,20 @@ def build_single_block(obj, leadCnt=0, position=C._AS_ELEMENT_): return _b(ret) if isinstance(obj, dict): + debug(0, leadCnt, 'is dict') ret += build_dict_block(obj, leadCnt, position) elif isinstance(obj, list): + debug(0, leadCnt, 'is list') ret += build_list_block(obj, leadCnt, position) elif isinstance(obj, tuple): + debug(0, leadCnt, 'is tuple') ret += build_tuple_block(obj, leadCnt, position) # hasattr(obj, '__dict__') or isinstance(obj, object): elif is_extendable(obj): + debug(0, leadCnt, 'is extendable') ret += build_class_block(obj, leadCnt, position) else: + debug(0, leadCnt, 'is simple type') ret += _b(leadCnt * S.leading + typeval(obj) + pstr(tail + '\n')) return ret @@ -320,15 +342,21 @@ def build_class_block(o, leadCnt=0, position=C._AS_ELEMENT_): def typeval(v): try: - m = pstr(v).replace(u'\n', u'\\n') - m = m.replace(u'\r', u'\\r') - - if isinstance(v, str): - ret = pstr('"') + m + pstr('"') - elif isinstance(v, unicode): - ret = pstr('u\'') + m + pstr('\'') + st = string_type(v) + ret = u'' + if st == C.ST_LITERAL: + ret = u'"' + pstr(v) + u'"' + elif st == C.ST_UNICODE: + ret = u"u'" + v + u"'" + elif st == C.ST_BYTES: + # in py3, printed string will enclose with b'' + ret = pstr(v) else: ret = pstr(v) + + ret = ret.replace(u'\n', u'\\n') + ret = ret.replace(u'\r', u'\\r') + except Exception as e: if S.priority_strategy == C._PS_CORRECTNESS_FIRST: print_exc_plus() @@ -340,46 +368,23 @@ def typeval(v): return ret -class testcls2: - - def __init__(self): - self.t1 = 't1' - self.t2 = 't三' +def string_type(s): - -class testcls: - a = 'aaaa' - b = 'bbbb' - c = '三三三' - - def __init__(self): - self.p1 = 'p1' - self.p2 = 222 - self.p3 = testcls2() - self.f = typeval - self.p4 = { - 'a': 'va', - 'u': u'unicode', - '键': '值', - 'i': 123, - 'list': ['值值', 1, 1.3], - 'tuple': ('中文', 3, 3.4, testcls2()), - 'obj': testcls2() - } - - def func(self): - pass - -if __name__ == '__main__': - - S.newline = False - S.bufferHandle = open("../tmps/tools/dump.test", "w+") - S.tuple_in_line = False - S.list_in_line = True - S.maxDeep = 3 - try: - t = testcls() - dump_obj(typeval) - open("afdasfa/fasdfasf") - except Exception as e: - print(e) + if pyv == 2: + # in py2, string literal is both instance of str and bytes + # a literal string is str + # a utf8 string is str + # a u-prefixed string is unicode + if isinstance(s, unicode): + return C.ST_UNICODE + elif isinstance(s, str): # same as isinstance(v, bytes) + return C.ST_LITERAL + else: + # in py3, + # a literal string is str + # a u-prefixed string is str + # a utf8 string is bytes + if isinstance(s, bytes): + return C.ST_BYTES + elif isinstance(s, str): + return C.ST_LITERAL diff --git a/settings.py b/beeprint/settings.py similarity index 73% rename from settings.py rename to beeprint/settings.py index c8b4a7d..a5a801c 100644 --- a/settings.py +++ b/beeprint/settings.py @@ -1,6 +1,12 @@ # -*- coding:utf-8 -*- +from __future__ import print_function +from __future__ import absolute_import +from __future__ import unicode_literals +from __future__ import division import sys import types + + from . import constants as C outfile = sys.stdout @@ -20,3 +26,4 @@ # >> 优先策略 priority_strategy = C._PS_CONTENT_FIRST +debug = False diff --git a/makefile b/makefile new file mode 100644 index 0000000..7e9764e --- /dev/null +++ b/makefile @@ -0,0 +1,15 @@ +sdist: + python setup.py sdist || true + +edist: + python setup.py bdist_egg || true + +dist: + python setup.py sdist bdist_egg || true + +register: + python setup.py register -r pypi || true + python setup.py register -r pypitest || true + +full: + python setup.py sdist bdist_egg upload diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..1301a60 --- /dev/null +++ b/setup.py @@ -0,0 +1,25 @@ +from distutils.core import setup +setup( + name = 'beeprint', + packages = ['beeprint'], # this must be the same as the name above + version = '0.1', + description = 'print object in beautiful format, like pprint', + author = 'Yangyang Pan', + author_email = '568397440@qq.com', + url = 'https://github.com/panyanyany/beeprint', # use the URL to the github repo + download_url = 'https://github.com/panyanyany/beeprint/archive/master.zip', # I'll explain this in a second + keywords = ['print', 'pprint', 'format'], # arbitrary keywords + classifiers = [ + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + + "Environment :: Console", + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Topic :: Software Development", + "Topic :: Utilities", + ], +) diff --git a/tests/test_default_beeprint.py b/tests/test_default_beeprint.py new file mode 100644 index 0000000..bbe42f5 --- /dev/null +++ b/tests/test_default_beeprint.py @@ -0,0 +1,49 @@ +# -*- coding:utf-8 -*- + +import unittest +import os +import sys + +CUR_SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__)) +BEEPRINT_PATH = os.path.abspath(os.path.join(CUR_SCRIPT_PATH, '..')) +sys.path.append(BEEPRINT_PATH) + +from beeprint.printer import beeprint, pyv +from beeprint import settings as S + + +class TestSimpleTypes(unittest.TestCase): + + def setUp(self): + pass + + def test_positive(self): + self.assertEqual(beeprint(1, output=False), '1\n') + self.assertEqual(beeprint(1.1, output=False), '1.1\n') + + def test_negative(self): + self.assertEqual(beeprint(-1, output=False), '-1\n') + self.assertEqual(beeprint(-1.1, output=False), '-1.1\n') + + def test_string(self): + # string literal + # S.debug = True + self.assertEqual(beeprint("plain string", output=False), '"plain string"\n') + + # unicode string + s = u'unicode string' + if pyv == 2: + self.assertEqual(beeprint(s, output=False), u"u'unicode string'\n") + elif pyv == 3: + self.assertEqual(beeprint(s, output=False), u'"unicode string"\n') + + # utf8 string + s = u'utf8 string'.encode('utf-8') + if pyv == 2: + self.assertEqual(beeprint(s, output=False), "\"utf8 string\"\n") + elif pyv == 3: + self.assertEqual(beeprint(s, output=False), "b'utf8 string'\n") + + +if __name__ == '__main__': + unittest.main()