##// END OF EJS Templates
update unicode range for python 3.13
Matthias Bussonnier -
Show More
@@ -1,1717 +1,1717 b''
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 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
64 gap_lens.append((start - pstop, hex(pstop+1), 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 assert len_exp <= 143041, message
102 assert len_exp <= 143668, 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 ip.ex("d = {'a b': str}")
547 547 _, c = ip.complete(".", line="a[0].")
548 548 self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
549 549
550 550 def _(line, cursor_pos, expect, message, completion):
551 551 with greedy_completion(), provisionalcompleter():
552 552 ip.Completer.use_jedi = False
553 553 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
554 554 self.assertIn(expect, c, message % c)
555 555
556 556 ip.Completer.use_jedi = True
557 557 with provisionalcompleter():
558 558 completions = ip.Completer.completions(line, cursor_pos)
559 559 self.assertIn(completion, completions)
560 560
561 561 with provisionalcompleter():
562 562 _(
563 563 "a[0].",
564 564 5,
565 565 ".real",
566 566 "Should have completed on a[0].: %s",
567 567 Completion(5, 5, "real"),
568 568 )
569 569 _(
570 570 "a[0].r",
571 571 6,
572 572 ".real",
573 573 "Should have completed on a[0].r: %s",
574 574 Completion(5, 6, "real"),
575 575 )
576 576
577 577 _(
578 578 "a[0].from_",
579 579 10,
580 580 ".from_bytes",
581 581 "Should have completed on a[0].from_: %s",
582 582 Completion(5, 10, "from_bytes"),
583 583 )
584 584 _(
585 585 "assert str.star",
586 586 14,
587 587 "str.startswith",
588 588 "Should have completed on `assert str.star`: %s",
589 589 Completion(11, 14, "startswith"),
590 590 )
591 591 _(
592 592 "d['a b'].str",
593 593 12,
594 594 ".strip",
595 595 "Should have completed on `d['a b'].str`: %s",
596 596 Completion(9, 12, "strip"),
597 597 )
598 598
599 599 def test_omit__names(self):
600 600 # also happens to test IPCompleter as a configurable
601 601 ip = get_ipython()
602 602 ip._hidden_attr = 1
603 603 ip._x = {}
604 604 c = ip.Completer
605 605 ip.ex("ip=get_ipython()")
606 606 cfg = Config()
607 607 cfg.IPCompleter.omit__names = 0
608 608 c.update_config(cfg)
609 609 with provisionalcompleter():
610 610 c.use_jedi = False
611 611 s, matches = c.complete("ip.")
612 612 self.assertIn("ip.__str__", matches)
613 613 self.assertIn("ip._hidden_attr", matches)
614 614
615 615 # c.use_jedi = True
616 616 # completions = set(c.completions('ip.', 3))
617 617 # self.assertIn(Completion(3, 3, '__str__'), completions)
618 618 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
619 619
620 620 cfg = Config()
621 621 cfg.IPCompleter.omit__names = 1
622 622 c.update_config(cfg)
623 623 with provisionalcompleter():
624 624 c.use_jedi = False
625 625 s, matches = c.complete("ip.")
626 626 self.assertNotIn("ip.__str__", matches)
627 627 # self.assertIn('ip._hidden_attr', matches)
628 628
629 629 # c.use_jedi = True
630 630 # completions = set(c.completions('ip.', 3))
631 631 # self.assertNotIn(Completion(3,3,'__str__'), completions)
632 632 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
633 633
634 634 cfg = Config()
635 635 cfg.IPCompleter.omit__names = 2
636 636 c.update_config(cfg)
637 637 with provisionalcompleter():
638 638 c.use_jedi = False
639 639 s, matches = c.complete("ip.")
640 640 self.assertNotIn("ip.__str__", matches)
641 641 self.assertNotIn("ip._hidden_attr", matches)
642 642
643 643 # c.use_jedi = True
644 644 # completions = set(c.completions('ip.', 3))
645 645 # self.assertNotIn(Completion(3,3,'__str__'), completions)
646 646 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
647 647
648 648 with provisionalcompleter():
649 649 c.use_jedi = False
650 650 s, matches = c.complete("ip._x.")
651 651 self.assertIn("ip._x.keys", matches)
652 652
653 653 # c.use_jedi = True
654 654 # completions = set(c.completions('ip._x.', 6))
655 655 # self.assertIn(Completion(6,6, "keys"), completions)
656 656
657 657 del ip._hidden_attr
658 658 del ip._x
659 659
660 660 def test_limit_to__all__False_ok(self):
661 661 """
662 662 Limit to all is deprecated, once we remove it this test can go away.
663 663 """
664 664 ip = get_ipython()
665 665 c = ip.Completer
666 666 c.use_jedi = False
667 667 ip.ex("class D: x=24")
668 668 ip.ex("d=D()")
669 669 cfg = Config()
670 670 cfg.IPCompleter.limit_to__all__ = False
671 671 c.update_config(cfg)
672 672 s, matches = c.complete("d.")
673 673 self.assertIn("d.x", matches)
674 674
675 675 def test_get__all__entries_ok(self):
676 676 class A:
677 677 __all__ = ["x", 1]
678 678
679 679 words = completer.get__all__entries(A())
680 680 self.assertEqual(words, ["x"])
681 681
682 682 def test_get__all__entries_no__all__ok(self):
683 683 class A:
684 684 pass
685 685
686 686 words = completer.get__all__entries(A())
687 687 self.assertEqual(words, [])
688 688
689 689 def test_func_kw_completions(self):
690 690 ip = get_ipython()
691 691 c = ip.Completer
692 692 c.use_jedi = False
693 693 ip.ex("def myfunc(a=1,b=2): return a+b")
694 694 s, matches = c.complete(None, "myfunc(1,b")
695 695 self.assertIn("b=", matches)
696 696 # Simulate completing with cursor right after b (pos==10):
697 697 s, matches = c.complete(None, "myfunc(1,b)", 10)
698 698 self.assertIn("b=", matches)
699 699 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
700 700 self.assertIn("b=", matches)
701 701 # builtin function
702 702 s, matches = c.complete(None, "min(k, k")
703 703 self.assertIn("key=", matches)
704 704
705 705 def test_default_arguments_from_docstring(self):
706 706 ip = get_ipython()
707 707 c = ip.Completer
708 708 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
709 709 self.assertEqual(kwd, ["key"])
710 710 # with cython type etc
711 711 kwd = c._default_arguments_from_docstring(
712 712 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
713 713 )
714 714 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
715 715 # white spaces
716 716 kwd = c._default_arguments_from_docstring(
717 717 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
718 718 )
719 719 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
720 720
721 721 def test_line_magics(self):
722 722 ip = get_ipython()
723 723 c = ip.Completer
724 724 s, matches = c.complete(None, "lsmag")
725 725 self.assertIn("%lsmagic", matches)
726 726 s, matches = c.complete(None, "%lsmag")
727 727 self.assertIn("%lsmagic", matches)
728 728
729 729 def test_cell_magics(self):
730 730 from IPython.core.magic import register_cell_magic
731 731
732 732 @register_cell_magic
733 733 def _foo_cellm(line, cell):
734 734 pass
735 735
736 736 ip = get_ipython()
737 737 c = ip.Completer
738 738
739 739 s, matches = c.complete(None, "_foo_ce")
740 740 self.assertIn("%%_foo_cellm", matches)
741 741 s, matches = c.complete(None, "%%_foo_ce")
742 742 self.assertIn("%%_foo_cellm", matches)
743 743
744 744 def test_line_cell_magics(self):
745 745 from IPython.core.magic import register_line_cell_magic
746 746
747 747 @register_line_cell_magic
748 748 def _bar_cellm(line, cell):
749 749 pass
750 750
751 751 ip = get_ipython()
752 752 c = ip.Completer
753 753
754 754 # The policy here is trickier, see comments in completion code. The
755 755 # returned values depend on whether the user passes %% or not explicitly,
756 756 # and this will show a difference if the same name is both a line and cell
757 757 # magic.
758 758 s, matches = c.complete(None, "_bar_ce")
759 759 self.assertIn("%_bar_cellm", matches)
760 760 self.assertIn("%%_bar_cellm", matches)
761 761 s, matches = c.complete(None, "%_bar_ce")
762 762 self.assertIn("%_bar_cellm", matches)
763 763 self.assertIn("%%_bar_cellm", matches)
764 764 s, matches = c.complete(None, "%%_bar_ce")
765 765 self.assertNotIn("%_bar_cellm", matches)
766 766 self.assertIn("%%_bar_cellm", matches)
767 767
768 768 def test_magic_completion_order(self):
769 769 ip = get_ipython()
770 770 c = ip.Completer
771 771
772 772 # Test ordering of line and cell magics.
773 773 text, matches = c.complete("timeit")
774 774 self.assertEqual(matches, ["%timeit", "%%timeit"])
775 775
776 776 def test_magic_completion_shadowing(self):
777 777 ip = get_ipython()
778 778 c = ip.Completer
779 779 c.use_jedi = False
780 780
781 781 # Before importing matplotlib, %matplotlib magic should be the only option.
782 782 text, matches = c.complete("mat")
783 783 self.assertEqual(matches, ["%matplotlib"])
784 784
785 785 # The newly introduced name should shadow the magic.
786 786 ip.run_cell("matplotlib = 1")
787 787 text, matches = c.complete("mat")
788 788 self.assertEqual(matches, ["matplotlib"])
789 789
790 790 # After removing matplotlib from namespace, the magic should again be
791 791 # the only option.
792 792 del ip.user_ns["matplotlib"]
793 793 text, matches = c.complete("mat")
794 794 self.assertEqual(matches, ["%matplotlib"])
795 795
796 796 def test_magic_completion_shadowing_explicit(self):
797 797 """
798 798 If the user try to complete a shadowed magic, and explicit % start should
799 799 still return the completions.
800 800 """
801 801 ip = get_ipython()
802 802 c = ip.Completer
803 803
804 804 # Before importing matplotlib, %matplotlib magic should be the only option.
805 805 text, matches = c.complete("%mat")
806 806 self.assertEqual(matches, ["%matplotlib"])
807 807
808 808 ip.run_cell("matplotlib = 1")
809 809
810 810 # After removing matplotlib from namespace, the magic should still be
811 811 # the only option.
812 812 text, matches = c.complete("%mat")
813 813 self.assertEqual(matches, ["%matplotlib"])
814 814
815 815 def test_magic_config(self):
816 816 ip = get_ipython()
817 817 c = ip.Completer
818 818
819 819 s, matches = c.complete(None, "conf")
820 820 self.assertIn("%config", matches)
821 821 s, matches = c.complete(None, "conf")
822 822 self.assertNotIn("AliasManager", matches)
823 823 s, matches = c.complete(None, "config ")
824 824 self.assertIn("AliasManager", matches)
825 825 s, matches = c.complete(None, "%config ")
826 826 self.assertIn("AliasManager", matches)
827 827 s, matches = c.complete(None, "config Ali")
828 828 self.assertListEqual(["AliasManager"], matches)
829 829 s, matches = c.complete(None, "%config Ali")
830 830 self.assertListEqual(["AliasManager"], matches)
831 831 s, matches = c.complete(None, "config AliasManager")
832 832 self.assertListEqual(["AliasManager"], matches)
833 833 s, matches = c.complete(None, "%config AliasManager")
834 834 self.assertListEqual(["AliasManager"], matches)
835 835 s, matches = c.complete(None, "config AliasManager.")
836 836 self.assertIn("AliasManager.default_aliases", matches)
837 837 s, matches = c.complete(None, "%config AliasManager.")
838 838 self.assertIn("AliasManager.default_aliases", matches)
839 839 s, matches = c.complete(None, "config AliasManager.de")
840 840 self.assertListEqual(["AliasManager.default_aliases"], matches)
841 841 s, matches = c.complete(None, "config AliasManager.de")
842 842 self.assertListEqual(["AliasManager.default_aliases"], matches)
843 843
844 844 def test_magic_color(self):
845 845 ip = get_ipython()
846 846 c = ip.Completer
847 847
848 848 s, matches = c.complete(None, "colo")
849 849 self.assertIn("%colors", matches)
850 850 s, matches = c.complete(None, "colo")
851 851 self.assertNotIn("NoColor", matches)
852 852 s, matches = c.complete(None, "%colors") # No trailing space
853 853 self.assertNotIn("NoColor", matches)
854 854 s, matches = c.complete(None, "colors ")
855 855 self.assertIn("NoColor", matches)
856 856 s, matches = c.complete(None, "%colors ")
857 857 self.assertIn("NoColor", matches)
858 858 s, matches = c.complete(None, "colors NoCo")
859 859 self.assertListEqual(["NoColor"], matches)
860 860 s, matches = c.complete(None, "%colors NoCo")
861 861 self.assertListEqual(["NoColor"], matches)
862 862
863 863 def test_match_dict_keys(self):
864 864 """
865 865 Test that match_dict_keys works on a couple of use case does return what
866 866 expected, and does not crash
867 867 """
868 868 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
869 869
870 870 def match(*args, **kwargs):
871 871 quote, offset, matches = match_dict_keys(*args, delims=delims, **kwargs)
872 872 return quote, offset, list(matches)
873 873
874 874 keys = ["foo", b"far"]
875 875 assert match(keys, "b'") == ("'", 2, ["far"])
876 876 assert match(keys, "b'f") == ("'", 2, ["far"])
877 877 assert match(keys, 'b"') == ('"', 2, ["far"])
878 878 assert match(keys, 'b"f') == ('"', 2, ["far"])
879 879
880 880 assert match(keys, "'") == ("'", 1, ["foo"])
881 881 assert match(keys, "'f") == ("'", 1, ["foo"])
882 882 assert match(keys, '"') == ('"', 1, ["foo"])
883 883 assert match(keys, '"f') == ('"', 1, ["foo"])
884 884
885 885 # Completion on first item of tuple
886 886 keys = [("foo", 1111), ("foo", 2222), (3333, "bar"), (3333, "test")]
887 887 assert match(keys, "'f") == ("'", 1, ["foo"])
888 888 assert match(keys, "33") == ("", 0, ["3333"])
889 889
890 890 # Completion on numbers
891 891 keys = [
892 892 0xDEADBEEF,
893 893 1111,
894 894 1234,
895 895 "1999",
896 896 0b10101,
897 897 22,
898 898 ] # 0xDEADBEEF = 3735928559; 0b10101 = 21
899 899 assert match(keys, "0xdead") == ("", 0, ["0xdeadbeef"])
900 900 assert match(keys, "1") == ("", 0, ["1111", "1234"])
901 901 assert match(keys, "2") == ("", 0, ["21", "22"])
902 902 assert match(keys, "0b101") == ("", 0, ["0b10101", "0b10110"])
903 903
904 904 # Should yield on variables
905 905 assert match(keys, "a_variable") == ("", 0, [])
906 906
907 907 # Should pass over invalid literals
908 908 assert match(keys, "'' ''") == ("", 0, [])
909 909
910 910 def test_match_dict_keys_tuple(self):
911 911 """
912 912 Test that match_dict_keys called with extra prefix works on a couple of use case,
913 913 does return what expected, and does not crash.
914 914 """
915 915 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
916 916
917 917 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
918 918
919 919 def match(*args, extra=None, **kwargs):
920 920 quote, offset, matches = match_dict_keys(
921 921 *args, delims=delims, extra_prefix=extra, **kwargs
922 922 )
923 923 return quote, offset, list(matches)
924 924
925 925 # Completion on first key == "foo"
926 926 assert match(keys, "'", extra=("foo",)) == ("'", 1, ["bar", "oof"])
927 927 assert match(keys, '"', extra=("foo",)) == ('"', 1, ["bar", "oof"])
928 928 assert match(keys, "'o", extra=("foo",)) == ("'", 1, ["oof"])
929 929 assert match(keys, '"o', extra=("foo",)) == ('"', 1, ["oof"])
930 930 assert match(keys, "b'", extra=("foo",)) == ("'", 2, ["bar"])
931 931 assert match(keys, 'b"', extra=("foo",)) == ('"', 2, ["bar"])
932 932 assert match(keys, "b'b", extra=("foo",)) == ("'", 2, ["bar"])
933 933 assert match(keys, 'b"b', extra=("foo",)) == ('"', 2, ["bar"])
934 934
935 935 # No Completion
936 936 assert match(keys, "'", extra=("no_foo",)) == ("'", 1, [])
937 937 assert match(keys, "'", extra=("fo",)) == ("'", 1, [])
938 938
939 939 keys = [("foo1", "foo2", "foo3", "foo4"), ("foo1", "foo2", "bar", "foo4")]
940 940 assert match(keys, "'foo", extra=("foo1",)) == ("'", 1, ["foo2"])
941 941 assert match(keys, "'foo", extra=("foo1", "foo2")) == ("'", 1, ["foo3"])
942 942 assert match(keys, "'foo", extra=("foo1", "foo2", "foo3")) == ("'", 1, ["foo4"])
943 943 assert match(keys, "'foo", extra=("foo1", "foo2", "foo3", "foo4")) == (
944 944 "'",
945 945 1,
946 946 [],
947 947 )
948 948
949 949 keys = [("foo", 1111), ("foo", "2222"), (3333, "bar"), (3333, 4444)]
950 950 assert match(keys, "'", extra=("foo",)) == ("'", 1, ["2222"])
951 951 assert match(keys, "", extra=("foo",)) == ("", 0, ["1111", "'2222'"])
952 952 assert match(keys, "'", extra=(3333,)) == ("'", 1, ["bar"])
953 953 assert match(keys, "", extra=(3333,)) == ("", 0, ["'bar'", "4444"])
954 954 assert match(keys, "'", extra=("3333",)) == ("'", 1, [])
955 955 assert match(keys, "33") == ("", 0, ["3333"])
956 956
957 957 def test_dict_key_completion_closures(self):
958 958 ip = get_ipython()
959 959 complete = ip.Completer.complete
960 960 ip.Completer.auto_close_dict_keys = True
961 961
962 962 ip.user_ns["d"] = {
963 963 # tuple only
964 964 ("aa", 11): None,
965 965 # tuple and non-tuple
966 966 ("bb", 22): None,
967 967 "bb": None,
968 968 # non-tuple only
969 969 "cc": None,
970 970 # numeric tuple only
971 971 (77, "x"): None,
972 972 # numeric tuple and non-tuple
973 973 (88, "y"): None,
974 974 88: None,
975 975 # numeric non-tuple only
976 976 99: None,
977 977 }
978 978
979 979 _, matches = complete(line_buffer="d[")
980 980 # should append `, ` if matches a tuple only
981 981 self.assertIn("'aa', ", matches)
982 982 # should not append anything if matches a tuple and an item
983 983 self.assertIn("'bb'", matches)
984 984 # should append `]` if matches and item only
985 985 self.assertIn("'cc']", matches)
986 986
987 987 # should append `, ` if matches a tuple only
988 988 self.assertIn("77, ", matches)
989 989 # should not append anything if matches a tuple and an item
990 990 self.assertIn("88", matches)
991 991 # should append `]` if matches and item only
992 992 self.assertIn("99]", matches)
993 993
994 994 _, matches = complete(line_buffer="d['aa', ")
995 995 # should restrict matches to those matching tuple prefix
996 996 self.assertIn("11]", matches)
997 997 self.assertNotIn("'bb'", matches)
998 998 self.assertNotIn("'bb', ", matches)
999 999 self.assertNotIn("'bb']", matches)
1000 1000 self.assertNotIn("'cc'", matches)
1001 1001 self.assertNotIn("'cc', ", matches)
1002 1002 self.assertNotIn("'cc']", matches)
1003 1003 ip.Completer.auto_close_dict_keys = False
1004 1004
1005 1005 def test_dict_key_completion_string(self):
1006 1006 """Test dictionary key completion for string keys"""
1007 1007 ip = get_ipython()
1008 1008 complete = ip.Completer.complete
1009 1009
1010 1010 ip.user_ns["d"] = {"abc": None}
1011 1011
1012 1012 # check completion at different stages
1013 1013 _, matches = complete(line_buffer="d[")
1014 1014 self.assertIn("'abc'", matches)
1015 1015 self.assertNotIn("'abc']", matches)
1016 1016
1017 1017 _, matches = complete(line_buffer="d['")
1018 1018 self.assertIn("abc", matches)
1019 1019 self.assertNotIn("abc']", matches)
1020 1020
1021 1021 _, matches = complete(line_buffer="d['a")
1022 1022 self.assertIn("abc", matches)
1023 1023 self.assertNotIn("abc']", matches)
1024 1024
1025 1025 # check use of different quoting
1026 1026 _, matches = complete(line_buffer='d["')
1027 1027 self.assertIn("abc", matches)
1028 1028 self.assertNotIn('abc"]', matches)
1029 1029
1030 1030 _, matches = complete(line_buffer='d["a')
1031 1031 self.assertIn("abc", matches)
1032 1032 self.assertNotIn('abc"]', matches)
1033 1033
1034 1034 # check sensitivity to following context
1035 1035 _, matches = complete(line_buffer="d[]", cursor_pos=2)
1036 1036 self.assertIn("'abc'", matches)
1037 1037
1038 1038 _, matches = complete(line_buffer="d['']", cursor_pos=3)
1039 1039 self.assertIn("abc", matches)
1040 1040 self.assertNotIn("abc'", matches)
1041 1041 self.assertNotIn("abc']", matches)
1042 1042
1043 1043 # check multiple solutions are correctly returned and that noise is not
1044 1044 ip.user_ns["d"] = {
1045 1045 "abc": None,
1046 1046 "abd": None,
1047 1047 "bad": None,
1048 1048 object(): None,
1049 1049 5: None,
1050 1050 ("abe", None): None,
1051 1051 (None, "abf"): None
1052 1052 }
1053 1053
1054 1054 _, matches = complete(line_buffer="d['a")
1055 1055 self.assertIn("abc", matches)
1056 1056 self.assertIn("abd", matches)
1057 1057 self.assertNotIn("bad", matches)
1058 1058 self.assertNotIn("abe", matches)
1059 1059 self.assertNotIn("abf", matches)
1060 1060 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1061 1061
1062 1062 # check escaping and whitespace
1063 1063 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
1064 1064 _, matches = complete(line_buffer="d['a")
1065 1065 self.assertIn("a\\nb", matches)
1066 1066 self.assertIn("a\\'b", matches)
1067 1067 self.assertIn('a"b', matches)
1068 1068 self.assertIn("a word", matches)
1069 1069 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1070 1070
1071 1071 # - can complete on non-initial word of the string
1072 1072 _, matches = complete(line_buffer="d['a w")
1073 1073 self.assertIn("word", matches)
1074 1074
1075 1075 # - understands quote escaping
1076 1076 _, matches = complete(line_buffer="d['a\\'")
1077 1077 self.assertIn("b", matches)
1078 1078
1079 1079 # - default quoting should work like repr
1080 1080 _, matches = complete(line_buffer="d[")
1081 1081 self.assertIn('"a\'b"', matches)
1082 1082
1083 1083 # - when opening quote with ", possible to match with unescaped apostrophe
1084 1084 _, matches = complete(line_buffer="d[\"a'")
1085 1085 self.assertIn("b", matches)
1086 1086
1087 1087 # need to not split at delims that readline won't split at
1088 1088 if "-" not in ip.Completer.splitter.delims:
1089 1089 ip.user_ns["d"] = {"before-after": None}
1090 1090 _, matches = complete(line_buffer="d['before-af")
1091 1091 self.assertIn("before-after", matches)
1092 1092
1093 1093 # check completion on tuple-of-string keys at different stage - on first key
1094 1094 ip.user_ns["d"] = {('foo', 'bar'): None}
1095 1095 _, matches = complete(line_buffer="d[")
1096 1096 self.assertIn("'foo'", matches)
1097 1097 self.assertNotIn("'foo']", matches)
1098 1098 self.assertNotIn("'bar'", matches)
1099 1099 self.assertNotIn("foo", matches)
1100 1100 self.assertNotIn("bar", matches)
1101 1101
1102 1102 # - match the prefix
1103 1103 _, matches = complete(line_buffer="d['f")
1104 1104 self.assertIn("foo", matches)
1105 1105 self.assertNotIn("foo']", matches)
1106 1106 self.assertNotIn('foo"]', matches)
1107 1107 _, matches = complete(line_buffer="d['foo")
1108 1108 self.assertIn("foo", matches)
1109 1109
1110 1110 # - can complete on second key
1111 1111 _, matches = complete(line_buffer="d['foo', ")
1112 1112 self.assertIn("'bar'", matches)
1113 1113 _, matches = complete(line_buffer="d['foo', 'b")
1114 1114 self.assertIn("bar", matches)
1115 1115 self.assertNotIn("foo", matches)
1116 1116
1117 1117 # - does not propose missing keys
1118 1118 _, matches = complete(line_buffer="d['foo', 'f")
1119 1119 self.assertNotIn("bar", matches)
1120 1120 self.assertNotIn("foo", matches)
1121 1121
1122 1122 # check sensitivity to following context
1123 1123 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
1124 1124 self.assertIn("'bar'", matches)
1125 1125 self.assertNotIn("bar", matches)
1126 1126 self.assertNotIn("'foo'", matches)
1127 1127 self.assertNotIn("foo", matches)
1128 1128
1129 1129 _, matches = complete(line_buffer="d['']", cursor_pos=3)
1130 1130 self.assertIn("foo", matches)
1131 1131 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1132 1132
1133 1133 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
1134 1134 self.assertIn("foo", matches)
1135 1135 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1136 1136
1137 1137 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
1138 1138 self.assertIn("bar", matches)
1139 1139 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1140 1140
1141 1141 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1142 1142 self.assertIn("'bar'", matches)
1143 1143 self.assertNotIn("bar", matches)
1144 1144
1145 1145 # Can complete with longer tuple keys
1146 1146 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1147 1147
1148 1148 # - can complete second key
1149 1149 _, matches = complete(line_buffer="d['foo', 'b")
1150 1150 self.assertIn("bar", matches)
1151 1151 self.assertNotIn("foo", matches)
1152 1152 self.assertNotIn("foobar", matches)
1153 1153
1154 1154 # - can complete third key
1155 1155 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1156 1156 self.assertIn("foobar", matches)
1157 1157 self.assertNotIn("foo", matches)
1158 1158 self.assertNotIn("bar", matches)
1159 1159
1160 1160 def test_dict_key_completion_numbers(self):
1161 1161 ip = get_ipython()
1162 1162 complete = ip.Completer.complete
1163 1163
1164 1164 ip.user_ns["d"] = {
1165 1165 0xDEADBEEF: None, # 3735928559
1166 1166 1111: None,
1167 1167 1234: None,
1168 1168 "1999": None,
1169 1169 0b10101: None, # 21
1170 1170 22: None,
1171 1171 }
1172 1172 _, matches = complete(line_buffer="d[1")
1173 1173 self.assertIn("1111", matches)
1174 1174 self.assertIn("1234", matches)
1175 1175 self.assertNotIn("1999", matches)
1176 1176 self.assertNotIn("'1999'", matches)
1177 1177
1178 1178 _, matches = complete(line_buffer="d[0xdead")
1179 1179 self.assertIn("0xdeadbeef", matches)
1180 1180
1181 1181 _, matches = complete(line_buffer="d[2")
1182 1182 self.assertIn("21", matches)
1183 1183 self.assertIn("22", matches)
1184 1184
1185 1185 _, matches = complete(line_buffer="d[0b101")
1186 1186 self.assertIn("0b10101", matches)
1187 1187 self.assertIn("0b10110", matches)
1188 1188
1189 1189 def test_dict_key_completion_contexts(self):
1190 1190 """Test expression contexts in which dict key completion occurs"""
1191 1191 ip = get_ipython()
1192 1192 complete = ip.Completer.complete
1193 1193 d = {"abc": None}
1194 1194 ip.user_ns["d"] = d
1195 1195
1196 1196 class C:
1197 1197 data = d
1198 1198
1199 1199 ip.user_ns["C"] = C
1200 1200 ip.user_ns["get"] = lambda: d
1201 1201 ip.user_ns["nested"] = {"x": d}
1202 1202
1203 1203 def assert_no_completion(**kwargs):
1204 1204 _, matches = complete(**kwargs)
1205 1205 self.assertNotIn("abc", matches)
1206 1206 self.assertNotIn("abc'", matches)
1207 1207 self.assertNotIn("abc']", matches)
1208 1208 self.assertNotIn("'abc'", matches)
1209 1209 self.assertNotIn("'abc']", matches)
1210 1210
1211 1211 def assert_completion(**kwargs):
1212 1212 _, matches = complete(**kwargs)
1213 1213 self.assertIn("'abc'", matches)
1214 1214 self.assertNotIn("'abc']", matches)
1215 1215
1216 1216 # no completion after string closed, even if reopened
1217 1217 assert_no_completion(line_buffer="d['a'")
1218 1218 assert_no_completion(line_buffer='d["a"')
1219 1219 assert_no_completion(line_buffer="d['a' + ")
1220 1220 assert_no_completion(line_buffer="d['a' + '")
1221 1221
1222 1222 # completion in non-trivial expressions
1223 1223 assert_completion(line_buffer="+ d[")
1224 1224 assert_completion(line_buffer="(d[")
1225 1225 assert_completion(line_buffer="C.data[")
1226 1226
1227 1227 # nested dict completion
1228 1228 assert_completion(line_buffer="nested['x'][")
1229 1229
1230 1230 with evaluation_policy("minimal"):
1231 1231 with pytest.raises(AssertionError):
1232 1232 assert_completion(line_buffer="nested['x'][")
1233 1233
1234 1234 # greedy flag
1235 1235 def assert_completion(**kwargs):
1236 1236 _, matches = complete(**kwargs)
1237 1237 self.assertIn("get()['abc']", matches)
1238 1238
1239 1239 assert_no_completion(line_buffer="get()[")
1240 1240 with greedy_completion():
1241 1241 assert_completion(line_buffer="get()[")
1242 1242 assert_completion(line_buffer="get()['")
1243 1243 assert_completion(line_buffer="get()['a")
1244 1244 assert_completion(line_buffer="get()['ab")
1245 1245 assert_completion(line_buffer="get()['abc")
1246 1246
1247 1247 def test_dict_key_completion_bytes(self):
1248 1248 """Test handling of bytes in dict key completion"""
1249 1249 ip = get_ipython()
1250 1250 complete = ip.Completer.complete
1251 1251
1252 1252 ip.user_ns["d"] = {"abc": None, b"abd": None}
1253 1253
1254 1254 _, matches = complete(line_buffer="d[")
1255 1255 self.assertIn("'abc'", matches)
1256 1256 self.assertIn("b'abd'", matches)
1257 1257
1258 1258 if False: # not currently implemented
1259 1259 _, matches = complete(line_buffer="d[b")
1260 1260 self.assertIn("b'abd'", matches)
1261 1261 self.assertNotIn("b'abc'", matches)
1262 1262
1263 1263 _, matches = complete(line_buffer="d[b'")
1264 1264 self.assertIn("abd", matches)
1265 1265 self.assertNotIn("abc", matches)
1266 1266
1267 1267 _, matches = complete(line_buffer="d[B'")
1268 1268 self.assertIn("abd", matches)
1269 1269 self.assertNotIn("abc", matches)
1270 1270
1271 1271 _, matches = complete(line_buffer="d['")
1272 1272 self.assertIn("abc", matches)
1273 1273 self.assertNotIn("abd", matches)
1274 1274
1275 1275 def test_dict_key_completion_unicode_py3(self):
1276 1276 """Test handling of unicode in dict key completion"""
1277 1277 ip = get_ipython()
1278 1278 complete = ip.Completer.complete
1279 1279
1280 1280 ip.user_ns["d"] = {"a\u05d0": None}
1281 1281
1282 1282 # query using escape
1283 1283 if sys.platform != "win32":
1284 1284 # Known failure on Windows
1285 1285 _, matches = complete(line_buffer="d['a\\u05d0")
1286 1286 self.assertIn("u05d0", matches) # tokenized after \\
1287 1287
1288 1288 # query using character
1289 1289 _, matches = complete(line_buffer="d['a\u05d0")
1290 1290 self.assertIn("a\u05d0", matches)
1291 1291
1292 1292 with greedy_completion():
1293 1293 # query using escape
1294 1294 _, matches = complete(line_buffer="d['a\\u05d0")
1295 1295 self.assertIn("d['a\\u05d0']", matches) # tokenized after \\
1296 1296
1297 1297 # query using character
1298 1298 _, matches = complete(line_buffer="d['a\u05d0")
1299 1299 self.assertIn("d['a\u05d0']", matches)
1300 1300
1301 1301 @dec.skip_without("numpy")
1302 1302 def test_struct_array_key_completion(self):
1303 1303 """Test dict key completion applies to numpy struct arrays"""
1304 1304 import numpy
1305 1305
1306 1306 ip = get_ipython()
1307 1307 complete = ip.Completer.complete
1308 1308 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1309 1309 _, matches = complete(line_buffer="d['")
1310 1310 self.assertIn("hello", matches)
1311 1311 self.assertIn("world", matches)
1312 1312 # complete on the numpy struct itself
1313 1313 dt = numpy.dtype(
1314 1314 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1315 1315 )
1316 1316 x = numpy.zeros(2, dtype=dt)
1317 1317 ip.user_ns["d"] = x[1]
1318 1318 _, matches = complete(line_buffer="d['")
1319 1319 self.assertIn("my_head", matches)
1320 1320 self.assertIn("my_data", matches)
1321 1321
1322 1322 def completes_on_nested():
1323 1323 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1324 1324 _, matches = complete(line_buffer="d[1]['my_head']['")
1325 1325 self.assertTrue(any(["my_dt" in m for m in matches]))
1326 1326 self.assertTrue(any(["my_df" in m for m in matches]))
1327 1327 # complete on a nested level
1328 1328 with greedy_completion():
1329 1329 completes_on_nested()
1330 1330
1331 1331 with evaluation_policy("limited"):
1332 1332 completes_on_nested()
1333 1333
1334 1334 with evaluation_policy("minimal"):
1335 1335 with pytest.raises(AssertionError):
1336 1336 completes_on_nested()
1337 1337
1338 1338 @dec.skip_without("pandas")
1339 1339 def test_dataframe_key_completion(self):
1340 1340 """Test dict key completion applies to pandas DataFrames"""
1341 1341 import pandas
1342 1342
1343 1343 ip = get_ipython()
1344 1344 complete = ip.Completer.complete
1345 1345 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1346 1346 _, matches = complete(line_buffer="d['")
1347 1347 self.assertIn("hello", matches)
1348 1348 self.assertIn("world", matches)
1349 1349 _, matches = complete(line_buffer="d.loc[:, '")
1350 1350 self.assertIn("hello", matches)
1351 1351 self.assertIn("world", matches)
1352 1352 _, matches = complete(line_buffer="d.loc[1:, '")
1353 1353 self.assertIn("hello", matches)
1354 1354 _, matches = complete(line_buffer="d.loc[1:1, '")
1355 1355 self.assertIn("hello", matches)
1356 1356 _, matches = complete(line_buffer="d.loc[1:1:-1, '")
1357 1357 self.assertIn("hello", matches)
1358 1358 _, matches = complete(line_buffer="d.loc[::, '")
1359 1359 self.assertIn("hello", matches)
1360 1360
1361 1361 def test_dict_key_completion_invalids(self):
1362 1362 """Smoke test cases dict key completion can't handle"""
1363 1363 ip = get_ipython()
1364 1364 complete = ip.Completer.complete
1365 1365
1366 1366 ip.user_ns["no_getitem"] = None
1367 1367 ip.user_ns["no_keys"] = []
1368 1368 ip.user_ns["cant_call_keys"] = dict
1369 1369 ip.user_ns["empty"] = {}
1370 1370 ip.user_ns["d"] = {"abc": 5}
1371 1371
1372 1372 _, matches = complete(line_buffer="no_getitem['")
1373 1373 _, matches = complete(line_buffer="no_keys['")
1374 1374 _, matches = complete(line_buffer="cant_call_keys['")
1375 1375 _, matches = complete(line_buffer="empty['")
1376 1376 _, matches = complete(line_buffer="name_error['")
1377 1377 _, matches = complete(line_buffer="d['\\") # incomplete escape
1378 1378
1379 1379 def test_object_key_completion(self):
1380 1380 ip = get_ipython()
1381 1381 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1382 1382
1383 1383 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1384 1384 self.assertIn("qwerty", matches)
1385 1385 self.assertIn("qwick", matches)
1386 1386
1387 1387 def test_class_key_completion(self):
1388 1388 ip = get_ipython()
1389 1389 NamedInstanceClass("qwerty")
1390 1390 NamedInstanceClass("qwick")
1391 1391 ip.user_ns["named_instance_class"] = NamedInstanceClass
1392 1392
1393 1393 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1394 1394 self.assertIn("qwerty", matches)
1395 1395 self.assertIn("qwick", matches)
1396 1396
1397 1397 def test_tryimport(self):
1398 1398 """
1399 1399 Test that try-import don't crash on trailing dot, and import modules before
1400 1400 """
1401 1401 from IPython.core.completerlib import try_import
1402 1402
1403 1403 assert try_import("IPython.")
1404 1404
1405 1405 def test_aimport_module_completer(self):
1406 1406 ip = get_ipython()
1407 1407 _, matches = ip.complete("i", "%aimport i")
1408 1408 self.assertIn("io", matches)
1409 1409 self.assertNotIn("int", matches)
1410 1410
1411 1411 def test_nested_import_module_completer(self):
1412 1412 ip = get_ipython()
1413 1413 _, matches = ip.complete(None, "import IPython.co", 17)
1414 1414 self.assertIn("IPython.core", matches)
1415 1415 self.assertNotIn("import IPython.core", matches)
1416 1416 self.assertNotIn("IPython.display", matches)
1417 1417
1418 1418 def test_import_module_completer(self):
1419 1419 ip = get_ipython()
1420 1420 _, matches = ip.complete("i", "import i")
1421 1421 self.assertIn("io", matches)
1422 1422 self.assertNotIn("int", matches)
1423 1423
1424 1424 def test_from_module_completer(self):
1425 1425 ip = get_ipython()
1426 1426 _, matches = ip.complete("B", "from io import B", 16)
1427 1427 self.assertIn("BytesIO", matches)
1428 1428 self.assertNotIn("BaseException", matches)
1429 1429
1430 1430 def test_snake_case_completion(self):
1431 1431 ip = get_ipython()
1432 1432 ip.Completer.use_jedi = False
1433 1433 ip.user_ns["some_three"] = 3
1434 1434 ip.user_ns["some_four"] = 4
1435 1435 _, matches = ip.complete("s_", "print(s_f")
1436 1436 self.assertIn("some_three", matches)
1437 1437 self.assertIn("some_four", matches)
1438 1438
1439 1439 def test_mix_terms(self):
1440 1440 ip = get_ipython()
1441 1441 from textwrap import dedent
1442 1442
1443 1443 ip.Completer.use_jedi = False
1444 1444 ip.ex(
1445 1445 dedent(
1446 1446 """
1447 1447 class Test:
1448 1448 def meth(self, meth_arg1):
1449 1449 print("meth")
1450 1450
1451 1451 def meth_1(self, meth1_arg1, meth1_arg2):
1452 1452 print("meth1")
1453 1453
1454 1454 def meth_2(self, meth2_arg1, meth2_arg2):
1455 1455 print("meth2")
1456 1456 test = Test()
1457 1457 """
1458 1458 )
1459 1459 )
1460 1460 _, matches = ip.complete(None, "test.meth(")
1461 1461 self.assertIn("meth_arg1=", matches)
1462 1462 self.assertNotIn("meth2_arg1=", matches)
1463 1463
1464 1464 def test_percent_symbol_restrict_to_magic_completions(self):
1465 1465 ip = get_ipython()
1466 1466 completer = ip.Completer
1467 1467 text = "%a"
1468 1468
1469 1469 with provisionalcompleter():
1470 1470 completer.use_jedi = True
1471 1471 completions = completer.completions(text, len(text))
1472 1472 for c in completions:
1473 1473 self.assertEqual(c.text[0], "%")
1474 1474
1475 1475 def test_fwd_unicode_restricts(self):
1476 1476 ip = get_ipython()
1477 1477 completer = ip.Completer
1478 1478 text = "\\ROMAN NUMERAL FIVE"
1479 1479
1480 1480 with provisionalcompleter():
1481 1481 completer.use_jedi = True
1482 1482 completions = [
1483 1483 completion.text for completion in completer.completions(text, len(text))
1484 1484 ]
1485 1485 self.assertEqual(completions, ["\u2164"])
1486 1486
1487 1487 def test_dict_key_restrict_to_dicts(self):
1488 1488 """Test that dict key suppresses non-dict completion items"""
1489 1489 ip = get_ipython()
1490 1490 c = ip.Completer
1491 1491 d = {"abc": None}
1492 1492 ip.user_ns["d"] = d
1493 1493
1494 1494 text = 'd["a'
1495 1495
1496 1496 def _():
1497 1497 with provisionalcompleter():
1498 1498 c.use_jedi = True
1499 1499 return [
1500 1500 completion.text for completion in c.completions(text, len(text))
1501 1501 ]
1502 1502
1503 1503 completions = _()
1504 1504 self.assertEqual(completions, ["abc"])
1505 1505
1506 1506 # check that it can be disabled in granular manner:
1507 1507 cfg = Config()
1508 1508 cfg.IPCompleter.suppress_competing_matchers = {
1509 1509 "IPCompleter.dict_key_matcher": False
1510 1510 }
1511 1511 c.update_config(cfg)
1512 1512
1513 1513 completions = _()
1514 1514 self.assertIn("abc", completions)
1515 1515 self.assertGreater(len(completions), 1)
1516 1516
1517 1517 def test_matcher_suppression(self):
1518 1518 @completion_matcher(identifier="a_matcher")
1519 1519 def a_matcher(text):
1520 1520 return ["completion_a"]
1521 1521
1522 1522 @completion_matcher(identifier="b_matcher", api_version=2)
1523 1523 def b_matcher(context: CompletionContext):
1524 1524 text = context.token
1525 1525 result = {"completions": [SimpleCompletion("completion_b")]}
1526 1526
1527 1527 if text == "suppress c":
1528 1528 result["suppress"] = {"c_matcher"}
1529 1529
1530 1530 if text.startswith("suppress all"):
1531 1531 result["suppress"] = True
1532 1532 if text == "suppress all but c":
1533 1533 result["do_not_suppress"] = {"c_matcher"}
1534 1534 if text == "suppress all but a":
1535 1535 result["do_not_suppress"] = {"a_matcher"}
1536 1536
1537 1537 return result
1538 1538
1539 1539 @completion_matcher(identifier="c_matcher")
1540 1540 def c_matcher(text):
1541 1541 return ["completion_c"]
1542 1542
1543 1543 with custom_matchers([a_matcher, b_matcher, c_matcher]):
1544 1544 ip = get_ipython()
1545 1545 c = ip.Completer
1546 1546
1547 1547 def _(text, expected):
1548 1548 c.use_jedi = False
1549 1549 s, matches = c.complete(text)
1550 1550 self.assertEqual(expected, matches)
1551 1551
1552 1552 _("do not suppress", ["completion_a", "completion_b", "completion_c"])
1553 1553 _("suppress all", ["completion_b"])
1554 1554 _("suppress all but a", ["completion_a", "completion_b"])
1555 1555 _("suppress all but c", ["completion_b", "completion_c"])
1556 1556
1557 1557 def configure(suppression_config):
1558 1558 cfg = Config()
1559 1559 cfg.IPCompleter.suppress_competing_matchers = suppression_config
1560 1560 c.update_config(cfg)
1561 1561
1562 1562 # test that configuration takes priority over the run-time decisions
1563 1563
1564 1564 configure(False)
1565 1565 _("suppress all", ["completion_a", "completion_b", "completion_c"])
1566 1566
1567 1567 configure({"b_matcher": False})
1568 1568 _("suppress all", ["completion_a", "completion_b", "completion_c"])
1569 1569
1570 1570 configure({"a_matcher": False})
1571 1571 _("suppress all", ["completion_b"])
1572 1572
1573 1573 configure({"b_matcher": True})
1574 1574 _("do not suppress", ["completion_b"])
1575 1575
1576 1576 configure(True)
1577 1577 _("do not suppress", ["completion_a"])
1578 1578
1579 1579 def test_matcher_suppression_with_iterator(self):
1580 1580 @completion_matcher(identifier="matcher_returning_iterator")
1581 1581 def matcher_returning_iterator(text):
1582 1582 return iter(["completion_iter"])
1583 1583
1584 1584 @completion_matcher(identifier="matcher_returning_list")
1585 1585 def matcher_returning_list(text):
1586 1586 return ["completion_list"]
1587 1587
1588 1588 with custom_matchers([matcher_returning_iterator, matcher_returning_list]):
1589 1589 ip = get_ipython()
1590 1590 c = ip.Completer
1591 1591
1592 1592 def _(text, expected):
1593 1593 c.use_jedi = False
1594 1594 s, matches = c.complete(text)
1595 1595 self.assertEqual(expected, matches)
1596 1596
1597 1597 def configure(suppression_config):
1598 1598 cfg = Config()
1599 1599 cfg.IPCompleter.suppress_competing_matchers = suppression_config
1600 1600 c.update_config(cfg)
1601 1601
1602 1602 configure(False)
1603 1603 _("---", ["completion_iter", "completion_list"])
1604 1604
1605 1605 configure(True)
1606 1606 _("---", ["completion_iter"])
1607 1607
1608 1608 configure(None)
1609 1609 _("--", ["completion_iter", "completion_list"])
1610 1610
1611 1611 def test_matcher_suppression_with_jedi(self):
1612 1612 ip = get_ipython()
1613 1613 c = ip.Completer
1614 1614 c.use_jedi = True
1615 1615
1616 1616 def configure(suppression_config):
1617 1617 cfg = Config()
1618 1618 cfg.IPCompleter.suppress_competing_matchers = suppression_config
1619 1619 c.update_config(cfg)
1620 1620
1621 1621 def _():
1622 1622 with provisionalcompleter():
1623 1623 matches = [completion.text for completion in c.completions("dict.", 5)]
1624 1624 self.assertIn("keys", matches)
1625 1625
1626 1626 configure(False)
1627 1627 _()
1628 1628
1629 1629 configure(True)
1630 1630 _()
1631 1631
1632 1632 configure(None)
1633 1633 _()
1634 1634
1635 1635 def test_matcher_disabling(self):
1636 1636 @completion_matcher(identifier="a_matcher")
1637 1637 def a_matcher(text):
1638 1638 return ["completion_a"]
1639 1639
1640 1640 @completion_matcher(identifier="b_matcher")
1641 1641 def b_matcher(text):
1642 1642 return ["completion_b"]
1643 1643
1644 1644 def _(expected):
1645 1645 s, matches = c.complete("completion_")
1646 1646 self.assertEqual(expected, matches)
1647 1647
1648 1648 with custom_matchers([a_matcher, b_matcher]):
1649 1649 ip = get_ipython()
1650 1650 c = ip.Completer
1651 1651
1652 1652 _(["completion_a", "completion_b"])
1653 1653
1654 1654 cfg = Config()
1655 1655 cfg.IPCompleter.disable_matchers = ["b_matcher"]
1656 1656 c.update_config(cfg)
1657 1657
1658 1658 _(["completion_a"])
1659 1659
1660 1660 cfg.IPCompleter.disable_matchers = []
1661 1661 c.update_config(cfg)
1662 1662
1663 1663 def test_matcher_priority(self):
1664 1664 @completion_matcher(identifier="a_matcher", priority=0, api_version=2)
1665 1665 def a_matcher(text):
1666 1666 return {"completions": [SimpleCompletion("completion_a")], "suppress": True}
1667 1667
1668 1668 @completion_matcher(identifier="b_matcher", priority=2, api_version=2)
1669 1669 def b_matcher(text):
1670 1670 return {"completions": [SimpleCompletion("completion_b")], "suppress": True}
1671 1671
1672 1672 def _(expected):
1673 1673 s, matches = c.complete("completion_")
1674 1674 self.assertEqual(expected, matches)
1675 1675
1676 1676 with custom_matchers([a_matcher, b_matcher]):
1677 1677 ip = get_ipython()
1678 1678 c = ip.Completer
1679 1679
1680 1680 _(["completion_b"])
1681 1681 a_matcher.matcher_priority = 3
1682 1682 _(["completion_a"])
1683 1683
1684 1684
1685 1685 @pytest.mark.parametrize(
1686 1686 "input, expected",
1687 1687 [
1688 1688 ["1.234", "1.234"],
1689 1689 # should match signed numbers
1690 1690 ["+1", "+1"],
1691 1691 ["-1", "-1"],
1692 1692 ["-1.0", "-1.0"],
1693 1693 ["-1.", "-1."],
1694 1694 ["+1.", "+1."],
1695 1695 [".1", ".1"],
1696 1696 # should not match non-numbers
1697 1697 ["1..", None],
1698 1698 ["..", None],
1699 1699 [".1.", None],
1700 1700 # should match after comma
1701 1701 [",1", "1"],
1702 1702 [", 1", "1"],
1703 1703 [", .1", ".1"],
1704 1704 [", +.1", "+.1"],
1705 1705 # should not match after trailing spaces
1706 1706 [".1 ", None],
1707 1707 # some complex cases
1708 1708 ["0b_0011_1111_0100_1110", "0b_0011_1111_0100_1110"],
1709 1709 ["0xdeadbeef", "0xdeadbeef"],
1710 1710 ["0b_1110_0101", "0b_1110_0101"],
1711 1711 # should not match if in an operation
1712 1712 ["1 + 1", None],
1713 1713 [", 1 + 1", None],
1714 1714 ],
1715 1715 )
1716 1716 def test_match_numeric_literal_for_dict_key(input, expected):
1717 1717 assert _match_number_in_dict_key_prefix(input) == expected
General Comments 0
You need to be logged in to leave comments. Login now