Update projects commands to use pluggable formatters

This allows users to specify the formatter they want to use and have the
project-* subcommands honor it.

Change-Id: I4ea6f0d679f6167a1b4865d8d51f5c6ef07c58cd
This commit is contained in:
Ian Cordasco
2017-02-28 13:15:10 -06:00
parent d8e31c39cc
commit 6bb372ea37
3 changed files with 32 additions and 37 deletions

View File

@@ -25,8 +25,7 @@ from cratonclient.v1 import projects
def do_project_show(cc, args):
"""Show detailed information about a project."""
project = cc.projects.get(args.id)
data = {f: getattr(project, f, '') for f in projects.PROJECT_FIELDS}
cliutils.print_dict(data, wrap=72)
args.formatter.configure(wrap=72).handle(project)
@cliutils.arg('-n', '--name',
@@ -88,7 +87,7 @@ def do_project_list(cc, args):
params['autopaginate'] = args.all
listed_projects = cc.projects.list(**params)
cliutils.print_list(listed_projects, list(fields))
args.formatter.configure(fields=list(fields)).handle(listed_projects)
@cliutils.arg('-n', '--name',
@@ -100,8 +99,7 @@ def do_project_create(cc, args):
fields = {k: v for (k, v) in vars(args).items()
if k in projects.PROJECT_FIELDS and not (v is None)}
project = cc.projects.create(**fields)
data = {f: getattr(project, f, '') for f in projects.PROJECT_FIELDS}
cliutils.print_dict(data, wrap=72)
args.formatter.configure(wrap=72).handle(project)
@cliutils.arg('id',

View File

@@ -29,14 +29,22 @@ class TestProjectsShell(base.ShellTestCase):
re_options = re.DOTALL | re.MULTILINE
project_valid_fields = None
project_invalid_field = None
project_invalid_fields = None
def setUp(self):
"""Setup required test fixtures."""
super(TestProjectsShell, self).setUp()
self.project_valid_fields = Namespace(name='mock_project')
self.project_invalid_field = Namespace(name='mock_project',
invalid_foo='ignored')
self.project_valid_kwargs = {
'name': 'mock_project',
}
self.project_invalid_kwargs = {
'name': 'mock_project',
'invalid_foo': 'ignored',
}
self.project_valid_fields = Namespace(**self.project_valid_kwargs)
self.project_invalid_fields = Namespace(**self.project_invalid_kwargs)
self.project_valid_fields.formatter = mock.Mock()
self.project_invalid_fields.formatter = mock.Mock()
@mock.patch('cratonclient.v1.projects.ProjectManager.list')
def test_project_list_success(self, mock_list):
@@ -92,17 +100,13 @@ class TestProjectsShell(base.ShellTestCase):
)
@mock.patch('cratonclient.v1.projects.ProjectManager.list')
@mock.patch('cratonclient.common.cliutils.print_list')
def test_project_list_fields_success(self, mock_printlist, mock_list):
def test_project_list_fields_success(self, mock_list):
"""Verify --fields argument successfully passed to Client."""
self.shell('project-list --fields id name')
mock_list.assert_called_once_with(
marker=None,
autopaginate=False,
)
mock_printlist.assert_called_once_with(mock.ANY,
list({'id': 'ID',
'name': 'Name'}))
def test_project_create_missing_required_args(self):
"""Verify that missing required args results in error message."""
@@ -126,7 +130,7 @@ class TestProjectsShell(base.ShellTestCase):
region_id=mock.ANY,
)
projects_shell.do_project_create(client, self.project_valid_fields)
mock_create.assert_called_once_with(**vars(self.project_valid_fields))
mock_create.assert_called_once_with(**self.project_valid_kwargs)
@mock.patch('cratonclient.v1.projects.ProjectManager.create')
def test_do_project_create_ignores_unknown_fields(self, mock_create):
@@ -136,8 +140,8 @@ class TestProjectsShell(base.ShellTestCase):
mock.ANY, 'http://127.0.0.1/',
region_id=mock.ANY,
)
projects_shell.do_project_create(client, self.project_invalid_field)
mock_create.assert_called_once_with(**vars(self.project_valid_fields))
projects_shell.do_project_create(client, self.project_invalid_fields)
mock_create.assert_called_once_with(**self.project_valid_kwargs)
def test_project_show_missing_required_args(self):
"""Verify that missing required args results in error message."""
@@ -159,9 +163,9 @@ class TestProjectsShell(base.ShellTestCase):
mock.ANY, 'http://127.0.0.1/',
region_id=mock.ANY,
)
test_args = Namespace(id=1)
test_args = Namespace(id=1, formatter=mock.Mock())
projects_shell.do_project_show(client, test_args)
mock_get.assert_called_once_with(vars(test_args)['id'])
mock_get.assert_called_once_with(1)
def test_project_delete_missing_required_args(self):
"""Verify that missing required args results in error message."""

