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