16 Commits

Author SHA1 Message Date
star:Kenneth Reitz 2f6e9cbfaa added args.starts_with for flag catcher 2011-03-22 14:07:34 -04:00
star:Kenneth Reitz b576ccbaae disable colors, clean available externally. 2011-03-22 13:56:23 -04:00
star:Kenneth Reitz 8e021f95e9 join returns colored string (for now) 2011-03-22 13:33:56 -04:00
star:Kenneth Reitz 83bf2288dd text_width example 2011-03-22 08:44:00 -04:00
star:Kenneth Reitz f2fc21755b COLUMNS! 2011-03-22 08:03:35 -04:00
star:Kenneth Reitz 52488ace36 ColoredString support for width formatters 2011-03-22 08:03:24 -04:00
star:Kenneth Reitz 8b6eb543b9 textui.clean for stripping colored cli output 2011-03-22 08:02:36 -04:00
star:Kenneth Reitz 2cd9bd5263 min/max widths in textui core
configurable newlines
2011-03-22 04:36:06 -04:00
star:Kenneth Reitz 76bee9c4ba max_width in place. 2011-03-22 04:35:38 -04:00
star:Kenneth Reitz 14c4cdf904 Added utils.schunk() for bytes chunking 2011-03-22 04:18:25 -04:00
star:Kenneth Reitz f6a20fc413 test commit 2011-03-22 03:11:18 -04:00
Kenneth Reitz fc3eeca54f :octocat: says: 'the 🍰 is a lie!' 2011-03-22 03:05:04 -04:00
Kenneth Reitz ebdb04848a fix for found arg at pos 0 2011-03-22 01:17:16 -04:00
Kenneth Reitz f0206b21fc fix for found arg at pos 0 2011-03-22 01:02:07 -04:00
Kenneth Reitz 5366c7e5b2 not_files should return Args object. 2011-03-21 23:53:16 -04:00
Kenneth Reitz 35ec821e37 case typo 2011-03-21 22:36:34 -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): 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 (dir, dirs, files) in os.walk(path):
for file in files: for file in files:
paths.append(os.path.join(dir, file)) paths.append(os.path.join(dir, file))
else: else:
paths.extend(glob(path)) paths.extend(glob(path))
return paths return paths
class Args(object): class Args(object):
@@ -69,7 +69,7 @@ class Args(object):
def __contains__(self, x): def __contains__(self, x):
return bool(self.first(x)) return self.first(x) is not None
def get(self, x): def get(self, x):
@@ -90,7 +90,7 @@ class Args(object):
def _remove(x): def _remove(x):
found = self.first(x) found = self.first(x)
if found: if found is not None:
self._args.pop(found) self._args.pop(found)
if is_collection(x): if is_collection(x):
@@ -133,7 +133,7 @@ class Args(object):
if is_collection(x): if is_collection(x):
for item in x: for item in x:
found = _find(item) found = _find(item)
if found: if found is not None:
return found return found
return None return None
else: else:
@@ -181,6 +181,25 @@ class Args(object):
else: else:
return _find(x) 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): def contains_at(self, x, index):
"""Tests if given [list of] string is at given index.""" """Tests if given [list of] string is at given index."""
@@ -305,7 +324,7 @@ class Args(object):
def flags(self): def flags(self):
"""Returns Arg object including only flagged arguments.""" """Returns Arg object including only flagged arguments."""
return self.all_with('-') return self.start_with('-')
@property @property
@@ -343,7 +362,7 @@ class Args(object):
if not os.path.exists(arg): if not os.path.exists(arg):
_args.append(arg) _args.append(arg)
return _args return Args(_args, no_argv=True)
@property @property
def copy(self): 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 from __future__ import absolute_import
import re
import sys
from ..packages import colorama from ..packages import colorama
DISABLE_COLOR = False
if sys.stdout.isatty():
colorama.init(autoreset=True) colorama.init(autoreset=True)
__all__ = ( __all__ = (
'red', 'green', 'yellow', 'blue', '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__() super(ColoredString, self).__init__()
self.s = s self.s = s
self.color = color 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): def __len__(self):
return len(self.s) return len(self.s)
@@ -46,17 +58,31 @@ class ColoredString(object):
return self.color_str return self.color_str
def __add__(self, other): def __add__(self, other):
return str(self.color_str) + str(other) self.s += other
return self
def __radd__(self, other): def __radd__(self, other):
return str(other) + str(self.color_str) self.s = other + self.s
return self
def __mul__(self, other): def __mul__(self, other):
return (self.color_str * other) return (self.color_str * other)
def split(self, x=' '): 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): def black(string):
@@ -82,3 +108,9 @@ def cyan(string):
def white(string): def white(string):
return ColoredString('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 import sys
from .progress import progressbar from .progress import progressbar
from .formatters import max_width, min_width
from ..utils import tsplit from ..utils import tsplit
__all__ = ('puts', 'puts_err', 'indent', 'progressbar') __all__ = ('puts', 'puts_err', 'indent', 'progressbar', 'max_width', 'min_width')
STDOUT = sys.stdout.write STDOUT = sys.stdout.write
STDERR = sys.stderr.write STDERR = sys.stderr.write
NEWLINES = ('\n', '\r', '\r\n')
class Writer(object): class Writer(object):
"""WriterUtilized by context managers.""" """WriterUtilized by context managers."""
@@ -60,10 +64,11 @@ class Writer(object):
def __call__(self, s, newline=True, stream=STDOUT): def __call__(self, s, newline=True, stream=STDOUT):
if newline: if newline:
s = tsplit(s, ('\n', '\r', '\r\n')) s = tsplit(s, NEWLINES)
s = map(str, s)
indent = ''.join(self.shared['indent_strings']) indent = ''.join(self.shared['indent_strings'])
s = ('\n' + indent).join(s) s = (str('\n' + indent)).join(s)
_str = ''.join(( _str = ''.join((
''.join(self.shared['indent_strings']), ''.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 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 import unittest
class TablibTestCase(unittest.TestCas): class TablibTestCase(unittest.TestCase):
"""Tablib test cases.""" """Tablib test cases."""
def setUp(self): def setUp(self):
@@ -16,7 +16,5 @@ class TablibTestCase(unittest.TestCas):
def tearDown(self): def tearDown(self):
pass pass
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()