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