##// END OF EJS Templates
Increase coverage for completer tests
krassowski -
Show More
@@ -1,1693 +1,1702
1 1 # encoding: utf-8
2 2 """Tests for the IPython tab-completion machinery."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import os
8 8 import pytest
9 9 import sys
10 10 import textwrap
11 11 import unittest
12 12
13 13 from contextlib import contextmanager
14 14
15 15 from traitlets.config.loader import Config
16 16 from IPython import get_ipython
17 17 from IPython.core import completer
18 18 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
19 19 from IPython.utils.generics import complete_object
20 20 from IPython.testing import decorators as dec
21 21
22 22 from IPython.core.completer import (
23 23 Completion,
24 24 provisionalcompleter,
25 25 match_dict_keys,
26 26 _deduplicate_completions,
27 27 _match_number_in_dict_key_prefix,
28 28 completion_matcher,
29 29 SimpleCompletion,
30 30 CompletionContext,
31 31 )
32 32
33 33 # -----------------------------------------------------------------------------
34 34 # Test functions
35 35 # -----------------------------------------------------------------------------
36 36
37 37 def recompute_unicode_ranges():
38 38 """
39 39 utility to recompute the largest unicode range without any characters
40 40
41 41 use to recompute the gap in the global _UNICODE_RANGES of completer.py
42 42 """
43 43 import itertools
44 44 import unicodedata
45 45 valid = []
46 46 for c in range(0,0x10FFFF + 1):
47 47 try:
48 48 unicodedata.name(chr(c))
49 49 except ValueError:
50 50 continue
51 51 valid.append(c)
52 52
53 53 def ranges(i):
54 54 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
55 55 b = list(b)
56 56 yield b[0][1], b[-1][1]
57 57
58 58 rg = list(ranges(valid))
59 59 lens = []
60 60 gap_lens = []
61 61 pstart, pstop = 0,0
62 62 for start, stop in rg:
63 63 lens.append(stop-start)
64 64 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
65 65 pstart, pstop = start, stop
66 66
67 67 return sorted(gap_lens)[-1]
68 68
69 69
70 70
71 71 def test_unicode_range():
72 72 """
73 73 Test that the ranges we test for unicode names give the same number of
74 74 results than testing the full length.
75 75 """
76 76 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
77 77
78 78 expected_list = _unicode_name_compute([(0, 0x110000)])
79 79 test = _unicode_name_compute(_UNICODE_RANGES)
80 80 len_exp = len(expected_list)
81 81 len_test = len(test)
82 82
83 83 # do not inline the len() or on error pytest will try to print the 130 000 +
84 84 # elements.
85 85 message = None
86 86 if len_exp != len_test or len_exp > 131808:
87 87 size, start, stop, prct = recompute_unicode_ranges()
88 88 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
89 89 likely due to a new release of Python. We've find that the biggest gap
90 90 in unicode characters has reduces in size to be {size} characters
91 91 ({prct}), from {start}, to {stop}. In completer.py likely update to
92 92
93 93 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
94 94
95 95 And update the assertion below to use
96 96
97 97 len_exp <= {len_exp}
98 98 """
99 99 assert len_exp == len_test, message
100 100
101 101 # fail if new unicode symbols have been added.
102 102 assert len_exp <= 138552, message
103 103
104 104
105 105 @contextmanager
106 106 def greedy_completion():
107 107 ip = get_ipython()
108 108 greedy_original = ip.Completer.greedy
109 109 try:
110 110 ip.Completer.greedy = True
111 111 yield
112 112 finally:
113 113 ip.Completer.greedy = greedy_original
114 114
115 115
116 116 @contextmanager
117 117 def evaluation_policy(evaluation: str):
118 118 ip = get_ipython()
119 119 evaluation_original = ip.Completer.evaluation
120 120 try:
121 121 ip.Completer.evaluation = evaluation
122 122 yield
123 123 finally:
124 124 ip.Completer.evaluation = evaluation_original
125 125
126 126
127 127 @contextmanager
128 128 def custom_matchers(matchers):
129 129 ip = get_ipython()
130 130 try:
131 131 ip.Completer.custom_matchers.extend(matchers)
132 132 yield
133 133 finally:
134 134 ip.Completer.custom_matchers.clear()
135 135
136 136
137 137 def test_protect_filename():
138 138 if sys.platform == "win32":
139 139 pairs = [
140 140 ("abc", "abc"),
141 141 (" abc", '" abc"'),
142 142 ("a bc", '"a bc"'),
143 143 ("a bc", '"a bc"'),
144 144 (" bc", '" bc"'),
145 145 ]
146 146 else:
147 147 pairs = [
148 148 ("abc", "abc"),
149 149 (" abc", r"\ abc"),
150 150 ("a bc", r"a\ bc"),
151 151 ("a bc", r"a\ \ bc"),
152 152 (" bc", r"\ \ bc"),
153 153 # On posix, we also protect parens and other special characters.
154 154 ("a(bc", r"a\(bc"),
155 155 ("a)bc", r"a\)bc"),
156 156 ("a( )bc", r"a\(\ \)bc"),
157 157 ("a[1]bc", r"a\[1\]bc"),
158 158 ("a{1}bc", r"a\{1\}bc"),
159 159 ("a#bc", r"a\#bc"),
160 160 ("a?bc", r"a\?bc"),
161 161 ("a=bc", r"a\=bc"),
162 162 ("a\\bc", r"a\\bc"),
163 163 ("a|bc", r"a\|bc"),
164 164 ("a;bc", r"a\;bc"),
165 165 ("a:bc", r"a\:bc"),
166 166 ("a'bc", r"a\'bc"),
167 167 ("a*bc", r"a\*bc"),
168 168 ('a"bc', r"a\"bc"),
169 169 ("a^bc", r"a\^bc"),
170 170 ("a&bc", r"a\&bc"),
171 171 ]
172 172 # run the actual tests
173 173 for s1, s2 in pairs:
174 174 s1p = completer.protect_filename(s1)
175 175 assert s1p == s2
176 176
177 177
178 178 def check_line_split(splitter, test_specs):
179 179 for part1, part2, split in test_specs:
180 180 cursor_pos = len(part1)
181 181 line = part1 + part2
182 182 out = splitter.split_line(line, cursor_pos)
183 183 assert out == split
184 184
185 185 def test_line_split():
186 186 """Basic line splitter test with default specs."""
187 187 sp = completer.CompletionSplitter()
188 188 # The format of the test specs is: part1, part2, expected answer. Parts 1
189 189 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
190 190 # was at the end of part1. So an empty part2 represents someone hitting
191 191 # tab at the end of the line, the most common case.
192 192 t = [
193 193 ("run some/scrip", "", "some/scrip"),
194 194 ("run scripts/er", "ror.py foo", "scripts/er"),
195 195 ("echo $HOM", "", "HOM"),
196 196 ("print sys.pa", "", "sys.pa"),
197 197 ("print(sys.pa", "", "sys.pa"),
198 198 ("execfile('scripts/er", "", "scripts/er"),
199 199 ("a[x.", "", "x."),
200 200 ("a[x.", "y", "x."),
201 201 ('cd "some_file/', "", "some_file/"),
202 202 ]
203 203 check_line_split(sp, t)
204 204 # Ensure splitting works OK with unicode by re-running the tests with
205 205 # all inputs turned into unicode
206 206 check_line_split(sp, [map(str, p) for p in t])
207 207
208 208
209 209 class NamedInstanceClass:
210 210 instances = {}
211 211
212 212 def __init__(self, name):
213 213 self.instances[name] = self
214 214
215 215 @classmethod
216 216 def _ipython_key_completions_(cls):
217 217 return cls.instances.keys()
218 218
219 219
220 220 class KeyCompletable:
221 221 def __init__(self, things=()):
222 222 self.things = things
223 223
224 224 def _ipython_key_completions_(self):
225 225 return list(self.things)
226 226
227 227
228 228 class TestCompleter(unittest.TestCase):
229 229 def setUp(self):
230 230 """
231 231 We want to silence all PendingDeprecationWarning when testing the completer
232 232 """
233 233 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
234 234 self._assertwarns.__enter__()
235 235
236 236 def tearDown(self):
237 237 try:
238 238 self._assertwarns.__exit__(None, None, None)
239 239 except AssertionError:
240 240 pass
241 241
242 242 def test_custom_completion_error(self):
243 243 """Test that errors from custom attribute completers are silenced."""
244 244 ip = get_ipython()
245 245
246 246 class A:
247 247 pass
248 248
249 249 ip.user_ns["x"] = A()
250 250
251 251 @complete_object.register(A)
252 252 def complete_A(a, existing_completions):
253 253 raise TypeError("this should be silenced")
254 254
255 255 ip.complete("x.")
256 256
257 257 def test_custom_completion_ordering(self):
258 258 """Test that errors from custom attribute completers are silenced."""
259 259 ip = get_ipython()
260 260
261 261 _, matches = ip.complete('in')
262 262 assert matches.index('input') < matches.index('int')
263 263
264 264 def complete_example(a):
265 265 return ['example2', 'example1']
266 266
267 267 ip.Completer.custom_completers.add_re('ex*', complete_example)
268 268 _, matches = ip.complete('ex')
269 269 assert matches.index('example2') < matches.index('example1')
270 270
271 271 def test_unicode_completions(self):
272 272 ip = get_ipython()
273 273 # Some strings that trigger different types of completion. Check them both
274 274 # in str and unicode forms
275 275 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
276 276 for t in s + list(map(str, s)):
277 277 # We don't need to check exact completion values (they may change
278 278 # depending on the state of the namespace, but at least no exceptions
279 279 # should be thrown and the return value should be a pair of text, list
280 280 # values.
281 281 text, matches = ip.complete(t)
282 282 self.assertIsInstance(text, str)
283 283 self.assertIsInstance(matches, list)
284 284
285 285 def test_latex_completions(self):
286 286 from IPython.core.latex_symbols import latex_symbols
287 287 import random
288 288
289 289 ip = get_ipython()
290 290 # Test some random unicode symbols
291 291 keys = random.sample(sorted(latex_symbols), 10)
292 292 for k in keys:
293 293 text, matches = ip.complete(k)
294 294 self.assertEqual(text, k)
295 295 self.assertEqual(matches, [latex_symbols[k]])
296 296 # Test a more complex line
297 297 text, matches = ip.complete("print(\\alpha")
298 298 self.assertEqual(text, "\\alpha")
299 299 self.assertEqual(matches[0], latex_symbols["\\alpha"])
300 300 # Test multiple matching latex symbols
301 301 text, matches = ip.complete("\\al")
302 302 self.assertIn("\\alpha", matches)
303 303 self.assertIn("\\aleph", matches)
304 304
305 305 def test_latex_no_results(self):
306 306 """
307 307 forward latex should really return nothing in either field if nothing is found.
308 308 """
309 309 ip = get_ipython()
310 310 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
311 311 self.assertEqual(text, "")
312 312 self.assertEqual(matches, ())
313 313
314 314 def test_back_latex_completion(self):
315 315 ip = get_ipython()
316 316
317 317 # do not return more than 1 matches for \beta, only the latex one.
318 318 name, matches = ip.complete("\\β")
319 319 self.assertEqual(matches, ["\\beta"])
320 320
321 321 def test_back_unicode_completion(self):
322 322 ip = get_ipython()
323 323
324 324 name, matches = ip.complete("\\Ⅴ")
325 325 self.assertEqual(matches, ["\\ROMAN NUMERAL FIVE"])
326 326
327 327 def test_forward_unicode_completion(self):
328 328 ip = get_ipython()
329 329
330 330 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
331 331 self.assertEqual(matches, ["Ⅴ"]) # This is not a V
332 332 self.assertEqual(matches, ["\u2164"]) # same as above but explicit.
333 333
334 334 def test_delim_setting(self):
335 335 sp = completer.CompletionSplitter()
336 336 sp.delims = " "
337 337 self.assertEqual(sp.delims, " ")
338 338 self.assertEqual(sp._delim_expr, r"[\ ]")
339 339
340 340 def test_spaces(self):
341 341 """Test with only spaces as split chars."""
342 342 sp = completer.CompletionSplitter()
343 343 sp.delims = " "
344 344 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
345 345 check_line_split(sp, t)
346 346
347 347 def test_has_open_quotes1(self):
348 348 for s in ["'", "'''", "'hi' '"]:
349 349 self.assertEqual(completer.has_open_quotes(s), "'")
350 350
351 351 def test_has_open_quotes2(self):
352 352 for s in ['"', '"""', '"hi" "']:
353 353 self.assertEqual(completer.has_open_quotes(s), '"')
354 354
355 355 def test_has_open_quotes3(self):
356 356 for s in ["''", "''' '''", "'hi' 'ipython'"]:
357 357 self.assertFalse(completer.has_open_quotes(s))
358 358
359 359 def test_has_open_quotes4(self):
360 360 for s in ['""', '""" """', '"hi" "ipython"']:
361 361 self.assertFalse(completer.has_open_quotes(s))
362 362
363 363 @pytest.mark.xfail(
364 364 sys.platform == "win32", reason="abspath completions fail on Windows"
365 365 )
366 366 def test_abspath_file_completions(self):
367 367 ip = get_ipython()
368 368 with TemporaryDirectory() as tmpdir:
369 369 prefix = os.path.join(tmpdir, "foo")
370 370 suffixes = ["1", "2"]
371 371 names = [prefix + s for s in suffixes]
372 372 for n in names:
373 373 open(n, "w", encoding="utf-8").close()
374 374
375 375 # Check simple completion
376 376 c = ip.complete(prefix)[1]
377 377 self.assertEqual(c, names)
378 378
379 379 # Now check with a function call
380 380 cmd = 'a = f("%s' % prefix
381 381 c = ip.complete(prefix, cmd)[1]
382 382 comp = [prefix + s for s in suffixes]
383 383 self.assertEqual(c, comp)
384 384
385 385 def test_local_file_completions(self):
386 386 ip = get_ipython()
387 387 with TemporaryWorkingDirectory():
388 388 prefix = "./foo"
389 389 suffixes = ["1", "2"]
390 390 names = [prefix + s for s in suffixes]
391 391 for n in names:
392 392 open(n, "w", encoding="utf-8").close()
393 393
394 394 # Check simple completion
395 395 c = ip.complete(prefix)[1]
396 396 self.assertEqual(c, names)
397 397
398 398 # Now check with a function call
399 399 cmd = 'a = f("%s' % prefix
400 400 c = ip.complete(prefix, cmd)[1]
401 401 comp = {prefix + s for s in suffixes}
402 402 self.assertTrue(comp.issubset(set(c)))
403 403
404 404 def test_quoted_file_completions(self):
405 405 ip = get_ipython()
406 406
407 407 def _(text):
408 408 return ip.Completer._complete(
409 409 cursor_line=0, cursor_pos=len(text), full_text=text
410 410 )["IPCompleter.file_matcher"]["completions"]
411 411
412 412 with TemporaryWorkingDirectory():
413 413 name = "foo'bar"
414 414 open(name, "w", encoding="utf-8").close()
415 415
416 416 # Don't escape Windows
417 417 escaped = name if sys.platform == "win32" else "foo\\'bar"
418 418
419 419 # Single quote matches embedded single quote
420 420 c = _("open('foo")[0]
421 421 self.assertEqual(c.text, escaped)
422 422
423 423 # Double quote requires no escape
424 424 c = _('open("foo')[0]
425 425 self.assertEqual(c.text, name)
426 426
427 427 # No quote requires an escape
428 428 c = _("%ls foo")[0]
429 429 self.assertEqual(c.text, escaped)
430 430
431 431 def test_all_completions_dups(self):
432 432 """
433 433 Make sure the output of `IPCompleter.all_completions` does not have
434 434 duplicated prefixes.
435 435 """
436 436 ip = get_ipython()
437 437 c = ip.Completer
438 438 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
439 439 for jedi_status in [True, False]:
440 440 with provisionalcompleter():
441 441 ip.Completer.use_jedi = jedi_status
442 442 matches = c.all_completions("TestCl")
443 443 assert matches == ["TestClass"], (jedi_status, matches)
444 444 matches = c.all_completions("TestClass.")
445 445 assert len(matches) > 2, (jedi_status, matches)
446 446 matches = c.all_completions("TestClass.a")
447 447 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
448 448
449 449 def test_jedi(self):
450 450 """
451 451 A couple of issue we had with Jedi
452 452 """
453 453 ip = get_ipython()
454 454
455 455 def _test_complete(reason, s, comp, start=None, end=None):
456 456 l = len(s)
457 457 start = start if start is not None else l
458 458 end = end if end is not None else l
459 459 with provisionalcompleter():
460 460 ip.Completer.use_jedi = True
461 461 completions = set(ip.Completer.completions(s, l))
462 462 ip.Completer.use_jedi = False
463 463 assert Completion(start, end, comp) in completions, reason
464 464
465 465 def _test_not_complete(reason, s, comp):
466 466 l = len(s)
467 467 with provisionalcompleter():
468 468 ip.Completer.use_jedi = True
469 469 completions = set(ip.Completer.completions(s, l))
470 470 ip.Completer.use_jedi = False
471 471 assert Completion(l, l, comp) not in completions, reason
472 472
473 473 import jedi
474 474
475 475 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
476 476 if jedi_version > (0, 10):
477 477 _test_complete("jedi >0.9 should complete and not crash", "a=1;a.", "real")
478 478 _test_complete("can infer first argument", 'a=(1,"foo");a[0].', "real")
479 479 _test_complete("can infer second argument", 'a=(1,"foo");a[1].', "capitalize")
480 480 _test_complete("cover duplicate completions", "im", "import", 0, 2)
481 481
482 482 _test_not_complete("does not mix types", 'a=(1,"foo");a[0].', "capitalize")
483 483
484 484 def test_completion_have_signature(self):
485 485 """
486 486 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
487 487 """
488 488 ip = get_ipython()
489 489 with provisionalcompleter():
490 490 ip.Completer.use_jedi = True
491 491 completions = ip.Completer.completions("ope", 3)
492 492 c = next(completions) # should be `open`
493 493 ip.Completer.use_jedi = False
494 494 assert "file" in c.signature, "Signature of function was not found by completer"
495 495 assert (
496 496 "encoding" in c.signature
497 497 ), "Signature of function was not found by completer"
498 498
499 499 def test_completions_have_type(self):
500 500 """
501 501 Lets make sure matchers provide completion type.
502 502 """
503 503 ip = get_ipython()
504 504 with provisionalcompleter():
505 505 ip.Completer.use_jedi = False
506 506 completions = ip.Completer.completions("%tim", 3)
507 507 c = next(completions) # should be `%time` or similar
508 508 assert c.type == "magic", "Type of magic was not assigned by completer"
509 509
510 510 @pytest.mark.xfail(reason="Known failure on jedi<=0.18.0")
511 511 def test_deduplicate_completions(self):
512 512 """
513 513 Test that completions are correctly deduplicated (even if ranges are not the same)
514 514 """
515 515 ip = get_ipython()
516 516 ip.ex(
517 517 textwrap.dedent(
518 518 """
519 519 class Z:
520 520 zoo = 1
521 521 """
522 522 )
523 523 )
524 524 with provisionalcompleter():
525 525 ip.Completer.use_jedi = True
526 526 l = list(
527 527 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
528 528 )
529 529 ip.Completer.use_jedi = False
530 530
531 531 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
532 532 assert l[0].text == "zoo" # and not `it.accumulate`
533 533
534 534 def test_greedy_completions(self):
535 535 """
536 536 Test the capability of the Greedy completer.
537 537
538 538 Most of the test here does not really show off the greedy completer, for proof
539 539 each of the text below now pass with Jedi. The greedy completer is capable of more.
540 540
541 541 See the :any:`test_dict_key_completion_contexts`
542 542
543 543 """
544 544 ip = get_ipython()
545 545 ip.ex("a=list(range(5))")
546 546 _, c = ip.complete(".", line="a[0].")
547 547 self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
548 548
549 549 def _(line, cursor_pos, expect, message, completion):
550 550 with greedy_completion(), provisionalcompleter():
551 551 ip.Completer.use_jedi = False
552 552 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
553 553 self.assertIn(expect, c, message % c)
554 554
555 555 ip.Completer.use_jedi = True
556 556 with provisionalcompleter():
557 557 completions = ip.Completer.completions(line, cursor_pos)
558 558 self.assertIn(completion, completions)
559 559
560 560 with provisionalcompleter():
561 561 _(
562 562 "a[0].",
563 563 5,
564 564 "a[0].real",
565 565 "Should have completed on a[0].: %s",
566 566 Completion(5, 5, "real"),
567 567 )
568 568 _(
569 569 "a[0].r",
570 570 6,
571 571 "a[0].real",
572 572 "Should have completed on a[0].r: %s",
573 573 Completion(5, 6, "real"),
574 574 )
575 575
576 576 _(
577 577 "a[0].from_",
578 578 10,
579 579 "a[0].from_bytes",
580 580 "Should have completed on a[0].from_: %s",
581 581 Completion(5, 10, "from_bytes"),
582 582 )
583 583
584 584 def test_omit__names(self):
585 585 # also happens to test IPCompleter as a configurable
586 586 ip = get_ipython()
587 587 ip._hidden_attr = 1
588 588 ip._x = {}
589 589 c = ip.Completer
590 590 ip.ex("ip=get_ipython()")
591 591 cfg = Config()
592 592 cfg.IPCompleter.omit__names = 0
593 593 c.update_config(cfg)
594 594 with provisionalcompleter():
595 595 c.use_jedi = False
596 596 s, matches = c.complete("ip.")
597 597 self.assertIn("ip.__str__", matches)
598 598 self.assertIn("ip._hidden_attr", matches)
599 599
600 600 # c.use_jedi = True
601 601 # completions = set(c.completions('ip.', 3))
602 602 # self.assertIn(Completion(3, 3, '__str__'), completions)
603 603 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
604 604
605 605 cfg = Config()
606 606 cfg.IPCompleter.omit__names = 1
607 607 c.update_config(cfg)
608 608 with provisionalcompleter():
609 609 c.use_jedi = False
610 610 s, matches = c.complete("ip.")
611 611 self.assertNotIn("ip.__str__", matches)
612 612 # self.assertIn('ip._hidden_attr', matches)
613 613
614 614 # c.use_jedi = True
615 615 # completions = set(c.completions('ip.', 3))
616 616 # self.assertNotIn(Completion(3,3,'__str__'), completions)
617 617 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
618 618
619 619 cfg = Config()
620 620 cfg.IPCompleter.omit__names = 2
621 621 c.update_config(cfg)
622 622 with provisionalcompleter():
623 623 c.use_jedi = False
624 624 s, matches = c.complete("ip.")
625 625 self.assertNotIn("ip.__str__", matches)
626 626 self.assertNotIn("ip._hidden_attr", matches)
627 627
628 628 # c.use_jedi = True
629 629 # completions = set(c.completions('ip.', 3))
630 630 # self.assertNotIn(Completion(3,3,'__str__'), completions)
631 631 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
632 632
633 633 with provisionalcompleter():
634 634 c.use_jedi = False
635 635 s, matches = c.complete("ip._x.")
636 636 self.assertIn("ip._x.keys", matches)
637 637
638 638 # c.use_jedi = True
639 639 # completions = set(c.completions('ip._x.', 6))
640 640 # self.assertIn(Completion(6,6, "keys"), completions)
641 641
642 642 del ip._hidden_attr
643 643 del ip._x
644 644
645 645 def test_limit_to__all__False_ok(self):
646 646 """
647 647 Limit to all is deprecated, once we remove it this test can go away.
648 648 """
649 649 ip = get_ipython()
650 650 c = ip.Completer
651 651 c.use_jedi = False
652 652 ip.ex("class D: x=24")
653 653 ip.ex("d=D()")
654 654 cfg = Config()
655 655 cfg.IPCompleter.limit_to__all__ = False
656 656 c.update_config(cfg)
657 657 s, matches = c.complete("d.")
658 658 self.assertIn("d.x", matches)
659 659
660 660 def test_get__all__entries_ok(self):
661 661 class A:
662 662 __all__ = ["x", 1]
663 663
664 664 words = completer.get__all__entries(A())
665 665 self.assertEqual(words, ["x"])
666 666
667 667 def test_get__all__entries_no__all__ok(self):
668 668 class A:
669 669 pass
670 670
671 671 words = completer.get__all__entries(A())
672 672 self.assertEqual(words, [])
673 673
674 674 def test_func_kw_completions(self):
675 675 ip = get_ipython()
676 676 c = ip.Completer
677 677 c.use_jedi = False
678 678 ip.ex("def myfunc(a=1,b=2): return a+b")
679 679 s, matches = c.complete(None, "myfunc(1,b")
680 680 self.assertIn("b=", matches)
681 681 # Simulate completing with cursor right after b (pos==10):
682 682 s, matches = c.complete(None, "myfunc(1,b)", 10)
683 683 self.assertIn("b=", matches)
684 684 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
685 685 self.assertIn("b=", matches)
686 686 # builtin function
687 687 s, matches = c.complete(None, "min(k, k")
688 688 self.assertIn("key=", matches)
689 689
690 690 def test_default_arguments_from_docstring(self):
691 691 ip = get_ipython()
692 692 c = ip.Completer
693 693 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
694 694 self.assertEqual(kwd, ["key"])
695 695 # with cython type etc
696 696 kwd = c._default_arguments_from_docstring(
697 697 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
698 698 )
699 699 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
700 700 # white spaces
701 701 kwd = c._default_arguments_from_docstring(
702 702 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
703 703 )
704 704 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
705 705
706 706 def test_line_magics(self):
707 707 ip = get_ipython()
708 708 c = ip.Completer
709 709 s, matches = c.complete(None, "lsmag")
710 710 self.assertIn("%lsmagic", matches)
711 711 s, matches = c.complete(None, "%lsmag")
712 712 self.assertIn("%lsmagic", matches)
713 713
714 714 def test_cell_magics(self):
715 715 from IPython.core.magic import register_cell_magic
716 716
717 717 @register_cell_magic
718 718 def _foo_cellm(line, cell):
719 719 pass
720 720
721 721 ip = get_ipython()
722 722 c = ip.Completer
723 723
724 724 s, matches = c.complete(None, "_foo_ce")
725 725 self.assertIn("%%_foo_cellm", matches)
726 726 s, matches = c.complete(None, "%%_foo_ce")
727 727 self.assertIn("%%_foo_cellm", matches)
728 728
729 729 def test_line_cell_magics(self):
730 730 from IPython.core.magic import register_line_cell_magic
731 731
732 732 @register_line_cell_magic
733 733 def _bar_cellm(line, cell):
734 734 pass
735 735
736 736 ip = get_ipython()
737 737 c = ip.Completer
738 738
739 739 # The policy here is trickier, see comments in completion code. The
740 740 # returned values depend on whether the user passes %% or not explicitly,
741 741 # and this will show a difference if the same name is both a line and cell
742 742 # magic.
743 743 s, matches = c.complete(None, "_bar_ce")
744 744 self.assertIn("%_bar_cellm", matches)
745 745 self.assertIn("%%_bar_cellm", matches)
746 746 s, matches = c.complete(None, "%_bar_ce")
747 747 self.assertIn("%_bar_cellm", matches)
748 748 self.assertIn("%%_bar_cellm", matches)
749 749 s, matches = c.complete(None, "%%_bar_ce")
750 750 self.assertNotIn("%_bar_cellm", matches)
751 751 self.assertIn("%%_bar_cellm", matches)
752 752
753 753 def test_magic_completion_order(self):
754 754 ip = get_ipython()
755 755 c = ip.Completer
756 756
757 757 # Test ordering of line and cell magics.
758 758 text, matches = c.complete("timeit")
759 759 self.assertEqual(matches, ["%timeit", "%%timeit"])
760 760
761 761 def test_magic_completion_shadowing(self):
762 762 ip = get_ipython()
763 763 c = ip.Completer
764 764 c.use_jedi = False
765 765
766 766 # Before importing matplotlib, %matplotlib magic should be the only option.
767 767 text, matches = c.complete("mat")
768 768 self.assertEqual(matches, ["%matplotlib"])
769 769
770 770 # The newly introduced name should shadow the magic.
771 771 ip.run_cell("matplotlib = 1")
772 772 text, matches = c.complete("mat")
773 773 self.assertEqual(matches, ["matplotlib"])
774 774
775 775 # After removing matplotlib from namespace, the magic should again be
776 776 # the only option.
777 777 del ip.user_ns["matplotlib"]
778 778 text, matches = c.complete("mat")
779 779 self.assertEqual(matches, ["%matplotlib"])
780 780
781 781 def test_magic_completion_shadowing_explicit(self):
782 782 """
783 783 If the user try to complete a shadowed magic, and explicit % start should
784 784 still return the completions.
785 785 """
786 786 ip = get_ipython()
787 787 c = ip.Completer
788 788
789 789 # Before importing matplotlib, %matplotlib magic should be the only option.
790 790 text, matches = c.complete("%mat")
791 791 self.assertEqual(matches, ["%matplotlib"])
792 792
793 793 ip.run_cell("matplotlib = 1")
794 794
795 795 # After removing matplotlib from namespace, the magic should still be
796 796 # the only option.
797 797 text, matches = c.complete("%mat")
798 798 self.assertEqual(matches, ["%matplotlib"])
799 799
800 800 def test_magic_config(self):
801 801 ip = get_ipython()
802 802 c = ip.Completer
803 803
804 804 s, matches = c.complete(None, "conf")
805 805 self.assertIn("%config", matches)
806 806 s, matches = c.complete(None, "conf")
807 807 self.assertNotIn("AliasManager", matches)
808 808 s, matches = c.complete(None, "config ")
809 809 self.assertIn("AliasManager", matches)
810 810 s, matches = c.complete(None, "%config ")
811 811 self.assertIn("AliasManager", matches)
812 812 s, matches = c.complete(None, "config Ali")
813 813 self.assertListEqual(["AliasManager"], matches)
814 814 s, matches = c.complete(None, "%config Ali")
815 815 self.assertListEqual(["AliasManager"], matches)
816 816 s, matches = c.complete(None, "config AliasManager")
817 817 self.assertListEqual(["AliasManager"], matches)
818 818 s, matches = c.complete(None, "%config AliasManager")
819 819 self.assertListEqual(["AliasManager"], matches)
820 820 s, matches = c.complete(None, "config AliasManager.")
821 821 self.assertIn("AliasManager.default_aliases", matches)
822 822 s, matches = c.complete(None, "%config AliasManager.")
823 823 self.assertIn("AliasManager.default_aliases", matches)
824 824 s, matches = c.complete(None, "config AliasManager.de")
825 825 self.assertListEqual(["AliasManager.default_aliases"], matches)
826 826 s, matches = c.complete(None, "config AliasManager.de")
827 827 self.assertListEqual(["AliasManager.default_aliases"], matches)
828 828
829 829 def test_magic_color(self):
830 830 ip = get_ipython()
831 831 c = ip.Completer
832 832
833 833 s, matches = c.complete(None, "colo")
834 834 self.assertIn("%colors", matches)
835 835 s, matches = c.complete(None, "colo")
836 836 self.assertNotIn("NoColor", matches)
837 837 s, matches = c.complete(None, "%colors") # No trailing space
838 838 self.assertNotIn("NoColor", matches)
839 839 s, matches = c.complete(None, "colors ")
840 840 self.assertIn("NoColor", matches)
841 841 s, matches = c.complete(None, "%colors ")
842 842 self.assertIn("NoColor", matches)
843 843 s, matches = c.complete(None, "colors NoCo")
844 844 self.assertListEqual(["NoColor"], matches)
845 845 s, matches = c.complete(None, "%colors NoCo")
846 846 self.assertListEqual(["NoColor"], matches)
847 847
848 848 def test_match_dict_keys(self):
849 849 """
850 850 Test that match_dict_keys works on a couple of use case does return what
851 851 expected, and does not crash
852 852 """
853 853 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
854 854
855 855 def match(*args, **kwargs):
856 856 quote, offset, matches = match_dict_keys(*args, delims=delims, **kwargs)
857 857 return quote, offset, list(matches)
858 858
859 859 keys = ["foo", b"far"]
860 860 assert match(keys, "b'") == ("'", 2, ["far"])
861 861 assert match(keys, "b'f") == ("'", 2, ["far"])
862 862 assert match(keys, 'b"') == ('"', 2, ["far"])
863 863 assert match(keys, 'b"f') == ('"', 2, ["far"])
864 864
865 865 assert match(keys, "'") == ("'", 1, ["foo"])
866 866 assert match(keys, "'f") == ("'", 1, ["foo"])
867 867 assert match(keys, '"') == ('"', 1, ["foo"])
868 868 assert match(keys, '"f') == ('"', 1, ["foo"])
869 869
870 870 # Completion on first item of tuple
871 871 keys = [("foo", 1111), ("foo", 2222), (3333, "bar"), (3333, "test")]
872 872 assert match(keys, "'f") == ("'", 1, ["foo"])
873 873 assert match(keys, "33") == ("", 0, ["3333"])
874 874
875 875 # Completion on numbers
876 876 keys = [
877 877 0xDEADBEEF,
878 878 1111,
879 879 1234,
880 880 "1999",
881 881 0b10101,
882 882 22,
883 883 ] # 0xDEADBEEF = 3735928559; 0b10101 = 21
884 884 assert match(keys, "0xdead") == ("", 0, ["0xdeadbeef"])
885 885 assert match(keys, "1") == ("", 0, ["1111", "1234"])
886 886 assert match(keys, "2") == ("", 0, ["21", "22"])
887 887 assert match(keys, "0b101") == ("", 0, ["0b10101", "0b10110"])
888 888
889 # Should yield on variables
890 assert match(keys, "a_variable") == ("", 0, [])
891
892 # Should pass over invalid literals
893 assert match(keys, "'' ''") == ("", 0, [])
894
889 895 def test_match_dict_keys_tuple(self):
890 896 """
891 897 Test that match_dict_keys called with extra prefix works on a couple of use case,
892 898 does return what expected, and does not crash.
893 899 """
894 900 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
895 901
896 902 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
897 903
898 904 def match(*args, extra=None, **kwargs):
899 905 quote, offset, matches = match_dict_keys(
900 906 *args, delims=delims, extra_prefix=extra, **kwargs
901 907 )
902 908 return quote, offset, list(matches)
903 909
904 910 # Completion on first key == "foo"
905 911 assert match(keys, "'", extra=("foo",)) == ("'", 1, ["bar", "oof"])
906 912 assert match(keys, '"', extra=("foo",)) == ('"', 1, ["bar", "oof"])
907 913 assert match(keys, "'o", extra=("foo",)) == ("'", 1, ["oof"])
908 914 assert match(keys, '"o', extra=("foo",)) == ('"', 1, ["oof"])
909 915 assert match(keys, "b'", extra=("foo",)) == ("'", 2, ["bar"])
910 916 assert match(keys, 'b"', extra=("foo",)) == ('"', 2, ["bar"])
911 917 assert match(keys, "b'b", extra=("foo",)) == ("'", 2, ["bar"])
912 918 assert match(keys, 'b"b', extra=("foo",)) == ('"', 2, ["bar"])
913 919
914 920 # No Completion
915 921 assert match(keys, "'", extra=("no_foo",)) == ("'", 1, [])
916 922 assert match(keys, "'", extra=("fo",)) == ("'", 1, [])
917 923
918 924 keys = [("foo1", "foo2", "foo3", "foo4"), ("foo1", "foo2", "bar", "foo4")]
919 925 assert match(keys, "'foo", extra=("foo1",)) == ("'", 1, ["foo2"])
920 926 assert match(keys, "'foo", extra=("foo1", "foo2")) == ("'", 1, ["foo3"])
921 927 assert match(keys, "'foo", extra=("foo1", "foo2", "foo3")) == ("'", 1, ["foo4"])
922 928 assert match(keys, "'foo", extra=("foo1", "foo2", "foo3", "foo4")) == (
923 929 "'",
924 930 1,
925 931 [],
926 932 )
927 933
928 934 keys = [("foo", 1111), ("foo", "2222"), (3333, "bar"), (3333, 4444)]
929 935 assert match(keys, "'", extra=("foo",)) == ("'", 1, ["2222"])
930 936 assert match(keys, "", extra=("foo",)) == ("", 0, ["1111", "'2222'"])
931 937 assert match(keys, "'", extra=(3333,)) == ("'", 1, ["bar"])
932 938 assert match(keys, "", extra=(3333,)) == ("", 0, ["'bar'", "4444"])
933 939 assert match(keys, "'", extra=("3333",)) == ("'", 1, [])
934 940 assert match(keys, "33") == ("", 0, ["3333"])
935 941
936 942 def test_dict_key_completion_closures(self):
937 943 ip = get_ipython()
938 944 complete = ip.Completer.complete
939 945 ip.Completer.auto_close_dict_keys = True
940 946
941 947 ip.user_ns["d"] = {
942 948 # tuple only
943 949 ("aa", 11): None,
944 950 # tuple and non-tuple
945 951 ("bb", 22): None,
946 952 "bb": None,
947 953 # non-tuple only
948 954 "cc": None,
949 955 # numeric tuple only
950 956 (77, "x"): None,
951 957 # numeric tuple and non-tuple
952 958 (88, "y"): None,
953 959 88: None,
954 960 # numeric non-tuple only
955 961 99: None,
956 962 }
957 963
958 964 _, matches = complete(line_buffer="d[")
959 965 # should append `, ` if matches a tuple only
960 966 self.assertIn("'aa', ", matches)
961 967 # should not append anything if matches a tuple and an item
962 968 self.assertIn("'bb'", matches)
963 969 # should append `]` if matches and item only
964 970 self.assertIn("'cc']", matches)
965 971
966 972 # should append `, ` if matches a tuple only
967 973 self.assertIn("77, ", matches)
968 974 # should not append anything if matches a tuple and an item
969 975 self.assertIn("88", matches)
970 976 # should append `]` if matches and item only
971 977 self.assertIn("99]", matches)
972 978
973 979 _, matches = complete(line_buffer="d['aa', ")
974 980 # should restrict matches to those matching tuple prefix
975 981 self.assertIn("11]", matches)
976 982 self.assertNotIn("'bb'", matches)
977 983 self.assertNotIn("'bb', ", matches)
978 984 self.assertNotIn("'bb']", matches)
979 985 self.assertNotIn("'cc'", matches)
980 986 self.assertNotIn("'cc', ", matches)
981 987 self.assertNotIn("'cc']", matches)
982 988 ip.Completer.auto_close_dict_keys = False
983 989
984 990 def test_dict_key_completion_string(self):
985 991 """Test dictionary key completion for string keys"""
986 992 ip = get_ipython()
987 993 complete = ip.Completer.complete
988 994
989 995 ip.user_ns["d"] = {"abc": None}
990 996
991 997 # check completion at different stages
992 998 _, matches = complete(line_buffer="d[")
993 999 self.assertIn("'abc'", matches)
994 1000 self.assertNotIn("'abc']", matches)
995 1001
996 1002 _, matches = complete(line_buffer="d['")
997 1003 self.assertIn("abc", matches)
998 1004 self.assertNotIn("abc']", matches)
999 1005
1000 1006 _, matches = complete(line_buffer="d['a")
1001 1007 self.assertIn("abc", matches)
1002 1008 self.assertNotIn("abc']", matches)
1003 1009
1004 1010 # check use of different quoting
1005 1011 _, matches = complete(line_buffer='d["')
1006 1012 self.assertIn("abc", matches)
1007 1013 self.assertNotIn('abc"]', matches)
1008 1014
1009 1015 _, matches = complete(line_buffer='d["a')
1010 1016 self.assertIn("abc", matches)
1011 1017 self.assertNotIn('abc"]', matches)
1012 1018
1013 1019 # check sensitivity to following context
1014 1020 _, matches = complete(line_buffer="d[]", cursor_pos=2)
1015 1021 self.assertIn("'abc'", matches)
1016 1022
1017 1023 _, matches = complete(line_buffer="d['']", cursor_pos=3)
1018 1024 self.assertIn("abc", matches)
1019 1025 self.assertNotIn("abc'", matches)
1020 1026 self.assertNotIn("abc']", matches)
1021 1027
1022 1028 # check multiple solutions are correctly returned and that noise is not
1023 1029 ip.user_ns["d"] = {
1024 1030 "abc": None,
1025 1031 "abd": None,
1026 1032 "bad": None,
1027 1033 object(): None,
1028 1034 5: None,
1029 1035 ("abe", None): None,
1030 1036 (None, "abf"): None
1031 1037 }
1032 1038
1033 1039 _, matches = complete(line_buffer="d['a")
1034 1040 self.assertIn("abc", matches)
1035 1041 self.assertIn("abd", matches)
1036 1042 self.assertNotIn("bad", matches)
1037 1043 self.assertNotIn("abe", matches)
1038 1044 self.assertNotIn("abf", matches)
1039 1045 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1040 1046
1041 1047 # check escaping and whitespace
1042 1048 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
1043 1049 _, matches = complete(line_buffer="d['a")
1044 1050 self.assertIn("a\\nb", matches)
1045 1051 self.assertIn("a\\'b", matches)
1046 1052 self.assertIn('a"b', matches)
1047 1053 self.assertIn("a word", matches)
1048 1054 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1049 1055
1050 1056 # - can complete on non-initial word of the string
1051 1057 _, matches = complete(line_buffer="d['a w")
1052 1058 self.assertIn("word", matches)
1053 1059
1054 1060 # - understands quote escaping
1055 1061 _, matches = complete(line_buffer="d['a\\'")
1056 1062 self.assertIn("b", matches)
1057 1063
1058 1064 # - default quoting should work like repr
1059 1065 _, matches = complete(line_buffer="d[")
1060 1066 self.assertIn('"a\'b"', matches)
1061 1067
1062 1068 # - when opening quote with ", possible to match with unescaped apostrophe
1063 1069 _, matches = complete(line_buffer="d[\"a'")
1064 1070 self.assertIn("b", matches)
1065 1071
1066 1072 # need to not split at delims that readline won't split at
1067 1073 if "-" not in ip.Completer.splitter.delims:
1068 1074 ip.user_ns["d"] = {"before-after": None}
1069 1075 _, matches = complete(line_buffer="d['before-af")
1070 1076 self.assertIn("before-after", matches)
1071 1077
1072 1078 # check completion on tuple-of-string keys at different stage - on first key
1073 1079 ip.user_ns["d"] = {('foo', 'bar'): None}
1074 1080 _, matches = complete(line_buffer="d[")
1075 1081 self.assertIn("'foo'", matches)
1076 1082 self.assertNotIn("'foo']", matches)
1077 1083 self.assertNotIn("'bar'", matches)
1078 1084 self.assertNotIn("foo", matches)
1079 1085 self.assertNotIn("bar", matches)
1080 1086
1081 1087 # - match the prefix
1082 1088 _, matches = complete(line_buffer="d['f")
1083 1089 self.assertIn("foo", matches)
1084 1090 self.assertNotIn("foo']", matches)
1085 1091 self.assertNotIn('foo"]', matches)
1086 1092 _, matches = complete(line_buffer="d['foo")
1087 1093 self.assertIn("foo", matches)
1088 1094
1089 1095 # - can complete on second key
1090 1096 _, matches = complete(line_buffer="d['foo', ")
1091 1097 self.assertIn("'bar'", matches)
1092 1098 _, matches = complete(line_buffer="d['foo', 'b")
1093 1099 self.assertIn("bar", matches)
1094 1100 self.assertNotIn("foo", matches)
1095 1101
1096 1102 # - does not propose missing keys
1097 1103 _, matches = complete(line_buffer="d['foo', 'f")
1098 1104 self.assertNotIn("bar", matches)
1099 1105 self.assertNotIn("foo", matches)
1100 1106
1101 1107 # check sensitivity to following context
1102 1108 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
1103 1109 self.assertIn("'bar'", matches)
1104 1110 self.assertNotIn("bar", matches)
1105 1111 self.assertNotIn("'foo'", matches)
1106 1112 self.assertNotIn("foo", matches)
1107 1113
1108 1114 _, matches = complete(line_buffer="d['']", cursor_pos=3)
1109 1115 self.assertIn("foo", matches)
1110 1116 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1111 1117
1112 1118 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
1113 1119 self.assertIn("foo", matches)
1114 1120 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1115 1121
1116 1122 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
1117 1123 self.assertIn("bar", matches)
1118 1124 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1119 1125
1120 1126 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1121 1127 self.assertIn("'bar'", matches)
1122 1128 self.assertNotIn("bar", matches)
1123 1129
1124 1130 # Can complete with longer tuple keys
1125 1131 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1126 1132
1127 1133 # - can complete second key
1128 1134 _, matches = complete(line_buffer="d['foo', 'b")
1129 1135 self.assertIn("bar", matches)
1130 1136 self.assertNotIn("foo", matches)
1131 1137 self.assertNotIn("foobar", matches)
1132 1138
1133 1139 # - can complete third key
1134 1140 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1135 1141 self.assertIn("foobar", matches)
1136 1142 self.assertNotIn("foo", matches)
1137 1143 self.assertNotIn("bar", matches)
1138 1144
1139 1145 def test_dict_key_completion_numbers(self):
1140 1146 ip = get_ipython()
1141 1147 complete = ip.Completer.complete
1142 1148
1143 1149 ip.user_ns["d"] = {
1144 1150 0xDEADBEEF: None, # 3735928559
1145 1151 1111: None,
1146 1152 1234: None,
1147 1153 "1999": None,
1148 1154 0b10101: None, # 21
1149 1155 22: None,
1150 1156 }
1151 1157 _, matches = complete(line_buffer="d[1")
1152 1158 self.assertIn("1111", matches)
1153 1159 self.assertIn("1234", matches)
1154 1160 self.assertNotIn("1999", matches)
1155 1161 self.assertNotIn("'1999'", matches)
1156 1162
1157 1163 _, matches = complete(line_buffer="d[0xdead")
1158 1164 self.assertIn("0xdeadbeef", matches)
1159 1165
1160 1166 _, matches = complete(line_buffer="d[2")
1161 1167 self.assertIn("21", matches)
1162 1168 self.assertIn("22", matches)
1163 1169
1164 1170 _, matches = complete(line_buffer="d[0b101")
1165 1171 self.assertIn("0b10101", matches)
1166 1172 self.assertIn("0b10110", matches)
1167 1173
1168 1174 def test_dict_key_completion_contexts(self):
1169 1175 """Test expression contexts in which dict key completion occurs"""
1170 1176 ip = get_ipython()
1171 1177 complete = ip.Completer.complete
1172 1178 d = {"abc": None}
1173 1179 ip.user_ns["d"] = d
1174 1180
1175 1181 class C:
1176 1182 data = d
1177 1183
1178 1184 ip.user_ns["C"] = C
1179 1185 ip.user_ns["get"] = lambda: d
1180 1186 ip.user_ns["nested"] = {"x": d}
1181 1187
1182 1188 def assert_no_completion(**kwargs):
1183 1189 _, matches = complete(**kwargs)
1184 1190 self.assertNotIn("abc", matches)
1185 1191 self.assertNotIn("abc'", matches)
1186 1192 self.assertNotIn("abc']", matches)
1187 1193 self.assertNotIn("'abc'", matches)
1188 1194 self.assertNotIn("'abc']", matches)
1189 1195
1190 1196 def assert_completion(**kwargs):
1191 1197 _, matches = complete(**kwargs)
1192 1198 self.assertIn("'abc'", matches)
1193 1199 self.assertNotIn("'abc']", matches)
1194 1200
1195 1201 # no completion after string closed, even if reopened
1196 1202 assert_no_completion(line_buffer="d['a'")
1197 1203 assert_no_completion(line_buffer='d["a"')
1198 1204 assert_no_completion(line_buffer="d['a' + ")
1199 1205 assert_no_completion(line_buffer="d['a' + '")
1200 1206
1201 1207 # completion in non-trivial expressions
1202 1208 assert_completion(line_buffer="+ d[")
1203 1209 assert_completion(line_buffer="(d[")
1204 1210 assert_completion(line_buffer="C.data[")
1205 1211
1206 1212 # nested dict completion
1207 1213 assert_completion(line_buffer="nested['x'][")
1208 1214
1209 1215 with evaluation_policy("minimal"):
1210 1216 with pytest.raises(AssertionError):
1211 1217 assert_completion(line_buffer="nested['x'][")
1212 1218
1213 1219 # greedy flag
1214 1220 def assert_completion(**kwargs):
1215 1221 _, matches = complete(**kwargs)
1216 1222 self.assertIn("get()['abc']", matches)
1217 1223
1218 1224 assert_no_completion(line_buffer="get()[")
1219 1225 with greedy_completion():
1220 1226 assert_completion(line_buffer="get()[")
1221 1227 assert_completion(line_buffer="get()['")
1222 1228 assert_completion(line_buffer="get()['a")
1223 1229 assert_completion(line_buffer="get()['ab")
1224 1230 assert_completion(line_buffer="get()['abc")
1225 1231
1226 1232 def test_dict_key_completion_bytes(self):
1227 1233 """Test handling of bytes in dict key completion"""
1228 1234 ip = get_ipython()
1229 1235 complete = ip.Completer.complete
1230 1236
1231 1237 ip.user_ns["d"] = {"abc": None, b"abd": None}
1232 1238
1233 1239 _, matches = complete(line_buffer="d[")
1234 1240 self.assertIn("'abc'", matches)
1235 1241 self.assertIn("b'abd'", matches)
1236 1242
1237 1243 if False: # not currently implemented
1238 1244 _, matches = complete(line_buffer="d[b")
1239 1245 self.assertIn("b'abd'", matches)
1240 1246 self.assertNotIn("b'abc'", matches)
1241 1247
1242 1248 _, matches = complete(line_buffer="d[b'")
1243 1249 self.assertIn("abd", matches)
1244 1250 self.assertNotIn("abc", matches)
1245 1251
1246 1252 _, matches = complete(line_buffer="d[B'")
1247 1253 self.assertIn("abd", matches)
1248 1254 self.assertNotIn("abc", matches)
1249 1255
1250 1256 _, matches = complete(line_buffer="d['")
1251 1257 self.assertIn("abc", matches)
1252 1258 self.assertNotIn("abd", matches)
1253 1259
1254 1260 def test_dict_key_completion_unicode_py3(self):
1255 1261 """Test handling of unicode in dict key completion"""
1256 1262 ip = get_ipython()
1257 1263 complete = ip.Completer.complete
1258 1264
1259 1265 ip.user_ns["d"] = {"a\u05d0": None}
1260 1266
1261 1267 # query using escape
1262 1268 if sys.platform != "win32":
1263 1269 # Known failure on Windows
1264 1270 _, matches = complete(line_buffer="d['a\\u05d0")
1265 1271 self.assertIn("u05d0", matches) # tokenized after \\
1266 1272
1267 1273 # query using character
1268 1274 _, matches = complete(line_buffer="d['a\u05d0")
1269 1275 self.assertIn("a\u05d0", matches)
1270 1276
1271 1277 with greedy_completion():
1272 1278 # query using escape
1273 1279 _, matches = complete(line_buffer="d['a\\u05d0")
1274 1280 self.assertIn("d['a\\u05d0']", matches) # tokenized after \\
1275 1281
1276 1282 # query using character
1277 1283 _, matches = complete(line_buffer="d['a\u05d0")
1278 1284 self.assertIn("d['a\u05d0']", matches)
1279 1285
1280 1286 @dec.skip_without("numpy")
1281 1287 def test_struct_array_key_completion(self):
1282 1288 """Test dict key completion applies to numpy struct arrays"""
1283 1289 import numpy
1284 1290
1285 1291 ip = get_ipython()
1286 1292 complete = ip.Completer.complete
1287 1293 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1288 1294 _, matches = complete(line_buffer="d['")
1289 1295 self.assertIn("hello", matches)
1290 1296 self.assertIn("world", matches)
1291 1297 # complete on the numpy struct itself
1292 1298 dt = numpy.dtype(
1293 1299 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1294 1300 )
1295 1301 x = numpy.zeros(2, dtype=dt)
1296 1302 ip.user_ns["d"] = x[1]
1297 1303 _, matches = complete(line_buffer="d['")
1298 1304 self.assertIn("my_head", matches)
1299 1305 self.assertIn("my_data", matches)
1300 1306
1301 1307 def completes_on_nested():
1302 1308 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1303 1309 _, matches = complete(line_buffer="d[1]['my_head']['")
1304 1310 self.assertTrue(any(["my_dt" in m for m in matches]))
1305 1311 self.assertTrue(any(["my_df" in m for m in matches]))
1306 1312 # complete on a nested level
1307 1313 with greedy_completion():
1308 1314 completes_on_nested()
1309 1315
1310 1316 with evaluation_policy("limited"):
1311 1317 completes_on_nested()
1312 1318
1313 1319 with evaluation_policy("minimal"):
1314 1320 with pytest.raises(AssertionError):
1315 1321 completes_on_nested()
1316 1322
1317 1323 @dec.skip_without("pandas")
1318 1324 def test_dataframe_key_completion(self):
1319 1325 """Test dict key completion applies to pandas DataFrames"""
1320 1326 import pandas
1321 1327
1322 1328 ip = get_ipython()
1323 1329 complete = ip.Completer.complete
1324 1330 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1325 1331 _, matches = complete(line_buffer="d['")
1326 1332 self.assertIn("hello", matches)
1327 1333 self.assertIn("world", matches)
1328 1334 _, matches = complete(line_buffer="d.loc[:, '")
1329 1335 self.assertIn("hello", matches)
1330 1336 self.assertIn("world", matches)
1331 1337 _, matches = complete(line_buffer="d.loc[1:, '")
1332 1338 self.assertIn("hello", matches)
1333 1339 _, matches = complete(line_buffer="d.loc[1:1, '")
1334 1340 self.assertIn("hello", matches)
1335 1341 _, matches = complete(line_buffer="d.loc[1:1:-1, '")
1336 1342 self.assertIn("hello", matches)
1337 1343 _, matches = complete(line_buffer="d.loc[::, '")
1338 1344 self.assertIn("hello", matches)
1339 1345
1340 1346 def test_dict_key_completion_invalids(self):
1341 1347 """Smoke test cases dict key completion can't handle"""
1342 1348 ip = get_ipython()
1343 1349 complete = ip.Completer.complete
1344 1350
1345 1351 ip.user_ns["no_getitem"] = None
1346 1352 ip.user_ns["no_keys"] = []
1347 1353 ip.user_ns["cant_call_keys"] = dict
1348 1354 ip.user_ns["empty"] = {}
1349 1355 ip.user_ns["d"] = {"abc": 5}
1350 1356
1351 1357 _, matches = complete(line_buffer="no_getitem['")
1352 1358 _, matches = complete(line_buffer="no_keys['")
1353 1359 _, matches = complete(line_buffer="cant_call_keys['")
1354 1360 _, matches = complete(line_buffer="empty['")
1355 1361 _, matches = complete(line_buffer="name_error['")
1356 1362 _, matches = complete(line_buffer="d['\\") # incomplete escape
1357 1363
1358 1364 def test_object_key_completion(self):
1359 1365 ip = get_ipython()
1360 1366 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1361 1367
1362 1368 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1363 1369 self.assertIn("qwerty", matches)
1364 1370 self.assertIn("qwick", matches)
1365 1371
1366 1372 def test_class_key_completion(self):
1367 1373 ip = get_ipython()
1368 1374 NamedInstanceClass("qwerty")
1369 1375 NamedInstanceClass("qwick")
1370 1376 ip.user_ns["named_instance_class"] = NamedInstanceClass
1371 1377
1372 1378 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1373 1379 self.assertIn("qwerty", matches)
1374 1380 self.assertIn("qwick", matches)
1375 1381
1376 1382 def test_tryimport(self):
1377 1383 """
1378 1384 Test that try-import don't crash on trailing dot, and import modules before
1379 1385 """
1380 1386 from IPython.core.completerlib import try_import
1381 1387
1382 1388 assert try_import("IPython.")
1383 1389
1384 1390 def test_aimport_module_completer(self):
1385 1391 ip = get_ipython()
1386 1392 _, matches = ip.complete("i", "%aimport i")
1387 1393 self.assertIn("io", matches)
1388 1394 self.assertNotIn("int", matches)
1389 1395
1390 1396 def test_nested_import_module_completer(self):
1391 1397 ip = get_ipython()
1392 1398 _, matches = ip.complete(None, "import IPython.co", 17)
1393 1399 self.assertIn("IPython.core", matches)
1394 1400 self.assertNotIn("import IPython.core", matches)
1395 1401 self.assertNotIn("IPython.display", matches)
1396 1402
1397 1403 def test_import_module_completer(self):
1398 1404 ip = get_ipython()
1399 1405 _, matches = ip.complete("i", "import i")
1400 1406 self.assertIn("io", matches)
1401 1407 self.assertNotIn("int", matches)
1402 1408
1403 1409 def test_from_module_completer(self):
1404 1410 ip = get_ipython()
1405 1411 _, matches = ip.complete("B", "from io import B", 16)
1406 1412 self.assertIn("BytesIO", matches)
1407 1413 self.assertNotIn("BaseException", matches)
1408 1414
1409 1415 def test_snake_case_completion(self):
1410 1416 ip = get_ipython()
1411 1417 ip.Completer.use_jedi = False
1412 1418 ip.user_ns["some_three"] = 3
1413 1419 ip.user_ns["some_four"] = 4
1414 1420 _, matches = ip.complete("s_", "print(s_f")
1415 1421 self.assertIn("some_three", matches)
1416 1422 self.assertIn("some_four", matches)
1417 1423
1418 1424 def test_mix_terms(self):
1419 1425 ip = get_ipython()
1420 1426 from textwrap import dedent
1421 1427
1422 1428 ip.Completer.use_jedi = False
1423 1429 ip.ex(
1424 1430 dedent(
1425 1431 """
1426 1432 class Test:
1427 1433 def meth(self, meth_arg1):
1428 1434 print("meth")
1429 1435
1430 1436 def meth_1(self, meth1_arg1, meth1_arg2):
1431 1437 print("meth1")
1432 1438
1433 1439 def meth_2(self, meth2_arg1, meth2_arg2):
1434 1440 print("meth2")
1435 1441 test = Test()
1436 1442 """
1437 1443 )
1438 1444 )
1439 1445 _, matches = ip.complete(None, "test.meth(")
1440 1446 self.assertIn("meth_arg1=", matches)
1441 1447 self.assertNotIn("meth2_arg1=", matches)
1442 1448
1443 1449 def test_percent_symbol_restrict_to_magic_completions(self):
1444 1450 ip = get_ipython()
1445 1451 completer = ip.Completer
1446 1452 text = "%a"
1447 1453
1448 1454 with provisionalcompleter():
1449 1455 completer.use_jedi = True
1450 1456 completions = completer.completions(text, len(text))
1451 1457 for c in completions:
1452 1458 self.assertEqual(c.text[0], "%")
1453 1459
1454 1460 def test_fwd_unicode_restricts(self):
1455 1461 ip = get_ipython()
1456 1462 completer = ip.Completer
1457 1463 text = "\\ROMAN NUMERAL FIVE"
1458 1464
1459 1465 with provisionalcompleter():
1460 1466 completer.use_jedi = True
1461 1467 completions = [
1462 1468 completion.text for completion in completer.completions(text, len(text))
1463 1469 ]
1464 1470 self.assertEqual(completions, ["\u2164"])
1465 1471
1466 1472 def test_dict_key_restrict_to_dicts(self):
1467 1473 """Test that dict key suppresses non-dict completion items"""
1468 1474 ip = get_ipython()
1469 1475 c = ip.Completer
1470 1476 d = {"abc": None}
1471 1477 ip.user_ns["d"] = d
1472 1478
1473 1479 text = 'd["a'
1474 1480
1475 1481 def _():
1476 1482 with provisionalcompleter():
1477 1483 c.use_jedi = True
1478 1484 return [
1479 1485 completion.text for completion in c.completions(text, len(text))
1480 1486 ]
1481 1487
1482 1488 completions = _()
1483 1489 self.assertEqual(completions, ["abc"])
1484 1490
1485 1491 # check that it can be disabled in granular manner:
1486 1492 cfg = Config()
1487 1493 cfg.IPCompleter.suppress_competing_matchers = {
1488 1494 "IPCompleter.dict_key_matcher": False
1489 1495 }
1490 1496 c.update_config(cfg)
1491 1497
1492 1498 completions = _()
1493 1499 self.assertIn("abc", completions)
1494 1500 self.assertGreater(len(completions), 1)
1495 1501
1496 1502 def test_matcher_suppression(self):
1497 1503 @completion_matcher(identifier="a_matcher")
1498 1504 def a_matcher(text):
1499 1505 return ["completion_a"]
1500 1506
1501 1507 @completion_matcher(identifier="b_matcher", api_version=2)
1502 1508 def b_matcher(context: CompletionContext):
1503 1509 text = context.token
1504 1510 result = {"completions": [SimpleCompletion("completion_b")]}
1505 1511
1506 1512 if text == "suppress c":
1507 1513 result["suppress"] = {"c_matcher"}
1508 1514
1509 1515 if text.startswith("suppress all"):
1510 1516 result["suppress"] = True
1511 1517 if text == "suppress all but c":
1512 1518 result["do_not_suppress"] = {"c_matcher"}
1513 1519 if text == "suppress all but a":
1514 1520 result["do_not_suppress"] = {"a_matcher"}
1515 1521
1516 1522 return result
1517 1523
1518 1524 @completion_matcher(identifier="c_matcher")
1519 1525 def c_matcher(text):
1520 1526 return ["completion_c"]
1521 1527
1522 1528 with custom_matchers([a_matcher, b_matcher, c_matcher]):
1523 1529 ip = get_ipython()
1524 1530 c = ip.Completer
1525 1531
1526 1532 def _(text, expected):
1527 1533 c.use_jedi = False
1528 1534 s, matches = c.complete(text)
1529 1535 self.assertEqual(expected, matches)
1530 1536
1531 1537 _("do not suppress", ["completion_a", "completion_b", "completion_c"])
1532 1538 _("suppress all", ["completion_b"])
1533 1539 _("suppress all but a", ["completion_a", "completion_b"])
1534 1540 _("suppress all but c", ["completion_b", "completion_c"])
1535 1541
1536 1542 def configure(suppression_config):
1537 1543 cfg = Config()
1538 1544 cfg.IPCompleter.suppress_competing_matchers = suppression_config
1539 1545 c.update_config(cfg)
1540 1546
1541 1547 # test that configuration takes priority over the run-time decisions
1542 1548
1543 1549 configure(False)
1544 1550 _("suppress all", ["completion_a", "completion_b", "completion_c"])
1545 1551
1546 1552 configure({"b_matcher": False})
1547 1553 _("suppress all", ["completion_a", "completion_b", "completion_c"])
1548 1554
1549 1555 configure({"a_matcher": False})
1550 1556 _("suppress all", ["completion_b"])
1551 1557
1552 1558 configure({"b_matcher": True})
1553 1559 _("do not suppress", ["completion_b"])
1554 1560
1555 1561 configure(True)
1556 1562 _("do not suppress", ["completion_a"])
1557 1563
1558 1564 def test_matcher_suppression_with_iterator(self):
1559 1565 @completion_matcher(identifier="matcher_returning_iterator")
1560 1566 def matcher_returning_iterator(text):
1561 1567 return iter(["completion_iter"])
1562 1568
1563 1569 @completion_matcher(identifier="matcher_returning_list")
1564 1570 def matcher_returning_list(text):
1565 1571 return ["completion_list"]
1566 1572
1567 1573 with custom_matchers([matcher_returning_iterator, matcher_returning_list]):
1568 1574 ip = get_ipython()
1569 1575 c = ip.Completer
1570 1576
1571 1577 def _(text, expected):
1572 1578 c.use_jedi = False
1573 1579 s, matches = c.complete(text)
1574 1580 self.assertEqual(expected, matches)
1575 1581
1576 1582 def configure(suppression_config):
1577 1583 cfg = Config()
1578 1584 cfg.IPCompleter.suppress_competing_matchers = suppression_config
1579 1585 c.update_config(cfg)
1580 1586
1581 1587 configure(False)
1582 1588 _("---", ["completion_iter", "completion_list"])
1583 1589
1584 1590 configure(True)
1585 1591 _("---", ["completion_iter"])
1586 1592
1587 1593 configure(None)
1588 1594 _("--", ["completion_iter", "completion_list"])
1589 1595
1590 1596 def test_matcher_suppression_with_jedi(self):
1591 1597 ip = get_ipython()
1592 1598 c = ip.Completer
1593 1599 c.use_jedi = True
1594 1600
1595 1601 def configure(suppression_config):
1596 1602 cfg = Config()
1597 1603 cfg.IPCompleter.suppress_competing_matchers = suppression_config
1598 1604 c.update_config(cfg)
1599 1605
1600 1606 def _():
1601 1607 with provisionalcompleter():
1602 1608 matches = [completion.text for completion in c.completions("dict.", 5)]
1603 1609 self.assertIn("keys", matches)
1604 1610
1605 1611 configure(False)
1606 1612 _()
1607 1613
1608 1614 configure(True)
1609 1615 _()
1610 1616
1611 1617 configure(None)
1612 1618 _()
1613 1619
1614 1620 def test_matcher_disabling(self):
1615 1621 @completion_matcher(identifier="a_matcher")
1616 1622 def a_matcher(text):
1617 1623 return ["completion_a"]
1618 1624
1619 1625 @completion_matcher(identifier="b_matcher")
1620 1626 def b_matcher(text):
1621 1627 return ["completion_b"]
1622 1628
1623 1629 def _(expected):
1624 1630 s, matches = c.complete("completion_")
1625 1631 self.assertEqual(expected, matches)
1626 1632
1627 1633 with custom_matchers([a_matcher, b_matcher]):
1628 1634 ip = get_ipython()
1629 1635 c = ip.Completer
1630 1636
1631 1637 _(["completion_a", "completion_b"])
1632 1638
1633 1639 cfg = Config()
1634 1640 cfg.IPCompleter.disable_matchers = ["b_matcher"]
1635 1641 c.update_config(cfg)
1636 1642
1637 1643 _(["completion_a"])
1638 1644
1639 1645 cfg.IPCompleter.disable_matchers = []
1640 1646 c.update_config(cfg)
1641 1647
1642 1648 def test_matcher_priority(self):
1643 1649 @completion_matcher(identifier="a_matcher", priority=0, api_version=2)
1644 1650 def a_matcher(text):
1645 1651 return {"completions": [SimpleCompletion("completion_a")], "suppress": True}
1646 1652
1647 1653 @completion_matcher(identifier="b_matcher", priority=2, api_version=2)
1648 1654 def b_matcher(text):
1649 1655 return {"completions": [SimpleCompletion("completion_b")], "suppress": True}
1650 1656
1651 1657 def _(expected):
1652 1658 s, matches = c.complete("completion_")
1653 1659 self.assertEqual(expected, matches)
1654 1660
1655 1661 with custom_matchers([a_matcher, b_matcher]):
1656 1662 ip = get_ipython()
1657 1663 c = ip.Completer
1658 1664
1659 1665 _(["completion_b"])
1660 1666 a_matcher.matcher_priority = 3
1661 1667 _(["completion_a"])
1662 1668
1663 1669
1664 1670 @pytest.mark.parametrize(
1665 1671 "input, expected",
1666 1672 [
1667 1673 ["1.234", "1.234"],
1668 1674 # should match signed numbers
1669 1675 ["+1", "+1"],
1670 1676 ["-1", "-1"],
1671 1677 ["-1.0", "-1.0"],
1672 1678 ["-1.", "-1."],
1673 1679 ["+1.", "+1."],
1674 1680 [".1", ".1"],
1675 1681 # should not match non-numbers
1676 1682 ["1..", None],
1677 1683 ["..", None],
1678 1684 [".1.", None],
1679 1685 # should match after comma
1680 1686 [",1", "1"],
1681 1687 [", 1", "1"],
1682 1688 [", .1", ".1"],
1683 1689 [", +.1", "+.1"],
1684 1690 # should not match after trailing spaces
1685 1691 [".1 ", None],
1686 1692 # some complex cases
1687 1693 ["0b_0011_1111_0100_1110", "0b_0011_1111_0100_1110"],
1688 1694 ["0xdeadbeef", "0xdeadbeef"],
1689 1695 ["0b_1110_0101", "0b_1110_0101"],
1696 # should not match if in an operation
1697 ["1 + 1", None],
1698 [", 1 + 1", None],
1690 1699 ],
1691 1700 )
1692 1701 def test_match_numeric_literal_for_dict_key(input, expected):
1693 1702 assert _match_number_in_dict_key_prefix(input) == expected
General Comments 0
You need to be logged in to leave comments. Login now