Make column ordering consistent and predictable
This changes how we sort columns in listings and how we display the column headings. The default columns are now stored as lists so that they are the same from run to run. This simplifies some of the logic in the shell modules as well. Instead of keeping static mappings of attributes to column headings, we now use some simple python logic, to title case the columns. This commit covers: - cell-* commands - cloud-* commands - host-* commands - project-* commands - region-* commands Finally, we noticed that the cloud-list and region-list commands were behaving differently from the rest of the -list commands. This unifies the interface to add the --detail flag. Closes-bug: #1659103 Closes-bug: #1659427 Closes-bug: #1668221 Change-Id: If5906780e501c7b9ba93ecf54a7bcf6db5ddfa1c
This commit is contained in:
parent
cd1c025ae0
commit
683f342506
cratonclient
common
formatters
shell/v1
tests/unit
formatters
shell
v1
@ -51,6 +51,27 @@ def add_arg(func, *args, **kwargs):
|
||||
func.arguments.insert(0, (args, kwargs))
|
||||
|
||||
|
||||
def field_labels_from(attributes):
|
||||
"""Generate a list of slightly more human readable field names.
|
||||
|
||||
This takes the list of fields/attributes on the object and makes them
|
||||
easier to read.
|
||||
|
||||
:param list attributes:
|
||||
The attribute names to convert. For example, ``["parent_id"]``.
|
||||
:returns:
|
||||
List of field names. For example ``["Parent Id"]``
|
||||
:rtype:
|
||||
list
|
||||
|
||||
Example:
|
||||
|
||||
>>> field_labels_from(["id", "name", "cloud_id"])
|
||||
["Id", "Name", "Cloud Id"]
|
||||
"""
|
||||
return [field.replace('_', ' ').title() for field in attributes]
|
||||
|
||||
|
||||
def print_list(objs, fields, formatters=None, sortby_index=0,
|
||||
mixed_case_fields=None, field_labels=None):
|
||||
"""Print a list or objects as a table, one row per object.
|
||||
|
@ -18,6 +18,7 @@ from oslo_utils import encodeutils
|
||||
import prettytable
|
||||
import six
|
||||
|
||||
from cratonclient.common import cliutils
|
||||
from cratonclient.formatters import base
|
||||
|
||||
|
||||
@ -28,7 +29,7 @@ class Formatter(base.Formatter):
|
||||
"""Set-up after initialization."""
|
||||
self.fields = []
|
||||
self.formatters = {}
|
||||
self.sortby_index = 0
|
||||
self.sortby_index = None
|
||||
self.mixed_case_fields = set([])
|
||||
self.field_labels = []
|
||||
self.dict_property = "Property"
|
||||
@ -71,7 +72,7 @@ class Formatter(base.Formatter):
|
||||
if fields is not None:
|
||||
self.fields = fields
|
||||
if field_labels is None:
|
||||
self.field_labels = self.fields
|
||||
self.field_labels = cliutils.field_labels_from(self.fields)
|
||||
elif len(field_labels) != len(self.fields):
|
||||
raise ValueError(
|
||||
"Field labels list %(labels)s has different number "
|
||||
|
@ -16,7 +16,21 @@ from __future__ import print_function
|
||||
|
||||
from cratonclient.common import cliutils
|
||||
from cratonclient import exceptions as exc
|
||||
from cratonclient.v1 import cells
|
||||
|
||||
DEFAULT_CELL_FIELDS = [
|
||||
'id',
|
||||
'name',
|
||||
'cloud_id',
|
||||
'region_id',
|
||||
'created_at',
|
||||
]
|
||||
|
||||
CELL_FIELDS = DEFAULT_CELL_FIELDS + [
|
||||
'updated_at',
|
||||
'note',
|
||||
'variables',
|
||||
'project_id',
|
||||
]
|
||||
|
||||
|
||||
@cliutils.arg('id',
|
||||
@ -52,7 +66,7 @@ def do_cell_show(cc, args):
|
||||
@cliutils.arg('--fields',
|
||||
nargs='+',
|
||||
metavar='<fields>',
|
||||
default=[],
|
||||
default=DEFAULT_CELL_FIELDS,
|
||||
help='Space-separated list of fields to display. '
|
||||
'Only these fields will be fetched from the server. '
|
||||
'Can not be used when "--detail" is specified')
|
||||
@ -73,7 +87,6 @@ def do_cell_show(cc, args):
|
||||
def do_cell_list(cc, args):
|
||||
"""Print list of cells which are registered with the Craton service."""
|
||||
params = {}
|
||||
default_fields = ['id', 'name']
|
||||
if args.cloud is not None:
|
||||
params['cloud_id'] = args.cloud
|
||||
if args.limit is not None:
|
||||
@ -85,27 +98,29 @@ def do_cell_list(cc, args):
|
||||
if args.all is True:
|
||||
params['limit'] = 100
|
||||
|
||||
if args.fields and args.detail:
|
||||
raise exc.CommandError('Cannot specify both --fields and --detail.')
|
||||
|
||||
if args.detail:
|
||||
fields = cells.CELL_FIELDS
|
||||
if args.fields and args.fields == DEFAULT_CELL_FIELDS:
|
||||
args.fields = CELL_FIELDS
|
||||
else:
|
||||
raise exc.CommandError(
|
||||
'Cannot specify both --fields and --detail.'
|
||||
)
|
||||
params['detail'] = args.detail
|
||||
elif args.fields:
|
||||
try:
|
||||
fields = {x: cells.CELL_FIELDS[x] for x in args.fields}
|
||||
except KeyError as keyerr:
|
||||
raise exc.CommandError('Invalid field "{}"'.format(keyerr.args[0]))
|
||||
else:
|
||||
fields = {x: cells.CELL_FIELDS[x] for x in default_fields}
|
||||
|
||||
fields = args.fields
|
||||
for field in fields:
|
||||
if field not in CELL_FIELDS:
|
||||
raise exc.CommandError(
|
||||
'Invalid field "{}"'.format(field)
|
||||
)
|
||||
sort_key = args.sort_key and args.sort_key.lower()
|
||||
if sort_key is not None:
|
||||
if sort_key not in cells.CELL_FIELDS:
|
||||
if sort_key not in CELL_FIELDS:
|
||||
raise exc.CommandError(
|
||||
('"--sort-key" value was "{}" but should '
|
||||
'be one of: {}').format(
|
||||
args.sort_key,
|
||||
', '.join(cells.CELL_FIELDS.keys())
|
||||
', '.join(CELL_FIELDS)
|
||||
)
|
||||
)
|
||||
params['sort_key'] = sort_key
|
||||
@ -117,7 +132,7 @@ def do_cell_list(cc, args):
|
||||
params['autopaginate'] = args.all
|
||||
|
||||
listed_cells = cc.cells.list(**params)
|
||||
args.formatter.configure(fields=list(fields)).handle(listed_cells)
|
||||
args.formatter.configure(fields=fields).handle(listed_cells)
|
||||
|
||||
|
||||
@cliutils.arg('-n', '--name',
|
||||
@ -141,7 +156,7 @@ def do_cell_list(cc, args):
|
||||
def do_cell_create(cc, args):
|
||||
"""Register a new cell with the Craton service."""
|
||||
fields = {k: v for (k, v) in vars(args).items()
|
||||
if k in cells.CELL_FIELDS and not (v is None)}
|
||||
if k in CELL_FIELDS and not (v is None)}
|
||||
cell = cc.cells.create(**fields)
|
||||
args.formatter.configure(wrap=72).handle(cell)
|
||||
|
||||
@ -168,7 +183,7 @@ def do_cell_create(cc, args):
|
||||
def do_cell_update(cc, args):
|
||||
"""Update a cell that is registered with the Craton service."""
|
||||
fields = {k: v for (k, v) in vars(args).items()
|
||||
if k in cells.CELL_FIELDS and not (v is None)}
|
||||
if k in CELL_FIELDS and not (v is None)}
|
||||
cell_id = fields.pop('id')
|
||||
if not fields:
|
||||
raise exc.CommandError(
|
||||
|
@ -14,7 +14,18 @@ from __future__ import print_function
|
||||
|
||||
from cratonclient.common import cliutils
|
||||
from cratonclient import exceptions as exc
|
||||
from cratonclient.v1 import clouds
|
||||
|
||||
DEFAULT_CLOUD_FIELDS = [
|
||||
'id',
|
||||
'name',
|
||||
'created_at',
|
||||
]
|
||||
|
||||
CLOUD_FIELDS = DEFAULT_CLOUD_FIELDS + [
|
||||
'updated_at',
|
||||
'note',
|
||||
'project_id',
|
||||
]
|
||||
|
||||
|
||||
@cliutils.arg('-n', '--name',
|
||||
@ -26,7 +37,7 @@ from cratonclient.v1 import clouds
|
||||
def do_cloud_create(cc, args):
|
||||
"""Register a new cloud with the Craton service."""
|
||||
fields = {k: v for (k, v) in vars(args).items()
|
||||
if k in clouds.CLOUD_FIELDS and not (v is None)}
|
||||
if k in CLOUD_FIELDS and not (v is None)}
|
||||
|
||||
cloud = cc.clouds.create(**fields)
|
||||
args.formatter.configure(wrap=72).handle(cloud)
|
||||
@ -35,7 +46,7 @@ def do_cloud_create(cc, args):
|
||||
@cliutils.arg('--fields',
|
||||
nargs='+',
|
||||
metavar='<fields>',
|
||||
default=[],
|
||||
default=DEFAULT_CLOUD_FIELDS,
|
||||
help='Comma-separated list of fields to display. '
|
||||
'Only these fields will be fetched from the server. '
|
||||
'Can not be used when "--detail" is specified')
|
||||
@ -45,6 +56,10 @@ def do_cloud_create(cc, args):
|
||||
help='Retrieve and show all clouds. This will override '
|
||||
'the provided value for --limit and automatically '
|
||||
'retrieve each page of results.')
|
||||
@cliutils.arg('--detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Show detailed information about all clouds.')
|
||||
@cliutils.arg('--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
@ -56,7 +71,6 @@ def do_cloud_create(cc, args):
|
||||
def do_cloud_list(cc, args):
|
||||
"""List all clouds."""
|
||||
params = {}
|
||||
default_fields = ['id', 'name']
|
||||
if args.limit is not None:
|
||||
if args.limit < 0:
|
||||
raise exc.CommandError('Invalid limit specified. Expected '
|
||||
@ -66,13 +80,22 @@ def do_cloud_list(cc, args):
|
||||
if args.all is True:
|
||||
params['limit'] = 100
|
||||
|
||||
if args.fields:
|
||||
try:
|
||||
fields = {x: clouds.CLOUD_FIELDS[x] for x in args.fields}
|
||||
except KeyError as err:
|
||||
raise exc.CommandError('Invalid field "{}"'.format(err.args[0]))
|
||||
else:
|
||||
fields = default_fields
|
||||
if args.detail:
|
||||
if args.fields and args.fields == DEFAULT_CLOUD_FIELDS:
|
||||
args.fields = CLOUD_FIELDS
|
||||
else:
|
||||
raise exc.CommandError(
|
||||
'Cannot specify both --fields and --detail.'
|
||||
)
|
||||
params['detail'] = args.detail
|
||||
|
||||
fields = args.fields
|
||||
for field in args.fields:
|
||||
if field not in CLOUD_FIELDS:
|
||||
raise exc.CommandError(
|
||||
'Invalid field "{}"'.format(field)
|
||||
)
|
||||
|
||||
params['marker'] = args.marker
|
||||
params['autopaginate'] = args.all
|
||||
|
||||
@ -102,7 +125,7 @@ def do_cloud_show(cc, args):
|
||||
def do_cloud_update(cc, args):
|
||||
"""Update a cloud that is registered with the Craton service."""
|
||||
fields = {k: v for (k, v) in vars(args).items()
|
||||
if k in clouds.CLOUD_FIELDS and not (v is None)}
|
||||
if k in CLOUD_FIELDS and not (v is None)}
|
||||
item_id = fields.pop('id')
|
||||
if not fields:
|
||||
raise exc.CommandError(
|
||||
|
@ -16,7 +16,28 @@ from __future__ import print_function
|
||||
|
||||
from cratonclient.common import cliutils
|
||||
from cratonclient import exceptions as exc
|
||||
from cratonclient.v1 import hosts
|
||||
|
||||
|
||||
DEFAULT_HOST_FIELDS = [
|
||||
'id',
|
||||
'name',
|
||||
'active',
|
||||
'device_type',
|
||||
'ip_address',
|
||||
'cloud_id',
|
||||
'region_id',
|
||||
'cell_id',
|
||||
'created_at',
|
||||
]
|
||||
|
||||
HOST_FIELDS = DEFAULT_HOST_FIELDS + [
|
||||
'updated_at',
|
||||
'note',
|
||||
'variables',
|
||||
'labels',
|
||||
'parent_id',
|
||||
'project_id',
|
||||
]
|
||||
|
||||
|
||||
@cliutils.arg('id',
|
||||
@ -57,7 +78,7 @@ def do_host_show(cc, args):
|
||||
@cliutils.arg('--fields',
|
||||
nargs='+',
|
||||
metavar='<fields>',
|
||||
default=[],
|
||||
default=DEFAULT_HOST_FIELDS,
|
||||
help='Space-separated list of fields to display. '
|
||||
'Only these fields will be fetched from the server. '
|
||||
'Can not be used when "--detail" is specified')
|
||||
@ -94,7 +115,6 @@ def do_host_show(cc, args):
|
||||
def do_host_list(cc, args):
|
||||
"""Print list of hosts which are registered with the Craton service."""
|
||||
params = {}
|
||||
default_fields = ['id', 'name', 'device_type', 'active', 'cell_id']
|
||||
if args.cell is not None:
|
||||
params['cell_id'] = args.cell
|
||||
if args.cloud is not None:
|
||||
@ -116,26 +136,29 @@ def do_host_list(cc, args):
|
||||
if args.all is True:
|
||||
params['limit'] = 100
|
||||
|
||||
if args.fields and args.detail:
|
||||
raise exc.CommandError('Cannot specify both --fields and --detail.')
|
||||
|
||||
if args.detail:
|
||||
fields = hosts.HOST_FIELDS
|
||||
if args.fields and args.fields == DEFAULT_HOST_FIELDS:
|
||||
args.fields = HOST_FIELDS
|
||||
else:
|
||||
raise exc.CommandError(
|
||||
'Cannot specify both --fields and --detail.'
|
||||
)
|
||||
params['detail'] = args.detail
|
||||
elif args.fields:
|
||||
try:
|
||||
fields = {x: hosts.HOST_FIELDS[x] for x in args.fields}
|
||||
except KeyError as keyerr:
|
||||
raise exc.CommandError('Invalid field "{}"'.format(keyerr.args[0]))
|
||||
else:
|
||||
fields = {x: hosts.HOST_FIELDS[x] for x in default_fields}
|
||||
|
||||
fields = args.fields
|
||||
for field in args.fields:
|
||||
if field not in HOST_FIELDS:
|
||||
raise exc.CommandError(
|
||||
'Invalid field "{}"'.format(field)
|
||||
)
|
||||
|
||||
sort_key = args.sort_key and args.sort_key.lower()
|
||||
if sort_key is not None:
|
||||
if sort_key not in hosts.HOST_FIELDS:
|
||||
if sort_key not in HOST_FIELDS:
|
||||
raise exc.CommandError(
|
||||
'{0} is an invalid key for sorting, valid values for '
|
||||
'--sort-key are: {1}'.format(
|
||||
args.sort_key, hosts.HOST_FIELDS.keys()
|
||||
args.sort_key, HOST_FIELDS
|
||||
)
|
||||
)
|
||||
params['sort_key'] = sort_key
|
||||
@ -147,7 +170,7 @@ def do_host_list(cc, args):
|
||||
params['autopaginate'] = args.all
|
||||
|
||||
host_list = cc.hosts.list(**params)
|
||||
args.formatter.configure(fields=list(fields)).handle(host_list)
|
||||
args.formatter.configure(fields=fields).handle(host_list)
|
||||
|
||||
|
||||
@cliutils.arg('-n', '--name',
|
||||
@ -191,7 +214,7 @@ def do_host_list(cc, args):
|
||||
def do_host_create(cc, args):
|
||||
"""Register a new host with the Craton service."""
|
||||
fields = {k: v for (k, v) in vars(args).items()
|
||||
if k in hosts.HOST_FIELDS and (v or v is False)}
|
||||
if k in HOST_FIELDS and (v or v is False)}
|
||||
host = cc.hosts.create(**fields)
|
||||
args.formatter.configure(wrap=72).handle(host)
|
||||
|
||||
@ -232,7 +255,7 @@ def do_host_create(cc, args):
|
||||
def do_host_update(cc, args):
|
||||
"""Update a host that is registered with the Craton service."""
|
||||
fields = {k: v for (k, v) in vars(args).items()
|
||||
if k in hosts.HOST_FIELDS and (v or v is False)}
|
||||
if k in HOST_FIELDS and (v or v is False)}
|
||||
item_id = fields.pop('id')
|
||||
host = cc.hosts.update(item_id, **fields)
|
||||
print("Host {0} has been successfully updated.".format(host.id))
|
||||
|
@ -16,7 +16,17 @@ from __future__ import print_function
|
||||
|
||||
from cratonclient.common import cliutils
|
||||
from cratonclient import exceptions as exc
|
||||
from cratonclient.v1 import projects
|
||||
|
||||
|
||||
DEFAULT_PROJECT_FIELDS = [
|
||||
'id',
|
||||
'name',
|
||||
]
|
||||
|
||||
PROJECT_FIELDS = DEFAULT_PROJECT_FIELDS + [
|
||||
'created_at',
|
||||
'updated_at',
|
||||
]
|
||||
|
||||
|
||||
@cliutils.arg('id',
|
||||
@ -38,7 +48,7 @@ def do_project_show(cc, args):
|
||||
@cliutils.arg('--fields',
|
||||
nargs='+',
|
||||
metavar='<fields>',
|
||||
default=[],
|
||||
default=DEFAULT_PROJECT_FIELDS,
|
||||
help='Space-separated list of fields to display. '
|
||||
'Only these fields will be fetched from the server. '
|
||||
'Can not be used when "--detail" is specified')
|
||||
@ -59,7 +69,6 @@ def do_project_show(cc, args):
|
||||
def do_project_list(cc, args):
|
||||
"""Print list of projects which are registered with the Craton service."""
|
||||
params = {}
|
||||
default_fields = ['id', 'name']
|
||||
if args.limit is not None:
|
||||
if args.limit < 0:
|
||||
raise exc.CommandError('Invalid limit specified. Expected '
|
||||
@ -69,20 +78,24 @@ def do_project_list(cc, args):
|
||||
if args.all is True:
|
||||
params['limit'] = 100
|
||||
|
||||
if args.fields and args.detail:
|
||||
raise exc.CommandError('Cannot specify both --fields and --detail.')
|
||||
if args.detail:
|
||||
if args.fields and args.fields == DEFAULT_PROJECT_FIELDS:
|
||||
args.fields = PROJECT_FIELDS
|
||||
else:
|
||||
raise exc.CommandError(
|
||||
'Cannot specify both --fields and --detail.'
|
||||
)
|
||||
|
||||
fields = args.fields
|
||||
for field in fields:
|
||||
if field not in PROJECT_FIELDS:
|
||||
raise exc.CommandError(
|
||||
'Invalid field "{}"'.format(field)
|
||||
)
|
||||
|
||||
if args.name:
|
||||
params['name'] = args.name
|
||||
if args.detail:
|
||||
fields = projects.PROJECT_FIELDS
|
||||
elif args.fields:
|
||||
try:
|
||||
fields = {x: projects.PROJECT_FIELDS[x] for x in args.fields}
|
||||
except KeyError as keyerr:
|
||||
raise exc.CommandError('Invalid field "{}"'.format(keyerr.args[0]))
|
||||
else:
|
||||
fields = {x: projects.PROJECT_FIELDS[x] for x in default_fields}
|
||||
|
||||
params['marker'] = args.marker
|
||||
params['autopaginate'] = args.all
|
||||
|
||||
@ -97,7 +110,7 @@ def do_project_list(cc, args):
|
||||
def do_project_create(cc, args):
|
||||
"""Register a new project with the Craton service."""
|
||||
fields = {k: v for (k, v) in vars(args).items()
|
||||
if k in projects.PROJECT_FIELDS and not (v is None)}
|
||||
if k in PROJECT_FIELDS and not (v is None)}
|
||||
project = cc.projects.create(**fields)
|
||||
args.formatter.configure(wrap=72).handle(project)
|
||||
|
||||
|
@ -14,7 +14,19 @@ from __future__ import print_function
|
||||
|
||||
from cratonclient.common import cliutils
|
||||
from cratonclient import exceptions as exc
|
||||
from cratonclient.v1 import regions
|
||||
|
||||
DEFAULT_REGION_FIELDS = [
|
||||
'id',
|
||||
'name',
|
||||
'cloud_id',
|
||||
]
|
||||
|
||||
REGION_FIELDS = DEFAULT_REGION_FIELDS + [
|
||||
'project_id',
|
||||
'note',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
]
|
||||
|
||||
|
||||
@cliutils.arg('-n', '--name',
|
||||
@ -32,7 +44,7 @@ from cratonclient.v1 import regions
|
||||
def do_region_create(cc, args):
|
||||
"""Register a new region with the Craton service."""
|
||||
fields = {k: v for (k, v) in vars(args).items()
|
||||
if k in regions.REGION_FIELDS and not (v is None)}
|
||||
if k in REGION_FIELDS and not (v is None)}
|
||||
|
||||
region = cc.regions.create(**fields)
|
||||
args.formatter.configure(wrap=72).handle(region)
|
||||
@ -45,10 +57,14 @@ def do_region_create(cc, args):
|
||||
@cliutils.arg('--fields',
|
||||
nargs='+',
|
||||
metavar='<fields>',
|
||||
default=[],
|
||||
default=DEFAULT_REGION_FIELDS,
|
||||
help='Space-separated list of fields to display. '
|
||||
'Only these fields will be fetched from the server. '
|
||||
'Can not be used when "--detail" is specified')
|
||||
@cliutils.arg('--detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Show detailed information about the regions.')
|
||||
@cliutils.arg('--all',
|
||||
action='store_true',
|
||||
default=False,
|
||||
@ -66,7 +82,6 @@ def do_region_create(cc, args):
|
||||
def do_region_list(cc, args):
|
||||
"""List all regions."""
|
||||
params = {}
|
||||
default_fields = ['id', 'name']
|
||||
if args.cloud is not None:
|
||||
params['cloud_id'] = args.cloud
|
||||
if args.limit is not None:
|
||||
@ -78,13 +93,21 @@ def do_region_list(cc, args):
|
||||
if args.all is True:
|
||||
params['limit'] = 100
|
||||
|
||||
if args.fields:
|
||||
try:
|
||||
fields = {x: regions.REGION_FIELDS[x] for x in args.fields}
|
||||
except KeyError as err:
|
||||
raise exc.CommandError('Invalid field "{}"'.format(err.args[0]))
|
||||
else:
|
||||
fields = default_fields
|
||||
if args.detail:
|
||||
if args.fields and args.fields == DEFAULT_REGION_FIELDS:
|
||||
args.fields = REGION_FIELDS
|
||||
else:
|
||||
raise exc.CommandError(
|
||||
'Cannot specify both --fields and --detail.'
|
||||
)
|
||||
params['detail'] = args.detail
|
||||
|
||||
fields = args.fields
|
||||
for field in args.fields:
|
||||
if field not in REGION_FIELDS:
|
||||
raise exc.CommandError(
|
||||
'Invalid field "{}"'.format(field)
|
||||
)
|
||||
|
||||
params['marker'] = args.marker
|
||||
params['autopaginate'] = args.all
|
||||
@ -120,7 +143,7 @@ def do_region_show(cc, args):
|
||||
def do_region_update(cc, args):
|
||||
"""Update a region that is registered with the Craton service."""
|
||||
fields = {k: v for (k, v) in vars(args).items()
|
||||
if k in regions.REGION_FIELDS and not (v is None)}
|
||||
if k in REGION_FIELDS and not (v is None)}
|
||||
item_id = fields.pop('id')
|
||||
if not fields:
|
||||
raise exc.CommandError(
|
||||
|
@ -31,7 +31,7 @@ class TestTableFormatter(base.FormatterTestCase):
|
||||
"""Verify we set up defaults for our PrettyTable formatter."""
|
||||
self.assertEqual([], self.formatter.fields)
|
||||
self.assertEqual({}, self.formatter.formatters)
|
||||
self.assertEqual(0, self.formatter.sortby_index)
|
||||
self.assertIsNone(self.formatter.sortby_index)
|
||||
self.assertEqual(set([]), self.formatter.mixed_case_fields)
|
||||
self.assertEqual([], self.formatter.field_labels)
|
||||
self.assertEqual("Property", self.formatter.dict_property)
|
||||
@ -63,14 +63,14 @@ class TestTableFormatter(base.FormatterTestCase):
|
||||
# Assert defaults remain unchanged
|
||||
self.assertEqual([], self.formatter.fields)
|
||||
self.assertEqual([], self.formatter.field_labels)
|
||||
self.assertEqual(0, self.formatter.sortby_index)
|
||||
self.assertIsNone(self.formatter.sortby_index)
|
||||
|
||||
# Case 1: Just fields
|
||||
def test_configure_fields_only(self):
|
||||
"""Verify the logic for configuring fields."""
|
||||
self.formatter.configure(fields=['id', 'name'])
|
||||
self.assertListEqual(['id', 'name'], self.formatter.fields)
|
||||
self.assertListEqual(['id', 'name'], self.formatter.field_labels)
|
||||
self.assertListEqual(['Id', 'Name'], self.formatter.field_labels)
|
||||
|
||||
# Case 2: fields + field_labels
|
||||
def test_configure_fields_and_field_labels(self):
|
||||
@ -167,6 +167,7 @@ class TestTableFormatter(base.FormatterTestCase):
|
||||
def test_sortby_kwargs(self):
|
||||
"""Verify sortby_kwargs relies on sortby_index."""
|
||||
self.formatter.field_labels = ['id', 'created_at']
|
||||
self.formatter.sortby_index = 0
|
||||
self.assertDictEqual({'sortby': 'id'}, self.formatter.sortby_kwargs())
|
||||
|
||||
self.formatter.sortby_index = 1
|
||||
@ -219,10 +220,10 @@ class TestTableFormatter(base.FormatterTestCase):
|
||||
self.formatter.handle_generator(crud.Resource(mock.Mock(), info)
|
||||
for info in info_list)
|
||||
|
||||
PrettyTable.assert_called_once_with(['id', 'Name'])
|
||||
PrettyTable.assert_called_once_with(['Id', 'Name'])
|
||||
self.assertListEqual(
|
||||
[mock.call([i, 'Test Resource']) for i in range(15)],
|
||||
mocktable.add_row.call_args_list,
|
||||
)
|
||||
mocktable.get_string.assert_called_once_with(sortby='id')
|
||||
mocktable.get_string.assert_called_once_with()
|
||||
self.print_.assert_called_once_with('')
|
||||
|
@ -99,3 +99,8 @@ class TestShellCommandUsingPrintList(TestShellCommand):
|
||||
kwargs = self.formatter.configure.call_args[1]
|
||||
self.assertListEqual(expected_fields,
|
||||
sorted(kwargs['fields']))
|
||||
|
||||
def assertFieldsEqualTo(self, expected_fields):
|
||||
"""Assert the sorted fields parameter is equal expected_fields."""
|
||||
kwargs = self.formatter.configure.call_args[1]
|
||||
self.assertListEqual(expected_fields, kwargs['fields'])
|
||||
|
@ -17,7 +17,6 @@ import mock
|
||||
from cratonclient import exceptions
|
||||
from cratonclient.shell.v1 import cells_shell
|
||||
from cratonclient.tests.unit.shell import base
|
||||
from cratonclient.v1 import cells
|
||||
|
||||
|
||||
class TestDoShellShow(base.TestShellCommandUsingPrintDict):
|
||||
@ -54,7 +53,7 @@ class TestDoCellList(base.TestShellCommandUsingPrintList):
|
||||
kwargs.setdefault('limit', None)
|
||||
kwargs.setdefault('sort_key', None)
|
||||
kwargs.setdefault('sort_dir', 'asc')
|
||||
kwargs.setdefault('fields', [])
|
||||
kwargs.setdefault('fields', cells_shell.DEFAULT_CELL_FIELDS)
|
||||
kwargs.setdefault('marker', None)
|
||||
kwargs.setdefault('all', False)
|
||||
return super(TestDoCellList, self).args_for(**kwargs)
|
||||
@ -71,7 +70,7 @@ class TestDoCellList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(cells_shell.DEFAULT_CELL_FIELDS)
|
||||
|
||||
def test_with_cloud_id(self):
|
||||
"""Verify the behaviour of do_cell_list with mostly default values."""
|
||||
@ -86,7 +85,7 @@ class TestDoCellList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(cells_shell.DEFAULT_CELL_FIELDS)
|
||||
|
||||
def test_negative_limit(self):
|
||||
"""Ensure we raise an exception for negative limits."""
|
||||
@ -108,7 +107,7 @@ class TestDoCellList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(cells_shell.DEFAULT_CELL_FIELDS)
|
||||
|
||||
def test_valid_sort_key(self):
|
||||
"""Verify that we pass on our sort key."""
|
||||
@ -123,7 +122,7 @@ class TestDoCellList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(cells_shell.DEFAULT_CELL_FIELDS)
|
||||
|
||||
def test_invalid_sort_key(self):
|
||||
"""Verify that do not we pass on our sort key."""
|
||||
@ -145,7 +144,7 @@ class TestDoCellList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(sorted(list(cells.CELL_FIELDS)))
|
||||
self.assertFieldsEqualTo(cells_shell.CELL_FIELDS)
|
||||
|
||||
def test_raises_exception_with_detail_and_fields(self):
|
||||
"""Verify that we fail when users specify --detail and --fields."""
|
||||
@ -169,7 +168,7 @@ class TestDoCellList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name', 'note'])
|
||||
self.assertFieldsEqualTo(['id', 'name', 'note'])
|
||||
|
||||
def test_invalid_fields(self):
|
||||
"""Verify that we error out with invalid fields."""
|
||||
|
@ -196,7 +196,7 @@ class TestDoCloudList(base.TestShellCommandUsingPrintList):
|
||||
"""Generate the default argument list for cloud-list."""
|
||||
kwargs.setdefault('detail', False)
|
||||
kwargs.setdefault('limit', None)
|
||||
kwargs.setdefault('fields', [])
|
||||
kwargs.setdefault('fields', clouds_shell.DEFAULT_CLOUD_FIELDS)
|
||||
kwargs.setdefault('marker', None)
|
||||
kwargs.setdefault('all', False)
|
||||
return super(TestDoCloudList, self).args_for(**kwargs)
|
||||
@ -206,7 +206,7 @@ class TestDoCloudList(base.TestShellCommandUsingPrintList):
|
||||
args = self.args_for()
|
||||
clouds_shell.do_cloud_list(self.craton_client, args)
|
||||
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(clouds_shell.DEFAULT_CLOUD_FIELDS)
|
||||
|
||||
def test_negative_limit(self):
|
||||
"""Ensure we raise an exception for negative limits."""
|
||||
@ -222,13 +222,13 @@ class TestDoCloudList(base.TestShellCommandUsingPrintList):
|
||||
marker=None,
|
||||
autopaginate=False,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(clouds_shell.DEFAULT_CLOUD_FIELDS)
|
||||
|
||||
def test_fields(self):
|
||||
"""Verify that we print out specific fields."""
|
||||
args = self.args_for(fields=['id', 'name', 'note'])
|
||||
clouds_shell.do_cloud_list(self.craton_client, args)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name', 'note'])
|
||||
self.assertFieldsEqualTo(['id', 'name', 'note'])
|
||||
|
||||
def test_invalid_fields(self):
|
||||
"""Verify that we error out with invalid fields."""
|
||||
|
@ -46,7 +46,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
kwargs.setdefault('limit', None)
|
||||
kwargs.setdefault('sort_key', None)
|
||||
kwargs.setdefault('sort_dir', 'asc')
|
||||
kwargs.setdefault('fields', [])
|
||||
kwargs.setdefault('fields', hosts_shell.DEFAULT_HOST_FIELDS)
|
||||
kwargs.setdefault('marker', None)
|
||||
kwargs.setdefault('all', False)
|
||||
kwargs.setdefault('vars', None)
|
||||
@ -67,9 +67,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedPrintListFieldsEqualTo([
|
||||
'active', 'cell_id', 'device_type', 'id', 'name'
|
||||
])
|
||||
self.assertFieldsEqualTo(hosts_shell.DEFAULT_HOST_FIELDS)
|
||||
|
||||
def test_with_cell_id(self):
|
||||
"""Verify that we include the cell_id in the params."""
|
||||
@ -84,9 +82,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedPrintListFieldsEqualTo([
|
||||
'active', 'cell_id', 'device_type', 'id', 'name',
|
||||
])
|
||||
self.assertFieldsEqualTo(hosts_shell.DEFAULT_HOST_FIELDS)
|
||||
|
||||
def test_with_cloud_id(self):
|
||||
"""Verify that we include the cell_id in the params."""
|
||||
@ -101,9 +97,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedPrintListFieldsEqualTo([
|
||||
'active', 'cell_id', 'device_type', 'id', 'name',
|
||||
])
|
||||
self.assertFieldsEqualTo(hosts_shell.DEFAULT_HOST_FIELDS)
|
||||
|
||||
def test_with_detail(self):
|
||||
"""Verify the behaviour of specifying --detail."""
|
||||
@ -118,22 +112,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedPrintListFieldsEqualTo([
|
||||
'active',
|
||||
'cell_id',
|
||||
'cloud_id',
|
||||
'created_at',
|
||||
'device_type',
|
||||
'id',
|
||||
'ip_address',
|
||||
'labels',
|
||||
'name',
|
||||
'note',
|
||||
'parent_id',
|
||||
'project_id',
|
||||
'region_id',
|
||||
'updated_at',
|
||||
])
|
||||
self.assertFieldsEqualTo(hosts_shell.HOST_FIELDS)
|
||||
|
||||
def test_with_limit(self):
|
||||
"""Verify the behaviour with --limit specified."""
|
||||
@ -148,9 +127,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedPrintListFieldsEqualTo([
|
||||
'active', 'cell_id', 'device_type', 'id', 'name'
|
||||
])
|
||||
self.assertFieldsEqualTo(hosts_shell.DEFAULT_HOST_FIELDS)
|
||||
|
||||
def test_negative_limit_raises_command_error(self):
|
||||
"""Verify that we forbid negative limit values."""
|
||||
@ -172,9 +149,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedPrintListFieldsEqualTo([
|
||||
'active', 'cell_id', 'device_type', 'id', 'name'
|
||||
])
|
||||
self.assertFieldsEqualTo(hosts_shell.DEFAULT_HOST_FIELDS)
|
||||
|
||||
def test_with_label(self):
|
||||
"""Verify the behaviour with --label specified."""
|
||||
@ -189,9 +164,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedPrintListFieldsEqualTo([
|
||||
'active', 'cell_id', 'device_type', 'id', 'name'
|
||||
])
|
||||
self.assertFieldsEqualTo(hosts_shell.DEFAULT_HOST_FIELDS)
|
||||
|
||||
def test_with_device_type(self):
|
||||
"""Verify the behaviour with --device-type specified."""
|
||||
@ -206,9 +179,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedPrintListFieldsEqualTo([
|
||||
'active', 'cell_id', 'device_type', 'id', 'name'
|
||||
])
|
||||
self.assertFieldsEqualTo(hosts_shell.DEFAULT_HOST_FIELDS)
|
||||
|
||||
def test_with_ip(self):
|
||||
"""Verify the behaviour with --ip specified."""
|
||||
@ -223,9 +194,7 @@ class TestDoHostList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedPrintListFieldsEqualTo([
|
||||
'active', 'cell_id', 'device_type', 'id', 'name'
|
||||
])
|
||||
self.assertFieldsEqualTo(hosts_shell.DEFAULT_HOST_FIELDS)
|
||||
|
||||
def test_fields(self):
|
||||
"""Verify that we can specify custom fields."""
|
||||
|
@ -19,7 +19,6 @@ import mock
|
||||
from cratonclient import exceptions
|
||||
from cratonclient.shell.v1 import projects_shell
|
||||
from cratonclient.tests.unit.shell import base
|
||||
from cratonclient.v1 import projects
|
||||
|
||||
|
||||
class TestDoShellShow(base.TestShellCommandUsingPrintDict):
|
||||
@ -53,7 +52,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
|
||||
kwargs.setdefault('name', None)
|
||||
kwargs.setdefault('limit', None)
|
||||
kwargs.setdefault('detail', False)
|
||||
kwargs.setdefault('fields', [])
|
||||
kwargs.setdefault('fields', projects_shell.DEFAULT_PROJECT_FIELDS)
|
||||
kwargs.setdefault('marker', None)
|
||||
kwargs.setdefault('all', False)
|
||||
return super(TestDoProjectList, self).args_for(**kwargs)
|
||||
@ -68,7 +67,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
|
||||
marker=None,
|
||||
autopaginate=False,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(projects_shell.DEFAULT_PROJECT_FIELDS)
|
||||
|
||||
def test_negative_limit(self):
|
||||
"""Ensure we raise an exception for negative limits."""
|
||||
@ -89,7 +88,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(projects_shell.DEFAULT_PROJECT_FIELDS)
|
||||
|
||||
def test_detail(self):
|
||||
"""Verify the behaviour of specifying --detail."""
|
||||
@ -101,7 +100,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
|
||||
marker=None,
|
||||
autopaginate=False,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(sorted(list(projects.PROJECT_FIELDS)))
|
||||
self.assertFieldsEqualTo(projects_shell.PROJECT_FIELDS)
|
||||
|
||||
def test_list_name(self):
|
||||
"""Verify the behaviour of specifying --detail."""
|
||||
@ -114,13 +113,13 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(projects_shell.DEFAULT_PROJECT_FIELDS)
|
||||
|
||||
def test_raises_exception_with_detail_and_fields(self):
|
||||
"""Verify that we fail when users specify --detail and --fields."""
|
||||
args = self.args_for(
|
||||
detail=True,
|
||||
fields=['id', 'name'],
|
||||
fields=['name', 'id'],
|
||||
)
|
||||
|
||||
self.assertRaisesCommandErrorWith(projects_shell.do_project_list, args)
|
||||
@ -128,7 +127,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
|
||||
|
||||
def test_fields(self):
|
||||
"""Verify that we print out specific fields."""
|
||||
args = self.args_for(fields=['id', 'name'])
|
||||
args = self.args_for(fields=['name', 'id'])
|
||||
|
||||
projects_shell.do_project_list(self.craton_client, args)
|
||||
|
||||
@ -136,7 +135,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
|
||||
autopaginate=False,
|
||||
marker=None,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(['name', 'id'])
|
||||
|
||||
def test_invalid_fields(self):
|
||||
"""Verify that we error out with invalid fields."""
|
||||
|
@ -204,7 +204,7 @@ class TestDoRegionList(base.TestShellCommandUsingPrintList):
|
||||
kwargs.setdefault('detail', False)
|
||||
kwargs.setdefault('cloud', None)
|
||||
kwargs.setdefault('limit', None)
|
||||
kwargs.setdefault('fields', [])
|
||||
kwargs.setdefault('fields', regions_shell.DEFAULT_REGION_FIELDS)
|
||||
kwargs.setdefault('marker', None)
|
||||
kwargs.setdefault('all', False)
|
||||
return super(TestDoRegionList, self).args_for(**kwargs)
|
||||
@ -214,7 +214,7 @@ class TestDoRegionList(base.TestShellCommandUsingPrintList):
|
||||
args = self.args_for()
|
||||
regions_shell.do_region_list(self.craton_client, args)
|
||||
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(regions_shell.DEFAULT_REGION_FIELDS)
|
||||
|
||||
def test_with_cloud_id(self):
|
||||
"""Test region-list with default values."""
|
||||
@ -225,7 +225,7 @@ class TestDoRegionList(base.TestShellCommandUsingPrintList):
|
||||
marker=None,
|
||||
autopaginate=False,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(regions_shell.DEFAULT_REGION_FIELDS)
|
||||
|
||||
def test_negative_limit(self):
|
||||
"""Ensure we raise an exception for negative limits."""
|
||||
@ -241,13 +241,13 @@ class TestDoRegionList(base.TestShellCommandUsingPrintList):
|
||||
marker=None,
|
||||
autopaginate=False,
|
||||
)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name'])
|
||||
self.assertFieldsEqualTo(regions_shell.DEFAULT_REGION_FIELDS)
|
||||
|
||||
def test_fields(self):
|
||||
"""Verify that we print out specific fields."""
|
||||
args = self.args_for(fields=['id', 'name', 'note'])
|
||||
args = self.args_for(fields=['name', 'id', 'note'])
|
||||
regions_shell.do_region_list(self.craton_client, args)
|
||||
self.assertSortedFieldsEqualTo(['id', 'name', 'note'])
|
||||
self.assertFieldsEqualTo(['name', 'id', 'note'])
|
||||
|
||||
def test_invalid_fields(self):
|
||||
"""Verify that we error out with invalid fields."""
|
||||
|
@ -27,15 +27,3 @@ class CellManager(crud.CRUDClient):
|
||||
key = 'cell'
|
||||
base_path = '/cells'
|
||||
resource_class = Cell
|
||||
|
||||
|
||||
CELL_FIELDS = {
|
||||
'id': 'ID',
|
||||
'region_id': 'Region ID',
|
||||
'project_id': 'Project ID',
|
||||
'cloud_id': 'Cloud ID',
|
||||
'name': 'Name',
|
||||
'note': 'Note',
|
||||
'created_at': 'Created At',
|
||||
'updated_at': 'Updated At'
|
||||
}
|
||||
|
@ -27,12 +27,3 @@ class CloudManager(crud.CRUDClient):
|
||||
key = 'cloud'
|
||||
base_path = '/clouds'
|
||||
resource_class = Cloud
|
||||
|
||||
CLOUD_FIELDS = {
|
||||
'id': 'ID',
|
||||
'project_id': 'Project ID',
|
||||
'name': 'Name',
|
||||
'note': 'Note',
|
||||
'created_at': 'Created At',
|
||||
'updated_at': 'Updated At'
|
||||
}
|
||||
|
@ -27,21 +27,3 @@ class HostManager(crud.CRUDClient):
|
||||
key = 'host'
|
||||
base_path = '/hosts'
|
||||
resource_class = Host
|
||||
|
||||
|
||||
HOST_FIELDS = {
|
||||
'id': 'ID',
|
||||
'name': 'Name',
|
||||
'device_type': 'Device Type',
|
||||
'project_id': 'Project ID',
|
||||
'cloud_id': 'Cloud ID',
|
||||
'region_id': 'Region ID',
|
||||
'cell_id': 'Cell ID',
|
||||
'ip_address': 'IP Address',
|
||||
'active': 'Active',
|
||||
'note': 'Note',
|
||||
'created_at': 'Created At',
|
||||
'updated_at': 'Updated At',
|
||||
'labels': 'Labels',
|
||||
'parent_id': 'Parent ID',
|
||||
}
|
||||
|
@ -27,11 +27,3 @@ class ProjectManager(crud.CRUDClient):
|
||||
key = 'project'
|
||||
base_path = '/projects'
|
||||
resource_class = Project
|
||||
|
||||
|
||||
PROJECT_FIELDS = {
|
||||
'id': 'ID',
|
||||
'name': 'Name',
|
||||
'created_at': 'Created At',
|
||||
'updated_at': 'Updated At'
|
||||
}
|
||||
|
@ -28,13 +28,3 @@ class RegionManager(crud.CRUDClient):
|
||||
base_path = '/regions'
|
||||
resource_class = Region
|
||||
project_id = 0
|
||||
|
||||
REGION_FIELDS = {
|
||||
'id': 'ID',
|
||||
'project_id': 'Project ID',
|
||||
'cloud_id': 'Cloud ID',
|
||||
'name': 'Name',
|
||||
'note': 'Note',
|
||||
'created_at': 'Created At',
|
||||
'updated_at': 'Updated At'
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user