##// END OF EJS Templates
adjusted formating in test_shortcuts.py
Abdullah Habib -
Show More
@@ -1,485 +1,485 b''
1 1 import pytest
2 2 from IPython.terminal.shortcuts.auto_suggest import (
3 3 accept,
4 4 accept_or_jump_to_end,
5 5 accept_token,
6 6 accept_character,
7 7 accept_word,
8 8 accept_and_keep_cursor,
9 9 discard,
10 10 NavigableAutoSuggestFromHistory,
11 11 swap_autosuggestion_up,
12 12 swap_autosuggestion_down,
13 13 )
14 14 from IPython.terminal.shortcuts.auto_match import skip_over
15 from IPython.terminal.shortcuts import create_ipython_shortcuts,reset_search_buffer
15 from IPython.terminal.shortcuts import create_ipython_shortcuts, reset_search_buffer
16 16
17 17 from prompt_toolkit.history import InMemoryHistory
18 18 from prompt_toolkit.buffer import Buffer
19 19 from prompt_toolkit.document import Document
20 20 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
21 21 from prompt_toolkit.enums import DEFAULT_BUFFER
22 22
23 23 from unittest.mock import patch, Mock
24 24
25 25
26 26 def test_deprected():
27 27 import IPython.terminal.shortcuts.auto_suggest as iptsa
28 28
29 29 with pytest.warns(DeprecationWarning, match=r"8\.12.+accept_or_jump_to_end"):
30 30 iptsa.accept_in_vi_insert_mode
31 31
32 32
33 33 def make_event(text, cursor, suggestion):
34 34 event = Mock()
35 35 event.current_buffer = Mock()
36 36 event.current_buffer.suggestion = Mock()
37 37 event.current_buffer.text = text
38 38 event.current_buffer.cursor_position = cursor
39 39 event.current_buffer.suggestion.text = suggestion
40 40 event.current_buffer.document = Document(text=text, cursor_position=cursor)
41 41 return event
42 42
43 43
44 44 @pytest.mark.parametrize(
45 45 "text, suggestion, expected",
46 46 [
47 47 ("", "def out(tag: str, n=50):", "def out(tag: str, n=50):"),
48 48 ("def ", "out(tag: str, n=50):", "out(tag: str, n=50):"),
49 49 ],
50 50 )
51 51 def test_accept(text, suggestion, expected):
52 52 event = make_event(text, len(text), suggestion)
53 53 buffer = event.current_buffer
54 54 buffer.insert_text = Mock()
55 55 accept(event)
56 56 assert buffer.insert_text.called
57 57 assert buffer.insert_text.call_args[0] == (expected,)
58 58
59 59
60 60 @pytest.mark.parametrize(
61 61 "text, suggestion",
62 62 [
63 63 ("", "def out(tag: str, n=50):"),
64 64 ("def ", "out(tag: str, n=50):"),
65 65 ],
66 66 )
67 67 def test_discard(text, suggestion):
68 68 event = make_event(text, len(text), suggestion)
69 69 buffer = event.current_buffer
70 70 buffer.insert_text = Mock()
71 71 discard(event)
72 72 assert not buffer.insert_text.called
73 73 assert buffer.suggestion is None
74 74
75 75
76 76 @pytest.mark.parametrize(
77 77 "text, cursor, suggestion, called",
78 78 [
79 79 ("123456", 6, "123456789", True),
80 80 ("123456", 3, "123456789", False),
81 81 ("123456 \n789", 6, "123456789", True),
82 82 ],
83 83 )
84 84 def test_autosuggest_at_EOL(text, cursor, suggestion, called):
85 85 """
86 86 test that autosuggest is only applied at end of line.
87 87 """
88 88
89 89 event = make_event(text, cursor, suggestion)
90 90 event.current_buffer.insert_text = Mock()
91 91 accept_or_jump_to_end(event)
92 92 if called:
93 93 event.current_buffer.insert_text.assert_called()
94 94 else:
95 95 event.current_buffer.insert_text.assert_not_called()
96 96 # event.current_buffer.document.get_end_of_line_position.assert_called()
97 97
98 98
99 99 @pytest.mark.parametrize(
100 100 "text, suggestion, expected",
101 101 [
102 102 ("", "def out(tag: str, n=50):", "def "),
103 103 ("d", "ef out(tag: str, n=50):", "ef "),
104 104 ("de ", "f out(tag: str, n=50):", "f "),
105 105 ("def", " out(tag: str, n=50):", " "),
106 106 ("def ", "out(tag: str, n=50):", "out("),
107 107 ("def o", "ut(tag: str, n=50):", "ut("),
108 108 ("def ou", "t(tag: str, n=50):", "t("),
109 109 ("def out", "(tag: str, n=50):", "("),
110 110 ("def out(", "tag: str, n=50):", "tag: "),
111 111 ("def out(t", "ag: str, n=50):", "ag: "),
112 112 ("def out(ta", "g: str, n=50):", "g: "),
113 113 ("def out(tag", ": str, n=50):", ": "),
114 114 ("def out(tag:", " str, n=50):", " "),
115 115 ("def out(tag: ", "str, n=50):", "str, "),
116 116 ("def out(tag: s", "tr, n=50):", "tr, "),
117 117 ("def out(tag: st", "r, n=50):", "r, "),
118 118 ("def out(tag: str", ", n=50):", ", n"),
119 119 ("def out(tag: str,", " n=50):", " n"),
120 120 ("def out(tag: str, ", "n=50):", "n="),
121 121 ("def out(tag: str, n", "=50):", "="),
122 122 ("def out(tag: str, n=", "50):", "50)"),
123 123 ("def out(tag: str, n=5", "0):", "0)"),
124 124 ("def out(tag: str, n=50", "):", "):"),
125 125 ("def out(tag: str, n=50)", ":", ":"),
126 126 ],
127 127 )
128 128 def test_autosuggest_token(text, suggestion, expected):
129 129 event = make_event(text, len(text), suggestion)
130 130 event.current_buffer.insert_text = Mock()
131 131 accept_token(event)
132 132 assert event.current_buffer.insert_text.called
133 133 assert event.current_buffer.insert_text.call_args[0] == (expected,)
134 134
135 135
136 136 @pytest.mark.parametrize(
137 137 "text, suggestion, expected",
138 138 [
139 139 ("", "def out(tag: str, n=50):", "d"),
140 140 ("d", "ef out(tag: str, n=50):", "e"),
141 141 ("de ", "f out(tag: str, n=50):", "f"),
142 142 ("def", " out(tag: str, n=50):", " "),
143 143 ],
144 144 )
145 145 def test_accept_character(text, suggestion, expected):
146 146 event = make_event(text, len(text), suggestion)
147 147 event.current_buffer.insert_text = Mock()
148 148 accept_character(event)
149 149 assert event.current_buffer.insert_text.called
150 150 assert event.current_buffer.insert_text.call_args[0] == (expected,)
151 151
152 152
153 153 @pytest.mark.parametrize(
154 154 "text, suggestion, expected",
155 155 [
156 156 ("", "def out(tag: str, n=50):", "def "),
157 157 ("d", "ef out(tag: str, n=50):", "ef "),
158 158 ("de", "f out(tag: str, n=50):", "f "),
159 159 ("def", " out(tag: str, n=50):", " "),
160 160 # (this is why we also have accept_token)
161 161 ("def ", "out(tag: str, n=50):", "out(tag: "),
162 162 ],
163 163 )
164 164 def test_accept_word(text, suggestion, expected):
165 165 event = make_event(text, len(text), suggestion)
166 166 event.current_buffer.insert_text = Mock()
167 167 accept_word(event)
168 168 assert event.current_buffer.insert_text.called
169 169 assert event.current_buffer.insert_text.call_args[0] == (expected,)
170 170
171 171
172 172 @pytest.mark.parametrize(
173 173 "text, suggestion, expected, cursor",
174 174 [
175 175 ("", "def out(tag: str, n=50):", "def out(tag: str, n=50):", 0),
176 176 ("def ", "out(tag: str, n=50):", "out(tag: str, n=50):", 4),
177 177 ],
178 178 )
179 179 def test_accept_and_keep_cursor(text, suggestion, expected, cursor):
180 180 event = make_event(text, cursor, suggestion)
181 181 buffer = event.current_buffer
182 182 buffer.insert_text = Mock()
183 183 accept_and_keep_cursor(event)
184 184 assert buffer.insert_text.called
185 185 assert buffer.insert_text.call_args[0] == (expected,)
186 186 assert buffer.cursor_position == cursor
187 187
188 188
189 189 def test_autosuggest_token_empty():
190 190 full = "def out(tag: str, n=50):"
191 191 event = make_event(full, len(full), "")
192 192 event.current_buffer.insert_text = Mock()
193 193
194 194 with patch(
195 195 "prompt_toolkit.key_binding.bindings.named_commands.forward_word"
196 196 ) as forward_word:
197 197 accept_token(event)
198 198 assert not event.current_buffer.insert_text.called
199 199 assert forward_word.called
200 200
201 201
202 202 def test_reset_search_buffer():
203 203 event_with_text = Mock()
204 204 event_with_text.current_buffer.document.text = "some text"
205 205 event_with_text.current_buffer.reset = Mock()
206 206
207 207 event_empty = Mock()
208 208 event_empty.current_buffer.document.text = ""
209 209 event_empty.app.layout.focus = Mock()
210 210
211 211 reset_search_buffer(event_with_text)
212 212 event_with_text.current_buffer.reset.assert_called_once()
213 213
214 214 reset_search_buffer(event_empty)
215 215 event_empty.app.layout.focus.assert_called_once_with(DEFAULT_BUFFER)
216 216
217 217
218 218 def test_other_providers():
219 219 """Ensure that swapping autosuggestions does not break with other providers"""
220 220 provider = AutoSuggestFromHistory()
221 221 ip = get_ipython()
222 222 ip.auto_suggest = provider
223 223 event = Mock()
224 224 event.current_buffer = Buffer()
225 225 assert swap_autosuggestion_up(event) is None
226 226 assert swap_autosuggestion_down(event) is None
227 227
228 228
229 229 async def test_navigable_provider():
230 230 provider = NavigableAutoSuggestFromHistory()
231 231 history = InMemoryHistory(history_strings=["very_a", "very", "very_b", "very_c"])
232 232 buffer = Buffer(history=history)
233 233 ip = get_ipython()
234 234 ip.auto_suggest = provider
235 235
236 236 async for _ in history.load():
237 237 pass
238 238
239 239 buffer.cursor_position = 5
240 240 buffer.text = "very"
241 241
242 242 up = swap_autosuggestion_up
243 243 down = swap_autosuggestion_down
244 244
245 245 event = Mock()
246 246 event.current_buffer = buffer
247 247
248 248 def get_suggestion():
249 249 suggestion = provider.get_suggestion(buffer, buffer.document)
250 250 buffer.suggestion = suggestion
251 251 return suggestion
252 252
253 253 assert get_suggestion().text == "_c"
254 254
255 255 # should go up
256 256 up(event)
257 257 assert get_suggestion().text == "_b"
258 258
259 259 # should skip over 'very' which is identical to buffer content
260 260 up(event)
261 261 assert get_suggestion().text == "_a"
262 262
263 263 # should cycle back to beginning
264 264 up(event)
265 265 assert get_suggestion().text == "_c"
266 266
267 267 # should cycle back through end boundary
268 268 down(event)
269 269 assert get_suggestion().text == "_a"
270 270
271 271 down(event)
272 272 assert get_suggestion().text == "_b"
273 273
274 274 down(event)
275 275 assert get_suggestion().text == "_c"
276 276
277 277 down(event)
278 278 assert get_suggestion().text == "_a"
279 279
280 280
281 281 async def test_navigable_provider_multiline_entries():
282 282 provider = NavigableAutoSuggestFromHistory()
283 283 history = InMemoryHistory(history_strings=["very_a\nvery_b", "very_c"])
284 284 buffer = Buffer(history=history)
285 285 ip = get_ipython()
286 286 ip.auto_suggest = provider
287 287
288 288 async for _ in history.load():
289 289 pass
290 290
291 291 buffer.cursor_position = 5
292 292 buffer.text = "very"
293 293 up = swap_autosuggestion_up
294 294 down = swap_autosuggestion_down
295 295
296 296 event = Mock()
297 297 event.current_buffer = buffer
298 298
299 299 def get_suggestion():
300 300 suggestion = provider.get_suggestion(buffer, buffer.document)
301 301 buffer.suggestion = suggestion
302 302 return suggestion
303 303
304 304 assert get_suggestion().text == "_c"
305 305
306 306 up(event)
307 307 assert get_suggestion().text == "_b"
308 308
309 309 up(event)
310 310 assert get_suggestion().text == "_a"
311 311
312 312 down(event)
313 313 assert get_suggestion().text == "_b"
314 314
315 315 down(event)
316 316 assert get_suggestion().text == "_c"
317 317
318 318
319 319 def create_session_mock():
320 320 session = Mock()
321 321 session.default_buffer = Buffer()
322 322 return session
323 323
324 324
325 325 def test_navigable_provider_connection():
326 326 provider = NavigableAutoSuggestFromHistory()
327 327 provider.skip_lines = 1
328 328
329 329 session_1 = create_session_mock()
330 330 provider.connect(session_1)
331 331
332 332 assert provider.skip_lines == 1
333 333 session_1.default_buffer.on_text_insert.fire()
334 334 assert provider.skip_lines == 0
335 335
336 336 session_2 = create_session_mock()
337 337 provider.connect(session_2)
338 338 provider.skip_lines = 2
339 339
340 340 assert provider.skip_lines == 2
341 341 session_2.default_buffer.on_text_insert.fire()
342 342 assert provider.skip_lines == 0
343 343
344 344 provider.skip_lines = 3
345 345 provider.disconnect()
346 346 session_1.default_buffer.on_text_insert.fire()
347 347 session_2.default_buffer.on_text_insert.fire()
348 348 assert provider.skip_lines == 3
349 349
350 350
351 351 @pytest.fixture
352 352 def ipython_with_prompt():
353 353 ip = get_ipython()
354 354 ip.pt_app = Mock()
355 355 ip.pt_app.key_bindings = create_ipython_shortcuts(ip)
356 356 try:
357 357 yield ip
358 358 finally:
359 359 ip.pt_app = None
360 360
361 361
362 362 def find_bindings_by_command(command):
363 363 ip = get_ipython()
364 364 return [
365 365 binding
366 366 for binding in ip.pt_app.key_bindings.bindings
367 367 if binding.handler == command
368 368 ]
369 369
370 370
371 371 def test_modify_unique_shortcut(ipython_with_prompt):
372 372 original = find_bindings_by_command(accept_token)
373 373 assert len(original) == 1
374 374
375 375 ipython_with_prompt.shortcuts = [
376 376 {"command": "IPython:auto_suggest.accept_token", "new_keys": ["a", "b", "c"]}
377 377 ]
378 378 matched = find_bindings_by_command(accept_token)
379 379 assert len(matched) == 1
380 380 assert list(matched[0].keys) == ["a", "b", "c"]
381 381 assert list(matched[0].keys) != list(original[0].keys)
382 382 assert matched[0].filter == original[0].filter
383 383
384 384 ipython_with_prompt.shortcuts = [
385 385 {"command": "IPython:auto_suggest.accept_token", "new_filter": "always"}
386 386 ]
387 387 matched = find_bindings_by_command(accept_token)
388 388 assert len(matched) == 1
389 389 assert list(matched[0].keys) != ["a", "b", "c"]
390 390 assert list(matched[0].keys) == list(original[0].keys)
391 391 assert matched[0].filter != original[0].filter
392 392
393 393
394 394 def test_disable_shortcut(ipython_with_prompt):
395 395 matched = find_bindings_by_command(accept_token)
396 396 assert len(matched) == 1
397 397
398 398 ipython_with_prompt.shortcuts = [
399 399 {"command": "IPython:auto_suggest.accept_token", "new_keys": []}
400 400 ]
401 401 matched = find_bindings_by_command(accept_token)
402 402 assert len(matched) == 0
403 403
404 404 ipython_with_prompt.shortcuts = []
405 405 matched = find_bindings_by_command(accept_token)
406 406 assert len(matched) == 1
407 407
408 408
409 409 def test_modify_shortcut_with_filters(ipython_with_prompt):
410 410 matched = find_bindings_by_command(skip_over)
411 411 matched_keys = {m.keys[0] for m in matched}
412 412 assert matched_keys == {")", "]", "}", "'", '"'}
413 413
414 414 with pytest.raises(ValueError, match="Multiple shortcuts matching"):
415 415 ipython_with_prompt.shortcuts = [
416 416 {"command": "IPython:auto_match.skip_over", "new_keys": ["x"]}
417 417 ]
418 418
419 419 ipython_with_prompt.shortcuts = [
420 420 {
421 421 "command": "IPython:auto_match.skip_over",
422 422 "new_keys": ["x"],
423 423 "match_filter": "focused_insert & auto_match & followed_by_single_quote",
424 424 }
425 425 ]
426 426 matched = find_bindings_by_command(skip_over)
427 427 matched_keys = {m.keys[0] for m in matched}
428 428 assert matched_keys == {")", "]", "}", "x", '"'}
429 429
430 430
431 431 def example_command():
432 432 pass
433 433
434 434
435 435 def test_add_shortcut_for_new_command(ipython_with_prompt):
436 436 matched = find_bindings_by_command(example_command)
437 437 assert len(matched) == 0
438 438
439 439 with pytest.raises(ValueError, match="example_command is not a known"):
440 440 ipython_with_prompt.shortcuts = [
441 441 {"command": "example_command", "new_keys": ["x"]}
442 442 ]
443 443 matched = find_bindings_by_command(example_command)
444 444 assert len(matched) == 0
445 445
446 446
447 447 def test_modify_shortcut_failure(ipython_with_prompt):
448 448 with pytest.raises(ValueError, match="No shortcuts matching"):
449 449 ipython_with_prompt.shortcuts = [
450 450 {
451 451 "command": "IPython:auto_match.skip_over",
452 452 "match_keys": ["x"],
453 453 "new_keys": ["y"],
454 454 }
455 455 ]
456 456
457 457
458 458 def test_add_shortcut_for_existing_command(ipython_with_prompt):
459 459 matched = find_bindings_by_command(skip_over)
460 460 assert len(matched) == 5
461 461
462 462 with pytest.raises(ValueError, match="Cannot add a shortcut without keys"):
463 463 ipython_with_prompt.shortcuts = [
464 464 {"command": "IPython:auto_match.skip_over", "new_keys": [], "create": True}
465 465 ]
466 466
467 467 ipython_with_prompt.shortcuts = [
468 468 {"command": "IPython:auto_match.skip_over", "new_keys": ["x"], "create": True}
469 469 ]
470 470 matched = find_bindings_by_command(skip_over)
471 471 assert len(matched) == 6
472 472
473 473 ipython_with_prompt.shortcuts = []
474 474 matched = find_bindings_by_command(skip_over)
475 475 assert len(matched) == 5
476 476
477 477
478 478 def test_setting_shortcuts_before_pt_app_init():
479 479 ipython = get_ipython()
480 480 assert ipython.pt_app is None
481 481 shortcuts = [
482 482 {"command": "IPython:auto_match.skip_over", "new_keys": ["x"], "create": True}
483 483 ]
484 484 ipython.shortcuts = shortcuts
485 485 assert ipython.shortcuts == shortcuts
General Comments 0
You need to be logged in to leave comments. Login now