mirror of
https://github.com/kennethreitz/clint.git
synced 2026-06-05 23:00:18 +00:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9d3693d644 | |||
| ee695135a7 | |||
| e4ba837bad | |||
| 3b77ef3b43 | |||
| 2698af12dd | |||
| 195ab0de4d | |||
| b16b2248cd | |||
| dc8fbfd355 | |||
| 8f42b40900 | |||
| 96013432d9 | |||
| 84ce2ed9b1 | |||
| 8c3cbe984b | |||
| d0fe6df171 | |||
| 7865d7a375 | |||
| 0931dbff9f | |||
| 8dc046b9c7 | |||
| 39322ea11f | |||
| a190f64e3c | |||
| a7a28da410 | |||
| a1203ff9d9 | |||
| 16e50a62e1 | |||
| a173f763d0 | |||
| e101c56eed | |||
| 52ff92d7d5 | |||
| 34ec848479 | |||
| 2bd5aef5bc | |||
| a47ed4f711 | |||
| d0a5237afe | |||
| d6cb52f8b3 | |||
| a09b1efa76 | |||
| 85d5f52549 | |||
| 7be8140d91 | |||
| fb96edf52f | |||
| 439de410c0 | |||
| 5a88ee3a52 | |||
| 3077b0f53e | |||
| 5e7a191957 | |||
| 6aedd380cf |
+13
@@ -0,0 +1,13 @@
|
||||
language: python
|
||||
python:
|
||||
- 2.6
|
||||
- 2.7
|
||||
- 3.2
|
||||
- 3.3
|
||||
- pypy
|
||||
install:
|
||||
- pip install pytest args coveralls pytest-cov
|
||||
script:
|
||||
- py.test --cov clint
|
||||
after_success:
|
||||
- coveralls
|
||||
@@ -31,3 +31,4 @@ Patches and Suggestions
|
||||
- Eric Anderson
|
||||
- Joshua Richardson
|
||||
- Brandon Liu <thenovices>
|
||||
- Kentaro Wada <www.kentaro.wada@gmail.com>
|
||||
|
||||
+5
-1
@@ -1,6 +1,10 @@
|
||||
History
|
||||
-------
|
||||
|
||||
0.5.1
|
||||
+++++
|
||||
* Fix line width calculation in max_width when using coloured text (thanks to @wkentaro)
|
||||
|
||||
0.5.0
|
||||
+++++
|
||||
* Added option prompt
|
||||
@@ -73,7 +77,7 @@ History
|
||||
0.2.3
|
||||
+++++
|
||||
|
||||
* Only init colors if they are used (iPython compatability)
|
||||
* Only init colors if they are used (iPython compatibility)
|
||||
* New progress module
|
||||
* Various bugfixes
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2011, Kenneth Reitz <me@kennethreitz.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
@@ -10,4 +12,4 @@ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
Clint: Python Command-line Application Tools
|
||||
Clint: Python Command-line Interface Tools
|
||||
============================================
|
||||
|
||||
**Clint** is a module filled with a set of awesome tools for developing
|
||||
@@ -28,7 +28,8 @@ Run the various executables in examples_ to get a good feel for what Clint offer
|
||||
|
||||
You'll never want to not use it.
|
||||
|
||||
|
||||
.. image:: https://travis-ci.org/kennethreitz/clint.png?branch=master
|
||||
:target: https://travis-ci.org/kennethreitz/clint
|
||||
|
||||
Current Features:
|
||||
-----------------
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ from .pipes import piped_in
|
||||
|
||||
|
||||
__title__ = 'clint'
|
||||
__version__ = '0.5.0'
|
||||
__build__ = 0x000500
|
||||
__version__ = '0.5.1'
|
||||
__build__ = 0x000501
|
||||
__author__ = 'Kenneth Reitz'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = 'Copyright 2012 Kenneth Reitz'
|
||||
|
||||
@@ -18,6 +18,7 @@ import sys
|
||||
PY3 = sys.version_info[0] >= 3
|
||||
|
||||
from ..packages import colorama
|
||||
from ..utils import basestring
|
||||
|
||||
__all__ = (
|
||||
'red', 'green', 'yellow', 'blue',
|
||||
@@ -42,7 +43,10 @@ class ColoredString(object):
|
||||
"""Enhanced string for __len__ operations on Colored output."""
|
||||
def __init__(self, color, s, always_color=False, bold=False):
|
||||
super(ColoredString, self).__init__()
|
||||
self.s = s
|
||||
if not PY3 and isinstance(s, unicode):
|
||||
self.s = s.encode('utf-8')
|
||||
else:
|
||||
self.s = s
|
||||
self.color = color
|
||||
self.always_color = always_color
|
||||
self.bold = bold
|
||||
@@ -93,10 +97,7 @@ class ColoredString(object):
|
||||
__str__ = __unicode__
|
||||
else:
|
||||
def __str__(self):
|
||||
value = self.color_str
|
||||
if isinstance(value, bytes):
|
||||
return value
|
||||
return value.encode('utf8')
|
||||
return self.color_str
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.color_str)
|
||||
|
||||
@@ -15,7 +15,7 @@ import sys
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
from .formatters import max_width, min_width
|
||||
from .formatters import max_width, min_width, _get_max_width_context
|
||||
from .cols import columns
|
||||
from ..utils import tsplit
|
||||
|
||||
@@ -53,6 +53,11 @@ def _indent(indent=0, quote='', indent_char=' '):
|
||||
|
||||
def puts(s='', newline=True, stream=STDOUT):
|
||||
"""Prints given string to stdout."""
|
||||
max_width_ctx = _get_max_width_context()
|
||||
if max_width_ctx:
|
||||
cols, separator = max_width_ctx[-1]
|
||||
s = max_width(s, cols, separator)
|
||||
|
||||
if newline:
|
||||
s = tsplit(s, NEWLINES)
|
||||
s = map(str, s)
|
||||
|
||||
@@ -9,12 +9,14 @@ Core TextUI functionality for text formatting.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from contextlib import contextmanager
|
||||
|
||||
from .colored import ColoredString, clean
|
||||
from ..utils import tsplit, schunk
|
||||
|
||||
|
||||
NEWLINES = ('\n', '\r', '\r\n')
|
||||
MAX_WIDTHS = []
|
||||
|
||||
|
||||
def min_width(string, cols, padding=' '):
|
||||
@@ -33,17 +35,72 @@ def min_width(string, cols, padding=' '):
|
||||
return '\n'.join(stack)
|
||||
|
||||
|
||||
def max_width(string, cols, separator='\n'):
|
||||
"""Returns a freshly formatted """
|
||||
def _get_max_width_context():
|
||||
return MAX_WIDTHS
|
||||
|
||||
@contextmanager
|
||||
def _max_width_context():
|
||||
"""Max width context manager."""
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
MAX_WIDTHS.pop()
|
||||
|
||||
def max_width(*args, **kwargs):
|
||||
"""Returns formatted text or context manager for textui:puts.
|
||||
|
||||
>>> from clint.textui import puts, max_width
|
||||
>>> max_width('123 5678', 8)
|
||||
'123 5678'
|
||||
>>> max_width('123 5678', 7)
|
||||
'123 \n5678'
|
||||
>>> with max_width(7):
|
||||
... puts('123 5678')
|
||||
'123 \n5678'
|
||||
"""
|
||||
args = list(args)
|
||||
|
||||
if not args:
|
||||
args.append(kwargs.get('string'))
|
||||
args.append(kwargs.get('cols'))
|
||||
args.append(kwargs.get('separator'))
|
||||
elif len(args) == 1:
|
||||
args.append(kwargs.get('cols'))
|
||||
args.append(kwargs.get('separator'))
|
||||
elif len(args) == 2:
|
||||
args.append(kwargs.get('separator'))
|
||||
|
||||
string, cols, separator = args
|
||||
if separator is None:
|
||||
separator = '\n' # default value
|
||||
if cols is None:
|
||||
# cols should be specified vitally
|
||||
# because string can be specified at textui:puts function
|
||||
string, cols = cols, string
|
||||
|
||||
if string is None:
|
||||
MAX_WIDTHS.append((cols, separator))
|
||||
return _max_width_context()
|
||||
else:
|
||||
return _max_width_formatter(string, cols, separator)
|
||||
|
||||
|
||||
def _max_width_formatter(string, cols, separator='\n'):
|
||||
"""Returns a freshly formatted
|
||||
:param string: string to be formatted
|
||||
:type string: basestring or clint.textui.colored.ColoredString
|
||||
:param cols: max width the text to be formatted
|
||||
:type cols: int
|
||||
:param separator: separator to break rows
|
||||
:type separator: basestring
|
||||
"""
|
||||
|
||||
is_color = isinstance(string, ColoredString)
|
||||
|
||||
if is_color:
|
||||
offset = 10
|
||||
string_copy = string._new('')
|
||||
else:
|
||||
offset = 0
|
||||
|
||||
string = string.s
|
||||
|
||||
stack = tsplit(string, NEWLINES)
|
||||
|
||||
for i, substring in enumerate(stack):
|
||||
@@ -56,31 +113,36 @@ def max_width(string, cols, separator='\n'):
|
||||
_row_i = 0
|
||||
|
||||
for word in row:
|
||||
if (len(_row[_row_i]) + len(word)) < (cols + offset):
|
||||
if (len(_row[_row_i]) + len(word)) <= cols:
|
||||
_row[_row_i] += word
|
||||
_row[_row_i] += ' '
|
||||
|
||||
elif len(word) > (cols - offset):
|
||||
elif len(word) > cols:
|
||||
|
||||
# ensure empty row
|
||||
if len(_row[_row_i]):
|
||||
_row[_row_i] = _row[_row_i].rstrip()
|
||||
_row.append('')
|
||||
_row_i += 1
|
||||
|
||||
chunks = schunk(word, (cols + offset))
|
||||
chunks = schunk(word, cols)
|
||||
for i, chunk in enumerate(chunks):
|
||||
if not (i + 1) == len(chunks):
|
||||
_row[_row_i] += chunk
|
||||
_row[_row_i] = _row[_row_i].rstrip()
|
||||
_row.append('')
|
||||
_row_i += 1
|
||||
else:
|
||||
_row[_row_i] += chunk
|
||||
_row[_row_i] += ' '
|
||||
else:
|
||||
_row[_row_i] = _row[_row_i].rstrip()
|
||||
_row.append('')
|
||||
_row_i += 1
|
||||
_row[_row_i] += word
|
||||
_row[_row_i] += ' '
|
||||
else:
|
||||
_row[_row_i] = _row[_row_i].rstrip()
|
||||
|
||||
_row = map(str, _row)
|
||||
_stack.append(separator.join(_row))
|
||||
|
||||
@@ -109,8 +109,8 @@ def bar(it, label='', width=32, hide=None, empty_char=BAR_EMPTY_CHAR,
|
||||
|
||||
count = len(it) if expected_size is None else expected_size
|
||||
|
||||
with Bar(label=label, width=width, hide=hide, empty_char=BAR_EMPTY_CHAR,
|
||||
filled_char=BAR_FILLED_CHAR, expected_size=count, every=every) \
|
||||
with Bar(label=label, width=width, hide=hide, empty_char=empty_char,
|
||||
filled_char=filled_char, expected_size=count, every=every) \
|
||||
as bar:
|
||||
for i, item in enumerate(it):
|
||||
yield item
|
||||
|
||||
@@ -11,6 +11,7 @@ Module for simple interactive prompts handling
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
from re import match, I
|
||||
import getpass
|
||||
|
||||
from .core import puts
|
||||
from .colored import yellow
|
||||
@@ -59,7 +60,7 @@ def yn(prompt, default='y', batch=False):
|
||||
return True if default == 'n' else False
|
||||
|
||||
|
||||
def query(prompt, default='', validators=None, batch=False):
|
||||
def query(prompt, default='', validators=None, batch=False, mask_input=False):
|
||||
# Set the nonempty validator as default
|
||||
if validators is None:
|
||||
validators = [RegexValidator(r'.+')]
|
||||
@@ -76,7 +77,8 @@ def query(prompt, default='', validators=None, batch=False):
|
||||
# If batch option is True then auto reply
|
||||
# with default input
|
||||
if not batch:
|
||||
user_input = raw_input(prompt).strip() or default
|
||||
user_input_fn = getpass.getpass if mask_input else raw_input
|
||||
user_input = user_input_fn(prompt).strip() or default
|
||||
else:
|
||||
print(prompt)
|
||||
user_input = ''
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ from os import makedirs
|
||||
from glob import glob
|
||||
|
||||
try:
|
||||
basestring
|
||||
basestring = basestring
|
||||
except NameError:
|
||||
basestring = str
|
||||
|
||||
|
||||
+4
-2
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
@@ -17,6 +19,6 @@ with indent(4, quote='>>>'):
|
||||
puts(colored.red('Files detected: ') + str(args.files))
|
||||
puts(colored.red('NOT Files detected: ') + str(args.not_files))
|
||||
puts(colored.red('Grouped Arguments: ') + str(dict(args.grouped)))
|
||||
|
||||
print
|
||||
|
||||
print()
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
from clint.arguments import Args
|
||||
from clint.textui import puts, colored
|
||||
|
||||
@@ -8,6 +13,6 @@ all_args = Args().grouped
|
||||
|
||||
for item in all_args:
|
||||
if item is not '_':
|
||||
puts(colored.red("key:%s"%item))
|
||||
puts(colored.red("key:%s" % item))
|
||||
print(all_args[item].all)
|
||||
|
||||
|
||||
@@ -54,4 +54,5 @@ setup(
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Topic :: Terminals :: Terminal Emulators/X Terminals',
|
||||
],
|
||||
test_suite='test_clint',
|
||||
)
|
||||
|
||||
+36
-6
@@ -18,25 +18,25 @@ class ClintTestCase(unittest.TestCase):
|
||||
pass
|
||||
|
||||
class ColoredStringTestCase(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
from clint.textui.colored import ColoredString
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
|
||||
def test_split(self):
|
||||
from clint.textui.colored import ColoredString
|
||||
new_str = ColoredString('red', "hello world")
|
||||
output = new_str.split()
|
||||
assert output[0].s == "hello"
|
||||
|
||||
|
||||
def test_find(self):
|
||||
from clint.textui.colored import ColoredString
|
||||
new_str = ColoredString('blue', "hello world")
|
||||
output = new_str.find('h')
|
||||
self.assertEqual(output, 0)
|
||||
|
||||
|
||||
def test_replace(self):
|
||||
from clint.textui.colored import ColoredString
|
||||
new_str = ColoredString('green', "hello world")
|
||||
@@ -49,7 +49,6 @@ class ColoredStringTestCase(unittest.TestCase):
|
||||
new_str = ColoredString('RED', '\xe4')
|
||||
assert '\xe4' in str(new_str)
|
||||
from clint.textui import puts
|
||||
puts(new_str)
|
||||
|
||||
def test_clint_force_color_env_var(self):
|
||||
from clint.textui.colored import ColoredString
|
||||
@@ -57,6 +56,37 @@ class ColoredStringTestCase(unittest.TestCase):
|
||||
new_str = ColoredString('RED', 'hello world')
|
||||
assert new_str.always_color == True
|
||||
|
||||
def test_clint_unicode_radd(self):
|
||||
from clint.textui.colored import ColoredString
|
||||
inp_str = u'hello \u263A'
|
||||
new_str = u'' + ColoredString('RED', inp_str)
|
||||
assert inp_str.encode('utf-8') in new_str
|
||||
|
||||
|
||||
class TextuiFormatterTestCase(unittest.TestCase):
|
||||
|
||||
def test_max_width(self):
|
||||
|
||||
def _test_n_rows_width(ins, rows, n_rows, max_width):
|
||||
ins.assertEqual(len(rows), n_rows)
|
||||
for row in rows:
|
||||
ins.assertLessEqual(len(row), max_width)
|
||||
|
||||
from clint.textui.formatters import max_width
|
||||
from clint.textui import colored
|
||||
# normal text
|
||||
text = ' '.join(['XXX'] * 3)
|
||||
rows = max_width(text, 6).split('\n')
|
||||
_test_n_rows_width(self, rows, 3, 6)
|
||||
rows = max_width(text, 7).split('\n')
|
||||
_test_n_rows_width(self, rows, 2, 7)
|
||||
# colored text
|
||||
c_text = colored.yellow(text)
|
||||
rows = max_width(c_text, 6).split('\n')
|
||||
_test_n_rows_width(self, rows, 3, 6)
|
||||
rows = max_width(c_text, 7).split('\n')
|
||||
_test_n_rows_width(self, rows, 2, 7)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user