Merge lp:~frankban/juju-quickstart/improve-input-handling into lp:juju-quickstart
- improve-input-handling
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 39 |
Proposed branch: | lp:~frankban/juju-quickstart/improve-input-handling |
Merge into: | lp:juju-quickstart |
Diff against target: |
337 lines (+110/-41) 6 files modified
cli-app-demo.py (+3/-0) quickstart/cli/base.py (+17/-2) quickstart/cli/views.py (+25/-17) quickstart/tests/cli/helpers.py (+31/-0) quickstart/tests/cli/test_base.py (+20/-1) quickstart/tests/cli/test_views.py (+14/-21) |
To merge this branch: | bzr merge lp:~frankban/juju-quickstart/improve-input-handling |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju GUI Hackers | Pending | ||
Review via email:
|
Commit message
Description of the change
Improve views input handling.
Add a new set_return_
views can call to set the value encapsulated
in the AppExit exception raised when the user
quits the application with ^X.
Tests: `make check`
QA: start the demo app
(`make` and `./cli-
Try exiting with ^X: you should see the
"no environment selected" message.
Restart and exit selecting an environment:
you should see a message indicating that
environment has been selected.
Restart and change the default environment,
then exit: you should see the new env_db
printed and the new default environment.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Francesco Banconi (frankban) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Madison Scott-Clary (makyo) wrote : | # |
LGTM, thanks!
- 44. By Francesco Banconi
-
Add missing import unicode_literals.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Francesco Banconi (frankban) wrote : | # |
*** Submitted:
Improve views input handling.
Add a new set_return_
views can call to set the value encapsulated
in the AppExit exception raised when the user
quits the application with ^X.
Tests: `make check`
QA: start the demo app
(`make` and `./cli-
Try exiting with ^X: you should see the
"no environment selected" message.
Restart and exit selecting an environment:
you should see a message indicating that
environment has been selected.
Restart and change the default environment,
then exit: you should see the new env_db
printed and the new default environment.
R=matthew.scott
CC=
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Francesco Banconi (frankban) wrote : | # |
Thank you!
Preview Diff
1 | === modified file 'cli-app-demo.py' | |||
2 | --- cli-app-demo.py 2013-12-18 15:41:31 +0000 | |||
3 | +++ cli-app-demo.py 2013-12-19 17:41:55 +0000 | |||
4 | @@ -27,6 +27,8 @@ | |||
5 | 27 | unicode_literals, | 27 | unicode_literals, |
6 | 28 | ) | 28 | ) |
7 | 29 | 29 | ||
8 | 30 | import pprint | ||
9 | 31 | |||
10 | 30 | from quickstart.cli import views | 32 | from quickstart.cli import views |
11 | 31 | from quickstart.models import envs | 33 | from quickstart.models import envs |
12 | 32 | from quickstart.tests import helpers | 34 | from quickstart.tests import helpers |
13 | @@ -43,6 +45,7 @@ | |||
14 | 43 | views.env_index, env_type_db, env_db, save_callable) | 45 | views.env_index, env_type_db, env_db, save_callable) |
15 | 44 | if new_env_db != env_db: | 46 | if new_env_db != env_db: |
16 | 45 | print('saved a new env db') | 47 | print('saved a new env db') |
17 | 48 | pprint.pprint(new_env_db) | ||
18 | 46 | print('default: {}'.format(new_env_db.get('default'))) | 49 | print('default: {}'.format(new_env_db.get('default'))) |
19 | 47 | if env_data is None: | 50 | if env_data is None: |
20 | 48 | print('no environment selected') | 51 | print('no environment selected') |
21 | 49 | 52 | ||
22 | === modified file 'quickstart/cli/base.py' | |||
23 | --- quickstart/cli/base.py 2013-12-19 09:12:37 +0000 | |||
24 | +++ quickstart/cli/base.py 2013-12-19 17:41:55 +0000 | |||
25 | @@ -40,6 +40,7 @@ | |||
26 | 40 | 'set_contents', 'get_contents', | 40 | 'set_contents', 'get_contents', |
27 | 41 | 'set_status', 'get_status', | 41 | 'set_status', 'get_status', |
28 | 42 | 'set_message', 'get_message', | 42 | 'set_message', 'get_message', |
29 | 43 | 'set_return_value_on_exit', | ||
30 | 43 | ], | 44 | ], |
31 | 44 | ) | 45 | ) |
32 | 45 | 46 | ||
33 | @@ -102,7 +103,12 @@ | |||
34 | 102 | - set_message(text): set/change a notification message, which is | 103 | - set_message(text): set/change a notification message, which is |
35 | 103 | displayed in the footer for a couple of seconds before disappearing; | 104 | displayed in the footer for a couple of seconds before disappearing; |
36 | 104 | - get_message(): return the message currently displayed in the | 105 | - get_message(): return the message currently displayed in the |
38 | 105 | notifications area. | 106 | notifications area; |
39 | 107 | |||
40 | 108 | - set_return_value_on_exit(value): set the value to be encapsulated | ||
41 | 109 | in the AppExit exception raised when the user quits the application | ||
42 | 110 | with the exit shortcut. See the quickstart.cli.views module docstring | ||
43 | 111 | for more information about this functionality. | ||
44 | 106 | """ | 112 | """ |
45 | 107 | # Set up the application header. | 113 | # Set up the application header. |
46 | 108 | title = urwid.Text('\npreparing...') | 114 | title = urwid.Text('\npreparing...') |
47 | @@ -143,10 +149,18 @@ | |||
48 | 143 | valign='middle', height=('relative', 90), | 149 | valign='middle', height=('relative', 90), |
49 | 144 | min_width=78, min_height=20) | 150 | min_width=78, min_height=20) |
50 | 145 | # Instantiate the Urwid main loop. | 151 | # Instantiate the Urwid main loop. |
52 | 146 | loop = _MainLoop(top_widget, palette=ui.PALETTE) | 152 | loop = _MainLoop( |
53 | 153 | top_widget, palette=ui.PALETTE, | ||
54 | 154 | unhandled_input=ui.exit_and_return(None)) | ||
55 | 147 | # Add a timeout to the notification message. | 155 | # Add a timeout to the notification message. |
56 | 148 | timeout_message = ui.TimeoutText( | 156 | timeout_message = ui.TimeoutText( |
57 | 149 | message, 3, loop.set_alarm_in, loop.remove_alarm) | 157 | message, 3, loop.set_alarm_in, loop.remove_alarm) |
58 | 158 | |||
59 | 159 | # Allow views to set the value returned when the user quits the session. | ||
60 | 160 | def set_return_value_on_exit(return_value): | ||
61 | 161 | unhandled_input = ui.exit_and_return(return_value) | ||
62 | 162 | loop.set_unhandled_input(unhandled_input) | ||
63 | 163 | |||
64 | 150 | # Create the App named tuple. If, in the future, we have a view that | 164 | # Create the App named tuple. If, in the future, we have a view that |
65 | 151 | # requires additional capabilities or API access, this is the place to add | 165 | # requires additional capabilities or API access, this is the place to add |
66 | 152 | # those. | 166 | # those. |
67 | @@ -159,5 +173,6 @@ | |||
68 | 159 | get_status=lambda: status.text, | 173 | get_status=lambda: status.text, |
69 | 160 | set_message=lambda msg: timeout_message.set_text(('message', msg)), | 174 | set_message=lambda msg: timeout_message.set_text(('message', msg)), |
70 | 161 | get_message=lambda: timeout_message.text, | 175 | get_message=lambda: timeout_message.text, |
71 | 176 | set_return_value_on_exit=set_return_value_on_exit, | ||
72 | 162 | ) | 177 | ) |
73 | 163 | return loop, app | 178 | return loop, app |
74 | 164 | 179 | ||
75 | === modified file 'quickstart/cli/views.py' | |||
76 | --- quickstart/cli/views.py 2013-12-19 09:30:08 +0000 | |||
77 | +++ quickstart/cli/views.py 2013-12-19 17:41:55 +0000 | |||
78 | @@ -38,7 +38,7 @@ | |||
79 | 38 | 38 | ||
80 | 39 | def myview(app, title): | 39 | def myview(app, title): |
81 | 40 | app.set_title(title) | 40 | app.set_title(title) |
83 | 41 | return 42 | 41 | app.set_return_value_on_exit(42) |
84 | 42 | 42 | ||
85 | 43 | The view above, requiring a title argument, can be started this way: | 43 | The view above, requiring a title argument, can be started this way: |
86 | 44 | 44 | ||
87 | @@ -52,9 +52,12 @@ | |||
88 | 52 | 2) a view decides it is time to quit (e.g. reacting to an event/input). | 52 | 2) a view decides it is time to quit (e.g. reacting to an event/input). |
89 | 53 | 53 | ||
90 | 54 | In both cases, the show function returns something to the caller: | 54 | In both cases, the show function returns something to the caller: |
94 | 55 | 1) when the user explicitly requests to quit, the value returned by the | 55 | 1) when the user explicitly requests to quit, None is returned by default. |
95 | 56 | view itself (the callable passed to show()) is returned. For instance, | 56 | However, the view can change this default value by calling |
96 | 57 | the show(myview...) call above would return 42; | 57 | app.set_return_value_on_exit(some value). For instance, the |
97 | 58 | show(myview...) call above would return 42. It is safe to call the | ||
98 | 59 | set_return_value_on_exit API multiple times in order to overwrite the | ||
99 | 60 | value returned on user exit; | ||
100 | 58 | 2) to force the end of the interactive session, a view can raise a | 61 | 2) to force the end of the interactive session, a view can raise a |
101 | 59 | quickstart.cli.ui.AppExit exception, passing a return value: if the | 62 | quickstart.cli.ui.AppExit exception, passing a return value: if the |
102 | 60 | application is exited this way, then show() returns the value | 63 | application is exited this way, then show() returns the value |
103 | @@ -71,18 +74,19 @@ | |||
104 | 71 | def exit(): | 74 | def exit(): |
105 | 72 | raise ui.AppExit(True) | 75 | raise ui.AppExit(True) |
106 | 73 | 76 | ||
107 | 77 | app.set_return_value_on_exit(False) | ||
108 | 74 | app.set_title('behold the button below') | 78 | app.set_title('behold the button below') |
109 | 75 | button = ui.MenuButton('press to exit', ui.thunk(exit)) | 79 | button = ui.MenuButton('press to exit', ui.thunk(exit)) |
110 | 76 | widgets = urwid.ListBox(urwid.SimpleFocusListWalker([button])) | 80 | widgets = urwid.ListBox(urwid.SimpleFocusListWalker([button])) |
111 | 77 | app.set_contents(widgets) | 81 | app.set_contents(widgets) |
112 | 78 | return False | ||
113 | 79 | 82 | ||
114 | 80 | pressed = views.show(button_view) | 83 | pressed = views.show(button_view) |
115 | 81 | 84 | ||
116 | 82 | In this example the button_view function configures the App to show a button. | 85 | In this example the button_view function configures the App to show a button. |
120 | 83 | Clicking that button an AppExit(True) is raised. The view itself instead just | 86 | Clicking that button an AppExit(True) is raised. The return value on exit |
121 | 84 | returns False. This means that "pressed" will be True if the user exited using | 87 | instead is set by the view itself to False. This means that "pressed" will be |
122 | 85 | the button, or False if the user exited using the global shortcut. | 88 | True if the user exited using the button, or False if the user exited using the |
123 | 89 | global shortcut. | ||
124 | 86 | 90 | ||
125 | 87 | As a final note, it is absolutely safe for a view to call, directly or | 91 | As a final note, it is absolutely safe for a view to call, directly or |
126 | 88 | indirectly, other views, as long as all the arguments required by the other | 92 | indirectly, other views, as long as all the arguments required by the other |
127 | @@ -111,16 +115,14 @@ | |||
128 | 111 | The view is called passing an App named tuple and the provided *args. | 115 | The view is called passing an App named tuple and the provided *args. |
129 | 112 | 116 | ||
130 | 113 | Block until the main loop is stopped, either by the user with the exit | 117 | Block until the main loop is stopped, either by the user with the exit |
134 | 114 | shortcut or by the view itself with the AppExit exception. In the former | 118 | shortcut or by the view itself. In both cases, an ui.AppExit is raised, and |
135 | 115 | case, return what is returned by the view. In the AppExit case, return | 119 | the return value is encapsulated in the exception. |
133 | 116 | the value encapsulated in the exception. | ||
136 | 117 | """ | 120 | """ |
137 | 118 | loop, app = base.setup_urwid_app() | 121 | loop, app = base.setup_urwid_app() |
138 | 119 | default_return_value = view(app, *args) | ||
139 | 120 | unhandled_input = ui.exit_and_return(default_return_value) | ||
140 | 121 | loop.set_unhandled_input(unhandled_input) | ||
141 | 122 | # Start the Urwid interactive session (main loop). | ||
142 | 123 | try: | 122 | try: |
143 | 123 | # Execute the view. | ||
144 | 124 | view(app, *args) | ||
145 | 125 | # Start the Urwid interactive session (main loop). | ||
146 | 124 | loop.run() | 126 | loop.run() |
147 | 125 | except ui.AppExit as err: | 127 | except ui.AppExit as err: |
148 | 126 | return err.return_value | 128 | return err.return_value |
149 | @@ -137,6 +139,10 @@ | |||
150 | 137 | - save_callable: a function called to save a new environment database. | 139 | - save_callable: a function called to save a new environment database. |
151 | 138 | """ | 140 | """ |
152 | 139 | env_db = copy.deepcopy(env_db) | 141 | env_db = copy.deepcopy(env_db) |
153 | 142 | # All the environment views return a tuple (new_env_db, env_data). | ||
154 | 143 | # Set the env_data to None in the case the user quits the application | ||
155 | 144 | # without selecting an environment to use. | ||
156 | 145 | app.set_return_value_on_exit((env_db, None)) | ||
157 | 140 | detail_view = functools.partial( | 146 | detail_view = functools.partial( |
158 | 141 | env_detail, app, env_type_db, env_db, save_callable) | 147 | env_detail, app, env_type_db, env_db, save_callable) |
159 | 142 | # Alphabetically sort the existing environments. | 148 | # Alphabetically sort the existing environments. |
160 | @@ -185,7 +191,6 @@ | |||
161 | 185 | if status: | 191 | if status: |
162 | 186 | app.set_status(status) | 192 | app.set_status(status) |
163 | 187 | app.set_contents(contents) | 193 | app.set_contents(contents) |
164 | 188 | return env_db, None | ||
165 | 189 | 194 | ||
166 | 190 | 195 | ||
167 | 191 | def env_detail(app, env_type_db, env_db, save_callable, env_data): | 196 | def env_detail(app, env_type_db, env_db, save_callable, env_data): |
168 | @@ -201,6 +206,10 @@ | |||
169 | 201 | - env_data: the environment data. | 206 | - env_data: the environment data. |
170 | 202 | """ | 207 | """ |
171 | 203 | env_db = copy.deepcopy(env_db) | 208 | env_db = copy.deepcopy(env_db) |
172 | 209 | # All the environment views return a tuple (new_env_db, env_data). | ||
173 | 210 | # Set the env_data to None in the case the user quits the application | ||
174 | 211 | # without selecting an environment to use. | ||
175 | 212 | app.set_return_value_on_exit((env_db, None)) | ||
176 | 204 | index_view = functools.partial( | 213 | index_view = functools.partial( |
177 | 205 | env_index, app, env_type_db, env_db, save_callable) | 214 | env_index, app, env_type_db, env_db, save_callable) |
178 | 206 | 215 | ||
179 | @@ -250,4 +259,3 @@ | |||
180 | 250 | widgets.append(ui.create_controls(*controls)) | 259 | widgets.append(ui.create_controls(*controls)) |
181 | 251 | listbox = urwid.ListBox(urwid.SimpleFocusListWalker(widgets)) | 260 | listbox = urwid.ListBox(urwid.SimpleFocusListWalker(widgets)) |
182 | 252 | app.set_contents(listbox) | 261 | app.set_contents(listbox) |
183 | 253 | return env_db, None | ||
184 | 254 | 262 | ||
185 | === added file 'quickstart/tests/cli/helpers.py' | |||
186 | --- quickstart/tests/cli/helpers.py 1970-01-01 00:00:00 +0000 | |||
187 | +++ quickstart/tests/cli/helpers.py 2013-12-19 17:41:55 +0000 | |||
188 | @@ -0,0 +1,31 @@ | |||
189 | 1 | # This file is part of the Juju Quickstart Plugin, which lets users set up a | ||
190 | 2 | # Juju environment in very few steps (https://launchpad.net/juju-quickstart). | ||
191 | 3 | # Copyright (C) 2013 Canonical Ltd. | ||
192 | 4 | # | ||
193 | 5 | # This program is free software: you can redistribute it and/or modify it under | ||
194 | 6 | # the terms of the GNU Affero General Public License version 3, as published by | ||
195 | 7 | # the Free Software Foundation. | ||
196 | 8 | # | ||
197 | 9 | # This program is distributed in the hope that it will be useful, but WITHOUT | ||
198 | 10 | # ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | ||
199 | 11 | # SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
200 | 12 | # Affero General Public License for more details. | ||
201 | 13 | # | ||
202 | 14 | # You should have received a copy of the GNU Affero General Public License | ||
203 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
204 | 16 | |||
205 | 17 | """Test helpers for the Juju Quickstart CLI infrastructure.""" | ||
206 | 18 | |||
207 | 19 | from __future__ import unicode_literals | ||
208 | 20 | |||
209 | 21 | from quickstart.cli import ui | ||
210 | 22 | |||
211 | 23 | |||
212 | 24 | class CliAppTestsMixin(object): | ||
213 | 25 | """Helper methods to test Quickstart CLI applications.""" | ||
214 | 26 | |||
215 | 27 | def get_on_exit_return_value(self, loop): | ||
216 | 28 | """Return the value returned by the application when the user quits.""" | ||
217 | 29 | with self.assertRaises(ui.AppExit) as context_manager: | ||
218 | 30 | loop.unhandled_input(ui.EXIT_KEY) | ||
219 | 31 | return context_manager.exception.return_value | ||
220 | 0 | 32 | ||
221 | === modified file 'quickstart/tests/cli/test_base.py' | |||
222 | --- quickstart/tests/cli/test_base.py 2013-12-19 09:12:37 +0000 | |||
223 | +++ quickstart/tests/cli/test_base.py 2013-12-19 17:41:55 +0000 | |||
224 | @@ -23,6 +23,7 @@ | |||
225 | 23 | import urwid | 23 | import urwid |
226 | 24 | 24 | ||
227 | 25 | from quickstart.cli import base | 25 | from quickstart.cli import base |
228 | 26 | from quickstart.tests.cli import helpers as cli_helpers | ||
229 | 26 | 27 | ||
230 | 27 | 28 | ||
231 | 28 | class TestMainLoop(unittest.TestCase): | 29 | class TestMainLoop(unittest.TestCase): |
232 | @@ -57,7 +58,7 @@ | |||
233 | 57 | self.assertEqual(1, sum(times_called)) | 58 | self.assertEqual(1, sum(times_called)) |
234 | 58 | 59 | ||
235 | 59 | 60 | ||
237 | 60 | class TestSetupUrwidApp(unittest.TestCase): | 61 | class TestSetupUrwidApp(cli_helpers.CliAppTestsMixin, unittest.TestCase): |
238 | 61 | 62 | ||
239 | 62 | def setUp(self): | 63 | def setUp(self): |
240 | 63 | # Set up the base Urwid application. | 64 | # Set up the base Urwid application. |
241 | @@ -164,3 +165,21 @@ | |||
242 | 164 | message_widget = self.get_message_widget(self.loop) | 165 | message_widget = self.get_message_widget(self.loop) |
243 | 165 | message_widget.set_text('42') | 166 | message_widget.set_text('42') |
244 | 166 | self.assertEqual('42', self.app.get_message()) | 167 | self.assertEqual('42', self.app.get_message()) |
245 | 168 | |||
246 | 169 | def test_default_unhandled_input(self): | ||
247 | 170 | # The default unhandled_input function is configured so that a | ||
248 | 171 | # quickstart.cli.ui.AppExit exception is raised. The exception's | ||
249 | 172 | # return value is None by default. | ||
250 | 173 | return_value = self.get_on_exit_return_value(self.loop) | ||
251 | 174 | self.assertIsNone(return_value) | ||
252 | 175 | |||
253 | 176 | def test_set_return_value_on_exit(self): | ||
254 | 177 | # It is possible to change the value returned by the AppExit exception | ||
255 | 178 | # when the user quits the application using the exit shortcut. | ||
256 | 179 | self.app.set_return_value_on_exit(42) | ||
257 | 180 | return_value = self.get_on_exit_return_value(self.loop) | ||
258 | 181 | self.assertEqual(42, return_value) | ||
259 | 182 | # The value can be changed multiple times. | ||
260 | 183 | self.app.set_return_value_on_exit([47, None]) | ||
261 | 184 | return_value = self.get_on_exit_return_value(self.loop) | ||
262 | 185 | self.assertEqual([47, None], return_value) | ||
263 | 167 | 186 | ||
264 | === modified file 'quickstart/tests/cli/test_views.py' | |||
265 | --- quickstart/tests/cli/test_views.py 2013-12-19 09:30:08 +0000 | |||
266 | +++ quickstart/tests/cli/test_views.py 2013-12-19 17:41:55 +0000 | |||
267 | @@ -31,6 +31,7 @@ | |||
268 | 31 | ) | 31 | ) |
269 | 32 | from quickstart.models import envs | 32 | from quickstart.models import envs |
270 | 33 | from quickstart.tests import helpers | 33 | from quickstart.tests import helpers |
271 | 34 | from quickstart.tests.cli import helpers as cli_helpers | ||
272 | 34 | 35 | ||
273 | 35 | 36 | ||
274 | 36 | class TestShow(unittest.TestCase): | 37 | class TestShow(unittest.TestCase): |
275 | @@ -70,17 +71,6 @@ | |||
276 | 70 | return_value = views.show(view) | 71 | return_value = views.show(view) |
277 | 71 | self.assertEqual('bad wolf', return_value) | 72 | self.assertEqual('bad wolf', return_value) |
278 | 72 | 73 | ||
279 | 73 | def test_unhandled_input(self): | ||
280 | 74 | # The unhandled_input callable is properly set up and registered to | ||
281 | 75 | # the main loop. | ||
282 | 76 | view = mock.Mock(return_value=42) | ||
283 | 77 | with self.patch_setup_urwid_app() as (mock_loop, mock_app): | ||
284 | 78 | views.show(view) | ||
285 | 79 | unhandled_input = mock_loop.set_unhandled_input.call_args[0][0] | ||
286 | 80 | with self.assertRaises(ui.AppExit) as context_manager: | ||
287 | 81 | unhandled_input(ui.EXIT_KEY) | ||
288 | 82 | self.assertEqual(42, context_manager.exception.return_value) | ||
289 | 83 | |||
290 | 84 | def test_view_arguments(self): | 74 | def test_view_arguments(self): |
291 | 85 | # The view is invoked passing the app and all the optional show | 75 | # The view is invoked passing the app and all the optional show |
292 | 86 | # function arguments. | 76 | # function arguments. |
293 | @@ -90,7 +80,7 @@ | |||
294 | 90 | view.assert_called_once_with(mock_app, 'arg1', 'arg2') | 80 | view.assert_called_once_with(mock_app, 'arg1', 'arg2') |
295 | 91 | 81 | ||
296 | 92 | 82 | ||
298 | 93 | class EnvViewTestsMixin(object): | 83 | class EnvViewTestsMixin(cli_helpers.CliAppTestsMixin): |
299 | 94 | """Shared helpers for testing environment views.""" | 84 | """Shared helpers for testing environment views.""" |
300 | 95 | 85 | ||
301 | 96 | env_type_db = envs.get_env_type_db() | 86 | env_type_db = envs.get_env_type_db() |
302 | @@ -145,12 +135,13 @@ | |||
303 | 145 | 135 | ||
304 | 146 | class TestEnvIndex(EnvViewTestsMixin, unittest.TestCase): | 136 | class TestEnvIndex(EnvViewTestsMixin, unittest.TestCase): |
305 | 147 | 137 | ||
309 | 148 | def test_view_return_value(self): | 138 | def test_view_default_return_value_on_exit(self): |
310 | 149 | # The view returns a tuple including a copy of the given env_db and | 139 | # The view configures the app so that the return value on user exit is |
311 | 150 | # None, the latter meaning no environment has been selected. | 140 | # a tuple including a copy of the given env_db and None, the latter |
312 | 141 | # meaning no environment has been selected. | ||
313 | 151 | env_db = helpers.make_env_db() | 142 | env_db = helpers.make_env_db() |
316 | 152 | new_env_db, env_data = views.env_index( | 143 | views.env_index(self.app, self.env_type_db, env_db, self.save_callable) |
317 | 153 | self.app, self.env_type_db, env_db, self.save_callable) | 144 | new_env_db, env_data = self.get_on_exit_return_value(self.loop) |
318 | 154 | self.assertEqual(env_db, new_env_db) | 145 | self.assertEqual(env_db, new_env_db) |
319 | 155 | self.assertIsNot(env_db, new_env_db) | 146 | self.assertIsNot(env_db, new_env_db) |
320 | 156 | self.assertIsNone(env_data) | 147 | self.assertIsNone(env_data) |
321 | @@ -249,10 +240,12 @@ | |||
322 | 249 | self.app, self.env_type_db, self.env_db, self.save_callable, | 240 | self.app, self.env_type_db, self.env_db, self.save_callable, |
323 | 250 | self.env_data) | 241 | self.env_data) |
324 | 251 | 242 | ||
329 | 252 | def test_view_return_value(self): | 243 | def test_view_default_return_value_on_exit(self): |
330 | 253 | # The view returns a tuple including a copy of the given env_db and | 244 | # The view configures the app so that the return value on user exit is |
331 | 254 | # None, the latter meaning no environment has been selected (for now). | 245 | # a tuple including a copy of the given env_db and None, the latter |
332 | 255 | new_env_db, env_data = self.call_view() | 246 | # meaning no environment has been selected (for now). |
333 | 247 | self.call_view() | ||
334 | 248 | new_env_db, env_data = self.get_on_exit_return_value(self.loop) | ||
335 | 256 | self.assertEqual(self.env_db, new_env_db) | 249 | self.assertEqual(self.env_db, new_env_db) |
336 | 257 | self.assertIsNot(self.env_db, new_env_db) | 250 | self.assertIsNot(self.env_db, new_env_db) |
337 | 258 | self.assertIsNone(env_data) | 251 | self.assertIsNone(env_data) |
Reviewers: mp+199640_ code.launchpad. net,
Message:
Please take a look.
Description:
Improve views input handling.
Add a new set_return_ value_on_ exit API that
views can call to set the value encapsulated
in the AppExit exception raised when the user
quits the application with ^X.
Tests: `make check`
QA: start the demo app app-demo. py).
(`make` and `./cli-
Try exiting with ^X: you should see the
"no environment selected" message.
Restart and exit selecting an environment:
you should see a message indicating that
environment has been selected.
Restart and change the default environment,
then exit: you should see the new env_db
printed and the new default environment.
https:/ /code.launchpad .net/~frankban/ juju-quickstart /improve- input-handling/ +merge/ 199640
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/43600047/
Affected files (+110, -41 lines): cli/base. py cli/views. py tests/cli/ helpers. py tests/cli/ test_base. py tests/cli/ test_views. py
A [revision details]
M cli-app-demo.py
M quickstart/
M quickstart/
A quickstart/
M quickstart/
M quickstart/