Skip to content

Commit 96852f1

Browse files
authored
Merge pull request #144 from joguSD/info-select
Info Select & Rendering responses JSON
2 parents 6f43f8e + 87d47ea commit 96852f1

File tree

6 files changed

+38
-11
lines changed

6 files changed

+38
-11
lines changed

awsshell/interaction.py

+16-2
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,32 @@ def __init__(self, model, prompt_msg, prompter=select_prompt):
7777
super(SimpleSelect, self).__init__(model, prompt_msg)
7878
self._prompter = prompter
7979

80-
def execute(self, data):
80+
def execute(self, data, show_meta=False):
8181
if not isinstance(data, list) or len(data) < 1:
8282
raise InteractionException('SimpleSelect expects a non-empty list')
8383
if self._model.get('Path') is not None:
8484
display_data = jmespath.search(self._model['Path'], data)
85-
result = self._prompter('%s ' % self.prompt, display_data)
85+
options_meta = data if show_meta else None
86+
result = self._prompter('%s ' % self.prompt, display_data,
87+
options_meta=options_meta)
8688
(selected, index) = result
8789
return data[index]
8890
else:
8991
(selected, index) = self._prompter('%s ' % self.prompt, data)
9092
return selected
9193

9294

95+
class InfoSelect(SimpleSelect):
96+
"""Display a list of options with meta information.
97+
98+
Small extension of :class:`SimpleSelect` that turns the show_meta flag on
99+
to display what the complete object looks like rendered as json in a pane
100+
below the prompt.
101+
"""
102+
def execute(self, data):
103+
return super(InfoSelect, self).execute(data, show_meta=True)
104+
105+
93106
class SimplePrompt(Interaction):
94107
"""Prompt the user to type in responses for each field.
95108
@@ -174,6 +187,7 @@ class InteractionLoader(object):
174187
Interaction objects can be instantiated from their corresponding str.
175188
"""
176189
_INTERACTIONS = {
190+
'InfoSelect': InfoSelect,
177191
'FuzzySelect': FuzzySelect,
178192
'SimpleSelect': SimpleSelect,
179193
'SimplePrompt': SimplePrompt,

awsshell/selectmenu.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import json
21
from pygments.lexers import find_lexer_class
32
from prompt_toolkit.keys import Keys
43
from prompt_toolkit.token import Token
@@ -21,6 +20,7 @@
2120
from prompt_toolkit.layout import Window, HSplit, FloatContainer, Float
2221
from prompt_toolkit.layout.containers import ScrollOffsets, \
2322
ConditionalContainer
23+
from awsshell.utils import format_json
2424

2525
"""An implementation of a selection menu using prompt toolkit.
2626
@@ -261,8 +261,7 @@ def return_selection(cli, buf):
261261
def selection_changed(cli):
262262
index = self.menu_control.get_index()
263263
info = options_meta[index]
264-
formatted_info = json.dumps(info, indent=4, sort_keys=True,
265-
ensure_ascii=False)
264+
formatted_info = format_json(info)
266265
buffers['INFO'].text = formatted_info
267266
default_buf.on_text_changed += selection_changed
268267

awsshell/utils.py

+7
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
import tempfile
77
import uuid
88
import logging
9+
import json
910

1011
import awscli
1112

13+
from awscli.utils import json_encoder
1214
from awsshell.compat import HTMLParser
1315

1416

@@ -142,3 +144,8 @@ def force_unicode(obj, encoding='utf8'):
142144
if not isinstance(obj, six.text_type):
143145
obj = _attempt_decode(obj, encoding)
144146
return obj
147+
148+
149+
def format_json(response):
150+
return json.dumps(response, indent=4, default=json_encoder,
151+
ensure_ascii=False, sort_keys=True)

awsshell/wizard.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import sys
22
import copy
3-
import json
43
import logging
54
import jmespath
65

@@ -9,7 +8,7 @@
98
from botocore.exceptions import BotoCoreError, ClientError
109

1110
from awsshell.resource import index
12-
from awsshell.utils import force_unicode
11+
from awsshell.utils import force_unicode, format_json
1312
from awsshell.selectmenu import select_prompt
1413
from awsshell.interaction import InteractionLoader, InteractionException
1514

@@ -348,7 +347,7 @@ def __init__(self):
348347
self._variables = {}
349348

350349
def __str__(self):
351-
return json.dumps(self._variables, indent=4, sort_keys=True)
350+
return format_json(self._variables)
352351

353352
def update(self, environment):
354353
assert isinstance(environment, Environment)

tests/unit/test_interaction.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from prompt_toolkit.contrib.validators.base import Validator, ValidationError
77
from awsshell.interaction import InteractionLoader, InteractionException
88
from awsshell.interaction import SimpleSelect, SimplePrompt, FilePrompt
9-
from awsshell.interaction import FuzzyCompleter, FuzzySelect
9+
from awsshell.interaction import FuzzyCompleter, FuzzySelect, InfoSelect
1010

1111

1212
@pytest.fixture
@@ -88,12 +88,13 @@ def test_simple_select():
8888
assert xformed == options[1]
8989

9090

91-
def test_simple_select_with_path():
91+
@pytest.mark.parametrize('selector', [SimpleSelect, InfoSelect])
92+
def test_simple_select_with_path(selector):
9293
# Verify that SimpleSelect calls prompt and it returns the corresponding
9394
# item derived from the path.
9495
prompt = mock.Mock()
9596
model = {'Path': '[].a'}
96-
simple_selector = SimpleSelect(model, 'Promptingu', prompt)
97+
simple_selector = selector(model, 'Promptingu', prompt)
9798
options = [{'a': '1', 'b': 'one'}, {'a': '2', 'b': 'two'}]
9899
prompt.return_value = ('2', 1)
99100
xformed = simple_selector.execute(options)

tests/unit/test_utils.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from tests import unittest
22
import os
33
import tempfile
4+
import datetime
45
import shutil
56
import six
67
import pytest
@@ -10,6 +11,7 @@
1011
from awsshell.utils import FileReadError
1112
from awsshell.utils import temporary_file
1213
from awsshell.utils import force_unicode
14+
from awsshell.utils import format_json
1315

1416

1517
class TestFSLayer(unittest.TestCase):
@@ -127,3 +129,8 @@ def test_force_unicode_recursion():
127129
assert isinstance(clean_obj['b']['str'], six.text_type)
128130
assert clean_obj['c'] is obj['c']
129131
assert obj == clean_obj
132+
133+
134+
def test_format_json():
135+
data = {'Key': datetime.datetime(2016, 12, 12)}
136+
assert format_json(data) == '{\n "Key": "2016-12-12T00:00:00"\n}'

0 commit comments

Comments
 (0)