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