Skip to content

Commit cb7a8de

Browse files
committed
add text and stack utils, method binding - bump 0.0.6
1 parent 804c69e commit cb7a8de

File tree

8 files changed

+256
-6
lines changed

8 files changed

+256
-6
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name=NAME,
8-
version='0.0.5',
8+
version='0.0.6',
99
description='',
1010
long_description=open('README.md').read().strip(),
1111
long_description_content_type='text/markdown',

tests/test_objects.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,19 @@ class B:
100100
x = 5
101101
y = 6
102102

103+
def getx(self):
104+
return self.x
105+
106+
@property
107+
def xx(self):
108+
return self.x
109+
103110
a = B()
104111
x = wp.Mask(a, x=10)
105112
# test that mask is applied
106113
assert a.x == 5 and x.x == 10
114+
assert x.getx() == 10
115+
# assert x.xx == 10
107116
# test partial mask - mask change
108117
x.y = 8
109118
assert a.y == 8 and x.y == 8

tests/test_text.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import wrappingpaper as wp
2+
3+
4+
def test_text():
5+
prep = lambda t: wp.text.strip_trailing_whitespace(wp.text.striplines(t)).rstrip().replace('\t', ' '*4)
6+
inspect = lambda *xs: print(wp.text.block_text(*xs, *(repr(x) for x in xs), div='----'))
7+
8+
original = prep('''
9+
asdf
10+
11+
asdfsadf
12+
asdf
13+
''')
14+
indented = prep('''
15+
asdf
16+
17+
asdfsadf
18+
asdf
19+
''')
20+
# inspect(original, indented)
21+
# test indent
22+
assert wp.text.strip_trailing_whitespace(wp.text.indent(original)) == indented
23+
assert wp.text.trim_indent(indented) == original
24+
assert wp.text.strip_trailing_whitespace(wp.text.tabindent(original.replace(' '*4, '\t'))) == indented.replace(' '*4, '\t')
25+
26+
assert wp.text.striplines('\n'*3 + indented + '\n'*3) == indented
27+
28+
# test commenting
29+
commented = prep('''
30+
# asdf
31+
#
32+
# asdfsadf
33+
# asdf
34+
''')
35+
36+
assert wp.text.strip_trailing_whitespace(wp.text.comment(original)) == commented
37+
assert wp.text.strip_trailing_whitespace(wp.text.comment(original, ch='//')) == commented.replace('#', '//')
38+
39+
# test block text
40+
block_text = prep('''
41+
********************
42+
* asdf
43+
*
44+
* asdfsadf
45+
* asdf
46+
*
47+
* hello
48+
********************
49+
''')
50+
assert wp.text.strip_trailing_whitespace(wp.text.block_text(original, '', 'hello')) == block_text
51+
52+
# test line and block
53+
assert wp.text.l_('asdf', 5, 5) == 'asdf 5 5'
54+
assert wp.text.b_('asdf', (5, 6, 7, 8), 5) == '''
55+
asdf
56+
5 6 7 8
57+
5
58+
'''.strip()
59+
60+
# text fixed width format
61+
assert wp.text.fw_('asdf', w=10) == 'asdf '
62+
63+
# test table
64+
assert wp.text.strip_trailing_whitespace(wp.text.tbl(
65+
('asdf', 6, 7, 'asdf'),
66+
(5, 6, 7, 8),
67+
(5, 'asdf', 7, 'asdf'))) == '''
68+
asdf 6 7 asdf
69+
5 6 7 8
70+
5 asdf 7 asdf
71+
'''.strip()
72+
73+
# test colors
74+
assert wp.text.red('a b c') == '\033[91ma b c\033[0m'
75+
assert wp.text.blue('a b c') == '\033[94ma b c\033[0m'
76+
assert wp.text.green('a b c') == '\033[92ma b c\033[0m'
77+
assert wp.text.yellow('a b c') == '\033[93ma b c\033[0m'
78+
assert wp.text.bold('a b c') == '\033[1ma b c\033[0m'
79+
assert wp.text.underline('a b c') == '\033[4ma b c\033[0m'

