CLOUDSTACK-545: Tabularize cloudmonkey's response using filter=<fields,> argument

- Adds new cloudmonkey config field, tabularize
- If tabularize is set to true, all the list of dict in response are printed as
  table
- The columns of the tables can be filtered using the filter= argument, for ex:
  list domains listall=true filter=id,name,path
- filter arg will take comma separated values, if they have space put them under
  quotes
- Empty filter argument will cause it to print the whole table
- Multiple fields with the same name will cause it to print the column again
- In case there is a typo in the field, that column is skipped. It takes an
  intersection of response dict keys and filter keys provided
- Uses opensource prettytable library to pretty print tabular data

TODOs:
- Handle recursive table printing for nested list of dicts
- Colorize table columns if community wants such a feature

Signed-off-by: Rohit Yadav <bhaisaab@apache.org>
This commit is contained in:
Rohit Yadav 2012-12-20 16:28:32 -08:00
parent 264a0670a8
commit 8f51c630bd
3 changed files with 49 additions and 10 deletions

View File

@ -37,6 +37,7 @@ try:
from urllib2 import HTTPError, URLError
from httplib import BadStatusLine
from prettytable import PrettyTable
from common import __version__, config_file, config_fields
from common import grammar, precached_verbs
from marvin.cloudstackConnection import cloudConnection
@ -173,29 +174,58 @@ class CloudStackShell(cmd.Cmd, object):
except Exception, e:
print colored.red("Error: "), e
def print_result(self, result):
def print_result(self, result, result_filter=None):
if result is None or len(result) == 0:
return
def print_result_as_dict(result):
def printer_helper(printer, toprow):
if printer:
print printer
return PrettyTable(toprow)
def print_result_tabular(result, result_filter=None):
toprow = None
printer = None
for node in result:
if toprow != node.keys():
if result_filter is not None and len(result_filter) != 0:
commonkeys = filter(lambda x: x in node.keys(),
result_filter)
if commonkeys != toprow:
toprow = commonkeys
printer = printer_helper(printer, toprow)
else:
toprow = node.keys()
printer = printer_helper(printer, toprow)
row = map(lambda x: node[x], toprow)
if printer and row:
printer.add_row(row)
if printer:
print printer
def print_result_as_dict(result, result_filter=None):
for key in result.keys():
if not (isinstance(result[key], list) or
isinstance(result[key], dict)):
self.print_shell("%s = %s" % (key, result[key]))
else:
self.print_shell(key + ":\n" + len(key) * "=")
self.print_result(result[key])
self.print_shell(key + ":\n" + len(key) * self.ruler)
self.print_result(result[key], result_filter)
def print_result_as_list(result):
def print_result_as_list(result, result_filter=None):
for node in result:
# Tabular print if it's a list of dict and tabularize is true
if isinstance(node, dict) and self.tabularize == 'true':
print_result_tabular(result, result_filter)
break
self.print_result(node)
if len(result) > 1:
self.print_shell(self.ruler * 80)
if isinstance(result, dict):
print_result_as_dict(result)
print_result_as_dict(result, result_filter)
elif isinstance(result, list):
print_result_as_list(result)
print_result_as_list(result, result_filter)
elif isinstance(result, str):
print result
elif not (str(result) is None):
@ -281,6 +311,11 @@ class CloudStackShell(cmd.Cmd, object):
args_dict = dict(map(lambda x: [x.partition("=")[0],
x.partition("=")[2]],
args[1:])[x] for x in range(len(args) - 1))
field_filter = None
if 'filter' in args_dict:
field_filter = filter(lambda x: x is not '',
map(lambda x: x.strip(),
args_dict.pop('filter').split(',')))
api_cmd_str = "%sCmd" % api_name
api_mod = self.get_api_module(api_name, [api_cmd_str])
@ -313,7 +348,8 @@ class CloudStackShell(cmd.Cmd, object):
return
try:
# Response is in the key "apiname+response" (lowercase)
self.print_result(result[api_name.lower()+'response'])
self.print_result(result[api_name.lower() + 'response'],
field_filter)
print
except Exception as e:
self.print_shell("🙈 Error on parsing and printing", e)
@ -367,6 +403,7 @@ class CloudStackShell(cmd.Cmd, object):
self.cache_verbs[verb][subject][1])
search_string = text
autocompletions.append("filter=")
return [s for s in autocompletions if s.startswith(search_string)]
def do_api(self, args):
@ -496,7 +533,6 @@ def main():
try:
args_partition = args.partition(" ")
res = self.cache_verbs[rule][args_partition[0]]
except KeyError, e:
self.print_shell("Error: invalid %s api arg" % rule, e)
return

View File

@ -33,6 +33,7 @@ config_fields = {'host': 'localhost', 'port': '8080',
'apikey': '', 'secretkey': '',
'timeout': '3600', 'asyncblock': 'true',
'prompt': '🐵 cloudmonkey>', 'color': 'true',
'tabularize': 'false',
'log_file':
os.path.expanduser('~/.cloudmonkey_log'),
'history_file':

View File

@ -26,7 +26,9 @@ from cloudmonkey import __version__
name = 'cloudmonkey'
version = __version__
requires = ['clint>=0.3.0',]
requires = ['clint>=0.3.0',
'prettytable>=0.5',
]
try:
import readline