View File

@@ -35,10 +35,8 @@ class TestDoShellShow(base.TestShellCommandUsingPrintDict):
projects_shell.do_project_show(self.craton_client, args)
self.craton_client.projects.get.assert_called_once_with(456)
self.print_dict.assert_called_once_with(
{f: mock.ANY for f in projects.PROJECT_FIELDS},
wrap=72,
)
self.formatter.configure.assert_called_once_with(wrap=72)
self.assertEqual(1, self.formatter.handle.call_count)
class TestDoProjectList(base.TestShellCommandUsingPrintList):
@@ -47,7 +45,8 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
def assertNothingWasCalled(self):
"""Assert inventory, list, and print_list were not called."""
super(TestDoProjectList, self).assertNothingWasCalled()
self.assertFalse(self.print_list.called)
self.assertFalse(self.formatter.configure.called)
self.assertFalse(self.formatter.handle.called)
def args_for(self, **kwargs):
"""Generate the default argument list for project-list."""
@@ -69,9 +68,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
marker=None,
autopaginate=False,
)
self.assertTrue(self.print_list.called)
self.assertEqual(['id', 'name'],
sorted(self.print_list.call_args[0][-1]))
self.assertSortedFieldsEqualTo(['id', 'name'])
def test_negative_limit(self):
"""Ensure we raise an exception for negative limits."""
@@ -92,9 +89,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
autopaginate=False,
marker=None,
)
self.assertTrue(self.print_list.called)
self.assertEqual(['id', 'name'],
sorted(self.print_list.call_args[0][-1]))
self.assertSortedFieldsEqualTo(['id', 'name'])
def test_detail(self):
"""Verify the behaviour of specifying --detail."""
@@ -106,8 +101,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
marker=None,
autopaginate=False,
)
self.assertEqual(sorted(list(projects.PROJECT_FIELDS)),
sorted(self.print_list.call_args[0][-1]))
self.assertSortedFieldsEqualTo(sorted(list(projects.PROJECT_FIELDS)))
def test_list_name(self):
"""Verify the behaviour of specifying --detail."""
@@ -120,8 +114,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
autopaginate=False,
marker=None,
)
self.assertEqual(['id', 'name'],
sorted(self.print_list.call_args[0][-1]))
self.assertSortedFieldsEqualTo(['id', 'name'])
def test_raises_exception_with_detail_and_fields(self):
"""Verify that we fail when users specify --detail and --fields."""
@@ -143,8 +136,7 @@ class TestDoProjectList(base.TestShellCommandUsingPrintList):
autopaginate=False,
marker=None,
)
self.assertEqual(['id', 'name'],
sorted(self.print_list.call_args[0][-1]))
self.assertSortedFieldsEqualTo(['id', 'name'])
def test_invalid_fields(self):
"""Verify that we error out with invalid fields."""
@@ -207,7 +199,8 @@ class TestDoProjectCreate(base.TestShellCommandUsingPrintDict):
self.craton_client.projects.create.assert_called_once_with(
name='New Project'
)
self.print_dict.assert_called_once_with(mock.ANY, wrap=72)
self.formatter.configure.assert_called_once_with(wrap=72)
self.assertEqual(1, self.formatter.handle.call_count)
class TestDoProjectDelete(base.TestShellCommand):