Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions awsshell/interaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,32 @@ def __init__(self, model, prompt_msg, prompter=select_prompt):
super(SimpleSelect, self).__init__(model, prompt_msg)
self._prompter = prompter

def execute(self, data):
def execute(self, data, show_meta=False):
if not isinstance(data, list) or len(data) < 1:
raise InteractionException('SimpleSelect expects a non-empty list')
if self._model.get('Path') is not None:
display_data = jmespath.search(self._model['Path'], data)
result = self._prompter('%s ' % self.prompt, display_data)
options_meta = data if show_meta else None
result = self._prompter('%s ' % self.prompt, display_data,
options_meta=options_meta)
(selected, index) = result
return data[index]
else:
(selected, index) = self._prompter('%s ' % self.prompt, data)
return selected


class InfoSelect(SimpleSelect):
"""Display a list of options with meta information.

Small extension of :class:`SimpleSelect` that turns the show_meta flag on
to display what the complete object looks like rendered as json in a pane
below the prompt.
"""
def execute(self, data):
return super(InfoSelect, self).execute(data, show_meta=True)


class SimplePrompt(Interaction):
"""Prompt the user to type in responses for each field.

Expand Down Expand Up @@ -174,6 +187,7 @@ class InteractionLoader(object):
Interaction objects can be instantiated from their corresponding str.
"""
_INTERACTIONS = {
'InfoSelect': InfoSelect,
'FuzzySelect': FuzzySelect,
'SimpleSelect': SimpleSelect,
'SimplePrompt': SimplePrompt,
Expand Down
5 changes: 2 additions & 3 deletions awsshell/selectmenu.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import json
from pygments.lexers import find_lexer_class
from prompt_toolkit.keys import Keys
from prompt_toolkit.token import Token
Expand All @@ -21,6 +20,7 @@
from prompt_toolkit.layout import Window, HSplit, FloatContainer, Float
from prompt_toolkit.layout.containers import ScrollOffsets, \
ConditionalContainer
from awsshell.utils import format_json

"""An implementation of a selection menu using prompt toolkit.

Expand Down Expand Up @@ -261,8 +261,7 @@ def return_selection(cli, buf):
def selection_changed(cli):
index = self.menu_control.get_index()
info = options_meta[index]
formatted_info = json.dumps(info, indent=4, sort_keys=True,
ensure_ascii=False)
formatted_info = format_json(info)
buffers['INFO'].text = formatted_info
default_buf.on_text_changed += selection_changed

Expand Down
7 changes: 7 additions & 0 deletions awsshell/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import tempfile
import uuid
import logging
import json

import awscli

from awscli.utils import json_encoder
from awsshell.compat import HTMLParser


Expand Down Expand Up @@ -142,3 +144,8 @@ def force_unicode(obj, encoding='utf8'):
if not isinstance(obj, six.text_type):
obj = _attempt_decode(obj, encoding)
return obj


def format_json(response):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simple though this one-line function is, it should still have a test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was being implicitly tested through one of the Environment's unit tests, but I agree an explicit test for this too makes sense.

return json.dumps(response, indent=4, default=json_encoder,
ensure_ascii=False, sort_keys=True)
5 changes: 2 additions & 3 deletions awsshell/wizard.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import sys
import copy
import json
import logging
import jmespath

Expand All @@ -9,7 +8,7 @@
from botocore.exceptions import BotoCoreError, ClientError

from awsshell.resource import index
from awsshell.utils import force_unicode
from awsshell.utils import force_unicode, format_json
from awsshell.selectmenu import select_prompt
from awsshell.interaction import InteractionLoader, InteractionException

Expand Down Expand Up @@ -348,7 +347,7 @@ def __init__(self):
self._variables = {}

def __str__(self):
return json.dumps(self._variables, indent=4, sort_keys=True)
return format_json(self._variables)

def update(self, environment):
assert isinstance(environment, Environment)
Expand Down
7 changes: 4 additions & 3 deletions tests/unit/test_interaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from prompt_toolkit.contrib.validators.base import Validator, ValidationError
from awsshell.interaction import InteractionLoader, InteractionException
from awsshell.interaction import SimpleSelect, SimplePrompt, FilePrompt
from awsshell.interaction import FuzzyCompleter, FuzzySelect
from awsshell.interaction import FuzzyCompleter, FuzzySelect, InfoSelect


@pytest.fixture
Expand Down Expand Up @@ -88,12 +88,13 @@ def test_simple_select():
assert xformed == options[1]


def test_simple_select_with_path():
@pytest.mark.parametrize('selector', [SimpleSelect, InfoSelect])
def test_simple_select_with_path(selector):
# Verify that SimpleSelect calls prompt and it returns the corresponding
# item derived from the path.
prompt = mock.Mock()
model = {'Path': '[].a'}
simple_selector = SimpleSelect(model, 'Promptingu', prompt)
simple_selector = selector(model, 'Promptingu', prompt)
options = [{'a': '1', 'b': 'one'}, {'a': '2', 'b': 'two'}]
prompt.return_value = ('2', 1)
xformed = simple_selector.execute(options)
Expand Down
7 changes: 7 additions & 0 deletions tests/unit/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from tests import unittest
import os
import tempfile
import datetime
import shutil
import six
import pytest
Expand All @@ -10,6 +11,7 @@
from awsshell.utils import FileReadError
from awsshell.utils import temporary_file
from awsshell.utils import force_unicode
from awsshell.utils import format_json


class TestFSLayer(unittest.TestCase):
Expand Down Expand Up @@ -127,3 +129,8 @@ def test_force_unicode_recursion():
assert isinstance(clean_obj['b']['str'], six.text_type)
assert clean_obj['c'] is obj['c']
assert obj == clean_obj


def test_format_json():
data = {'Key': datetime.datetime(2016, 12, 12)}
assert format_json(data) == '{\n "Key": "2016-12-12T00:00:00"\n}'