Skip to content

Commit

Permalink
ppretty library v.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
symonsoft committed Jul 28, 2016
0 parents commit edfbb2f
Show file tree
Hide file tree
Showing 7 changed files with 352 additions and 0 deletions.
94 changes: 94 additions & 0 deletions .gitignore
@@ -0,0 +1,94 @@
# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# IPython Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# dotenv
.env

# virtualenv
venv/
ENV/

# Spyder project settings
.spyderproject

# Rope project settings
.ropeproject

.gitignore
.idea/
24 changes: 24 additions & 0 deletions LICENSE.txt
@@ -0,0 +1,24 @@
Copyright (c) 2016, SymonSoft All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Neither the name of the SymonSoft nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
46 changes: 46 additions & 0 deletions README.md
@@ -0,0 +1,46 @@
# ppretty v.1.0

## About
Convert any python object to a human readable format.

## Installation
```sh
$ pip install ppretty
```

## Examples
Here's a basic example:
```python
from ppretty import ppretty


class MyClass(object):
def __init__(self):
self.a = range(10)

b = 'static var'

@property
def _c(self):
return 'protected property'

my_obj = MyClass()

print ppretty(my_obj)
print
print ppretty(my_obj, indent=' ', width=40, seq_length=10,
show_protected=True, show_static=True, show_properties=True, show_address=True)
```
Output:
```
__main__.MyClass(a = [0, 1, ..., 8, 9])
__main__.MyClass at 0x1f6bda0L (
_c = 'protected property',
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
b = 'static var'
)
```

## License
BSD
3 changes: 3 additions & 0 deletions ppretty/__init__.py
@@ -0,0 +1,3 @@
from ppretty import ppretty

__all__ = 'ppretty'
161 changes: 161 additions & 0 deletions ppretty/ppretty.py
@@ -0,0 +1,161 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

from functools import partial
from inspect import isroutine


def ppretty(obj, indent=' ', depth=4, width=120, seq_length=5, show_protected=False, show_private=False, show_static=False, show_properties=False, show_address=False):
seq_formats = {list: ('[', ']'), tuple: ('(', ')'), set: ('set([', '])'), dict: ('{', '}')}

def inspect_object(current_obj, current_depth, current_width):
inspect_nested_object = partial(inspect_object, current_depth=current_depth - 1, current_width=current_width - len(indent))

# Basic types
if isinstance(current_obj, (int, long, float, basestring)):
return [repr(current_obj)]

# Class object
if isinstance(current_obj, type):
module = current_obj.__module__ + '.' if hasattr(current_obj, '__module__') else ''
return ["<class '" + module + current_obj.__name__ + "'>"]

# None
if current_obj is None:
return ['None']

# Format block of lines
def format_block(lines, open_bkt='', close_bkt=''):
new_lines = []
one_line = ''
if open_bkt:
new_lines.append(open_bkt)
one_line += open_bkt
for line in lines:
new_lines.append(indent + line)
if len(one_line) <= current_width:
one_line += line
if close_bkt:
if lines:
new_lines.append(close_bkt)
else:
new_lines[-1] += close_bkt
one_line += close_bkt

return [one_line] if len(one_line) <= current_width and one_line else new_lines

class SkipElement(object):
pass

class ErrorAttr(object):
def __init__(self, e):
self.e = e

def cut_seq(seq):
if current_depth < 1:
return [SkipElement()]
if len(seq) <= seq_length:
return seq
elif seq_length > 1:
seq = list(seq) if isinstance(seq, tuple) else seq
return seq[:seq_length / 2] + [SkipElement()] + seq[(1 - seq_length) / 2:]
return [SkipElement()]

def format_seq():
r = []
items = cut_seq(obj_items)
for n, i in enumerate(items, 1):
if type(i) is SkipElement:
r.append('...')
else:
if type(current_obj) is dict:
(k, v) = i
k = inspect_nested_object(k)
v = inspect_nested_object(v)
k[-1] += ': ' + v.pop(0)
r.extend(k)
r.extend(format_block(v))
elif type(current_obj) in seq_formats:
r.extend(inspect_nested_object(i))
else:
(k, v) = i
k = [k]
v = inspect_nested_object(v) if type(v) is not ErrorAttr else ['<Error attribute: ' + type(v.e).__name__ + ': ' + v.e.message + '>']
k[-1] += ' = ' + v.pop(0)
r.extend(k)
r.extend(format_block(v))
if n < len(items):
r[-1] += ', '
return format_block(r, *brackets)

# Sequence types
# Others objects are considered as sequence of members
if type(current_obj) in seq_formats:
if type(current_obj) is dict:
obj_items = current_obj.items()
else:
obj_items = current_obj
brackets = seq_formats[type(current_obj)]
else:
obj_items = []
for k in dir(current_obj):
if not show_private and k.startswith('_') and '__' in k:
continue
if not show_protected and k.startswith('_'):
continue
try:
v = getattr(current_obj, k)
if isroutine(v):
continue
if not show_static and hasattr(type(current_obj), k) and v is getattr(type(current_obj), k):
continue
if not show_properties and hasattr(type(current_obj), k) and isinstance(
getattr(type(current_obj), k), property):
continue
except Exception as e:
v = ErrorAttr(e)

obj_items.append((k, v))

module = current_obj.__module__ + '.' if hasattr(current_obj, '__module__') else ''
address = ' at ' + hex(id(current_obj)) + ' ' if show_address else ''
brackets = (module + type(current_obj).__name__ + address + '(', ')')

return format_seq()

return '\n'.join(inspect_object(obj, depth, width))


if __name__ == '__main__':
class B(object):
def __init__(self, b):
self.b = b

class A(object):
i = [-3, 4.5, ('6', B({'\x07': 8}))]

def __init__(self, a):
self.a = a

class C(object):
def __init__(self):
self.a = {u'1': A(2), '9': [10L, 11, {(12, 13): {14, None}}], 15: [16, 17, 18, 19, 20]}
self.b = 'd'
self._c = 'b'
self.e = C.D

d = 'c'

def foo(self):
pass

@property
def bar(self):
return 'e'

class D(object):
pass


print ppretty(C(), indent=' ', depth=8, width=41, seq_length=6, show_static=True, show_protected=True, show_properties=True, show_address=True)
print ppretty(C(), depth=8, width=200, seq_length=4)
2 changes: 2 additions & 0 deletions setup.cfg
@@ -0,0 +1,2 @@
[metadata]
description-file = README.md
22 changes: 22 additions & 0 deletions setup.py
@@ -0,0 +1,22 @@
from distutils.core import setup


setup(
name='ppretty',
packages=['ppretty'],
version='1.0',
description='Convert python objects to a human readable format',
author='SymonSoft',
author_email='symonsoft@gmail.com',
url='https://github.com/symonsoft/ppretty',
download_url='https://github.com/symonsoft/ppretty/tarball/1.0',
keywords=['pretty', 'print', 'format', 'object', 'human'],
classifiers=[
'Development Status :: 5 - Production/Stable',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.7',
'Topic :: Software Development :: Debuggers',
'Topic :: Utilities'
],
)

0 comments on commit edfbb2f

Please sign in to comment.