##// END OF EJS Templates
Remove parso xfail for Python>=3.11...
Nikita Kniazev -
Show More
@@ -1,1280 +1,1275 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for the IPython tab-completion machinery."""
2 """Tests for the IPython tab-completion machinery."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import pytest
8 import pytest
9 import sys
9 import sys
10 import textwrap
10 import textwrap
11 import unittest
11 import unittest
12
12
13 from contextlib import contextmanager
13 from contextlib import contextmanager
14
14
15 from traitlets.config.loader import Config
15 from traitlets.config.loader import Config
16 from IPython import get_ipython
16 from IPython import get_ipython
17 from IPython.core import completer
17 from IPython.core import completer
18 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
18 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
19 from IPython.utils.generics import complete_object
19 from IPython.utils.generics import complete_object
20 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
21
21
22 from IPython.core.completer import (
22 from IPython.core.completer import (
23 Completion,
23 Completion,
24 provisionalcompleter,
24 provisionalcompleter,
25 match_dict_keys,
25 match_dict_keys,
26 _deduplicate_completions,
26 _deduplicate_completions,
27 )
27 )
28
28
29 if sys.version_info >= (3, 10):
29 if sys.version_info >= (3, 10):
30 import jedi
30 import jedi
31 from pkg_resources import parse_version
31 from pkg_resources import parse_version
32
32
33 # Requires https://github.com/davidhalter/jedi/pull/1795
33 # Requires https://github.com/davidhalter/jedi/pull/1795
34 jedi_issue = parse_version(jedi.__version__) <= parse_version("0.18.0")
34 jedi_issue = parse_version(jedi.__version__) <= parse_version("0.18.0")
35 else:
35 else:
36 jedi_issue = False
36 jedi_issue = False
37
37
38 # -----------------------------------------------------------------------------
38 # -----------------------------------------------------------------------------
39 # Test functions
39 # Test functions
40 # -----------------------------------------------------------------------------
40 # -----------------------------------------------------------------------------
41
41
42 def recompute_unicode_ranges():
42 def recompute_unicode_ranges():
43 """
43 """
44 utility to recompute the largest unicode range without any characters
44 utility to recompute the largest unicode range without any characters
45
45
46 use to recompute the gap in the global _UNICODE_RANGES of completer.py
46 use to recompute the gap in the global _UNICODE_RANGES of completer.py
47 """
47 """
48 import itertools
48 import itertools
49 import unicodedata
49 import unicodedata
50 valid = []
50 valid = []
51 for c in range(0,0x10FFFF + 1):
51 for c in range(0,0x10FFFF + 1):
52 try:
52 try:
53 unicodedata.name(chr(c))
53 unicodedata.name(chr(c))
54 except ValueError:
54 except ValueError:
55 continue
55 continue
56 valid.append(c)
56 valid.append(c)
57
57
58 def ranges(i):
58 def ranges(i):
59 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
59 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
60 b = list(b)
60 b = list(b)
61 yield b[0][1], b[-1][1]
61 yield b[0][1], b[-1][1]
62
62
63 rg = list(ranges(valid))
63 rg = list(ranges(valid))
64 lens = []
64 lens = []
65 gap_lens = []
65 gap_lens = []
66 pstart, pstop = 0,0
66 pstart, pstop = 0,0
67 for start, stop in rg:
67 for start, stop in rg:
68 lens.append(stop-start)
68 lens.append(stop-start)
69 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
69 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
70 pstart, pstop = start, stop
70 pstart, pstop = start, stop
71
71
72 return sorted(gap_lens)[-1]
72 return sorted(gap_lens)[-1]
73
73
74
74
75
75
76 def test_unicode_range():
76 def test_unicode_range():
77 """
77 """
78 Test that the ranges we test for unicode names give the same number of
78 Test that the ranges we test for unicode names give the same number of
79 results than testing the full length.
79 results than testing the full length.
80 """
80 """
81 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
81 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
82
82
83 expected_list = _unicode_name_compute([(0, 0x110000)])
83 expected_list = _unicode_name_compute([(0, 0x110000)])
84 test = _unicode_name_compute(_UNICODE_RANGES)
84 test = _unicode_name_compute(_UNICODE_RANGES)
85 len_exp = len(expected_list)
85 len_exp = len(expected_list)
86 len_test = len(test)
86 len_test = len(test)
87
87
88 # do not inline the len() or on error pytest will try to print the 130 000 +
88 # do not inline the len() or on error pytest will try to print the 130 000 +
89 # elements.
89 # elements.
90 message = None
90 message = None
91 if len_exp != len_test or len_exp > 131808:
91 if len_exp != len_test or len_exp > 131808:
92 size, start, stop, prct = recompute_unicode_ranges()
92 size, start, stop, prct = recompute_unicode_ranges()
93 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
93 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
94 likely due to a new release of Python. We've find that the biggest gap
94 likely due to a new release of Python. We've find that the biggest gap
95 in unicode characters has reduces in size to be {size} characters
95 in unicode characters has reduces in size to be {size} characters
96 ({prct}), from {start}, to {stop}. In completer.py likely update to
96 ({prct}), from {start}, to {stop}. In completer.py likely update to
97
97
98 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
98 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
99
99
100 And update the assertion below to use
100 And update the assertion below to use
101
101
102 len_exp <= {len_exp}
102 len_exp <= {len_exp}
103 """
103 """
104 assert len_exp == len_test, message
104 assert len_exp == len_test, message
105
105
106 # fail if new unicode symbols have been added.
106 # fail if new unicode symbols have been added.
107 assert len_exp <= 138552, message
107 assert len_exp <= 138552, message
108
108
109
109
110 @contextmanager
110 @contextmanager
111 def greedy_completion():
111 def greedy_completion():
112 ip = get_ipython()
112 ip = get_ipython()
113 greedy_original = ip.Completer.greedy
113 greedy_original = ip.Completer.greedy
114 try:
114 try:
115 ip.Completer.greedy = True
115 ip.Completer.greedy = True
116 yield
116 yield
117 finally:
117 finally:
118 ip.Completer.greedy = greedy_original
118 ip.Completer.greedy = greedy_original
119
119
120
120
121 def test_protect_filename():
121 def test_protect_filename():
122 if sys.platform == "win32":
122 if sys.platform == "win32":
123 pairs = [
123 pairs = [
124 ("abc", "abc"),
124 ("abc", "abc"),
125 (" abc", '" abc"'),
125 (" abc", '" abc"'),
126 ("a bc", '"a bc"'),
126 ("a bc", '"a bc"'),
127 ("a bc", '"a bc"'),
127 ("a bc", '"a bc"'),
128 (" bc", '" bc"'),
128 (" bc", '" bc"'),
129 ]
129 ]
130 else:
130 else:
131 pairs = [
131 pairs = [
132 ("abc", "abc"),
132 ("abc", "abc"),
133 (" abc", r"\ abc"),
133 (" abc", r"\ abc"),
134 ("a bc", r"a\ bc"),
134 ("a bc", r"a\ bc"),
135 ("a bc", r"a\ \ bc"),
135 ("a bc", r"a\ \ bc"),
136 (" bc", r"\ \ bc"),
136 (" bc", r"\ \ bc"),
137 # On posix, we also protect parens and other special characters.
137 # On posix, we also protect parens and other special characters.
138 ("a(bc", r"a\(bc"),
138 ("a(bc", r"a\(bc"),
139 ("a)bc", r"a\)bc"),
139 ("a)bc", r"a\)bc"),
140 ("a( )bc", r"a\(\ \)bc"),
140 ("a( )bc", r"a\(\ \)bc"),
141 ("a[1]bc", r"a\[1\]bc"),
141 ("a[1]bc", r"a\[1\]bc"),
142 ("a{1}bc", r"a\{1\}bc"),
142 ("a{1}bc", r"a\{1\}bc"),
143 ("a#bc", r"a\#bc"),
143 ("a#bc", r"a\#bc"),
144 ("a?bc", r"a\?bc"),
144 ("a?bc", r"a\?bc"),
145 ("a=bc", r"a\=bc"),
145 ("a=bc", r"a\=bc"),
146 ("a\\bc", r"a\\bc"),
146 ("a\\bc", r"a\\bc"),
147 ("a|bc", r"a\|bc"),
147 ("a|bc", r"a\|bc"),
148 ("a;bc", r"a\;bc"),
148 ("a;bc", r"a\;bc"),
149 ("a:bc", r"a\:bc"),
149 ("a:bc", r"a\:bc"),
150 ("a'bc", r"a\'bc"),
150 ("a'bc", r"a\'bc"),
151 ("a*bc", r"a\*bc"),
151 ("a*bc", r"a\*bc"),
152 ('a"bc', r"a\"bc"),
152 ('a"bc', r"a\"bc"),
153 ("a^bc", r"a\^bc"),
153 ("a^bc", r"a\^bc"),
154 ("a&bc", r"a\&bc"),
154 ("a&bc", r"a\&bc"),
155 ]
155 ]
156 # run the actual tests
156 # run the actual tests
157 for s1, s2 in pairs:
157 for s1, s2 in pairs:
158 s1p = completer.protect_filename(s1)
158 s1p = completer.protect_filename(s1)
159 assert s1p == s2
159 assert s1p == s2
160
160
161
161
162 def check_line_split(splitter, test_specs):
162 def check_line_split(splitter, test_specs):
163 for part1, part2, split in test_specs:
163 for part1, part2, split in test_specs:
164 cursor_pos = len(part1)
164 cursor_pos = len(part1)
165 line = part1 + part2
165 line = part1 + part2
166 out = splitter.split_line(line, cursor_pos)
166 out = splitter.split_line(line, cursor_pos)
167 assert out == split
167 assert out == split
168
168
169
169
170 def test_line_split():
170 def test_line_split():
171 """Basic line splitter test with default specs."""
171 """Basic line splitter test with default specs."""
172 sp = completer.CompletionSplitter()
172 sp = completer.CompletionSplitter()
173 # The format of the test specs is: part1, part2, expected answer. Parts 1
173 # The format of the test specs is: part1, part2, expected answer. Parts 1
174 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
174 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
175 # was at the end of part1. So an empty part2 represents someone hitting
175 # was at the end of part1. So an empty part2 represents someone hitting
176 # tab at the end of the line, the most common case.
176 # tab at the end of the line, the most common case.
177 t = [
177 t = [
178 ("run some/scrip", "", "some/scrip"),
178 ("run some/scrip", "", "some/scrip"),
179 ("run scripts/er", "ror.py foo", "scripts/er"),
179 ("run scripts/er", "ror.py foo", "scripts/er"),
180 ("echo $HOM", "", "HOM"),
180 ("echo $HOM", "", "HOM"),
181 ("print sys.pa", "", "sys.pa"),
181 ("print sys.pa", "", "sys.pa"),
182 ("print(sys.pa", "", "sys.pa"),
182 ("print(sys.pa", "", "sys.pa"),
183 ("execfile('scripts/er", "", "scripts/er"),
183 ("execfile('scripts/er", "", "scripts/er"),
184 ("a[x.", "", "x."),
184 ("a[x.", "", "x."),
185 ("a[x.", "y", "x."),
185 ("a[x.", "y", "x."),
186 ('cd "some_file/', "", "some_file/"),
186 ('cd "some_file/', "", "some_file/"),
187 ]
187 ]
188 check_line_split(sp, t)
188 check_line_split(sp, t)
189 # Ensure splitting works OK with unicode by re-running the tests with
189 # Ensure splitting works OK with unicode by re-running the tests with
190 # all inputs turned into unicode
190 # all inputs turned into unicode
191 check_line_split(sp, [map(str, p) for p in t])
191 check_line_split(sp, [map(str, p) for p in t])
192
192
193
193
194 class NamedInstanceClass:
194 class NamedInstanceClass:
195 instances = {}
195 instances = {}
196
196
197 def __init__(self, name):
197 def __init__(self, name):
198 self.instances[name] = self
198 self.instances[name] = self
199
199
200 @classmethod
200 @classmethod
201 def _ipython_key_completions_(cls):
201 def _ipython_key_completions_(cls):
202 return cls.instances.keys()
202 return cls.instances.keys()
203
203
204
204
205 class KeyCompletable:
205 class KeyCompletable:
206 def __init__(self, things=()):
206 def __init__(self, things=()):
207 self.things = things
207 self.things = things
208
208
209 def _ipython_key_completions_(self):
209 def _ipython_key_completions_(self):
210 return list(self.things)
210 return list(self.things)
211
211
212
212
213 @pytest.mark.xfail(
214 sys.version_info >= (3, 11),
215 reason="parso does not support 3.11 yet",
216 raises=NotImplementedError,
217 )
218 class TestCompleter(unittest.TestCase):
213 class TestCompleter(unittest.TestCase):
219 def setUp(self):
214 def setUp(self):
220 """
215 """
221 We want to silence all PendingDeprecationWarning when testing the completer
216 We want to silence all PendingDeprecationWarning when testing the completer
222 """
217 """
223 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
218 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
224 self._assertwarns.__enter__()
219 self._assertwarns.__enter__()
225
220
226 def tearDown(self):
221 def tearDown(self):
227 try:
222 try:
228 self._assertwarns.__exit__(None, None, None)
223 self._assertwarns.__exit__(None, None, None)
229 except AssertionError:
224 except AssertionError:
230 pass
225 pass
231
226
232 def test_custom_completion_error(self):
227 def test_custom_completion_error(self):
233 """Test that errors from custom attribute completers are silenced."""
228 """Test that errors from custom attribute completers are silenced."""
234 ip = get_ipython()
229 ip = get_ipython()
235
230
236 class A:
231 class A:
237 pass
232 pass
238
233
239 ip.user_ns["x"] = A()
234 ip.user_ns["x"] = A()
240
235
241 @complete_object.register(A)
236 @complete_object.register(A)
242 def complete_A(a, existing_completions):
237 def complete_A(a, existing_completions):
243 raise TypeError("this should be silenced")
238 raise TypeError("this should be silenced")
244
239
245 ip.complete("x.")
240 ip.complete("x.")
246
241
247 def test_custom_completion_ordering(self):
242 def test_custom_completion_ordering(self):
248 """Test that errors from custom attribute completers are silenced."""
243 """Test that errors from custom attribute completers are silenced."""
249 ip = get_ipython()
244 ip = get_ipython()
250
245
251 _, matches = ip.complete('in')
246 _, matches = ip.complete('in')
252 assert matches.index('input') < matches.index('int')
247 assert matches.index('input') < matches.index('int')
253
248
254 def complete_example(a):
249 def complete_example(a):
255 return ['example2', 'example1']
250 return ['example2', 'example1']
256
251
257 ip.Completer.custom_completers.add_re('ex*', complete_example)
252 ip.Completer.custom_completers.add_re('ex*', complete_example)
258 _, matches = ip.complete('ex')
253 _, matches = ip.complete('ex')
259 assert matches.index('example2') < matches.index('example1')
254 assert matches.index('example2') < matches.index('example1')
260
255
261 def test_unicode_completions(self):
256 def test_unicode_completions(self):
262 ip = get_ipython()
257 ip = get_ipython()
263 # Some strings that trigger different types of completion. Check them both
258 # Some strings that trigger different types of completion. Check them both
264 # in str and unicode forms
259 # in str and unicode forms
265 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
260 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
266 for t in s + list(map(str, s)):
261 for t in s + list(map(str, s)):
267 # We don't need to check exact completion values (they may change
262 # We don't need to check exact completion values (they may change
268 # depending on the state of the namespace, but at least no exceptions
263 # depending on the state of the namespace, but at least no exceptions
269 # should be thrown and the return value should be a pair of text, list
264 # should be thrown and the return value should be a pair of text, list
270 # values.
265 # values.
271 text, matches = ip.complete(t)
266 text, matches = ip.complete(t)
272 self.assertIsInstance(text, str)
267 self.assertIsInstance(text, str)
273 self.assertIsInstance(matches, list)
268 self.assertIsInstance(matches, list)
274
269
275 def test_latex_completions(self):
270 def test_latex_completions(self):
276 from IPython.core.latex_symbols import latex_symbols
271 from IPython.core.latex_symbols import latex_symbols
277 import random
272 import random
278
273
279 ip = get_ipython()
274 ip = get_ipython()
280 # Test some random unicode symbols
275 # Test some random unicode symbols
281 keys = random.sample(sorted(latex_symbols), 10)
276 keys = random.sample(sorted(latex_symbols), 10)
282 for k in keys:
277 for k in keys:
283 text, matches = ip.complete(k)
278 text, matches = ip.complete(k)
284 self.assertEqual(text, k)
279 self.assertEqual(text, k)
285 self.assertEqual(matches, [latex_symbols[k]])
280 self.assertEqual(matches, [latex_symbols[k]])
286 # Test a more complex line
281 # Test a more complex line
287 text, matches = ip.complete("print(\\alpha")
282 text, matches = ip.complete("print(\\alpha")
288 self.assertEqual(text, "\\alpha")
283 self.assertEqual(text, "\\alpha")
289 self.assertEqual(matches[0], latex_symbols["\\alpha"])
284 self.assertEqual(matches[0], latex_symbols["\\alpha"])
290 # Test multiple matching latex symbols
285 # Test multiple matching latex symbols
291 text, matches = ip.complete("\\al")
286 text, matches = ip.complete("\\al")
292 self.assertIn("\\alpha", matches)
287 self.assertIn("\\alpha", matches)
293 self.assertIn("\\aleph", matches)
288 self.assertIn("\\aleph", matches)
294
289
295 def test_latex_no_results(self):
290 def test_latex_no_results(self):
296 """
291 """
297 forward latex should really return nothing in either field if nothing is found.
292 forward latex should really return nothing in either field if nothing is found.
298 """
293 """
299 ip = get_ipython()
294 ip = get_ipython()
300 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
295 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
301 self.assertEqual(text, "")
296 self.assertEqual(text, "")
302 self.assertEqual(matches, ())
297 self.assertEqual(matches, ())
303
298
304 def test_back_latex_completion(self):
299 def test_back_latex_completion(self):
305 ip = get_ipython()
300 ip = get_ipython()
306
301
307 # do not return more than 1 matches for \beta, only the latex one.
302 # do not return more than 1 matches for \beta, only the latex one.
308 name, matches = ip.complete("\\Ξ²")
303 name, matches = ip.complete("\\Ξ²")
309 self.assertEqual(matches, ["\\beta"])
304 self.assertEqual(matches, ["\\beta"])
310
305
311 def test_back_unicode_completion(self):
306 def test_back_unicode_completion(self):
312 ip = get_ipython()
307 ip = get_ipython()
313
308
314 name, matches = ip.complete("\\β…€")
309 name, matches = ip.complete("\\β…€")
315 self.assertEqual(matches, ("\\ROMAN NUMERAL FIVE",))
310 self.assertEqual(matches, ("\\ROMAN NUMERAL FIVE",))
316
311
317 def test_forward_unicode_completion(self):
312 def test_forward_unicode_completion(self):
318 ip = get_ipython()
313 ip = get_ipython()
319
314
320 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
315 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
321 self.assertEqual(matches, ["β…€"]) # This is not a V
316 self.assertEqual(matches, ["β…€"]) # This is not a V
322 self.assertEqual(matches, ["\u2164"]) # same as above but explicit.
317 self.assertEqual(matches, ["\u2164"]) # same as above but explicit.
323
318
324 def test_delim_setting(self):
319 def test_delim_setting(self):
325 sp = completer.CompletionSplitter()
320 sp = completer.CompletionSplitter()
326 sp.delims = " "
321 sp.delims = " "
327 self.assertEqual(sp.delims, " ")
322 self.assertEqual(sp.delims, " ")
328 self.assertEqual(sp._delim_expr, r"[\ ]")
323 self.assertEqual(sp._delim_expr, r"[\ ]")
329
324
330 def test_spaces(self):
325 def test_spaces(self):
331 """Test with only spaces as split chars."""
326 """Test with only spaces as split chars."""
332 sp = completer.CompletionSplitter()
327 sp = completer.CompletionSplitter()
333 sp.delims = " "
328 sp.delims = " "
334 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
329 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
335 check_line_split(sp, t)
330 check_line_split(sp, t)
336
331
337 def test_has_open_quotes1(self):
332 def test_has_open_quotes1(self):
338 for s in ["'", "'''", "'hi' '"]:
333 for s in ["'", "'''", "'hi' '"]:
339 self.assertEqual(completer.has_open_quotes(s), "'")
334 self.assertEqual(completer.has_open_quotes(s), "'")
340
335
341 def test_has_open_quotes2(self):
336 def test_has_open_quotes2(self):
342 for s in ['"', '"""', '"hi" "']:
337 for s in ['"', '"""', '"hi" "']:
343 self.assertEqual(completer.has_open_quotes(s), '"')
338 self.assertEqual(completer.has_open_quotes(s), '"')
344
339
345 def test_has_open_quotes3(self):
340 def test_has_open_quotes3(self):
346 for s in ["''", "''' '''", "'hi' 'ipython'"]:
341 for s in ["''", "''' '''", "'hi' 'ipython'"]:
347 self.assertFalse(completer.has_open_quotes(s))
342 self.assertFalse(completer.has_open_quotes(s))
348
343
349 def test_has_open_quotes4(self):
344 def test_has_open_quotes4(self):
350 for s in ['""', '""" """', '"hi" "ipython"']:
345 for s in ['""', '""" """', '"hi" "ipython"']:
351 self.assertFalse(completer.has_open_quotes(s))
346 self.assertFalse(completer.has_open_quotes(s))
352
347
353 @pytest.mark.xfail(
348 @pytest.mark.xfail(
354 sys.platform == "win32", reason="abspath completions fail on Windows"
349 sys.platform == "win32", reason="abspath completions fail on Windows"
355 )
350 )
356 def test_abspath_file_completions(self):
351 def test_abspath_file_completions(self):
357 ip = get_ipython()
352 ip = get_ipython()
358 with TemporaryDirectory() as tmpdir:
353 with TemporaryDirectory() as tmpdir:
359 prefix = os.path.join(tmpdir, "foo")
354 prefix = os.path.join(tmpdir, "foo")
360 suffixes = ["1", "2"]
355 suffixes = ["1", "2"]
361 names = [prefix + s for s in suffixes]
356 names = [prefix + s for s in suffixes]
362 for n in names:
357 for n in names:
363 open(n, "w").close()
358 open(n, "w").close()
364
359
365 # Check simple completion
360 # Check simple completion
366 c = ip.complete(prefix)[1]
361 c = ip.complete(prefix)[1]
367 self.assertEqual(c, names)
362 self.assertEqual(c, names)
368
363
369 # Now check with a function call
364 # Now check with a function call
370 cmd = 'a = f("%s' % prefix
365 cmd = 'a = f("%s' % prefix
371 c = ip.complete(prefix, cmd)[1]
366 c = ip.complete(prefix, cmd)[1]
372 comp = [prefix + s for s in suffixes]
367 comp = [prefix + s for s in suffixes]
373 self.assertEqual(c, comp)
368 self.assertEqual(c, comp)
374
369
375 def test_local_file_completions(self):
370 def test_local_file_completions(self):
376 ip = get_ipython()
371 ip = get_ipython()
377 with TemporaryWorkingDirectory():
372 with TemporaryWorkingDirectory():
378 prefix = "./foo"
373 prefix = "./foo"
379 suffixes = ["1", "2"]
374 suffixes = ["1", "2"]
380 names = [prefix + s for s in suffixes]
375 names = [prefix + s for s in suffixes]
381 for n in names:
376 for n in names:
382 open(n, "w").close()
377 open(n, "w").close()
383
378
384 # Check simple completion
379 # Check simple completion
385 c = ip.complete(prefix)[1]
380 c = ip.complete(prefix)[1]
386 self.assertEqual(c, names)
381 self.assertEqual(c, names)
387
382
388 # Now check with a function call
383 # Now check with a function call
389 cmd = 'a = f("%s' % prefix
384 cmd = 'a = f("%s' % prefix
390 c = ip.complete(prefix, cmd)[1]
385 c = ip.complete(prefix, cmd)[1]
391 comp = {prefix + s for s in suffixes}
386 comp = {prefix + s for s in suffixes}
392 self.assertTrue(comp.issubset(set(c)))
387 self.assertTrue(comp.issubset(set(c)))
393
388
394 def test_quoted_file_completions(self):
389 def test_quoted_file_completions(self):
395 ip = get_ipython()
390 ip = get_ipython()
396 with TemporaryWorkingDirectory():
391 with TemporaryWorkingDirectory():
397 name = "foo'bar"
392 name = "foo'bar"
398 open(name, "w").close()
393 open(name, "w").close()
399
394
400 # Don't escape Windows
395 # Don't escape Windows
401 escaped = name if sys.platform == "win32" else "foo\\'bar"
396 escaped = name if sys.platform == "win32" else "foo\\'bar"
402
397
403 # Single quote matches embedded single quote
398 # Single quote matches embedded single quote
404 text = "open('foo"
399 text = "open('foo"
405 c = ip.Completer._complete(
400 c = ip.Completer._complete(
406 cursor_line=0, cursor_pos=len(text), full_text=text
401 cursor_line=0, cursor_pos=len(text), full_text=text
407 )[1]
402 )[1]
408 self.assertEqual(c, [escaped])
403 self.assertEqual(c, [escaped])
409
404
410 # Double quote requires no escape
405 # Double quote requires no escape
411 text = 'open("foo'
406 text = 'open("foo'
412 c = ip.Completer._complete(
407 c = ip.Completer._complete(
413 cursor_line=0, cursor_pos=len(text), full_text=text
408 cursor_line=0, cursor_pos=len(text), full_text=text
414 )[1]
409 )[1]
415 self.assertEqual(c, [name])
410 self.assertEqual(c, [name])
416
411
417 # No quote requires an escape
412 # No quote requires an escape
418 text = "%ls foo"
413 text = "%ls foo"
419 c = ip.Completer._complete(
414 c = ip.Completer._complete(
420 cursor_line=0, cursor_pos=len(text), full_text=text
415 cursor_line=0, cursor_pos=len(text), full_text=text
421 )[1]
416 )[1]
422 self.assertEqual(c, [escaped])
417 self.assertEqual(c, [escaped])
423
418
424 def test_all_completions_dups(self):
419 def test_all_completions_dups(self):
425 """
420 """
426 Make sure the output of `IPCompleter.all_completions` does not have
421 Make sure the output of `IPCompleter.all_completions` does not have
427 duplicated prefixes.
422 duplicated prefixes.
428 """
423 """
429 ip = get_ipython()
424 ip = get_ipython()
430 c = ip.Completer
425 c = ip.Completer
431 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
426 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
432 for jedi_status in [True, False]:
427 for jedi_status in [True, False]:
433 with provisionalcompleter():
428 with provisionalcompleter():
434 ip.Completer.use_jedi = jedi_status
429 ip.Completer.use_jedi = jedi_status
435 matches = c.all_completions("TestCl")
430 matches = c.all_completions("TestCl")
436 assert matches == ['TestClass'], jedi_status
431 assert matches == ['TestClass'], jedi_status
437 matches = c.all_completions("TestClass.")
432 matches = c.all_completions("TestClass.")
438 if jedi_status and jedi_issue:
433 if jedi_status and jedi_issue:
439 continue
434 continue
440 assert len(matches) > 2, jedi_status
435 assert len(matches) > 2, jedi_status
441 matches = c.all_completions("TestClass.a")
436 matches = c.all_completions("TestClass.a")
442 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
437 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
443
438
444 def test_jedi(self):
439 def test_jedi(self):
445 """
440 """
446 A couple of issue we had with Jedi
441 A couple of issue we had with Jedi
447 """
442 """
448 ip = get_ipython()
443 ip = get_ipython()
449
444
450 def _test_complete(reason, s, comp, start=None, end=None):
445 def _test_complete(reason, s, comp, start=None, end=None):
451 l = len(s)
446 l = len(s)
452 start = start if start is not None else l
447 start = start if start is not None else l
453 end = end if end is not None else l
448 end = end if end is not None else l
454 with provisionalcompleter():
449 with provisionalcompleter():
455 ip.Completer.use_jedi = True
450 ip.Completer.use_jedi = True
456 completions = set(ip.Completer.completions(s, l))
451 completions = set(ip.Completer.completions(s, l))
457 ip.Completer.use_jedi = False
452 ip.Completer.use_jedi = False
458 assert Completion(start, end, comp) in completions, reason
453 assert Completion(start, end, comp) in completions, reason
459
454
460 def _test_not_complete(reason, s, comp):
455 def _test_not_complete(reason, s, comp):
461 l = len(s)
456 l = len(s)
462 with provisionalcompleter():
457 with provisionalcompleter():
463 ip.Completer.use_jedi = True
458 ip.Completer.use_jedi = True
464 completions = set(ip.Completer.completions(s, l))
459 completions = set(ip.Completer.completions(s, l))
465 ip.Completer.use_jedi = False
460 ip.Completer.use_jedi = False
466 assert Completion(l, l, comp) not in completions, reason
461 assert Completion(l, l, comp) not in completions, reason
467
462
468 import jedi
463 import jedi
469
464
470 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
465 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
471 if jedi_version > (0, 10):
466 if jedi_version > (0, 10):
472 _test_complete("jedi >0.9 should complete and not crash", "a=1;a.", "real")
467 _test_complete("jedi >0.9 should complete and not crash", "a=1;a.", "real")
473 _test_complete("can infer first argument", 'a=(1,"foo");a[0].', "real")
468 _test_complete("can infer first argument", 'a=(1,"foo");a[0].', "real")
474 _test_complete("can infer second argument", 'a=(1,"foo");a[1].', "capitalize")
469 _test_complete("can infer second argument", 'a=(1,"foo");a[1].', "capitalize")
475 _test_complete("cover duplicate completions", "im", "import", 0, 2)
470 _test_complete("cover duplicate completions", "im", "import", 0, 2)
476
471
477 _test_not_complete("does not mix types", 'a=(1,"foo");a[0].', "capitalize")
472 _test_not_complete("does not mix types", 'a=(1,"foo");a[0].', "capitalize")
478
473
479 def test_completion_have_signature(self):
474 def test_completion_have_signature(self):
480 """
475 """
481 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
476 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
482 """
477 """
483 ip = get_ipython()
478 ip = get_ipython()
484 with provisionalcompleter():
479 with provisionalcompleter():
485 ip.Completer.use_jedi = True
480 ip.Completer.use_jedi = True
486 completions = ip.Completer.completions("ope", 3)
481 completions = ip.Completer.completions("ope", 3)
487 c = next(completions) # should be `open`
482 c = next(completions) # should be `open`
488 ip.Completer.use_jedi = False
483 ip.Completer.use_jedi = False
489 assert "file" in c.signature, "Signature of function was not found by completer"
484 assert "file" in c.signature, "Signature of function was not found by completer"
490 assert (
485 assert (
491 "encoding" in c.signature
486 "encoding" in c.signature
492 ), "Signature of function was not found by completer"
487 ), "Signature of function was not found by completer"
493
488
494 @pytest.mark.xfail(jedi_issue, reason="Known failure on jedi<=0.18.0")
489 @pytest.mark.xfail(jedi_issue, reason="Known failure on jedi<=0.18.0")
495 def test_deduplicate_completions(self):
490 def test_deduplicate_completions(self):
496 """
491 """
497 Test that completions are correctly deduplicated (even if ranges are not the same)
492 Test that completions are correctly deduplicated (even if ranges are not the same)
498 """
493 """
499 ip = get_ipython()
494 ip = get_ipython()
500 ip.ex(
495 ip.ex(
501 textwrap.dedent(
496 textwrap.dedent(
502 """
497 """
503 class Z:
498 class Z:
504 zoo = 1
499 zoo = 1
505 """
500 """
506 )
501 )
507 )
502 )
508 with provisionalcompleter():
503 with provisionalcompleter():
509 ip.Completer.use_jedi = True
504 ip.Completer.use_jedi = True
510 l = list(
505 l = list(
511 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
506 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
512 )
507 )
513 ip.Completer.use_jedi = False
508 ip.Completer.use_jedi = False
514
509
515 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
510 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
516 assert l[0].text == "zoo" # and not `it.accumulate`
511 assert l[0].text == "zoo" # and not `it.accumulate`
517
512
518 def test_greedy_completions(self):
513 def test_greedy_completions(self):
519 """
514 """
520 Test the capability of the Greedy completer.
515 Test the capability of the Greedy completer.
521
516
522 Most of the test here does not really show off the greedy completer, for proof
517 Most of the test here does not really show off the greedy completer, for proof
523 each of the text below now pass with Jedi. The greedy completer is capable of more.
518 each of the text below now pass with Jedi. The greedy completer is capable of more.
524
519
525 See the :any:`test_dict_key_completion_contexts`
520 See the :any:`test_dict_key_completion_contexts`
526
521
527 """
522 """
528 ip = get_ipython()
523 ip = get_ipython()
529 ip.ex("a=list(range(5))")
524 ip.ex("a=list(range(5))")
530 _, c = ip.complete(".", line="a[0].")
525 _, c = ip.complete(".", line="a[0].")
531 self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
526 self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
532
527
533 def _(line, cursor_pos, expect, message, completion):
528 def _(line, cursor_pos, expect, message, completion):
534 with greedy_completion(), provisionalcompleter():
529 with greedy_completion(), provisionalcompleter():
535 ip.Completer.use_jedi = False
530 ip.Completer.use_jedi = False
536 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
531 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
537 self.assertIn(expect, c, message % c)
532 self.assertIn(expect, c, message % c)
538
533
539 ip.Completer.use_jedi = True
534 ip.Completer.use_jedi = True
540 with provisionalcompleter():
535 with provisionalcompleter():
541 completions = ip.Completer.completions(line, cursor_pos)
536 completions = ip.Completer.completions(line, cursor_pos)
542 self.assertIn(completion, completions)
537 self.assertIn(completion, completions)
543
538
544 with provisionalcompleter():
539 with provisionalcompleter():
545 _(
540 _(
546 "a[0].",
541 "a[0].",
547 5,
542 5,
548 "a[0].real",
543 "a[0].real",
549 "Should have completed on a[0].: %s",
544 "Should have completed on a[0].: %s",
550 Completion(5, 5, "real"),
545 Completion(5, 5, "real"),
551 )
546 )
552 _(
547 _(
553 "a[0].r",
548 "a[0].r",
554 6,
549 6,
555 "a[0].real",
550 "a[0].real",
556 "Should have completed on a[0].r: %s",
551 "Should have completed on a[0].r: %s",
557 Completion(5, 6, "real"),
552 Completion(5, 6, "real"),
558 )
553 )
559
554
560 _(
555 _(
561 "a[0].from_",
556 "a[0].from_",
562 10,
557 10,
563 "a[0].from_bytes",
558 "a[0].from_bytes",
564 "Should have completed on a[0].from_: %s",
559 "Should have completed on a[0].from_: %s",
565 Completion(5, 10, "from_bytes"),
560 Completion(5, 10, "from_bytes"),
566 )
561 )
567
562
568 def test_omit__names(self):
563 def test_omit__names(self):
569 # also happens to test IPCompleter as a configurable
564 # also happens to test IPCompleter as a configurable
570 ip = get_ipython()
565 ip = get_ipython()
571 ip._hidden_attr = 1
566 ip._hidden_attr = 1
572 ip._x = {}
567 ip._x = {}
573 c = ip.Completer
568 c = ip.Completer
574 ip.ex("ip=get_ipython()")
569 ip.ex("ip=get_ipython()")
575 cfg = Config()
570 cfg = Config()
576 cfg.IPCompleter.omit__names = 0
571 cfg.IPCompleter.omit__names = 0
577 c.update_config(cfg)
572 c.update_config(cfg)
578 with provisionalcompleter():
573 with provisionalcompleter():
579 c.use_jedi = False
574 c.use_jedi = False
580 s, matches = c.complete("ip.")
575 s, matches = c.complete("ip.")
581 self.assertIn("ip.__str__", matches)
576 self.assertIn("ip.__str__", matches)
582 self.assertIn("ip._hidden_attr", matches)
577 self.assertIn("ip._hidden_attr", matches)
583
578
584 # c.use_jedi = True
579 # c.use_jedi = True
585 # completions = set(c.completions('ip.', 3))
580 # completions = set(c.completions('ip.', 3))
586 # self.assertIn(Completion(3, 3, '__str__'), completions)
581 # self.assertIn(Completion(3, 3, '__str__'), completions)
587 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
582 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
588
583
589 cfg = Config()
584 cfg = Config()
590 cfg.IPCompleter.omit__names = 1
585 cfg.IPCompleter.omit__names = 1
591 c.update_config(cfg)
586 c.update_config(cfg)
592 with provisionalcompleter():
587 with provisionalcompleter():
593 c.use_jedi = False
588 c.use_jedi = False
594 s, matches = c.complete("ip.")
589 s, matches = c.complete("ip.")
595 self.assertNotIn("ip.__str__", matches)
590 self.assertNotIn("ip.__str__", matches)
596 # self.assertIn('ip._hidden_attr', matches)
591 # self.assertIn('ip._hidden_attr', matches)
597
592
598 # c.use_jedi = True
593 # c.use_jedi = True
599 # completions = set(c.completions('ip.', 3))
594 # completions = set(c.completions('ip.', 3))
600 # self.assertNotIn(Completion(3,3,'__str__'), completions)
595 # self.assertNotIn(Completion(3,3,'__str__'), completions)
601 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
596 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
602
597
603 cfg = Config()
598 cfg = Config()
604 cfg.IPCompleter.omit__names = 2
599 cfg.IPCompleter.omit__names = 2
605 c.update_config(cfg)
600 c.update_config(cfg)
606 with provisionalcompleter():
601 with provisionalcompleter():
607 c.use_jedi = False
602 c.use_jedi = False
608 s, matches = c.complete("ip.")
603 s, matches = c.complete("ip.")
609 self.assertNotIn("ip.__str__", matches)
604 self.assertNotIn("ip.__str__", matches)
610 self.assertNotIn("ip._hidden_attr", matches)
605 self.assertNotIn("ip._hidden_attr", matches)
611
606
612 # c.use_jedi = True
607 # c.use_jedi = True
613 # completions = set(c.completions('ip.', 3))
608 # completions = set(c.completions('ip.', 3))
614 # self.assertNotIn(Completion(3,3,'__str__'), completions)
609 # self.assertNotIn(Completion(3,3,'__str__'), completions)
615 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
610 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
616
611
617 with provisionalcompleter():
612 with provisionalcompleter():
618 c.use_jedi = False
613 c.use_jedi = False
619 s, matches = c.complete("ip._x.")
614 s, matches = c.complete("ip._x.")
620 self.assertIn("ip._x.keys", matches)
615 self.assertIn("ip._x.keys", matches)
621
616
622 # c.use_jedi = True
617 # c.use_jedi = True
623 # completions = set(c.completions('ip._x.', 6))
618 # completions = set(c.completions('ip._x.', 6))
624 # self.assertIn(Completion(6,6, "keys"), completions)
619 # self.assertIn(Completion(6,6, "keys"), completions)
625
620
626 del ip._hidden_attr
621 del ip._hidden_attr
627 del ip._x
622 del ip._x
628
623
629 def test_limit_to__all__False_ok(self):
624 def test_limit_to__all__False_ok(self):
630 """
625 """
631 Limit to all is deprecated, once we remove it this test can go away.
626 Limit to all is deprecated, once we remove it this test can go away.
632 """
627 """
633 ip = get_ipython()
628 ip = get_ipython()
634 c = ip.Completer
629 c = ip.Completer
635 c.use_jedi = False
630 c.use_jedi = False
636 ip.ex("class D: x=24")
631 ip.ex("class D: x=24")
637 ip.ex("d=D()")
632 ip.ex("d=D()")
638 cfg = Config()
633 cfg = Config()
639 cfg.IPCompleter.limit_to__all__ = False
634 cfg.IPCompleter.limit_to__all__ = False
640 c.update_config(cfg)
635 c.update_config(cfg)
641 s, matches = c.complete("d.")
636 s, matches = c.complete("d.")
642 self.assertIn("d.x", matches)
637 self.assertIn("d.x", matches)
643
638
644 def test_get__all__entries_ok(self):
639 def test_get__all__entries_ok(self):
645 class A:
640 class A:
646 __all__ = ["x", 1]
641 __all__ = ["x", 1]
647
642
648 words = completer.get__all__entries(A())
643 words = completer.get__all__entries(A())
649 self.assertEqual(words, ["x"])
644 self.assertEqual(words, ["x"])
650
645
651 def test_get__all__entries_no__all__ok(self):
646 def test_get__all__entries_no__all__ok(self):
652 class A:
647 class A:
653 pass
648 pass
654
649
655 words = completer.get__all__entries(A())
650 words = completer.get__all__entries(A())
656 self.assertEqual(words, [])
651 self.assertEqual(words, [])
657
652
658 def test_func_kw_completions(self):
653 def test_func_kw_completions(self):
659 ip = get_ipython()
654 ip = get_ipython()
660 c = ip.Completer
655 c = ip.Completer
661 c.use_jedi = False
656 c.use_jedi = False
662 ip.ex("def myfunc(a=1,b=2): return a+b")
657 ip.ex("def myfunc(a=1,b=2): return a+b")
663 s, matches = c.complete(None, "myfunc(1,b")
658 s, matches = c.complete(None, "myfunc(1,b")
664 self.assertIn("b=", matches)
659 self.assertIn("b=", matches)
665 # Simulate completing with cursor right after b (pos==10):
660 # Simulate completing with cursor right after b (pos==10):
666 s, matches = c.complete(None, "myfunc(1,b)", 10)
661 s, matches = c.complete(None, "myfunc(1,b)", 10)
667 self.assertIn("b=", matches)
662 self.assertIn("b=", matches)
668 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
663 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
669 self.assertIn("b=", matches)
664 self.assertIn("b=", matches)
670 # builtin function
665 # builtin function
671 s, matches = c.complete(None, "min(k, k")
666 s, matches = c.complete(None, "min(k, k")
672 self.assertIn("key=", matches)
667 self.assertIn("key=", matches)
673
668
674 def test_default_arguments_from_docstring(self):
669 def test_default_arguments_from_docstring(self):
675 ip = get_ipython()
670 ip = get_ipython()
676 c = ip.Completer
671 c = ip.Completer
677 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
672 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
678 self.assertEqual(kwd, ["key"])
673 self.assertEqual(kwd, ["key"])
679 # with cython type etc
674 # with cython type etc
680 kwd = c._default_arguments_from_docstring(
675 kwd = c._default_arguments_from_docstring(
681 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
676 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
682 )
677 )
683 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
678 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
684 # white spaces
679 # white spaces
685 kwd = c._default_arguments_from_docstring(
680 kwd = c._default_arguments_from_docstring(
686 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
681 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
687 )
682 )
688 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
683 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
689
684
690 def test_line_magics(self):
685 def test_line_magics(self):
691 ip = get_ipython()
686 ip = get_ipython()
692 c = ip.Completer
687 c = ip.Completer
693 s, matches = c.complete(None, "lsmag")
688 s, matches = c.complete(None, "lsmag")
694 self.assertIn("%lsmagic", matches)
689 self.assertIn("%lsmagic", matches)
695 s, matches = c.complete(None, "%lsmag")
690 s, matches = c.complete(None, "%lsmag")
696 self.assertIn("%lsmagic", matches)
691 self.assertIn("%lsmagic", matches)
697
692
698 def test_cell_magics(self):
693 def test_cell_magics(self):
699 from IPython.core.magic import register_cell_magic
694 from IPython.core.magic import register_cell_magic
700
695
701 @register_cell_magic
696 @register_cell_magic
702 def _foo_cellm(line, cell):
697 def _foo_cellm(line, cell):
703 pass
698 pass
704
699
705 ip = get_ipython()
700 ip = get_ipython()
706 c = ip.Completer
701 c = ip.Completer
707
702
708 s, matches = c.complete(None, "_foo_ce")
703 s, matches = c.complete(None, "_foo_ce")
709 self.assertIn("%%_foo_cellm", matches)
704 self.assertIn("%%_foo_cellm", matches)
710 s, matches = c.complete(None, "%%_foo_ce")
705 s, matches = c.complete(None, "%%_foo_ce")
711 self.assertIn("%%_foo_cellm", matches)
706 self.assertIn("%%_foo_cellm", matches)
712
707
713 def test_line_cell_magics(self):
708 def test_line_cell_magics(self):
714 from IPython.core.magic import register_line_cell_magic
709 from IPython.core.magic import register_line_cell_magic
715
710
716 @register_line_cell_magic
711 @register_line_cell_magic
717 def _bar_cellm(line, cell):
712 def _bar_cellm(line, cell):
718 pass
713 pass
719
714
720 ip = get_ipython()
715 ip = get_ipython()
721 c = ip.Completer
716 c = ip.Completer
722
717
723 # The policy here is trickier, see comments in completion code. The
718 # The policy here is trickier, see comments in completion code. The
724 # returned values depend on whether the user passes %% or not explicitly,
719 # returned values depend on whether the user passes %% or not explicitly,
725 # and this will show a difference if the same name is both a line and cell
720 # and this will show a difference if the same name is both a line and cell
726 # magic.
721 # magic.
727 s, matches = c.complete(None, "_bar_ce")
722 s, matches = c.complete(None, "_bar_ce")
728 self.assertIn("%_bar_cellm", matches)
723 self.assertIn("%_bar_cellm", matches)
729 self.assertIn("%%_bar_cellm", matches)
724 self.assertIn("%%_bar_cellm", matches)
730 s, matches = c.complete(None, "%_bar_ce")
725 s, matches = c.complete(None, "%_bar_ce")
731 self.assertIn("%_bar_cellm", matches)
726 self.assertIn("%_bar_cellm", matches)
732 self.assertIn("%%_bar_cellm", matches)
727 self.assertIn("%%_bar_cellm", matches)
733 s, matches = c.complete(None, "%%_bar_ce")
728 s, matches = c.complete(None, "%%_bar_ce")
734 self.assertNotIn("%_bar_cellm", matches)
729 self.assertNotIn("%_bar_cellm", matches)
735 self.assertIn("%%_bar_cellm", matches)
730 self.assertIn("%%_bar_cellm", matches)
736
731
737 def test_magic_completion_order(self):
732 def test_magic_completion_order(self):
738 ip = get_ipython()
733 ip = get_ipython()
739 c = ip.Completer
734 c = ip.Completer
740
735
741 # Test ordering of line and cell magics.
736 # Test ordering of line and cell magics.
742 text, matches = c.complete("timeit")
737 text, matches = c.complete("timeit")
743 self.assertEqual(matches, ["%timeit", "%%timeit"])
738 self.assertEqual(matches, ["%timeit", "%%timeit"])
744
739
745 def test_magic_completion_shadowing(self):
740 def test_magic_completion_shadowing(self):
746 ip = get_ipython()
741 ip = get_ipython()
747 c = ip.Completer
742 c = ip.Completer
748 c.use_jedi = False
743 c.use_jedi = False
749
744
750 # Before importing matplotlib, %matplotlib magic should be the only option.
745 # Before importing matplotlib, %matplotlib magic should be the only option.
751 text, matches = c.complete("mat")
746 text, matches = c.complete("mat")
752 self.assertEqual(matches, ["%matplotlib"])
747 self.assertEqual(matches, ["%matplotlib"])
753
748
754 # The newly introduced name should shadow the magic.
749 # The newly introduced name should shadow the magic.
755 ip.run_cell("matplotlib = 1")
750 ip.run_cell("matplotlib = 1")
756 text, matches = c.complete("mat")
751 text, matches = c.complete("mat")
757 self.assertEqual(matches, ["matplotlib"])
752 self.assertEqual(matches, ["matplotlib"])
758
753
759 # After removing matplotlib from namespace, the magic should again be
754 # After removing matplotlib from namespace, the magic should again be
760 # the only option.
755 # the only option.
761 del ip.user_ns["matplotlib"]
756 del ip.user_ns["matplotlib"]
762 text, matches = c.complete("mat")
757 text, matches = c.complete("mat")
763 self.assertEqual(matches, ["%matplotlib"])
758 self.assertEqual(matches, ["%matplotlib"])
764
759
765 def test_magic_completion_shadowing_explicit(self):
760 def test_magic_completion_shadowing_explicit(self):
766 """
761 """
767 If the user try to complete a shadowed magic, and explicit % start should
762 If the user try to complete a shadowed magic, and explicit % start should
768 still return the completions.
763 still return the completions.
769 """
764 """
770 ip = get_ipython()
765 ip = get_ipython()
771 c = ip.Completer
766 c = ip.Completer
772
767
773 # Before importing matplotlib, %matplotlib magic should be the only option.
768 # Before importing matplotlib, %matplotlib magic should be the only option.
774 text, matches = c.complete("%mat")
769 text, matches = c.complete("%mat")
775 self.assertEqual(matches, ["%matplotlib"])
770 self.assertEqual(matches, ["%matplotlib"])
776
771
777 ip.run_cell("matplotlib = 1")
772 ip.run_cell("matplotlib = 1")
778
773
779 # After removing matplotlib from namespace, the magic should still be
774 # After removing matplotlib from namespace, the magic should still be
780 # the only option.
775 # the only option.
781 text, matches = c.complete("%mat")
776 text, matches = c.complete("%mat")
782 self.assertEqual(matches, ["%matplotlib"])
777 self.assertEqual(matches, ["%matplotlib"])
783
778
784 def test_magic_config(self):
779 def test_magic_config(self):
785 ip = get_ipython()
780 ip = get_ipython()
786 c = ip.Completer
781 c = ip.Completer
787
782
788 s, matches = c.complete(None, "conf")
783 s, matches = c.complete(None, "conf")
789 self.assertIn("%config", matches)
784 self.assertIn("%config", matches)
790 s, matches = c.complete(None, "conf")
785 s, matches = c.complete(None, "conf")
791 self.assertNotIn("AliasManager", matches)
786 self.assertNotIn("AliasManager", matches)
792 s, matches = c.complete(None, "config ")
787 s, matches = c.complete(None, "config ")
793 self.assertIn("AliasManager", matches)
788 self.assertIn("AliasManager", matches)
794 s, matches = c.complete(None, "%config ")
789 s, matches = c.complete(None, "%config ")
795 self.assertIn("AliasManager", matches)
790 self.assertIn("AliasManager", matches)
796 s, matches = c.complete(None, "config Ali")
791 s, matches = c.complete(None, "config Ali")
797 self.assertListEqual(["AliasManager"], matches)
792 self.assertListEqual(["AliasManager"], matches)
798 s, matches = c.complete(None, "%config Ali")
793 s, matches = c.complete(None, "%config Ali")
799 self.assertListEqual(["AliasManager"], matches)
794 self.assertListEqual(["AliasManager"], matches)
800 s, matches = c.complete(None, "config AliasManager")
795 s, matches = c.complete(None, "config AliasManager")
801 self.assertListEqual(["AliasManager"], matches)
796 self.assertListEqual(["AliasManager"], matches)
802 s, matches = c.complete(None, "%config AliasManager")
797 s, matches = c.complete(None, "%config AliasManager")
803 self.assertListEqual(["AliasManager"], matches)
798 self.assertListEqual(["AliasManager"], matches)
804 s, matches = c.complete(None, "config AliasManager.")
799 s, matches = c.complete(None, "config AliasManager.")
805 self.assertIn("AliasManager.default_aliases", matches)
800 self.assertIn("AliasManager.default_aliases", matches)
806 s, matches = c.complete(None, "%config AliasManager.")
801 s, matches = c.complete(None, "%config AliasManager.")
807 self.assertIn("AliasManager.default_aliases", matches)
802 self.assertIn("AliasManager.default_aliases", matches)
808 s, matches = c.complete(None, "config AliasManager.de")
803 s, matches = c.complete(None, "config AliasManager.de")
809 self.assertListEqual(["AliasManager.default_aliases"], matches)
804 self.assertListEqual(["AliasManager.default_aliases"], matches)
810 s, matches = c.complete(None, "config AliasManager.de")
805 s, matches = c.complete(None, "config AliasManager.de")
811 self.assertListEqual(["AliasManager.default_aliases"], matches)
806 self.assertListEqual(["AliasManager.default_aliases"], matches)
812
807
813 def test_magic_color(self):
808 def test_magic_color(self):
814 ip = get_ipython()
809 ip = get_ipython()
815 c = ip.Completer
810 c = ip.Completer
816
811
817 s, matches = c.complete(None, "colo")
812 s, matches = c.complete(None, "colo")
818 self.assertIn("%colors", matches)
813 self.assertIn("%colors", matches)
819 s, matches = c.complete(None, "colo")
814 s, matches = c.complete(None, "colo")
820 self.assertNotIn("NoColor", matches)
815 self.assertNotIn("NoColor", matches)
821 s, matches = c.complete(None, "%colors") # No trailing space
816 s, matches = c.complete(None, "%colors") # No trailing space
822 self.assertNotIn("NoColor", matches)
817 self.assertNotIn("NoColor", matches)
823 s, matches = c.complete(None, "colors ")
818 s, matches = c.complete(None, "colors ")
824 self.assertIn("NoColor", matches)
819 self.assertIn("NoColor", matches)
825 s, matches = c.complete(None, "%colors ")
820 s, matches = c.complete(None, "%colors ")
826 self.assertIn("NoColor", matches)
821 self.assertIn("NoColor", matches)
827 s, matches = c.complete(None, "colors NoCo")
822 s, matches = c.complete(None, "colors NoCo")
828 self.assertListEqual(["NoColor"], matches)
823 self.assertListEqual(["NoColor"], matches)
829 s, matches = c.complete(None, "%colors NoCo")
824 s, matches = c.complete(None, "%colors NoCo")
830 self.assertListEqual(["NoColor"], matches)
825 self.assertListEqual(["NoColor"], matches)
831
826
832 def test_match_dict_keys(self):
827 def test_match_dict_keys(self):
833 """
828 """
834 Test that match_dict_keys works on a couple of use case does return what
829 Test that match_dict_keys works on a couple of use case does return what
835 expected, and does not crash
830 expected, and does not crash
836 """
831 """
837 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
832 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
838
833
839 keys = ["foo", b"far"]
834 keys = ["foo", b"far"]
840 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2, ["far"])
835 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2, ["far"])
841 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2, ["far"])
836 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2, ["far"])
842 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2, ["far"])
837 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2, ["far"])
843 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2, ["far"])
838 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2, ["far"])
844
839
845 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1, ["foo"])
840 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1, ["foo"])
846 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1, ["foo"])
841 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1, ["foo"])
847 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1, ["foo"])
842 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1, ["foo"])
848 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1, ["foo"])
843 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1, ["foo"])
849
844
850 match_dict_keys
845 match_dict_keys
851
846
852 def test_match_dict_keys_tuple(self):
847 def test_match_dict_keys_tuple(self):
853 """
848 """
854 Test that match_dict_keys called with extra prefix works on a couple of use case,
849 Test that match_dict_keys called with extra prefix works on a couple of use case,
855 does return what expected, and does not crash.
850 does return what expected, and does not crash.
856 """
851 """
857 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
852 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
858
853
859 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
854 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
860
855
861 # Completion on first key == "foo"
856 # Completion on first key == "foo"
862 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"])
857 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"])
863 assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"])
858 assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"])
864 assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"])
859 assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"])
865 assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"])
860 assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"])
866 assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
861 assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
867 assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
862 assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
868 assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
863 assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
869 assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
864 assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
870
865
871 # No Completion
866 # No Completion
872 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, [])
867 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, [])
873 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, [])
868 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, [])
874
869
875 keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')]
870 keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')]
876 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"])
871 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"])
877 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"])
872 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"])
878 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"])
873 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"])
879 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, [])
874 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, [])
880
875
881 def test_dict_key_completion_string(self):
876 def test_dict_key_completion_string(self):
882 """Test dictionary key completion for string keys"""
877 """Test dictionary key completion for string keys"""
883 ip = get_ipython()
878 ip = get_ipython()
884 complete = ip.Completer.complete
879 complete = ip.Completer.complete
885
880
886 ip.user_ns["d"] = {"abc": None}
881 ip.user_ns["d"] = {"abc": None}
887
882
888 # check completion at different stages
883 # check completion at different stages
889 _, matches = complete(line_buffer="d[")
884 _, matches = complete(line_buffer="d[")
890 self.assertIn("'abc'", matches)
885 self.assertIn("'abc'", matches)
891 self.assertNotIn("'abc']", matches)
886 self.assertNotIn("'abc']", matches)
892
887
893 _, matches = complete(line_buffer="d['")
888 _, matches = complete(line_buffer="d['")
894 self.assertIn("abc", matches)
889 self.assertIn("abc", matches)
895 self.assertNotIn("abc']", matches)
890 self.assertNotIn("abc']", matches)
896
891
897 _, matches = complete(line_buffer="d['a")
892 _, matches = complete(line_buffer="d['a")
898 self.assertIn("abc", matches)
893 self.assertIn("abc", matches)
899 self.assertNotIn("abc']", matches)
894 self.assertNotIn("abc']", matches)
900
895
901 # check use of different quoting
896 # check use of different quoting
902 _, matches = complete(line_buffer='d["')
897 _, matches = complete(line_buffer='d["')
903 self.assertIn("abc", matches)
898 self.assertIn("abc", matches)
904 self.assertNotIn('abc"]', matches)
899 self.assertNotIn('abc"]', matches)
905
900
906 _, matches = complete(line_buffer='d["a')
901 _, matches = complete(line_buffer='d["a')
907 self.assertIn("abc", matches)
902 self.assertIn("abc", matches)
908 self.assertNotIn('abc"]', matches)
903 self.assertNotIn('abc"]', matches)
909
904
910 # check sensitivity to following context
905 # check sensitivity to following context
911 _, matches = complete(line_buffer="d[]", cursor_pos=2)
906 _, matches = complete(line_buffer="d[]", cursor_pos=2)
912 self.assertIn("'abc'", matches)
907 self.assertIn("'abc'", matches)
913
908
914 _, matches = complete(line_buffer="d['']", cursor_pos=3)
909 _, matches = complete(line_buffer="d['']", cursor_pos=3)
915 self.assertIn("abc", matches)
910 self.assertIn("abc", matches)
916 self.assertNotIn("abc'", matches)
911 self.assertNotIn("abc'", matches)
917 self.assertNotIn("abc']", matches)
912 self.assertNotIn("abc']", matches)
918
913
919 # check multiple solutions are correctly returned and that noise is not
914 # check multiple solutions are correctly returned and that noise is not
920 ip.user_ns["d"] = {
915 ip.user_ns["d"] = {
921 "abc": None,
916 "abc": None,
922 "abd": None,
917 "abd": None,
923 "bad": None,
918 "bad": None,
924 object(): None,
919 object(): None,
925 5: None,
920 5: None,
926 ("abe", None): None,
921 ("abe", None): None,
927 (None, "abf"): None
922 (None, "abf"): None
928 }
923 }
929
924
930 _, matches = complete(line_buffer="d['a")
925 _, matches = complete(line_buffer="d['a")
931 self.assertIn("abc", matches)
926 self.assertIn("abc", matches)
932 self.assertIn("abd", matches)
927 self.assertIn("abd", matches)
933 self.assertNotIn("bad", matches)
928 self.assertNotIn("bad", matches)
934 self.assertNotIn("abe", matches)
929 self.assertNotIn("abe", matches)
935 self.assertNotIn("abf", matches)
930 self.assertNotIn("abf", matches)
936 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
931 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
937
932
938 # check escaping and whitespace
933 # check escaping and whitespace
939 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
934 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
940 _, matches = complete(line_buffer="d['a")
935 _, matches = complete(line_buffer="d['a")
941 self.assertIn("a\\nb", matches)
936 self.assertIn("a\\nb", matches)
942 self.assertIn("a\\'b", matches)
937 self.assertIn("a\\'b", matches)
943 self.assertIn('a"b', matches)
938 self.assertIn('a"b', matches)
944 self.assertIn("a word", matches)
939 self.assertIn("a word", matches)
945 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
940 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
946
941
947 # - can complete on non-initial word of the string
942 # - can complete on non-initial word of the string
948 _, matches = complete(line_buffer="d['a w")
943 _, matches = complete(line_buffer="d['a w")
949 self.assertIn("word", matches)
944 self.assertIn("word", matches)
950
945
951 # - understands quote escaping
946 # - understands quote escaping
952 _, matches = complete(line_buffer="d['a\\'")
947 _, matches = complete(line_buffer="d['a\\'")
953 self.assertIn("b", matches)
948 self.assertIn("b", matches)
954
949
955 # - default quoting should work like repr
950 # - default quoting should work like repr
956 _, matches = complete(line_buffer="d[")
951 _, matches = complete(line_buffer="d[")
957 self.assertIn('"a\'b"', matches)
952 self.assertIn('"a\'b"', matches)
958
953
959 # - when opening quote with ", possible to match with unescaped apostrophe
954 # - when opening quote with ", possible to match with unescaped apostrophe
960 _, matches = complete(line_buffer="d[\"a'")
955 _, matches = complete(line_buffer="d[\"a'")
961 self.assertIn("b", matches)
956 self.assertIn("b", matches)
962
957
963 # need to not split at delims that readline won't split at
958 # need to not split at delims that readline won't split at
964 if "-" not in ip.Completer.splitter.delims:
959 if "-" not in ip.Completer.splitter.delims:
965 ip.user_ns["d"] = {"before-after": None}
960 ip.user_ns["d"] = {"before-after": None}
966 _, matches = complete(line_buffer="d['before-af")
961 _, matches = complete(line_buffer="d['before-af")
967 self.assertIn("before-after", matches)
962 self.assertIn("before-after", matches)
968
963
969 # check completion on tuple-of-string keys at different stage - on first key
964 # check completion on tuple-of-string keys at different stage - on first key
970 ip.user_ns["d"] = {('foo', 'bar'): None}
965 ip.user_ns["d"] = {('foo', 'bar'): None}
971 _, matches = complete(line_buffer="d[")
966 _, matches = complete(line_buffer="d[")
972 self.assertIn("'foo'", matches)
967 self.assertIn("'foo'", matches)
973 self.assertNotIn("'foo']", matches)
968 self.assertNotIn("'foo']", matches)
974 self.assertNotIn("'bar'", matches)
969 self.assertNotIn("'bar'", matches)
975 self.assertNotIn("foo", matches)
970 self.assertNotIn("foo", matches)
976 self.assertNotIn("bar", matches)
971 self.assertNotIn("bar", matches)
977
972
978 # - match the prefix
973 # - match the prefix
979 _, matches = complete(line_buffer="d['f")
974 _, matches = complete(line_buffer="d['f")
980 self.assertIn("foo", matches)
975 self.assertIn("foo", matches)
981 self.assertNotIn("foo']", matches)
976 self.assertNotIn("foo']", matches)
982 self.assertNotIn('foo"]', matches)
977 self.assertNotIn('foo"]', matches)
983 _, matches = complete(line_buffer="d['foo")
978 _, matches = complete(line_buffer="d['foo")
984 self.assertIn("foo", matches)
979 self.assertIn("foo", matches)
985
980
986 # - can complete on second key
981 # - can complete on second key
987 _, matches = complete(line_buffer="d['foo', ")
982 _, matches = complete(line_buffer="d['foo', ")
988 self.assertIn("'bar'", matches)
983 self.assertIn("'bar'", matches)
989 _, matches = complete(line_buffer="d['foo', 'b")
984 _, matches = complete(line_buffer="d['foo', 'b")
990 self.assertIn("bar", matches)
985 self.assertIn("bar", matches)
991 self.assertNotIn("foo", matches)
986 self.assertNotIn("foo", matches)
992
987
993 # - does not propose missing keys
988 # - does not propose missing keys
994 _, matches = complete(line_buffer="d['foo', 'f")
989 _, matches = complete(line_buffer="d['foo', 'f")
995 self.assertNotIn("bar", matches)
990 self.assertNotIn("bar", matches)
996 self.assertNotIn("foo", matches)
991 self.assertNotIn("foo", matches)
997
992
998 # check sensitivity to following context
993 # check sensitivity to following context
999 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
994 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
1000 self.assertIn("'bar'", matches)
995 self.assertIn("'bar'", matches)
1001 self.assertNotIn("bar", matches)
996 self.assertNotIn("bar", matches)
1002 self.assertNotIn("'foo'", matches)
997 self.assertNotIn("'foo'", matches)
1003 self.assertNotIn("foo", matches)
998 self.assertNotIn("foo", matches)
1004
999
1005 _, matches = complete(line_buffer="d['']", cursor_pos=3)
1000 _, matches = complete(line_buffer="d['']", cursor_pos=3)
1006 self.assertIn("foo", matches)
1001 self.assertIn("foo", matches)
1007 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1002 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1008
1003
1009 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
1004 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
1010 self.assertIn("foo", matches)
1005 self.assertIn("foo", matches)
1011 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1006 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1012
1007
1013 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
1008 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
1014 self.assertIn("bar", matches)
1009 self.assertIn("bar", matches)
1015 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1010 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1016
1011
1017 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1012 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1018 self.assertIn("'bar'", matches)
1013 self.assertIn("'bar'", matches)
1019 self.assertNotIn("bar", matches)
1014 self.assertNotIn("bar", matches)
1020
1015
1021 # Can complete with longer tuple keys
1016 # Can complete with longer tuple keys
1022 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1017 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1023
1018
1024 # - can complete second key
1019 # - can complete second key
1025 _, matches = complete(line_buffer="d['foo', 'b")
1020 _, matches = complete(line_buffer="d['foo', 'b")
1026 self.assertIn("bar", matches)
1021 self.assertIn("bar", matches)
1027 self.assertNotIn("foo", matches)
1022 self.assertNotIn("foo", matches)
1028 self.assertNotIn("foobar", matches)
1023 self.assertNotIn("foobar", matches)
1029
1024
1030 # - can complete third key
1025 # - can complete third key
1031 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1026 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1032 self.assertIn("foobar", matches)
1027 self.assertIn("foobar", matches)
1033 self.assertNotIn("foo", matches)
1028 self.assertNotIn("foo", matches)
1034 self.assertNotIn("bar", matches)
1029 self.assertNotIn("bar", matches)
1035
1030
1036 def test_dict_key_completion_contexts(self):
1031 def test_dict_key_completion_contexts(self):
1037 """Test expression contexts in which dict key completion occurs"""
1032 """Test expression contexts in which dict key completion occurs"""
1038 ip = get_ipython()
1033 ip = get_ipython()
1039 complete = ip.Completer.complete
1034 complete = ip.Completer.complete
1040 d = {"abc": None}
1035 d = {"abc": None}
1041 ip.user_ns["d"] = d
1036 ip.user_ns["d"] = d
1042
1037
1043 class C:
1038 class C:
1044 data = d
1039 data = d
1045
1040
1046 ip.user_ns["C"] = C
1041 ip.user_ns["C"] = C
1047 ip.user_ns["get"] = lambda: d
1042 ip.user_ns["get"] = lambda: d
1048
1043
1049 def assert_no_completion(**kwargs):
1044 def assert_no_completion(**kwargs):
1050 _, matches = complete(**kwargs)
1045 _, matches = complete(**kwargs)
1051 self.assertNotIn("abc", matches)
1046 self.assertNotIn("abc", matches)
1052 self.assertNotIn("abc'", matches)
1047 self.assertNotIn("abc'", matches)
1053 self.assertNotIn("abc']", matches)
1048 self.assertNotIn("abc']", matches)
1054 self.assertNotIn("'abc'", matches)
1049 self.assertNotIn("'abc'", matches)
1055 self.assertNotIn("'abc']", matches)
1050 self.assertNotIn("'abc']", matches)
1056
1051
1057 def assert_completion(**kwargs):
1052 def assert_completion(**kwargs):
1058 _, matches = complete(**kwargs)
1053 _, matches = complete(**kwargs)
1059 self.assertIn("'abc'", matches)
1054 self.assertIn("'abc'", matches)
1060 self.assertNotIn("'abc']", matches)
1055 self.assertNotIn("'abc']", matches)
1061
1056
1062 # no completion after string closed, even if reopened
1057 # no completion after string closed, even if reopened
1063 assert_no_completion(line_buffer="d['a'")
1058 assert_no_completion(line_buffer="d['a'")
1064 assert_no_completion(line_buffer='d["a"')
1059 assert_no_completion(line_buffer='d["a"')
1065 assert_no_completion(line_buffer="d['a' + ")
1060 assert_no_completion(line_buffer="d['a' + ")
1066 assert_no_completion(line_buffer="d['a' + '")
1061 assert_no_completion(line_buffer="d['a' + '")
1067
1062
1068 # completion in non-trivial expressions
1063 # completion in non-trivial expressions
1069 assert_completion(line_buffer="+ d[")
1064 assert_completion(line_buffer="+ d[")
1070 assert_completion(line_buffer="(d[")
1065 assert_completion(line_buffer="(d[")
1071 assert_completion(line_buffer="C.data[")
1066 assert_completion(line_buffer="C.data[")
1072
1067
1073 # greedy flag
1068 # greedy flag
1074 def assert_completion(**kwargs):
1069 def assert_completion(**kwargs):
1075 _, matches = complete(**kwargs)
1070 _, matches = complete(**kwargs)
1076 self.assertIn("get()['abc']", matches)
1071 self.assertIn("get()['abc']", matches)
1077
1072
1078 assert_no_completion(line_buffer="get()[")
1073 assert_no_completion(line_buffer="get()[")
1079 with greedy_completion():
1074 with greedy_completion():
1080 assert_completion(line_buffer="get()[")
1075 assert_completion(line_buffer="get()[")
1081 assert_completion(line_buffer="get()['")
1076 assert_completion(line_buffer="get()['")
1082 assert_completion(line_buffer="get()['a")
1077 assert_completion(line_buffer="get()['a")
1083 assert_completion(line_buffer="get()['ab")
1078 assert_completion(line_buffer="get()['ab")
1084 assert_completion(line_buffer="get()['abc")
1079 assert_completion(line_buffer="get()['abc")
1085
1080
1086 def test_dict_key_completion_bytes(self):
1081 def test_dict_key_completion_bytes(self):
1087 """Test handling of bytes in dict key completion"""
1082 """Test handling of bytes in dict key completion"""
1088 ip = get_ipython()
1083 ip = get_ipython()
1089 complete = ip.Completer.complete
1084 complete = ip.Completer.complete
1090
1085
1091 ip.user_ns["d"] = {"abc": None, b"abd": None}
1086 ip.user_ns["d"] = {"abc": None, b"abd": None}
1092
1087
1093 _, matches = complete(line_buffer="d[")
1088 _, matches = complete(line_buffer="d[")
1094 self.assertIn("'abc'", matches)
1089 self.assertIn("'abc'", matches)
1095 self.assertIn("b'abd'", matches)
1090 self.assertIn("b'abd'", matches)
1096
1091
1097 if False: # not currently implemented
1092 if False: # not currently implemented
1098 _, matches = complete(line_buffer="d[b")
1093 _, matches = complete(line_buffer="d[b")
1099 self.assertIn("b'abd'", matches)
1094 self.assertIn("b'abd'", matches)
1100 self.assertNotIn("b'abc'", matches)
1095 self.assertNotIn("b'abc'", matches)
1101
1096
1102 _, matches = complete(line_buffer="d[b'")
1097 _, matches = complete(line_buffer="d[b'")
1103 self.assertIn("abd", matches)
1098 self.assertIn("abd", matches)
1104 self.assertNotIn("abc", matches)
1099 self.assertNotIn("abc", matches)
1105
1100
1106 _, matches = complete(line_buffer="d[B'")
1101 _, matches = complete(line_buffer="d[B'")
1107 self.assertIn("abd", matches)
1102 self.assertIn("abd", matches)
1108 self.assertNotIn("abc", matches)
1103 self.assertNotIn("abc", matches)
1109
1104
1110 _, matches = complete(line_buffer="d['")
1105 _, matches = complete(line_buffer="d['")
1111 self.assertIn("abc", matches)
1106 self.assertIn("abc", matches)
1112 self.assertNotIn("abd", matches)
1107 self.assertNotIn("abd", matches)
1113
1108
1114 def test_dict_key_completion_unicode_py3(self):
1109 def test_dict_key_completion_unicode_py3(self):
1115 """Test handling of unicode in dict key completion"""
1110 """Test handling of unicode in dict key completion"""
1116 ip = get_ipython()
1111 ip = get_ipython()
1117 complete = ip.Completer.complete
1112 complete = ip.Completer.complete
1118
1113
1119 ip.user_ns["d"] = {"a\u05d0": None}
1114 ip.user_ns["d"] = {"a\u05d0": None}
1120
1115
1121 # query using escape
1116 # query using escape
1122 if sys.platform != "win32":
1117 if sys.platform != "win32":
1123 # Known failure on Windows
1118 # Known failure on Windows
1124 _, matches = complete(line_buffer="d['a\\u05d0")
1119 _, matches = complete(line_buffer="d['a\\u05d0")
1125 self.assertIn("u05d0", matches) # tokenized after \\
1120 self.assertIn("u05d0", matches) # tokenized after \\
1126
1121
1127 # query using character
1122 # query using character
1128 _, matches = complete(line_buffer="d['a\u05d0")
1123 _, matches = complete(line_buffer="d['a\u05d0")
1129 self.assertIn("a\u05d0", matches)
1124 self.assertIn("a\u05d0", matches)
1130
1125
1131 with greedy_completion():
1126 with greedy_completion():
1132 # query using escape
1127 # query using escape
1133 _, matches = complete(line_buffer="d['a\\u05d0")
1128 _, matches = complete(line_buffer="d['a\\u05d0")
1134 self.assertIn("d['a\\u05d0']", matches) # tokenized after \\
1129 self.assertIn("d['a\\u05d0']", matches) # tokenized after \\
1135
1130
1136 # query using character
1131 # query using character
1137 _, matches = complete(line_buffer="d['a\u05d0")
1132 _, matches = complete(line_buffer="d['a\u05d0")
1138 self.assertIn("d['a\u05d0']", matches)
1133 self.assertIn("d['a\u05d0']", matches)
1139
1134
1140 @dec.skip_without("numpy")
1135 @dec.skip_without("numpy")
1141 def test_struct_array_key_completion(self):
1136 def test_struct_array_key_completion(self):
1142 """Test dict key completion applies to numpy struct arrays"""
1137 """Test dict key completion applies to numpy struct arrays"""
1143 import numpy
1138 import numpy
1144
1139
1145 ip = get_ipython()
1140 ip = get_ipython()
1146 complete = ip.Completer.complete
1141 complete = ip.Completer.complete
1147 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1142 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1148 _, matches = complete(line_buffer="d['")
1143 _, matches = complete(line_buffer="d['")
1149 self.assertIn("hello", matches)
1144 self.assertIn("hello", matches)
1150 self.assertIn("world", matches)
1145 self.assertIn("world", matches)
1151 # complete on the numpy struct itself
1146 # complete on the numpy struct itself
1152 dt = numpy.dtype(
1147 dt = numpy.dtype(
1153 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1148 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1154 )
1149 )
1155 x = numpy.zeros(2, dtype=dt)
1150 x = numpy.zeros(2, dtype=dt)
1156 ip.user_ns["d"] = x[1]
1151 ip.user_ns["d"] = x[1]
1157 _, matches = complete(line_buffer="d['")
1152 _, matches = complete(line_buffer="d['")
1158 self.assertIn("my_head", matches)
1153 self.assertIn("my_head", matches)
1159 self.assertIn("my_data", matches)
1154 self.assertIn("my_data", matches)
1160 # complete on a nested level
1155 # complete on a nested level
1161 with greedy_completion():
1156 with greedy_completion():
1162 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1157 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1163 _, matches = complete(line_buffer="d[1]['my_head']['")
1158 _, matches = complete(line_buffer="d[1]['my_head']['")
1164 self.assertTrue(any(["my_dt" in m for m in matches]))
1159 self.assertTrue(any(["my_dt" in m for m in matches]))
1165 self.assertTrue(any(["my_df" in m for m in matches]))
1160 self.assertTrue(any(["my_df" in m for m in matches]))
1166
1161
1167 @dec.skip_without("pandas")
1162 @dec.skip_without("pandas")
1168 def test_dataframe_key_completion(self):
1163 def test_dataframe_key_completion(self):
1169 """Test dict key completion applies to pandas DataFrames"""
1164 """Test dict key completion applies to pandas DataFrames"""
1170 import pandas
1165 import pandas
1171
1166
1172 ip = get_ipython()
1167 ip = get_ipython()
1173 complete = ip.Completer.complete
1168 complete = ip.Completer.complete
1174 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1169 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1175 _, matches = complete(line_buffer="d['")
1170 _, matches = complete(line_buffer="d['")
1176 self.assertIn("hello", matches)
1171 self.assertIn("hello", matches)
1177 self.assertIn("world", matches)
1172 self.assertIn("world", matches)
1178
1173
1179 def test_dict_key_completion_invalids(self):
1174 def test_dict_key_completion_invalids(self):
1180 """Smoke test cases dict key completion can't handle"""
1175 """Smoke test cases dict key completion can't handle"""
1181 ip = get_ipython()
1176 ip = get_ipython()
1182 complete = ip.Completer.complete
1177 complete = ip.Completer.complete
1183
1178
1184 ip.user_ns["no_getitem"] = None
1179 ip.user_ns["no_getitem"] = None
1185 ip.user_ns["no_keys"] = []
1180 ip.user_ns["no_keys"] = []
1186 ip.user_ns["cant_call_keys"] = dict
1181 ip.user_ns["cant_call_keys"] = dict
1187 ip.user_ns["empty"] = {}
1182 ip.user_ns["empty"] = {}
1188 ip.user_ns["d"] = {"abc": 5}
1183 ip.user_ns["d"] = {"abc": 5}
1189
1184
1190 _, matches = complete(line_buffer="no_getitem['")
1185 _, matches = complete(line_buffer="no_getitem['")
1191 _, matches = complete(line_buffer="no_keys['")
1186 _, matches = complete(line_buffer="no_keys['")
1192 _, matches = complete(line_buffer="cant_call_keys['")
1187 _, matches = complete(line_buffer="cant_call_keys['")
1193 _, matches = complete(line_buffer="empty['")
1188 _, matches = complete(line_buffer="empty['")
1194 _, matches = complete(line_buffer="name_error['")
1189 _, matches = complete(line_buffer="name_error['")
1195 _, matches = complete(line_buffer="d['\\") # incomplete escape
1190 _, matches = complete(line_buffer="d['\\") # incomplete escape
1196
1191
1197 def test_object_key_completion(self):
1192 def test_object_key_completion(self):
1198 ip = get_ipython()
1193 ip = get_ipython()
1199 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1194 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1200
1195
1201 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1196 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1202 self.assertIn("qwerty", matches)
1197 self.assertIn("qwerty", matches)
1203 self.assertIn("qwick", matches)
1198 self.assertIn("qwick", matches)
1204
1199
1205 def test_class_key_completion(self):
1200 def test_class_key_completion(self):
1206 ip = get_ipython()
1201 ip = get_ipython()
1207 NamedInstanceClass("qwerty")
1202 NamedInstanceClass("qwerty")
1208 NamedInstanceClass("qwick")
1203 NamedInstanceClass("qwick")
1209 ip.user_ns["named_instance_class"] = NamedInstanceClass
1204 ip.user_ns["named_instance_class"] = NamedInstanceClass
1210
1205
1211 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1206 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1212 self.assertIn("qwerty", matches)
1207 self.assertIn("qwerty", matches)
1213 self.assertIn("qwick", matches)
1208 self.assertIn("qwick", matches)
1214
1209
1215 def test_tryimport(self):
1210 def test_tryimport(self):
1216 """
1211 """
1217 Test that try-import don't crash on trailing dot, and import modules before
1212 Test that try-import don't crash on trailing dot, and import modules before
1218 """
1213 """
1219 from IPython.core.completerlib import try_import
1214 from IPython.core.completerlib import try_import
1220
1215
1221 assert try_import("IPython.")
1216 assert try_import("IPython.")
1222
1217
1223 def test_aimport_module_completer(self):
1218 def test_aimport_module_completer(self):
1224 ip = get_ipython()
1219 ip = get_ipython()
1225 _, matches = ip.complete("i", "%aimport i")
1220 _, matches = ip.complete("i", "%aimport i")
1226 self.assertIn("io", matches)
1221 self.assertIn("io", matches)
1227 self.assertNotIn("int", matches)
1222 self.assertNotIn("int", matches)
1228
1223
1229 def test_nested_import_module_completer(self):
1224 def test_nested_import_module_completer(self):
1230 ip = get_ipython()
1225 ip = get_ipython()
1231 _, matches = ip.complete(None, "import IPython.co", 17)
1226 _, matches = ip.complete(None, "import IPython.co", 17)
1232 self.assertIn("IPython.core", matches)
1227 self.assertIn("IPython.core", matches)
1233 self.assertNotIn("import IPython.core", matches)
1228 self.assertNotIn("import IPython.core", matches)
1234 self.assertNotIn("IPython.display", matches)
1229 self.assertNotIn("IPython.display", matches)
1235
1230
1236 def test_import_module_completer(self):
1231 def test_import_module_completer(self):
1237 ip = get_ipython()
1232 ip = get_ipython()
1238 _, matches = ip.complete("i", "import i")
1233 _, matches = ip.complete("i", "import i")
1239 self.assertIn("io", matches)
1234 self.assertIn("io", matches)
1240 self.assertNotIn("int", matches)
1235 self.assertNotIn("int", matches)
1241
1236
1242 def test_from_module_completer(self):
1237 def test_from_module_completer(self):
1243 ip = get_ipython()
1238 ip = get_ipython()
1244 _, matches = ip.complete("B", "from io import B", 16)
1239 _, matches = ip.complete("B", "from io import B", 16)
1245 self.assertIn("BytesIO", matches)
1240 self.assertIn("BytesIO", matches)
1246 self.assertNotIn("BaseException", matches)
1241 self.assertNotIn("BaseException", matches)
1247
1242
1248 def test_snake_case_completion(self):
1243 def test_snake_case_completion(self):
1249 ip = get_ipython()
1244 ip = get_ipython()
1250 ip.Completer.use_jedi = False
1245 ip.Completer.use_jedi = False
1251 ip.user_ns["some_three"] = 3
1246 ip.user_ns["some_three"] = 3
1252 ip.user_ns["some_four"] = 4
1247 ip.user_ns["some_four"] = 4
1253 _, matches = ip.complete("s_", "print(s_f")
1248 _, matches = ip.complete("s_", "print(s_f")
1254 self.assertIn("some_three", matches)
1249 self.assertIn("some_three", matches)
1255 self.assertIn("some_four", matches)
1250 self.assertIn("some_four", matches)
1256
1251
1257 def test_mix_terms(self):
1252 def test_mix_terms(self):
1258 ip = get_ipython()
1253 ip = get_ipython()
1259 from textwrap import dedent
1254 from textwrap import dedent
1260
1255
1261 ip.Completer.use_jedi = False
1256 ip.Completer.use_jedi = False
1262 ip.ex(
1257 ip.ex(
1263 dedent(
1258 dedent(
1264 """
1259 """
1265 class Test:
1260 class Test:
1266 def meth(self, meth_arg1):
1261 def meth(self, meth_arg1):
1267 print("meth")
1262 print("meth")
1268
1263
1269 def meth_1(self, meth1_arg1, meth1_arg2):
1264 def meth_1(self, meth1_arg1, meth1_arg2):
1270 print("meth1")
1265 print("meth1")
1271
1266
1272 def meth_2(self, meth2_arg1, meth2_arg2):
1267 def meth_2(self, meth2_arg1, meth2_arg2):
1273 print("meth2")
1268 print("meth2")
1274 test = Test()
1269 test = Test()
1275 """
1270 """
1276 )
1271 )
1277 )
1272 )
1278 _, matches = ip.complete(None, "test.meth(")
1273 _, matches = ip.complete(None, "test.meth(")
1279 self.assertIn("meth_arg1=", matches)
1274 self.assertIn("meth_arg1=", matches)
1280 self.assertNotIn("meth2_arg1=", matches)
1275 self.assertNotIn("meth2_arg1=", matches)
General Comments 0
You need to be logged in to leave comments. Login now