Merge branch 'feature/widths'

This commit is contained in:
star:Kenneth Reitz
2011-03-23 06:35:33 -04:00
9 changed files with 360 additions and 30 deletions
+1 -1
View File
@@ -1 +1 @@
include HISTORY.rst README.rst LICENSE AUTHORS NOTICE
include HISTORY.rst README.rst LICENSE AUTHORS NOTICE
+33 -14
View File
@@ -25,19 +25,19 @@ __all__ = ('Args', )
def _expand_path(path):
"""Expands directories and globs in given path."""
"""Expands directories and globs in given path."""
paths = []
paths = []
if os.path.isdir(path):
if os.path.isdir(path):
for (dir, dirs, files) in os.walk(path):
for file in files:
paths.append(os.path.join(dir, file))
else:
paths.extend(glob(path))
for (dir, dirs, files) in os.walk(path):
for file in files:
paths.append(os.path.join(dir, file))
else:
paths.extend(glob(path))
return paths
return paths
class Args(object):
@@ -69,7 +69,7 @@ class Args(object):
def __contains__(self, x):
return bool(self.first(x))
return self.first(x) is not None
def get(self, x):
@@ -90,7 +90,7 @@ class Args(object):
def _remove(x):
found = self.first(x)
if found:
if found is not None:
self._args.pop(found)
if is_collection(x):
@@ -133,7 +133,7 @@ class Args(object):
if is_collection(x):
for item in x:
found = _find(item)
if found:
if found is not None:
return found
return None
else:
@@ -181,6 +181,25 @@ class Args(object):
else:
return _find(x)
def start_with(self, x):
"""Returns all arguments beginning with given string (or list thereof)"""
_args = []
for arg in self.all:
if is_collection(x):
for _x in x:
if arg.startswith(x):
_args.append(arg)
break
else:
if arg.startswith(x):
_args.append(arg)
return Args(_args, no_argv=True)
def contains_at(self, x, index):
"""Tests if given [list of] string is at given index."""
@@ -305,7 +324,7 @@ class Args(object):
def flags(self):
"""Returns Arg object including only flagged arguments."""
return self.all_with('-')
return self.start_with('-')
@property
@@ -343,7 +362,7 @@ class Args(object):
if not os.path.exists(arg):
_args.append(arg)
return _args
return Args(_args, no_argv=True)
@property
def copy(self):
+41 -9
View File
@@ -11,16 +11,21 @@ This module provides a simple and elegant wrapper for colorama.
from __future__ import absolute_import
import re
import sys
from ..packages import colorama
DISABLE_COLOR = False
colorama.init(autoreset=True)
if sys.stdout.isatty():
colorama.init(autoreset=True)
__all__ = (
'red', 'green', 'yellow', 'blue',
'black', 'magenta', 'cyan', 'white'
'black', 'magenta', 'cyan', 'white',
'clean', 'disable'
)
@@ -30,9 +35,16 @@ class ColoredString(object):
super(ColoredString, self).__init__()
self.s = s
self.color = color
self.color_str = '%s%s%s' % (
getattr(colorama.Fore, self.color), self.s, colorama.Fore.RESET)
@property
def color_str(self):
if sys.stdout.isatty() and not DISABLE_COLOR:
return '%s%s%s' % (
getattr(colorama.Fore, self.color), self.s, colorama.Fore.RESET)
else:
return self.s
def __len__(self):
return len(self.s)
@@ -46,17 +58,31 @@ class ColoredString(object):
return self.color_str
def __add__(self, other):
return str(self.color_str) + str(other)
self.s += other
return self
def __radd__(self, other):
return str(other) + str(self.color_str)
self.s = other + self.s
return self
def __mul__(self, other):
return (self.color_str * other)
def split(self, x=' '):
return self.color_str.split(x)
return map(self._new, self.s.split(x))
def _new(self, s):
return ColoredString(self.color, s)
def clean(s):
strip = re.compile("([^-_a-zA-Z0-9!@#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)")
txt = strip.sub('', str(s))
strip = re.compile(r'\[\d+m')
txt = strip.sub('', txt)
return txt
def black(string):
@@ -82,3 +108,9 @@ def cyan(string):
def white(string):
return ColoredString('WHITE', string)
def disable():
"""Disables colors."""
global DISABLE_COLOR
DISABLE_COLOR = True
+141
View File
@@ -0,0 +1,141 @@
# -*- coding: utf-8 -*-
"""
clint.textui.columns
~~~~~~~~~~~~~~~~~~~~
Core TextUI functionality for column formatting.
"""
from __future__ import absolute_import
from .formatters import max_width, min_width
from ..utils import tsplit
import sys
NEWLINES = ('\n', '\r', '\r\n')
def _find_unix_console_width():
import termios, fcntl, struct, sys
# fcntl.ioctl will fail if stdout is not a tty
if not sys.stdout.isatty():
return None
s = struct.pack("HHHH", 0, 0, 0, 0)
fd_stdout = sys.stdout.fileno()
size = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
height, width = struct.unpack("HHHH", size)[:2]
return width
def _find_windows_console_width():
# http://code.activestate.com/recipes/440694/
from ctypes import windll, create_string_buffer
STDIN, STDOUT, STDERR = -10, -11, -12
h = windll.kernel32.GetStdHandle(STDERR)
csbi = create_string_buffer(22)
res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
if res:
import struct
(bufx, bufy, curx, cury, wattr,
left, top, right, bottom,
maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
sizex = right - left + 1
sizey = bottom - top + 1
return sizex
def console_width(kwargs):
""""Determine console_width."""
if sys.platform.startswith('win'):
console_width = _find_windows_console_width()
else:
console_width = _find_unix_console_width()
_width = kwargs.get('width', None)
if _width:
console_width = _width
else:
if not console_width:
console_width = 80
return console_width
def columns(*cols, **kwargs):
columns = list(cols)
cwidth = console_width(kwargs)
_big_col = None
_total_cols = 0
for i, (string, width) in enumerate(cols):
if width is not None:
_total_cols += (width + 1)
cols[i][0] = max_width(string, width).split('\n')
else:
_big_col = i
if _big_col:
cols[_big_col][1] = (cwidth - _total_cols) - len(cols)
cols[_big_col][0] = max_width(cols[_big_col][0], cols[_big_col][1]).split('\n')
height = len(max([c[0] for c in cols], key=len))
for i, (strings, width) in enumerate(cols):
for _ in range(height - len(strings)):
cols[i][0].append('')
for j, string in enumerate(strings):
cols[i][0][j] = min_width(string, width)
stack = [c[0] for c in cols]
_out = []
for i in range(height):
_row = ''
for col in stack:
_row += col[i]
_row += ' '
_out.append(_row)
# try:
# pass
# except:
# pass
return '\n'.join(_out)
# string = max_width(string, width)
# string = min_width(string, width)
# pass
# columns.append()
###########################
a = 'this is text that goes into a small column\n cool?'
b = 'this is other text\nothertext\nothertext'
#columns((a, 10), (b, 20), (b, None))
+8 -3
View File
@@ -14,15 +14,19 @@ from __future__ import absolute_import
import sys
from .progress import progressbar
from .formatters import max_width, min_width
from ..utils import tsplit
__all__ = ('puts', 'puts_err', 'indent', 'progressbar')
__all__ = ('puts', 'puts_err', 'indent', 'progressbar', 'max_width', 'min_width')
STDOUT = sys.stdout.write
STDERR = sys.stderr.write
NEWLINES = ('\n', '\r', '\r\n')
class Writer(object):
"""WriterUtilized by context managers."""
@@ -60,10 +64,11 @@ class Writer(object):
def __call__(self, s, newline=True, stream=STDOUT):
if newline:
s = tsplit(s, ('\n', '\r', '\r\n'))
s = tsplit(s, NEWLINES)
s = map(str, s)
indent = ''.join(self.shared['indent_strings'])
s = ('\n' + indent).join(s)
s = (str('\n' + indent)).join(s)
_str = ''.join((
''.join(self.shared['indent_strings']),
+91
View File
@@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
"""
clint.textui.formatters
~~~~~~~~~~~~~~~~~~~~~~~
Core TextUI functionality for text formatting.
"""
from __future__ import absolute_import
from .colored import ColoredString, clean
from ..utils import tsplit, schunk
NEWLINES = ('\n', '\r', '\r\n')
def min_width(string, cols, padding=' '):
"""Returns given string with right padding."""
is_color = isinstance(string, ColoredString)
stack = tsplit(str(string), NEWLINES)
for i, substring in enumerate(stack):
_sub = clean(substring).ljust((cols + 0), padding)
if is_color:
_sub = (_sub.replace(clean(substring), substring))
stack[i] = _sub
return '\n'.join(stack)
def max_width(string, cols, separator='\n'):
"""Returns a freshly formatted """
is_color = isinstance(string, ColoredString)
if is_color:
offset = 10
string_copy = string._new('')
else:
offset = 0
stack = tsplit(string, NEWLINES)
for i, substring in enumerate(stack):
stack[i] = substring.split()
_stack = []
for row in stack:
_row = ['',]
_row_i = 0
for word in row:
if (len(_row[_row_i]) + len(word)) < (cols + offset):
_row[_row_i] += word
_row[_row_i] += ' '
elif len(word) > (cols - offset):
# ensure empty row
if len(_row[_row_i]):
_row.append('')
_row_i += 1
chunks = schunk(word, (cols + offset))
for i, chunk in enumerate(chunks):
if not (i + 1) == len(chunks):
_row[_row_i] += chunk
_row.append('')
_row_i += 1
else:
_row[_row_i] += chunk
_row[_row_i] += ' '
else:
_row.append('')
_row_i += 1
_row[_row_i] += word
_row[_row_i] += ' '
_row = map(str, _row)
_stack.append(separator.join(_row))
_s = '\n'.join(_stack)
if is_color:
_s = string_copy._new(_s)
return _s
+21
View File
@@ -49,3 +49,24 @@ def tsplit(string, delimiters):
return stack
def schunk(string, size):
"""Splits string into n sized chunks."""
stack = []
substack = []
current_count = 0
for char in string:
if not current_count < size:
stack.append(''.join(substack))
substack = []
current_count = 0
substack.append(char)
current_count += 1
if len(substack):
stack.append(''.join(substack))
return stack
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
sys.path.insert(0, os.path.abspath('..'))
from clint.textui import puts, colored
from clint.textui.columns import columns
lorem = 'Lorem ipsum dolor sit amet, consehdfhdfhdfhdfhdfhctetur adi pisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
if __name__ == '__main__':
# puts(min_width('test\nit', 20) + ' me')
# puts(max_width(lorem, 20) + ' me')
# print max_width(lorem, 45)
col = 60
puts(columns([(colored.red('Column 1')), col], [(colored.green('Column Two')), None], [(colored.magenta('Column III')), col]))
puts(columns(['hi there my name is kenneth and this is a columns', col], [lorem, None], ['kenneths', col]))
+1 -3
View File
@@ -6,7 +6,7 @@
import unittest
class TablibTestCase(unittest.TestCas):
class TablibTestCase(unittest.TestCase):
"""Tablib test cases."""
def setUp(self):
@@ -16,7 +16,5 @@ class TablibTestCase(unittest.TestCas):
def tearDown(self):
pass
if __name__ == '__main__':
unittest.main()