wrappingpaper/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def __bool__(self):
1212
from .context import *
1313
from .logs import *
1414
from .props import *
15+
from . import text
1516
from .stack import *
1617
from .objects import *
1718
from .schedule import *

wrappingpaper/importmechanics.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,7 @@ def find_spec(self, fullname, path=None, target=None):
152152
parts = _as_parts(fullname)
153153

154154
# e.g. from presets import librosa <<<<
155-
explicit_import = (
156-
self.module_name[:len(parts)] ==
157-
parts[:len(self.module_name)])
155+
explicit_import = self.module_name[:len(parts)] == parts[:len(self.module_name)]
158156

159157
if explicit_import:
160158
parts = parts[len(self.module_name):] # cut off prefix

wrappingpaper/objects.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,13 @@ def __init__(self, base, d=None, full=False, **kw):
5858
def __getattribute__(self, name):
5959
if name not in {'__dict__', '__initialized__'}:
6060
if self.__initialized__ and name not in self.__dict__:
61-
return getattr(self.__masked__, name)
61+
value = getattr(self.__masked__, name)
62+
if hasattr(value, '__self__'):
63+
try:
64+
return value.__func__.__get__(self)
65+
except AttributeError:
66+
pass
67+
return value
6268
return super().__getattribute__(name)
6369

6470
def __setattr__(self, name, value):

wrappingpaper/stack.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import os
12
import hashlib
23
import inspect
3-
from .exceptions import CircularReference
4+
from . import text
5+
# from .exceptions import CircularReference
46

57

68
def uid(x, digits=None):
@@ -24,3 +26,30 @@ def get_stack_id(x=None, frames=1, digits=16):
2426
# yield
2527
# del circular.__stack_refs__[xid]
2628
# circular.__stack_refs__ = {}
29+
30+
31+
def stack_summary(message=None, fn=None, offset=0):
32+
stack = inspect.stack()
33+
f = stack[offset+1]
34+
return text.block_text(
35+
message,
36+
text.blue(text.l_(f.function, f.lineno, f.filename)), '',
37+
text.tbl(*(
38+
(f.function, f.lineno, f.filename, f'>>> {f.code_context[0].strip()}')
39+
for f in stack[offset+2:]
40+
if not fn or fn in f.filename
41+
)), ch=text.yellow('*')
42+
)
43+
44+
def print_stack(message=None, *a, offset=0, **kw):
45+
print(stack_summary(message, *a, offset=offset + 1, **kw))
46+
47+
48+
def short_stack_summary(match=None, file=False, sep=' << ', n=None):
49+
'''Print out a compressed view of the stack.'''
50+
return sep.join(
51+
(f'{f.function} ({os.path.basename(f.filename)}:{f.lineno})'
52+
if file else f.function)
53+
for f in inspect.stack()[1:][:n]
54+
if not match or match in f.filename
55+
)

wrappingpaper/text.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,109 @@
11

