from sys import stdout, stdin
from re import compile as regex_compile
from time import sleep
+from os import walk, path
+from json import dumps
from kamaki.cli.errors import raiseCLIError
+
+INDENT_TAB = 4
+
+
+suggest = dict(ansicolors=dict(
+ active=False,
+ url='#install-ansicolors-progress',
+ description='Add colors to console responses'))
+
try:
from colors import magenta, red, yellow, bold
except ImportError:
def dummy(val):
return val
red = yellow = magenta = bold = dummy
+ #from kamaki.cli import _colors
+ #if _colors.lower() == 'on':
+ suggest['ansicolors']['active'] = True
+
+try:
+ from progress.bar import ShadyBar
+except ImportError:
+ suggest['progress']['active'] = True
+
+
+def suggest_missing(miss=None, exclude=[]):
+ global suggest
+ sgs = dict(suggest)
+ for exc in exclude:
+ try:
+ sgs.pop(exc)
+ except KeyError:
+ pass
+ kamaki_docs = 'http://www.synnefo.org/docs/kamaki/latest'
+ for k, v in (miss, sgs[miss]) if miss else sgs.items():
+ if v['active'] and stdout.isatty():
+ print('Suggestion: for better user experience install %s' % k)
+ print('\t%s' % v['description'])
+ print('\tIt is easy, here are the instructions:')
+ print('\t%s/installation.html%s' % (kamaki_docs, v['url']))
+ print('')
def remove_colors():
return new_d
+def print_json(data):
+ """Print a list or dict as json in console
+
+ :param data: json-dumpable data
+ """
+ print(dumps(data, indent=INDENT_TAB))
+
+
+def pretty_dict(d, *args, **kwargs):
+ print_dict(pretty_keys(d, *args, **kwargs))
+
+
def print_dict(
- d, exclude=(), ident=0,
+ d,
+ exclude=(), indent=0,
with_enumeration=False, recursive_enumeration=False):
- """
- Pretty-print a dictionary object
+ """Pretty-print a dictionary object
+ <indent>key: <non iterable item>
+ <indent>key:
+ <indent + INDENT_TAB><pretty-print iterable>
- :param d: (dict) the input
+ :param d: (dict)
- :param excelude: (set or list) keys to exclude from printing
+ :param exclude: (iterable of strings) keys to exclude from printing
- :param ident: (int) initial indentation (recursive)
+ :param indent: (int) initial indentation (recursive)
- :param with_enumeration: (bool) enumerate each 1st level key if true
+ :param with_enumeration: (bool) enumerate 1st-level keys
- :recursive_enumeration: (bool) recursively enumerate dicts and lists of
- 2nd level or deeper
+ :param recursive_enumeration: (bool) recursively enumerate iterables (does
+ not enumerate 1st level keys)
- :raises CLIError: (TypeError wrapper) non-dict input
+ :raises CLIError: if preconditions fail
"""
- if not isinstance(d, dict):
- raiseCLIError(TypeError('Cannot dict_print a non-dict object'))
+ assert isinstance(d, dict), 'print_dict input must be a dict'
+ assert indent >= 0, 'print_dict indent must be >= 0'
- if d:
- margin = max(len(('%s' % key).strip()) for key in d.keys() if (
- key not in exclude))
-
- counter = 1
- for key, val in sorted(d.items()):
- if key in exclude:
+ for i, (k, v) in enumerate(d.items()):
+ k = ('%s' % k).strip()
+ if k in exclude:
continue
- print_str = ''
- if with_enumeration:
- print_str = '%s. ' % counter
- counter += 1
- print_str = '%s%s' % (' ' * (ident - len(print_str)), print_str)
- print_str += ('%s' % key).strip()
- print_str += ' ' * (margin - len(unicode(key).strip()))
- print_str += ': '
- if isinstance(val, dict):
- print(print_str)
+ print_str = ' ' * indent
+ print_str += '%s.' % (i + 1) if with_enumeration else ''
+ print_str += '%s:' % k
+ if isinstance(v, dict):
+ print print_str
print_dict(
- val,
- exclude=exclude,
- ident=margin + ident,
- with_enumeration=recursive_enumeration,
- recursive_enumeration=recursive_enumeration)
- elif isinstance(val, list):
- print(print_str)
+ v, exclude, indent + INDENT_TAB,
+ recursive_enumeration, recursive_enumeration)
+ elif isinstance(v, list) or isinstance(v, tuple):
+ print print_str
print_list(
- val,
- exclude=exclude,
- ident=margin + ident,
- with_enumeration=recursive_enumeration,
- recursive_enumeration=recursive_enumeration)
+ v, exclude, indent + INDENT_TAB,
+ recursive_enumeration, recursive_enumeration)
else:
- print print_str + ' ' + unicode(val).strip()
+ print '%s %s' % (print_str, v)
def print_list(
- l, exclude=(), ident=0,
+ l,
+ exclude=(), indent=0,
with_enumeration=False, recursive_enumeration=False):
- """
- Pretty-print a list object
+ """Pretty-print a list of items
+ <indent>key: <non iterable item>
+ <indent>key:
+ <indent + INDENT_TAB><pretty-print iterable>
- :param l: (list) the input
+ :param l: (list)
- :param excelude: (object - anytype) values to exclude from printing
+ :param exclude: (iterable of strings) items to exclude from printing
- :param ident: (int) initial indentation (recursive)
+ :param indent: (int) initial indentation (recursive)
- :param with_enumeration: (bool) enumerate each 1st level value if true
+ :param with_enumeration: (bool) enumerate 1st-level items
- :recursive_enumeration: (bool) recursively enumerate dicts and lists of
- 2nd level or deeper
+ :param recursive_enumeration: (bool) recursively enumerate iterables (does
+ not enumerate 1st level keys)
- :raises CLIError: (TypeError wrapper) non-list input
+ :raises CLIError: if preconditions fail
"""
- if not isinstance(l, list):
- raiseCLIError(TypeError('Cannot list_print a non-list object'))
-
- if l:
- try:
- margin = max(len(('%s' % item).strip()) for item in l if not (
- isinstance(item, dict) or
- isinstance(item, list) or
- item in exclude))
- except ValueError:
- margin = (2 + len(unicode(len(l)))) if enumerate else 1
-
- counter = 1
- prefix = ''
- for item in sorted(l):
- if item in exclude:
- continue
- elif with_enumeration:
- prefix = '%s. ' % counter
- counter += 1
- prefix = '%s%s' % (' ' * (ident - len(prefix)), prefix)
- else:
- prefix = ' ' * ident
+ assert isinstance(l, list) or isinstance(l, tuple), (
+ 'print_list prinbts a list or tuple')
+ assert indent >= 0, 'print_list indent must be >= 0'
+
+ counter = 0
+ for i, item in enumerate(l):
+ print_str = ' ' * indent
+ print_str += '%s.' % (i + 1) if with_enumeration else ''
if isinstance(item, dict):
if with_enumeration:
- print(prefix)
+ print print_str
+ elif counter and counter < len(l):
+ print
print_dict(
- item,
- exclude=exclude,
- ident=margin + ident,
- with_enumeration=recursive_enumeration,
- recursive_enumeration=recursive_enumeration)
- elif isinstance(item, list):
+ item, exclude,
+ indent + (INDENT_TAB if with_enumeration else 0),
+ recursive_enumeration, recursive_enumeration)
+ elif isinstance(item, list) or isinstance(item, tuple):
if with_enumeration:
- print(prefix)
+ print print_str
+ elif counter and counter < len(l):
+ print
print_list(
- item,
- exclude=exclude,
- ident=margin + ident,
- with_enumeration=recursive_enumeration,
- recursive_enumeration=recursive_enumeration)
+ item, exclude, indent + INDENT_TAB,
+ recursive_enumeration, recursive_enumeration)
else:
- print('%s%s' % (prefix, item))
+ item = ('%s' % item).strip()
+ if item in exclude:
+ continue
+ print '%s%s' % (print_str, item)
+ counter += 1
def page_hold(index, limit, maxlen):
Objects of next level don't inherit enumeration (default: off) or titles
:param items: (list) items are lists or dict
+
:param title: (tuple) keys to use their values as title
+
:param with_enumeration: (boolean) enumerate items (order id on title)
+
:param with_redundancy: (boolean) values in title also appear on body
+
:param page_size: (int) show results in pages of page_size items, enter to
continue
"""
if isinstance(item, dict):
title = sorted(set(title).intersection(item.keys()))
if with_redundancy:
- header = ' '.join(unicode(item[key]) for key in title)
+ header = ' '.join('%s' % item[key] for key in title)
else:
- header = ' '.join(unicode(item.pop(key)) for key in title)
+ header = ' '.join('%s' % item.pop(key) for key in title)
print(bold(header))
if isinstance(item, dict):
- print_dict(item, ident=1)
+ print_dict(item, indent=INDENT_TAB)
elif isinstance(item, list):
- print_list(item, ident=1)
+ print_list(item, indent=INDENT_TAB)
else:
print(' %s' % item)
page_hold(i + 1, page_size, len(items))
f.write('\n')
list2file(v, f, depth + 1)
else:
- f.write(' %s\n' % unicode(v))
+ f.write(' %s\n' % v)
def list2file(l, f, depth=1):
elif isinstance(item, list):
list2file(item, f, depth + 1)
else:
- f.write('%s%s\n' % ('\t' * depth, unicode(item)))
+ f.write('%s%s\n' % ('\t' * depth, item))
# Split input auxiliary
return terms
-def ask_user(msg, true_resp=['Y', 'y']):
+def ask_user(msg, true_resp=('y', )):
"""Print msg and read user response
:param true_resp: (tuple of chars)
:returns: (bool) True if reponse in true responses, False otherwise
"""
- stdout.write('%s (%s or enter for yes):' % (msg, ', '.join(true_resp)))
+ stdout.write('%s [%s/N]: ' % (msg, ', '.join(true_resp)))
stdout.flush()
user_response = stdin.readline()
- return user_response[0] in true_resp + ['\n']
+ return user_response[0].lower() in true_resp
def spiner(size=None):
print('%s. Split this: (%s)' % (i + 1, example))
ret = old_split_input(example)
print('\t(%s) of size %s' % (ret, len(ret)))
+
+
+def get_path_size(testpath):
+ if path.isfile(testpath):
+ return path.getsize(testpath)
+ total_size = 0
+ for top, dirs, files in walk(path.abspath(testpath)):
+ for f in files:
+ f = path.join(top, f)
+ if path.isfile(f):
+ total_size += path.getsize(f)
+ return total_size
+
+
+def remove_from_items(list_of_dicts, key_to_remove):
+ for item in list_of_dicts:
+ assert isinstance(item, dict), 'Item %s not a dict' % item
+ item.pop(key_to_remove, None)