Revision f55d3a15 kamaki/cli/utils.py
b/kamaki/cli/utils.py | ||
---|---|---|
39 | 39 |
|
40 | 40 |
from kamaki.cli.errors import raiseCLIError |
41 | 41 |
|
42 |
|
|
43 |
IDENT_TAB = 4 |
|
44 |
|
|
45 |
|
|
42 | 46 |
suggest = dict(ansicolors=dict( |
43 | 47 |
active=False, |
44 | 48 |
url='#install-ansicolors-progress', |
... | ... | |
109 | 113 |
|
110 | 114 |
:param data: json-dumpable data |
111 | 115 |
""" |
112 |
print(dumps(data, indent=2))
|
|
116 |
print(dumps(data, indent=IDENT_TAB))
|
|
113 | 117 |
|
114 | 118 |
|
115 | 119 |
def pretty_dict(d, *args, **kwargs): |
... | ... | |
117 | 121 |
|
118 | 122 |
|
119 | 123 |
def print_dict( |
120 |
d, exclude=(), ident=0, |
|
124 |
d, |
|
125 |
exclude=(), indent=0, |
|
121 | 126 |
with_enumeration=False, recursive_enumeration=False): |
122 |
""" |
|
123 |
Pretty-print a dictionary object |
|
127 |
"""Pretty-print a dictionary object |
|
128 |
<indent>key: <non iterable item> |
|
129 |
<indent>key: |
|
130 |
<indent + IDENT_TAB><pretty-print iterable> |
|
124 | 131 |
|
125 |
:param d: (dict) the input
|
|
132 |
:param d: (dict) |
|
126 | 133 |
|
127 |
:param excelude: (set or list) keys to exclude from printing
|
|
134 |
:param exclude: (iterable of strings) keys to exclude from printing
|
|
128 | 135 |
|
129 |
:param ident: (int) initial indentation (recursive) |
|
136 |
:param indent: (int) initial indentation (recursive)
|
|
130 | 137 |
|
131 |
:param with_enumeration: (bool) enumerate each 1st level key if true
|
|
138 |
:param with_enumeration: (bool) enumerate 1st-level keys
|
|
132 | 139 |
|
133 |
:recursive_enumeration: (bool) recursively enumerate dicts and lists of
|
|
134 |
2nd level or deeper
|
|
140 |
:param recursive_enumeration: (bool) recursively enumerate iterables (does
|
|
141 |
not enumerate 1st level keys)
|
|
135 | 142 |
|
136 |
:raises CLIError: (TypeError wrapper) non-dict input
|
|
143 |
:raises CLIError: if preconditions fail
|
|
137 | 144 |
""" |
138 |
if not isinstance(d, dict): |
|
139 |
raiseCLIError(TypeError('Cannot dict_print a non-dict object')) |
|
140 |
|
|
141 |
if d: |
|
142 |
margin = max(len(('%s' % key).strip()) for key in d.keys() if ( |
|
143 |
key not in exclude)) |
|
145 |
assert isinstance(d, dict), 'print_dict input must be a dict' |
|
146 |
assert indent >= 0, 'print_dict indent must be >= 0' |
|
144 | 147 |
|
145 |
counter = 1 |
|
146 |
for key, val in sorted(d.items()): |
|
147 |
key = '%s' % key |
|
148 |
if key in exclude: |
|
148 |
for i, (k, v) in enumerate(d.items()): |
|
149 |
k = ('%s' % k).strip() |
|
150 |
if k in exclude: |
|
149 | 151 |
continue |
150 |
print_str = '' |
|
151 |
if with_enumeration: |
|
152 |
print_str = '%s. ' % counter |
|
153 |
counter += 1 |
|
154 |
print_str = '%s%s' % (' ' * (ident - len(print_str)), print_str) |
|
155 |
print_str += key.strip() |
|
156 |
print_str += ':' |
|
157 |
print_str += ' ' * (margin - len(key.strip())) |
|
158 |
#print_str += ':' |
|
159 |
if isinstance(val, dict): |
|
160 |
print(print_str) |
|
152 |
print_str = ' ' * indent |
|
153 |
print_str += '%s.' % (i + 1) if with_enumeration else '' |
|
154 |
print_str += '%s:' % k |
|
155 |
if isinstance(v, dict): |
|
156 |
print print_str |
|
161 | 157 |
print_dict( |
162 |
val, |
|
163 |
exclude=exclude, |
|
164 |
ident=margin + ident, |
|
165 |
with_enumeration=recursive_enumeration, |
|
166 |
recursive_enumeration=recursive_enumeration) |
|
167 |
elif isinstance(val, list): |
|
168 |
print(print_str) |
|
158 |
v, exclude, indent + IDENT_TAB, |
|
159 |
recursive_enumeration, recursive_enumeration) |
|
160 |
elif isinstance(v, list) or isinstance(v, tuple): |
|
161 |
print print_str |
|
169 | 162 |
print_list( |
170 |
val, |
|
171 |
exclude=exclude, |
|
172 |
ident=margin + ident, |
|
173 |
with_enumeration=recursive_enumeration, |
|
174 |
recursive_enumeration=recursive_enumeration) |
|
163 |
v, exclude, indent + IDENT_TAB, |
|
164 |
recursive_enumeration, recursive_enumeration) |
|
175 | 165 |
else: |
176 |
print print_str + ' ' + ('%s' % val).strip()
|
|
166 |
print '%s %s' % (print_str, v)
|
|
177 | 167 |
|
178 | 168 |
|
179 | 169 |
def print_list( |
180 |
l, exclude=(), ident=0, |
|
170 |
l, |
|
171 |
exclude=(), indent=0, |
|
181 | 172 |
with_enumeration=False, recursive_enumeration=False): |
182 |
""" |
|
183 |
Pretty-print a list object |
|
173 |
"""Pretty-print a list of items |
|
174 |
<indent>key: <non iterable item> |
|
175 |
<indent>key: |
|
176 |
<indent + IDENT_TAB><pretty-print iterable> |
|
184 | 177 |
|
185 |
:param l: (list) the input
|
|
178 |
:param l: (list) |
|
186 | 179 |
|
187 |
:param excelude: (object - anytype) values to exclude from printing
|
|
180 |
:param exclude: (iterable of strings) items to exclude from printing
|
|
188 | 181 |
|
189 |
:param ident: (int) initial indentation (recursive) |
|
182 |
:param indent: (int) initial indentation (recursive)
|
|
190 | 183 |
|
191 |
:param with_enumeration: (bool) enumerate each 1st level value if true
|
|
184 |
:param with_enumeration: (bool) enumerate 1st-level items
|
|
192 | 185 |
|
193 |
:recursive_enumeration: (bool) recursively enumerate dicts and lists of
|
|
194 |
2nd level or deeper
|
|
186 |
:param recursive_enumeration: (bool) recursively enumerate iterables (does
|
|
187 |
not enumerate 1st level keys)
|
|
195 | 188 |
|
196 |
:raises CLIError: (TypeError wrapper) non-list input
|
|
189 |
:raises CLIError: if preconditions fail
|
|
197 | 190 |
""" |
198 |
if not isinstance(l, list): |
|
199 |
raiseCLIError(TypeError('Cannot list_print a non-list object')) |
|
191 |
assert isinstance(l, list) or isinstance(l, tuple), ( |
|
192 |
'print_list prinbts a list or tuple') |
|
193 |
assert indent >= 0, 'print_list indent must be >= 0' |
|
200 | 194 |
|
201 |
if l: |
|
202 |
try: |
|
203 |
margin = max(len(('%s' % item).strip()) for item in l if not ( |
|
204 |
isinstance(item, dict) or |
|
205 |
isinstance(item, list) or |
|
206 |
item in exclude)) |
|
207 |
except ValueError: |
|
208 |
margin = (2 + len(('%s' % len(l)))) if enumerate else 1 |
|
209 |
|
|
210 |
counter = 1 |
|
211 |
prefix = '' |
|
212 |
item_sep = False |
|
213 |
for item in sorted(l): |
|
214 |
if ('%s' % item) in exclude: |
|
215 |
continue |
|
216 |
elif with_enumeration: |
|
217 |
prefix = '%s. ' % counter |
|
218 |
counter += 1 |
|
219 |
prefix = '%s%s' % (' ' * (ident - len(prefix)), prefix) |
|
220 |
else: |
|
221 |
prefix = ' ' * ident |
|
222 |
if item_sep: |
|
223 |
print '%s. . . . . . .' % prefix |
|
224 |
else: |
|
225 |
item_sep = True |
|
195 |
for i, item in enumerate(l): |
|
196 |
print_str = ' ' * indent |
|
197 |
print_str += '%s.' % (i + 1) if with_enumeration else '' |
|
226 | 198 |
if isinstance(item, dict): |
227 | 199 |
if with_enumeration: |
228 |
print(prefix)
|
|
200 |
print print_str
|
|
229 | 201 |
print_dict( |
230 |
item, |
|
231 |
exclude=exclude, |
|
232 |
ident=margin + ident, |
|
233 |
with_enumeration=recursive_enumeration, |
|
234 |
recursive_enumeration=recursive_enumeration) |
|
235 |
elif isinstance(item, list): |
|
202 |
item, exclude, indent, |
|
203 |
recursive_enumeration, recursive_enumeration) |
|
204 |
elif isinstance(item, list) or isinstance(item, tuple): |
|
236 | 205 |
if with_enumeration: |
237 |
print(prefix)
|
|
206 |
print print_str
|
|
238 | 207 |
print_list( |
239 |
item, |
|
240 |
exclude=exclude, |
|
241 |
ident=margin + ident, |
|
242 |
with_enumeration=recursive_enumeration, |
|
243 |
recursive_enumeration=recursive_enumeration) |
|
208 |
item, exclude, indent + IDENT_TAB, |
|
209 |
recursive_enumeration, recursive_enumeration) |
|
244 | 210 |
else: |
245 |
print('%s%s' % (prefix, item)) |
|
211 |
item = ('%s' % item).strip() |
|
212 |
if item in exclude: |
|
213 |
continue |
|
214 |
print '%s%s' % (print_str, item) |
|
215 |
if (i + 1) < len(l): |
|
216 |
|
|
246 | 217 |
|
247 | 218 |
|
248 | 219 |
def page_hold(index, limit, maxlen): |
... | ... | |
274 | 245 |
Objects of next level don't inherit enumeration (default: off) or titles |
275 | 246 |
|
276 | 247 |
:param items: (list) items are lists or dict |
248 |
|
|
277 | 249 |
:param title: (tuple) keys to use their values as title |
250 |
|
|
278 | 251 |
:param with_enumeration: (boolean) enumerate items (order id on title) |
252 |
|
|
279 | 253 |
:param with_redundancy: (boolean) values in title also appear on body |
254 |
|
|
280 | 255 |
:param page_size: (int) show results in pages of page_size items, enter to |
281 | 256 |
continue |
282 | 257 |
""" |
... | ... | |
299 | 274 |
header = ' '.join('%s' % item.pop(key) for key in title) |
300 | 275 |
print(bold(header)) |
301 | 276 |
if isinstance(item, dict): |
302 |
print_dict(item, ident=1)
|
|
277 |
print_dict(item, indent=IDENT_TAB)
|
|
303 | 278 |
elif isinstance(item, list): |
304 |
print_list(item, ident=1)
|
|
279 |
print_list(item, indent=IDENT_TAB)
|
|
305 | 280 |
else: |
306 | 281 |
print(' %s' % item) |
307 | 282 |
page_hold(i + 1, page_size, len(items)) |
... | ... | |
433 | 408 |
return terms |
434 | 409 |
|
435 | 410 |
|
436 |
def ask_user(msg, true_resp=['Y', 'y']):
|
|
411 |
def ask_user(msg, true_resp=('y', )):
|
|
437 | 412 |
"""Print msg and read user response |
438 | 413 |
|
439 | 414 |
:param true_resp: (tuple of chars) |
440 | 415 |
|
441 | 416 |
:returns: (bool) True if reponse in true responses, False otherwise |
442 | 417 |
""" |
443 |
stdout.write('%s (%s or enter for yes):' % (msg, ', '.join(true_resp)))
|
|
418 |
stdout.write('%s [%s/N]: ' % (msg, ', '.join(true_resp)))
|
|
444 | 419 |
stdout.flush() |
445 | 420 |
user_response = stdin.readline() |
446 |
return user_response[0] in true_resp + ['\n']
|
|
421 |
return user_response[0].lower() in true_resp
|
|
447 | 422 |
|
448 | 423 |
|
449 | 424 |
def spiner(size=None): |
Also available in: Unified diff