2+
# Text formatting
3+
4+
class C:
5+
HEADER = '\033[95m'
6+
OKBLUE = '\033[94m'
7+
OKGREEN = '\033[92m'
8+
WARNING = '\033[93m'
9+
FAIL = '\033[91m'
10+
ENDC = '\033[0m'
11+
BOLD = '\033[1m'
12+
UNDERLINE = '\033[4m'
13+
14+
def _text_wrapper(start, end=C.ENDC):
15+
return f'{start}{{}}{end}'.format
16+
17+
red = _text_wrapper(C.FAIL)
18+
blue = _text_wrapper(C.OKBLUE)
19+
green = _text_wrapper(C.OKGREEN)
20+
yellow = _text_wrapper(C.WARNING)
21+
bold = _text_wrapper(C.BOLD)
22+
underline = _text_wrapper(C.UNDERLINE)
23+
24+
t4 = ' '*4
25+
t2 = ' '*2
26+
27+
# block text helpers
28+
29+
def indent(x, n=1, w=4, ch=' '):
30+
'''Indent text using spaces.'''
31+
return ''.join(ch * w * n + l for l in str(x).splitlines(keepends=True))
32+
33+
def tabindent(x, n=1, w=4):
34+
'''Indent text using tabs.'''
35+
return indent(space2tab(x, w=w), w=1, n=n, ch='\t')
36+
37+
38+
def tab2space(text, w=4):
39+
return text.replace('\t', ' '*w)
40+
41+
def space2tab(text, w=4):
42+
return text.replace(' '*w, '\t')
43+
44+
45+
def trim_indent(text, tw=2):
46+
'''Remove any common indent from text.
47+
48+
Arguments:
49+
text (str): the text to re-indent.
50+
tw (int): the number of spaces per tab character.
51+
'''
52+
# normalize tabs to spaces
53+
lines = text.replace('\t', ' '*tw).splitlines()
54+
# get the min indent to norm to
55+
m = min([len(l) - len(l.lstrip()) for l in lines if l.strip()], default=0)
56+
# rejoin the text with the proper indent
57+
return '\n'.join([l[m:] for l in lines])
58+
59+
60+
def striplines(text):
61+
'''Like text.strip() but it only removes lines with purely whitespace and
62+
leaves text indentation.'''
63+
lines = text.splitlines()
64+
i, j = 0, len(lines)
65+
while not lines[i].strip():
66+
i += 1
67+
while not lines[j-1].strip():
68+
j -= 1
69+
return '\n'.join(lines[i:j])
70+
71+
def strip_trailing_whitespace(txt):
72+
'''remove whitespace from the end of each line.'''
73+
return '\n'.join(l.rstrip() for l in txt.splitlines())
74+
75+
def comment(txt, ch='#', n=1, spaces=1):
76+
'''Apply prefix to each line. Defaults to python comments.'''
77+
ch, spaces = ch*n, " "*spaces
78+
return '\n'.join(f'{ch}{spaces}{l}' for l in txt.splitlines())
79+
80+
81+
def block_text(*txts, n=20, ch='*', div=''):
82+
'''Create a block of text with a character border.'''
83+
return ch * n + f'\n{comment(b_(*txts, div=div), ch=ch)}\n' + ch * n
84+
85+
def b_(*lines, div=''):
86+
'''Convert arguments to lines. Lines can be tuples (will be joined by a space.)'''
87+
div = f'\n{div}\n' if div else '\n'
88+
return div.join(
89+
l_(*l) if isinstance(l, (list, tuple)) else str(l)
90+
for l in lines if l is not None)
91+
92+
def l_(*line, div=' '):
93+
'''Convert arguments to a space separated string'''
94+
return div.join(map(str, line))
95+
96+
97+
def fw_(*line, w=20, right=False):
98+
'''As a fixed width string'''
99+
return f"{l_(*line):{'>' if right else '<'}{w}}"
100+
101+
def tbl(*rows, buffer=2):
102+
'''Format as a table. Calculates column widths.'''
103+
rows = [[str(c) for c in cs] for cs in rows]
104+
widths = [max((len(c) for c in cs), default=0) for cs in zip(*rows)]
105+
return b_(*([fw_(c, w=w + buffer-1) for c, w in zip(cs, widths)] for cs in rows))
106+
2107

3108

4109
def redent(text, n=0, tw=2, stripline=True, keep_leading=False):
@@ -29,3 +134,26 @@ def redent(text, n=0, tw=2, stripline=True, keep_leading=False):
29134
default=0))
30135
# rejoin the text with the proper indent
31136
return '\n'.join([n * tw * ' ' + l[m:] for l in lines])
137+
138+
139+
if __name__ == '__main__':
140+
print(red('this should be red'))
141+
print(blue('this should be blue'))
142+
print(green('this should be green'))
143+
print(yellow('this should be yellow'))
144+
print(underline('this should be underline'))
145+
146+
print()
147+
print(b_(
148+
('hi', blue('im blue'), 56),
149+
'okay',
150+
'',
151+
red('bloop'),
152+
))
153+
154+
print()
155+
print(block_text(
156+
l_('hiiii', red('okay')),
157+
bold('well'),
158+
green('alright'),
159+
))

0 commit comments

Comments
 (0)