##// END OF EJS Templates
Allow key completion for classes (#10903)
David Straub -
Show More
@@ -1,981 +1,1009 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for the IPython tab-completion machinery."""
2 """Tests for the IPython tab-completion machinery."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import sys
8 import sys
9 import textwrap
9 import textwrap
10 import unittest
10 import unittest
11
11
12 from contextlib import contextmanager
12 from contextlib import contextmanager
13
13
14 import nose.tools as nt
14 import nose.tools as nt
15
15
16 from traitlets.config.loader import Config
16 from traitlets.config.loader import Config
17 from IPython import get_ipython
17 from IPython import get_ipython
18 from IPython.core import completer
18 from IPython.core import completer
19 from IPython.external.decorators import knownfailureif
19 from IPython.external.decorators import knownfailureif
20 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
20 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
21 from IPython.utils.generics import complete_object
21 from IPython.utils.generics import complete_object
22 from IPython.testing import decorators as dec
22 from IPython.testing import decorators as dec
23
23
24 from IPython.core.completer import (
24 from IPython.core.completer import (
25 Completion, provisionalcompleter, match_dict_keys, _deduplicate_completions)
25 Completion, provisionalcompleter, match_dict_keys, _deduplicate_completions)
26 from nose.tools import assert_in, assert_not_in
26 from nose.tools import assert_in, assert_not_in
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Test functions
29 # Test functions
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 @contextmanager
32 @contextmanager
33 def greedy_completion():
33 def greedy_completion():
34 ip = get_ipython()
34 ip = get_ipython()
35 greedy_original = ip.Completer.greedy
35 greedy_original = ip.Completer.greedy
36 try:
36 try:
37 ip.Completer.greedy = True
37 ip.Completer.greedy = True
38 yield
38 yield
39 finally:
39 finally:
40 ip.Completer.greedy = greedy_original
40 ip.Completer.greedy = greedy_original
41
41
42 def test_protect_filename():
42 def test_protect_filename():
43 if sys.platform == 'win32':
43 if sys.platform == 'win32':
44 pairs = [('abc','abc'),
44 pairs = [('abc','abc'),
45 (' abc','" abc"'),
45 (' abc','" abc"'),
46 ('a bc','"a bc"'),
46 ('a bc','"a bc"'),
47 ('a bc','"a bc"'),
47 ('a bc','"a bc"'),
48 (' bc','" bc"'),
48 (' bc','" bc"'),
49 ]
49 ]
50 else:
50 else:
51 pairs = [('abc','abc'),
51 pairs = [('abc','abc'),
52 (' abc',r'\ abc'),
52 (' abc',r'\ abc'),
53 ('a bc',r'a\ bc'),
53 ('a bc',r'a\ bc'),
54 ('a bc',r'a\ \ bc'),
54 ('a bc',r'a\ \ bc'),
55 (' bc',r'\ \ bc'),
55 (' bc',r'\ \ bc'),
56 # On posix, we also protect parens and other special characters.
56 # On posix, we also protect parens and other special characters.
57 ('a(bc',r'a\(bc'),
57 ('a(bc',r'a\(bc'),
58 ('a)bc',r'a\)bc'),
58 ('a)bc',r'a\)bc'),
59 ('a( )bc',r'a\(\ \)bc'),
59 ('a( )bc',r'a\(\ \)bc'),
60 ('a[1]bc', r'a\[1\]bc'),
60 ('a[1]bc', r'a\[1\]bc'),
61 ('a{1}bc', r'a\{1\}bc'),
61 ('a{1}bc', r'a\{1\}bc'),
62 ('a#bc', r'a\#bc'),
62 ('a#bc', r'a\#bc'),
63 ('a?bc', r'a\?bc'),
63 ('a?bc', r'a\?bc'),
64 ('a=bc', r'a\=bc'),
64 ('a=bc', r'a\=bc'),
65 ('a\\bc', r'a\\bc'),
65 ('a\\bc', r'a\\bc'),
66 ('a|bc', r'a\|bc'),
66 ('a|bc', r'a\|bc'),
67 ('a;bc', r'a\;bc'),
67 ('a;bc', r'a\;bc'),
68 ('a:bc', r'a\:bc'),
68 ('a:bc', r'a\:bc'),
69 ("a'bc", r"a\'bc"),
69 ("a'bc", r"a\'bc"),
70 ('a*bc', r'a\*bc'),
70 ('a*bc', r'a\*bc'),
71 ('a"bc', r'a\"bc'),
71 ('a"bc', r'a\"bc'),
72 ('a^bc', r'a\^bc'),
72 ('a^bc', r'a\^bc'),
73 ('a&bc', r'a\&bc'),
73 ('a&bc', r'a\&bc'),
74 ]
74 ]
75 # run the actual tests
75 # run the actual tests
76 for s1, s2 in pairs:
76 for s1, s2 in pairs:
77 s1p = completer.protect_filename(s1)
77 s1p = completer.protect_filename(s1)
78 nt.assert_equal(s1p, s2)
78 nt.assert_equal(s1p, s2)
79
79
80
80
81 def check_line_split(splitter, test_specs):
81 def check_line_split(splitter, test_specs):
82 for part1, part2, split in test_specs:
82 for part1, part2, split in test_specs:
83 cursor_pos = len(part1)
83 cursor_pos = len(part1)
84 line = part1+part2
84 line = part1+part2
85 out = splitter.split_line(line, cursor_pos)
85 out = splitter.split_line(line, cursor_pos)
86 nt.assert_equal(out, split)
86 nt.assert_equal(out, split)
87
87
88
88
89 def test_line_split():
89 def test_line_split():
90 """Basic line splitter test with default specs."""
90 """Basic line splitter test with default specs."""
91 sp = completer.CompletionSplitter()
91 sp = completer.CompletionSplitter()
92 # The format of the test specs is: part1, part2, expected answer. Parts 1
92 # The format of the test specs is: part1, part2, expected answer. Parts 1
93 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
93 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
94 # was at the end of part1. So an empty part2 represents someone hitting
94 # was at the end of part1. So an empty part2 represents someone hitting
95 # tab at the end of the line, the most common case.
95 # tab at the end of the line, the most common case.
96 t = [('run some/scrip', '', 'some/scrip'),
96 t = [('run some/scrip', '', 'some/scrip'),
97 ('run scripts/er', 'ror.py foo', 'scripts/er'),
97 ('run scripts/er', 'ror.py foo', 'scripts/er'),
98 ('echo $HOM', '', 'HOM'),
98 ('echo $HOM', '', 'HOM'),
99 ('print sys.pa', '', 'sys.pa'),
99 ('print sys.pa', '', 'sys.pa'),
100 ('print(sys.pa', '', 'sys.pa'),
100 ('print(sys.pa', '', 'sys.pa'),
101 ("execfile('scripts/er", '', 'scripts/er'),
101 ("execfile('scripts/er", '', 'scripts/er'),
102 ('a[x.', '', 'x.'),
102 ('a[x.', '', 'x.'),
103 ('a[x.', 'y', 'x.'),
103 ('a[x.', 'y', 'x.'),
104 ('cd "some_file/', '', 'some_file/'),
104 ('cd "some_file/', '', 'some_file/'),
105 ]
105 ]
106 check_line_split(sp, t)
106 check_line_split(sp, t)
107 # Ensure splitting works OK with unicode by re-running the tests with
107 # Ensure splitting works OK with unicode by re-running the tests with
108 # all inputs turned into unicode
108 # all inputs turned into unicode
109 check_line_split(sp, [ map(str, p) for p in t] )
109 check_line_split(sp, [ map(str, p) for p in t] )
110
110
111
111
112 def test_custom_completion_error():
112 def test_custom_completion_error():
113 """Test that errors from custom attribute completers are silenced."""
113 """Test that errors from custom attribute completers are silenced."""
114 ip = get_ipython()
114 ip = get_ipython()
115 class A(object): pass
115 class A(object): pass
116 ip.user_ns['a'] = A()
116 ip.user_ns['a'] = A()
117
117
118 @complete_object.when_type(A)
118 @complete_object.when_type(A)
119 def complete_A(a, existing_completions):
119 def complete_A(a, existing_completions):
120 raise TypeError("this should be silenced")
120 raise TypeError("this should be silenced")
121
121
122 ip.complete("a.")
122 ip.complete("a.")
123
123
124
124
125 def test_unicode_completions():
125 def test_unicode_completions():
126 ip = get_ipython()
126 ip = get_ipython()
127 # Some strings that trigger different types of completion. Check them both
127 # Some strings that trigger different types of completion. Check them both
128 # in str and unicode forms
128 # in str and unicode forms
129 s = ['ru', '%ru', 'cd /', 'floa', 'float(x)/']
129 s = ['ru', '%ru', 'cd /', 'floa', 'float(x)/']
130 for t in s + list(map(str, s)):
130 for t in s + list(map(str, s)):
131 # We don't need to check exact completion values (they may change
131 # We don't need to check exact completion values (they may change
132 # depending on the state of the namespace, but at least no exceptions
132 # depending on the state of the namespace, but at least no exceptions
133 # should be thrown and the return value should be a pair of text, list
133 # should be thrown and the return value should be a pair of text, list
134 # values.
134 # values.
135 text, matches = ip.complete(t)
135 text, matches = ip.complete(t)
136 nt.assert_true(isinstance(text, str))
136 nt.assert_true(isinstance(text, str))
137 nt.assert_true(isinstance(matches, list))
137 nt.assert_true(isinstance(matches, list))
138
138
139 def test_latex_completions():
139 def test_latex_completions():
140 from IPython.core.latex_symbols import latex_symbols
140 from IPython.core.latex_symbols import latex_symbols
141 import random
141 import random
142 ip = get_ipython()
142 ip = get_ipython()
143 # Test some random unicode symbols
143 # Test some random unicode symbols
144 keys = random.sample(latex_symbols.keys(), 10)
144 keys = random.sample(latex_symbols.keys(), 10)
145 for k in keys:
145 for k in keys:
146 text, matches = ip.complete(k)
146 text, matches = ip.complete(k)
147 nt.assert_equal(len(matches),1)
147 nt.assert_equal(len(matches),1)
148 nt.assert_equal(text, k)
148 nt.assert_equal(text, k)
149 nt.assert_equal(matches[0], latex_symbols[k])
149 nt.assert_equal(matches[0], latex_symbols[k])
150 # Test a more complex line
150 # Test a more complex line
151 text, matches = ip.complete(u'print(\\alpha')
151 text, matches = ip.complete(u'print(\\alpha')
152 nt.assert_equal(text, u'\\alpha')
152 nt.assert_equal(text, u'\\alpha')
153 nt.assert_equal(matches[0], latex_symbols['\\alpha'])
153 nt.assert_equal(matches[0], latex_symbols['\\alpha'])
154 # Test multiple matching latex symbols
154 # Test multiple matching latex symbols
155 text, matches = ip.complete(u'\\al')
155 text, matches = ip.complete(u'\\al')
156 nt.assert_in('\\alpha', matches)
156 nt.assert_in('\\alpha', matches)
157 nt.assert_in('\\aleph', matches)
157 nt.assert_in('\\aleph', matches)
158
158
159
159
160
160
161
161
162 def test_back_latex_completion():
162 def test_back_latex_completion():
163 ip = get_ipython()
163 ip = get_ipython()
164
164
165 # do not return more than 1 matches fro \beta, only the latex one.
165 # do not return more than 1 matches fro \beta, only the latex one.
166 name, matches = ip.complete('\\Ξ²')
166 name, matches = ip.complete('\\Ξ²')
167 nt.assert_equal(len(matches), 1)
167 nt.assert_equal(len(matches), 1)
168 nt.assert_equal(matches[0], '\\beta')
168 nt.assert_equal(matches[0], '\\beta')
169
169
170 def test_back_unicode_completion():
170 def test_back_unicode_completion():
171 ip = get_ipython()
171 ip = get_ipython()
172
172
173 name, matches = ip.complete('\\β…€')
173 name, matches = ip.complete('\\β…€')
174 nt.assert_equal(len(matches), 1)
174 nt.assert_equal(len(matches), 1)
175 nt.assert_equal(matches[0], '\\ROMAN NUMERAL FIVE')
175 nt.assert_equal(matches[0], '\\ROMAN NUMERAL FIVE')
176
176
177
177
178 def test_forward_unicode_completion():
178 def test_forward_unicode_completion():
179 ip = get_ipython()
179 ip = get_ipython()
180
180
181 name, matches = ip.complete('\\ROMAN NUMERAL FIVE')
181 name, matches = ip.complete('\\ROMAN NUMERAL FIVE')
182 nt.assert_equal(len(matches), 1)
182 nt.assert_equal(len(matches), 1)
183 nt.assert_equal(matches[0], 'β…€')
183 nt.assert_equal(matches[0], 'β…€')
184
184
185 @dec.knownfailureif(sys.platform == 'win32', 'Fails if there is a C:\\j... path')
185 @dec.knownfailureif(sys.platform == 'win32', 'Fails if there is a C:\\j... path')
186 def test_no_ascii_back_completion():
186 def test_no_ascii_back_completion():
187 ip = get_ipython()
187 ip = get_ipython()
188 with TemporaryWorkingDirectory(): # Avoid any filename completions
188 with TemporaryWorkingDirectory(): # Avoid any filename completions
189 # single ascii letter that don't have yet completions
189 # single ascii letter that don't have yet completions
190 for letter in 'jJ' :
190 for letter in 'jJ' :
191 name, matches = ip.complete('\\'+letter)
191 name, matches = ip.complete('\\'+letter)
192 nt.assert_equal(matches, [])
192 nt.assert_equal(matches, [])
193
193
194
194
195
195
196
196
197 class CompletionSplitterTestCase(unittest.TestCase):
197 class CompletionSplitterTestCase(unittest.TestCase):
198 def setUp(self):
198 def setUp(self):
199 self.sp = completer.CompletionSplitter()
199 self.sp = completer.CompletionSplitter()
200
200
201 def test_delim_setting(self):
201 def test_delim_setting(self):
202 self.sp.delims = ' '
202 self.sp.delims = ' '
203 nt.assert_equal(self.sp.delims, ' ')
203 nt.assert_equal(self.sp.delims, ' ')
204 nt.assert_equal(self.sp._delim_expr, '[\ ]')
204 nt.assert_equal(self.sp._delim_expr, '[\ ]')
205
205
206 def test_spaces(self):
206 def test_spaces(self):
207 """Test with only spaces as split chars."""
207 """Test with only spaces as split chars."""
208 self.sp.delims = ' '
208 self.sp.delims = ' '
209 t = [('foo', '', 'foo'),
209 t = [('foo', '', 'foo'),
210 ('run foo', '', 'foo'),
210 ('run foo', '', 'foo'),
211 ('run foo', 'bar', 'foo'),
211 ('run foo', 'bar', 'foo'),
212 ]
212 ]
213 check_line_split(self.sp, t)
213 check_line_split(self.sp, t)
214
214
215
215
216 def test_has_open_quotes1():
216 def test_has_open_quotes1():
217 for s in ["'", "'''", "'hi' '"]:
217 for s in ["'", "'''", "'hi' '"]:
218 nt.assert_equal(completer.has_open_quotes(s), "'")
218 nt.assert_equal(completer.has_open_quotes(s), "'")
219
219
220
220
221 def test_has_open_quotes2():
221 def test_has_open_quotes2():
222 for s in ['"', '"""', '"hi" "']:
222 for s in ['"', '"""', '"hi" "']:
223 nt.assert_equal(completer.has_open_quotes(s), '"')
223 nt.assert_equal(completer.has_open_quotes(s), '"')
224
224
225
225
226 def test_has_open_quotes3():
226 def test_has_open_quotes3():
227 for s in ["''", "''' '''", "'hi' 'ipython'"]:
227 for s in ["''", "''' '''", "'hi' 'ipython'"]:
228 nt.assert_false(completer.has_open_quotes(s))
228 nt.assert_false(completer.has_open_quotes(s))
229
229
230
230
231 def test_has_open_quotes4():
231 def test_has_open_quotes4():
232 for s in ['""', '""" """', '"hi" "ipython"']:
232 for s in ['""', '""" """', '"hi" "ipython"']:
233 nt.assert_false(completer.has_open_quotes(s))
233 nt.assert_false(completer.has_open_quotes(s))
234
234
235
235
236 @knownfailureif(sys.platform == 'win32', "abspath completions fail on Windows")
236 @knownfailureif(sys.platform == 'win32', "abspath completions fail on Windows")
237 def test_abspath_file_completions():
237 def test_abspath_file_completions():
238 ip = get_ipython()
238 ip = get_ipython()
239 with TemporaryDirectory() as tmpdir:
239 with TemporaryDirectory() as tmpdir:
240 prefix = os.path.join(tmpdir, 'foo')
240 prefix = os.path.join(tmpdir, 'foo')
241 suffixes = ['1', '2']
241 suffixes = ['1', '2']
242 names = [prefix+s for s in suffixes]
242 names = [prefix+s for s in suffixes]
243 for n in names:
243 for n in names:
244 open(n, 'w').close()
244 open(n, 'w').close()
245
245
246 # Check simple completion
246 # Check simple completion
247 c = ip.complete(prefix)[1]
247 c = ip.complete(prefix)[1]
248 nt.assert_equal(c, names)
248 nt.assert_equal(c, names)
249
249
250 # Now check with a function call
250 # Now check with a function call
251 cmd = 'a = f("%s' % prefix
251 cmd = 'a = f("%s' % prefix
252 c = ip.complete(prefix, cmd)[1]
252 c = ip.complete(prefix, cmd)[1]
253 comp = [prefix+s for s in suffixes]
253 comp = [prefix+s for s in suffixes]
254 nt.assert_equal(c, comp)
254 nt.assert_equal(c, comp)
255
255
256
256
257 def test_local_file_completions():
257 def test_local_file_completions():
258 ip = get_ipython()
258 ip = get_ipython()
259 with TemporaryWorkingDirectory():
259 with TemporaryWorkingDirectory():
260 prefix = './foo'
260 prefix = './foo'
261 suffixes = ['1', '2']
261 suffixes = ['1', '2']
262 names = [prefix+s for s in suffixes]
262 names = [prefix+s for s in suffixes]
263 for n in names:
263 for n in names:
264 open(n, 'w').close()
264 open(n, 'w').close()
265
265
266 # Check simple completion
266 # Check simple completion
267 c = ip.complete(prefix)[1]
267 c = ip.complete(prefix)[1]
268 nt.assert_equal(c, names)
268 nt.assert_equal(c, names)
269
269
270 # Now check with a function call
270 # Now check with a function call
271 cmd = 'a = f("%s' % prefix
271 cmd = 'a = f("%s' % prefix
272 c = ip.complete(prefix, cmd)[1]
272 c = ip.complete(prefix, cmd)[1]
273 comp = set(prefix+s for s in suffixes)
273 comp = set(prefix+s for s in suffixes)
274 nt.assert_true(comp.issubset(set(c)))
274 nt.assert_true(comp.issubset(set(c)))
275
275
276
276
277 def test_quoted_file_completions():
277 def test_quoted_file_completions():
278 ip = get_ipython()
278 ip = get_ipython()
279 with TemporaryWorkingDirectory():
279 with TemporaryWorkingDirectory():
280 name = "foo'bar"
280 name = "foo'bar"
281 open(name, 'w').close()
281 open(name, 'w').close()
282
282
283 # Don't escape Windows
283 # Don't escape Windows
284 escaped = name if sys.platform == "win32" else "foo\\'bar"
284 escaped = name if sys.platform == "win32" else "foo\\'bar"
285
285
286 # Single quote matches embedded single quote
286 # Single quote matches embedded single quote
287 text = "open('foo"
287 text = "open('foo"
288 c = ip.Completer._complete(cursor_line=0,
288 c = ip.Completer._complete(cursor_line=0,
289 cursor_pos=len(text),
289 cursor_pos=len(text),
290 full_text=text)[1]
290 full_text=text)[1]
291 nt.assert_equal(c, [escaped])
291 nt.assert_equal(c, [escaped])
292
292
293 # Double quote requires no escape
293 # Double quote requires no escape
294 text = 'open("foo'
294 text = 'open("foo'
295 c = ip.Completer._complete(cursor_line=0,
295 c = ip.Completer._complete(cursor_line=0,
296 cursor_pos=len(text),
296 cursor_pos=len(text),
297 full_text=text)[1]
297 full_text=text)[1]
298 nt.assert_equal(c, [name])
298 nt.assert_equal(c, [name])
299
299
300 # No quote requires an escape
300 # No quote requires an escape
301 text = '%ls foo'
301 text = '%ls foo'
302 c = ip.Completer._complete(cursor_line=0,
302 c = ip.Completer._complete(cursor_line=0,
303 cursor_pos=len(text),
303 cursor_pos=len(text),
304 full_text=text)[1]
304 full_text=text)[1]
305 nt.assert_equal(c, [escaped])
305 nt.assert_equal(c, [escaped])
306
306
307
307
308 def test_jedi():
308 def test_jedi():
309 """
309 """
310 A couple of issue we had with Jedi
310 A couple of issue we had with Jedi
311 """
311 """
312 ip = get_ipython()
312 ip = get_ipython()
313
313
314 def _test_complete(reason, s, comp, start=None, end=None):
314 def _test_complete(reason, s, comp, start=None, end=None):
315 l = len(s)
315 l = len(s)
316 start = start if start is not None else l
316 start = start if start is not None else l
317 end = end if end is not None else l
317 end = end if end is not None else l
318 with provisionalcompleter():
318 with provisionalcompleter():
319 completions = set(ip.Completer.completions(s, l))
319 completions = set(ip.Completer.completions(s, l))
320 assert_in(Completion(start, end, comp), completions, reason)
320 assert_in(Completion(start, end, comp), completions, reason)
321
321
322 def _test_not_complete(reason, s, comp):
322 def _test_not_complete(reason, s, comp):
323 l = len(s)
323 l = len(s)
324 with provisionalcompleter():
324 with provisionalcompleter():
325 completions = set(ip.Completer.completions(s, l))
325 completions = set(ip.Completer.completions(s, l))
326 assert_not_in(Completion(l, l, comp), completions, reason)
326 assert_not_in(Completion(l, l, comp), completions, reason)
327
327
328 import jedi
328 import jedi
329 jedi_version = tuple(int(i) for i in jedi.__version__.split('.')[:3])
329 jedi_version = tuple(int(i) for i in jedi.__version__.split('.')[:3])
330 if jedi_version > (0, 10):
330 if jedi_version > (0, 10):
331 yield _test_complete, 'jedi >0.9 should complete and not crash', 'a=1;a.', 'real'
331 yield _test_complete, 'jedi >0.9 should complete and not crash', 'a=1;a.', 'real'
332 yield _test_complete, 'can infer first argument', 'a=(1,"foo");a[0].', 'real'
332 yield _test_complete, 'can infer first argument', 'a=(1,"foo");a[0].', 'real'
333 yield _test_complete, 'can infer second argument', 'a=(1,"foo");a[1].', 'capitalize'
333 yield _test_complete, 'can infer second argument', 'a=(1,"foo");a[1].', 'capitalize'
334 yield _test_complete, 'cover duplicate completions', 'im', 'import', 0, 2
334 yield _test_complete, 'cover duplicate completions', 'im', 'import', 0, 2
335
335
336 yield _test_not_complete, 'does not mix types', 'a=(1,"foo");a[0].', 'capitalize'
336 yield _test_not_complete, 'does not mix types', 'a=(1,"foo");a[0].', 'capitalize'
337
337
338 def test_completion_have_signature():
338 def test_completion_have_signature():
339 """
339 """
340 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
340 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
341 """
341 """
342 ip = get_ipython()
342 ip = get_ipython()
343 with provisionalcompleter():
343 with provisionalcompleter():
344 completions = ip.Completer.completions('ope', 3)
344 completions = ip.Completer.completions('ope', 3)
345 c = next(completions) # should be `open`
345 c = next(completions) # should be `open`
346 assert 'file' in c.signature, "Signature of function was not found by completer"
346 assert 'file' in c.signature, "Signature of function was not found by completer"
347 assert 'encoding' in c.signature, "Signature of function was not found by completer"
347 assert 'encoding' in c.signature, "Signature of function was not found by completer"
348
348
349
349
350 def test_deduplicate_completions():
350 def test_deduplicate_completions():
351 """
351 """
352 Test that completions are correctly deduplicated (even if ranges are not the same)
352 Test that completions are correctly deduplicated (even if ranges are not the same)
353 """
353 """
354 ip = get_ipython()
354 ip = get_ipython()
355 ip.ex(textwrap.dedent('''
355 ip.ex(textwrap.dedent('''
356 class Z:
356 class Z:
357 zoo = 1
357 zoo = 1
358 '''))
358 '''))
359 with provisionalcompleter():
359 with provisionalcompleter():
360 l = list(_deduplicate_completions('Z.z', ip.Completer.completions('Z.z', 3)))
360 l = list(_deduplicate_completions('Z.z', ip.Completer.completions('Z.z', 3)))
361
361
362 assert len(l) == 1, 'Completions (Z.z<tab>) correctly deduplicate: %s ' % l
362 assert len(l) == 1, 'Completions (Z.z<tab>) correctly deduplicate: %s ' % l
363 assert l[0].text == 'zoo' # and not `it.accumulate`
363 assert l[0].text == 'zoo' # and not `it.accumulate`
364
364
365
365
366 def test_greedy_completions():
366 def test_greedy_completions():
367 """
367 """
368 Test the capability of the Greedy completer.
368 Test the capability of the Greedy completer.
369
369
370 Most of the test here do not really show off the greedy completer, for proof
370 Most of the test here do not really show off the greedy completer, for proof
371 each of the text bellow now pass with Jedi. The greedy completer is capable of more.
371 each of the text bellow now pass with Jedi. The greedy completer is capable of more.
372
372
373 See the :any:`test_dict_key_completion_contexts`
373 See the :any:`test_dict_key_completion_contexts`
374
374
375 """
375 """
376 ip = get_ipython()
376 ip = get_ipython()
377 ip.ex('a=list(range(5))')
377 ip.ex('a=list(range(5))')
378 _,c = ip.complete('.',line='a[0].')
378 _,c = ip.complete('.',line='a[0].')
379 nt.assert_false('.real' in c,
379 nt.assert_false('.real' in c,
380 "Shouldn't have completed on a[0]: %s"%c)
380 "Shouldn't have completed on a[0]: %s"%c)
381 with greedy_completion(), provisionalcompleter():
381 with greedy_completion(), provisionalcompleter():
382 def _(line, cursor_pos, expect, message, completion):
382 def _(line, cursor_pos, expect, message, completion):
383 _,c = ip.complete('.', line=line, cursor_pos=cursor_pos)
383 _,c = ip.complete('.', line=line, cursor_pos=cursor_pos)
384 with provisionalcompleter():
384 with provisionalcompleter():
385 completions = ip.Completer.completions(line, cursor_pos)
385 completions = ip.Completer.completions(line, cursor_pos)
386 nt.assert_in(expect, c, message%c)
386 nt.assert_in(expect, c, message%c)
387 nt.assert_in(completion, completions)
387 nt.assert_in(completion, completions)
388
388
389 yield _, 'a[0].', 5, 'a[0].real', "Should have completed on a[0].: %s", Completion(5,5, 'real')
389 yield _, 'a[0].', 5, 'a[0].real', "Should have completed on a[0].: %s", Completion(5,5, 'real')
390 yield _, 'a[0].r', 6, 'a[0].real', "Should have completed on a[0].r: %s", Completion(5,6, 'real')
390 yield _, 'a[0].r', 6, 'a[0].real', "Should have completed on a[0].r: %s", Completion(5,6, 'real')
391
391
392 if sys.version_info > (3, 4):
392 if sys.version_info > (3, 4):
393 yield _, 'a[0].from_', 10, 'a[0].from_bytes', "Should have completed on a[0].from_: %s", Completion(5, 10, 'from_bytes')
393 yield _, 'a[0].from_', 10, 'a[0].from_bytes', "Should have completed on a[0].from_: %s", Completion(5, 10, 'from_bytes')
394
394
395
395
396 def test_omit__names():
396 def test_omit__names():
397 # also happens to test IPCompleter as a configurable
397 # also happens to test IPCompleter as a configurable
398 ip = get_ipython()
398 ip = get_ipython()
399 ip._hidden_attr = 1
399 ip._hidden_attr = 1
400 ip._x = {}
400 ip._x = {}
401 c = ip.Completer
401 c = ip.Completer
402 ip.ex('ip=get_ipython()')
402 ip.ex('ip=get_ipython()')
403 cfg = Config()
403 cfg = Config()
404 cfg.IPCompleter.omit__names = 0
404 cfg.IPCompleter.omit__names = 0
405 c.update_config(cfg)
405 c.update_config(cfg)
406 with provisionalcompleter():
406 with provisionalcompleter():
407 s,matches = c.complete('ip.')
407 s,matches = c.complete('ip.')
408 completions = set(c.completions('ip.', 3))
408 completions = set(c.completions('ip.', 3))
409
409
410 nt.assert_in('ip.__str__', matches)
410 nt.assert_in('ip.__str__', matches)
411 nt.assert_in(Completion(3, 3, '__str__'), completions)
411 nt.assert_in(Completion(3, 3, '__str__'), completions)
412
412
413 nt.assert_in('ip._hidden_attr', matches)
413 nt.assert_in('ip._hidden_attr', matches)
414 nt.assert_in(Completion(3,3, "_hidden_attr"), completions)
414 nt.assert_in(Completion(3,3, "_hidden_attr"), completions)
415
415
416
416
417 cfg = Config()
417 cfg = Config()
418 cfg.IPCompleter.omit__names = 1
418 cfg.IPCompleter.omit__names = 1
419 c.update_config(cfg)
419 c.update_config(cfg)
420 with provisionalcompleter():
420 with provisionalcompleter():
421 s,matches = c.complete('ip.')
421 s,matches = c.complete('ip.')
422 completions = set(c.completions('ip.', 3))
422 completions = set(c.completions('ip.', 3))
423
423
424 nt.assert_not_in('ip.__str__', matches)
424 nt.assert_not_in('ip.__str__', matches)
425 nt.assert_not_in(Completion(3,3,'__str__'), completions)
425 nt.assert_not_in(Completion(3,3,'__str__'), completions)
426
426
427 # nt.assert_in('ip._hidden_attr', matches)
427 # nt.assert_in('ip._hidden_attr', matches)
428 nt.assert_in(Completion(3,3, "_hidden_attr"), completions)
428 nt.assert_in(Completion(3,3, "_hidden_attr"), completions)
429
429
430 cfg = Config()
430 cfg = Config()
431 cfg.IPCompleter.omit__names = 2
431 cfg.IPCompleter.omit__names = 2
432 c.update_config(cfg)
432 c.update_config(cfg)
433 with provisionalcompleter():
433 with provisionalcompleter():
434 s,matches = c.complete('ip.')
434 s,matches = c.complete('ip.')
435 completions = set(c.completions('ip.', 3))
435 completions = set(c.completions('ip.', 3))
436
436
437 nt.assert_not_in('ip.__str__', matches)
437 nt.assert_not_in('ip.__str__', matches)
438 nt.assert_not_in(Completion(3,3,'__str__'), completions)
438 nt.assert_not_in(Completion(3,3,'__str__'), completions)
439
439
440 nt.assert_not_in('ip._hidden_attr', matches)
440 nt.assert_not_in('ip._hidden_attr', matches)
441 nt.assert_not_in(Completion(3,3, "_hidden_attr"), completions)
441 nt.assert_not_in(Completion(3,3, "_hidden_attr"), completions)
442
442
443 with provisionalcompleter():
443 with provisionalcompleter():
444 s,matches = c.complete('ip._x.')
444 s,matches = c.complete('ip._x.')
445 completions = set(c.completions('ip._x.', 6))
445 completions = set(c.completions('ip._x.', 6))
446
446
447 nt.assert_in('ip._x.keys', matches)
447 nt.assert_in('ip._x.keys', matches)
448 nt.assert_in(Completion(6,6, "keys"), completions)
448 nt.assert_in(Completion(6,6, "keys"), completions)
449
449
450 del ip._hidden_attr
450 del ip._hidden_attr
451 del ip._x
451 del ip._x
452
452
453
453
454 def test_limit_to__all__False_ok():
454 def test_limit_to__all__False_ok():
455 """
455 """
456 Limit to all is deprecated, once we remove it this test can go away.
456 Limit to all is deprecated, once we remove it this test can go away.
457 """
457 """
458 ip = get_ipython()
458 ip = get_ipython()
459 c = ip.Completer
459 c = ip.Completer
460 ip.ex('class D: x=24')
460 ip.ex('class D: x=24')
461 ip.ex('d=D()')
461 ip.ex('d=D()')
462 cfg = Config()
462 cfg = Config()
463 cfg.IPCompleter.limit_to__all__ = False
463 cfg.IPCompleter.limit_to__all__ = False
464 c.update_config(cfg)
464 c.update_config(cfg)
465 s, matches = c.complete('d.')
465 s, matches = c.complete('d.')
466 nt.assert_in('d.x', matches)
466 nt.assert_in('d.x', matches)
467
467
468
468
469 def test_get__all__entries_ok():
469 def test_get__all__entries_ok():
470 class A(object):
470 class A(object):
471 __all__ = ['x', 1]
471 __all__ = ['x', 1]
472 words = completer.get__all__entries(A())
472 words = completer.get__all__entries(A())
473 nt.assert_equal(words, ['x'])
473 nt.assert_equal(words, ['x'])
474
474
475
475
476 def test_get__all__entries_no__all__ok():
476 def test_get__all__entries_no__all__ok():
477 class A(object):
477 class A(object):
478 pass
478 pass
479 words = completer.get__all__entries(A())
479 words = completer.get__all__entries(A())
480 nt.assert_equal(words, [])
480 nt.assert_equal(words, [])
481
481
482
482
483 def test_func_kw_completions():
483 def test_func_kw_completions():
484 ip = get_ipython()
484 ip = get_ipython()
485 c = ip.Completer
485 c = ip.Completer
486 ip.ex('def myfunc(a=1,b=2): return a+b')
486 ip.ex('def myfunc(a=1,b=2): return a+b')
487 s, matches = c.complete(None, 'myfunc(1,b')
487 s, matches = c.complete(None, 'myfunc(1,b')
488 nt.assert_in('b=', matches)
488 nt.assert_in('b=', matches)
489 # Simulate completing with cursor right after b (pos==10):
489 # Simulate completing with cursor right after b (pos==10):
490 s, matches = c.complete(None, 'myfunc(1,b)', 10)
490 s, matches = c.complete(None, 'myfunc(1,b)', 10)
491 nt.assert_in('b=', matches)
491 nt.assert_in('b=', matches)
492 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
492 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
493 nt.assert_in('b=', matches)
493 nt.assert_in('b=', matches)
494 #builtin function
494 #builtin function
495 s, matches = c.complete(None, 'min(k, k')
495 s, matches = c.complete(None, 'min(k, k')
496 nt.assert_in('key=', matches)
496 nt.assert_in('key=', matches)
497
497
498
498
499 def test_default_arguments_from_docstring():
499 def test_default_arguments_from_docstring():
500 ip = get_ipython()
500 ip = get_ipython()
501 c = ip.Completer
501 c = ip.Completer
502 kwd = c._default_arguments_from_docstring(
502 kwd = c._default_arguments_from_docstring(
503 'min(iterable[, key=func]) -> value')
503 'min(iterable[, key=func]) -> value')
504 nt.assert_equal(kwd, ['key'])
504 nt.assert_equal(kwd, ['key'])
505 #with cython type etc
505 #with cython type etc
506 kwd = c._default_arguments_from_docstring(
506 kwd = c._default_arguments_from_docstring(
507 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n')
507 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n')
508 nt.assert_equal(kwd, ['ncall', 'resume', 'nsplit'])
508 nt.assert_equal(kwd, ['ncall', 'resume', 'nsplit'])
509 #white spaces
509 #white spaces
510 kwd = c._default_arguments_from_docstring(
510 kwd = c._default_arguments_from_docstring(
511 '\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n')
511 '\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n')
512 nt.assert_equal(kwd, ['ncall', 'resume', 'nsplit'])
512 nt.assert_equal(kwd, ['ncall', 'resume', 'nsplit'])
513
513
514 def test_line_magics():
514 def test_line_magics():
515 ip = get_ipython()
515 ip = get_ipython()
516 c = ip.Completer
516 c = ip.Completer
517 s, matches = c.complete(None, 'lsmag')
517 s, matches = c.complete(None, 'lsmag')
518 nt.assert_in('%lsmagic', matches)
518 nt.assert_in('%lsmagic', matches)
519 s, matches = c.complete(None, '%lsmag')
519 s, matches = c.complete(None, '%lsmag')
520 nt.assert_in('%lsmagic', matches)
520 nt.assert_in('%lsmagic', matches)
521
521
522
522
523 def test_cell_magics():
523 def test_cell_magics():
524 from IPython.core.magic import register_cell_magic
524 from IPython.core.magic import register_cell_magic
525
525
526 @register_cell_magic
526 @register_cell_magic
527 def _foo_cellm(line, cell):
527 def _foo_cellm(line, cell):
528 pass
528 pass
529
529
530 ip = get_ipython()
530 ip = get_ipython()
531 c = ip.Completer
531 c = ip.Completer
532
532
533 s, matches = c.complete(None, '_foo_ce')
533 s, matches = c.complete(None, '_foo_ce')
534 nt.assert_in('%%_foo_cellm', matches)
534 nt.assert_in('%%_foo_cellm', matches)
535 s, matches = c.complete(None, '%%_foo_ce')
535 s, matches = c.complete(None, '%%_foo_ce')
536 nt.assert_in('%%_foo_cellm', matches)
536 nt.assert_in('%%_foo_cellm', matches)
537
537
538
538
539 def test_line_cell_magics():
539 def test_line_cell_magics():
540 from IPython.core.magic import register_line_cell_magic
540 from IPython.core.magic import register_line_cell_magic
541
541
542 @register_line_cell_magic
542 @register_line_cell_magic
543 def _bar_cellm(line, cell):
543 def _bar_cellm(line, cell):
544 pass
544 pass
545
545
546 ip = get_ipython()
546 ip = get_ipython()
547 c = ip.Completer
547 c = ip.Completer
548
548
549 # The policy here is trickier, see comments in completion code. The
549 # The policy here is trickier, see comments in completion code. The
550 # returned values depend on whether the user passes %% or not explicitly,
550 # returned values depend on whether the user passes %% or not explicitly,
551 # and this will show a difference if the same name is both a line and cell
551 # and this will show a difference if the same name is both a line and cell
552 # magic.
552 # magic.
553 s, matches = c.complete(None, '_bar_ce')
553 s, matches = c.complete(None, '_bar_ce')
554 nt.assert_in('%_bar_cellm', matches)
554 nt.assert_in('%_bar_cellm', matches)
555 nt.assert_in('%%_bar_cellm', matches)
555 nt.assert_in('%%_bar_cellm', matches)
556 s, matches = c.complete(None, '%_bar_ce')
556 s, matches = c.complete(None, '%_bar_ce')
557 nt.assert_in('%_bar_cellm', matches)
557 nt.assert_in('%_bar_cellm', matches)
558 nt.assert_in('%%_bar_cellm', matches)
558 nt.assert_in('%%_bar_cellm', matches)
559 s, matches = c.complete(None, '%%_bar_ce')
559 s, matches = c.complete(None, '%%_bar_ce')
560 nt.assert_not_in('%_bar_cellm', matches)
560 nt.assert_not_in('%_bar_cellm', matches)
561 nt.assert_in('%%_bar_cellm', matches)
561 nt.assert_in('%%_bar_cellm', matches)
562
562
563
563
564 def test_magic_completion_order():
564 def test_magic_completion_order():
565 ip = get_ipython()
565 ip = get_ipython()
566 c = ip.Completer
566 c = ip.Completer
567
567
568 # Test ordering of line and cell magics.
568 # Test ordering of line and cell magics.
569 text, matches = c.complete("timeit")
569 text, matches = c.complete("timeit")
570 nt.assert_equal(matches, ["%timeit", "%%timeit"])
570 nt.assert_equal(matches, ["%timeit", "%%timeit"])
571
571
572
572
573 def test_magic_completion_shadowing():
573 def test_magic_completion_shadowing():
574 ip = get_ipython()
574 ip = get_ipython()
575 c = ip.Completer
575 c = ip.Completer
576
576
577 # Before importing matplotlib, %matplotlib magic should be the only option.
577 # Before importing matplotlib, %matplotlib magic should be the only option.
578 text, matches = c.complete("mat")
578 text, matches = c.complete("mat")
579 nt.assert_equal(matches, ["%matplotlib"])
579 nt.assert_equal(matches, ["%matplotlib"])
580
580
581 # The newly introduced name should shadow the magic.
581 # The newly introduced name should shadow the magic.
582 ip.run_cell("matplotlib = 1")
582 ip.run_cell("matplotlib = 1")
583 text, matches = c.complete("mat")
583 text, matches = c.complete("mat")
584 nt.assert_equal(matches, ["matplotlib"])
584 nt.assert_equal(matches, ["matplotlib"])
585
585
586 # After removing matplotlib from namespace, the magic should again be
586 # After removing matplotlib from namespace, the magic should again be
587 # the only option.
587 # the only option.
588 del ip.user_ns["matplotlib"]
588 del ip.user_ns["matplotlib"]
589 text, matches = c.complete("mat")
589 text, matches = c.complete("mat")
590 nt.assert_equal(matches, ["%matplotlib"])
590 nt.assert_equal(matches, ["%matplotlib"])
591
591
592 def test_magic_completion_shadowing_explicit():
592 def test_magic_completion_shadowing_explicit():
593 """
593 """
594 If the user try to complete a shadowed magic, and explicit % start should
594 If the user try to complete a shadowed magic, and explicit % start should
595 still return the completions.
595 still return the completions.
596 """
596 """
597 ip = get_ipython()
597 ip = get_ipython()
598 c = ip.Completer
598 c = ip.Completer
599
599
600 # Before importing matplotlib, %matplotlib magic should be the only option.
600 # Before importing matplotlib, %matplotlib magic should be the only option.
601 text, matches = c.complete("%mat")
601 text, matches = c.complete("%mat")
602 nt.assert_equal(matches, ["%matplotlib"])
602 nt.assert_equal(matches, ["%matplotlib"])
603
603
604 ip.run_cell("matplotlib = 1")
604 ip.run_cell("matplotlib = 1")
605
605
606 # After removing matplotlib from namespace, the magic should still be
606 # After removing matplotlib from namespace, the magic should still be
607 # the only option.
607 # the only option.
608 text, matches = c.complete("%mat")
608 text, matches = c.complete("%mat")
609 nt.assert_equal(matches, ["%matplotlib"])
609 nt.assert_equal(matches, ["%matplotlib"])
610
610
611 def test_magic_config():
611 def test_magic_config():
612 ip = get_ipython()
612 ip = get_ipython()
613 c = ip.Completer
613 c = ip.Completer
614
614
615 s, matches = c.complete(None, 'conf')
615 s, matches = c.complete(None, 'conf')
616 nt.assert_in('%config', matches)
616 nt.assert_in('%config', matches)
617 s, matches = c.complete(None, 'conf')
617 s, matches = c.complete(None, 'conf')
618 nt.assert_not_in('AliasManager', matches)
618 nt.assert_not_in('AliasManager', matches)
619 s, matches = c.complete(None, 'config ')
619 s, matches = c.complete(None, 'config ')
620 nt.assert_in('AliasManager', matches)
620 nt.assert_in('AliasManager', matches)
621 s, matches = c.complete(None, '%config ')
621 s, matches = c.complete(None, '%config ')
622 nt.assert_in('AliasManager', matches)
622 nt.assert_in('AliasManager', matches)
623 s, matches = c.complete(None, 'config Ali')
623 s, matches = c.complete(None, 'config Ali')
624 nt.assert_list_equal(['AliasManager'], matches)
624 nt.assert_list_equal(['AliasManager'], matches)
625 s, matches = c.complete(None, '%config Ali')
625 s, matches = c.complete(None, '%config Ali')
626 nt.assert_list_equal(['AliasManager'], matches)
626 nt.assert_list_equal(['AliasManager'], matches)
627 s, matches = c.complete(None, 'config AliasManager')
627 s, matches = c.complete(None, 'config AliasManager')
628 nt.assert_list_equal(['AliasManager'], matches)
628 nt.assert_list_equal(['AliasManager'], matches)
629 s, matches = c.complete(None, '%config AliasManager')
629 s, matches = c.complete(None, '%config AliasManager')
630 nt.assert_list_equal(['AliasManager'], matches)
630 nt.assert_list_equal(['AliasManager'], matches)
631 s, matches = c.complete(None, 'config AliasManager.')
631 s, matches = c.complete(None, 'config AliasManager.')
632 nt.assert_in('AliasManager.default_aliases', matches)
632 nt.assert_in('AliasManager.default_aliases', matches)
633 s, matches = c.complete(None, '%config AliasManager.')
633 s, matches = c.complete(None, '%config AliasManager.')
634 nt.assert_in('AliasManager.default_aliases', matches)
634 nt.assert_in('AliasManager.default_aliases', matches)
635 s, matches = c.complete(None, 'config AliasManager.de')
635 s, matches = c.complete(None, 'config AliasManager.de')
636 nt.assert_list_equal(['AliasManager.default_aliases'], matches)
636 nt.assert_list_equal(['AliasManager.default_aliases'], matches)
637 s, matches = c.complete(None, 'config AliasManager.de')
637 s, matches = c.complete(None, 'config AliasManager.de')
638 nt.assert_list_equal(['AliasManager.default_aliases'], matches)
638 nt.assert_list_equal(['AliasManager.default_aliases'], matches)
639
639
640
640
641 def test_magic_color():
641 def test_magic_color():
642 ip = get_ipython()
642 ip = get_ipython()
643 c = ip.Completer
643 c = ip.Completer
644
644
645 s, matches = c.complete(None, 'colo')
645 s, matches = c.complete(None, 'colo')
646 nt.assert_in('%colors', matches)
646 nt.assert_in('%colors', matches)
647 s, matches = c.complete(None, 'colo')
647 s, matches = c.complete(None, 'colo')
648 nt.assert_not_in('NoColor', matches)
648 nt.assert_not_in('NoColor', matches)
649 s, matches = c.complete(None, '%colors') # No trailing space
649 s, matches = c.complete(None, '%colors') # No trailing space
650 nt.assert_not_in('NoColor', matches)
650 nt.assert_not_in('NoColor', matches)
651 s, matches = c.complete(None, 'colors ')
651 s, matches = c.complete(None, 'colors ')
652 nt.assert_in('NoColor', matches)
652 nt.assert_in('NoColor', matches)
653 s, matches = c.complete(None, '%colors ')
653 s, matches = c.complete(None, '%colors ')
654 nt.assert_in('NoColor', matches)
654 nt.assert_in('NoColor', matches)
655 s, matches = c.complete(None, 'colors NoCo')
655 s, matches = c.complete(None, 'colors NoCo')
656 nt.assert_list_equal(['NoColor'], matches)
656 nt.assert_list_equal(['NoColor'], matches)
657 s, matches = c.complete(None, '%colors NoCo')
657 s, matches = c.complete(None, '%colors NoCo')
658 nt.assert_list_equal(['NoColor'], matches)
658 nt.assert_list_equal(['NoColor'], matches)
659
659
660
660
661 def test_match_dict_keys():
661 def test_match_dict_keys():
662 """
662 """
663 Test that match_dict_keys works on a couple of use case does return what
663 Test that match_dict_keys works on a couple of use case does return what
664 expected, and does not crash
664 expected, and does not crash
665 """
665 """
666 delims = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
666 delims = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
667
667
668
668
669 keys = ['foo', b'far']
669 keys = ['foo', b'far']
670 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2 ,['far'])
670 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2 ,['far'])
671 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2 ,['far'])
671 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2 ,['far'])
672 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2 ,['far'])
672 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2 ,['far'])
673 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2 ,['far'])
673 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2 ,['far'])
674
674
675 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1 ,['foo'])
675 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1 ,['foo'])
676 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1 ,['foo'])
676 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1 ,['foo'])
677 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1 ,['foo'])
677 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1 ,['foo'])
678 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1 ,['foo'])
678 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1 ,['foo'])
679
679
680 match_dict_keys
680 match_dict_keys
681
681
682
682
683 def test_dict_key_completion_string():
683 def test_dict_key_completion_string():
684 """Test dictionary key completion for string keys"""
684 """Test dictionary key completion for string keys"""
685 ip = get_ipython()
685 ip = get_ipython()
686 complete = ip.Completer.complete
686 complete = ip.Completer.complete
687
687
688 ip.user_ns['d'] = {'abc': None}
688 ip.user_ns['d'] = {'abc': None}
689
689
690 # check completion at different stages
690 # check completion at different stages
691 _, matches = complete(line_buffer="d[")
691 _, matches = complete(line_buffer="d[")
692 nt.assert_in("'abc'", matches)
692 nt.assert_in("'abc'", matches)
693 nt.assert_not_in("'abc']", matches)
693 nt.assert_not_in("'abc']", matches)
694
694
695 _, matches = complete(line_buffer="d['")
695 _, matches = complete(line_buffer="d['")
696 nt.assert_in("abc", matches)
696 nt.assert_in("abc", matches)
697 nt.assert_not_in("abc']", matches)
697 nt.assert_not_in("abc']", matches)
698
698
699 _, matches = complete(line_buffer="d['a")
699 _, matches = complete(line_buffer="d['a")
700 nt.assert_in("abc", matches)
700 nt.assert_in("abc", matches)
701 nt.assert_not_in("abc']", matches)
701 nt.assert_not_in("abc']", matches)
702
702
703 # check use of different quoting
703 # check use of different quoting
704 _, matches = complete(line_buffer="d[\"")
704 _, matches = complete(line_buffer="d[\"")
705 nt.assert_in("abc", matches)
705 nt.assert_in("abc", matches)
706 nt.assert_not_in('abc\"]', matches)
706 nt.assert_not_in('abc\"]', matches)
707
707
708 _, matches = complete(line_buffer="d[\"a")
708 _, matches = complete(line_buffer="d[\"a")
709 nt.assert_in("abc", matches)
709 nt.assert_in("abc", matches)
710 nt.assert_not_in('abc\"]', matches)
710 nt.assert_not_in('abc\"]', matches)
711
711
712 # check sensitivity to following context
712 # check sensitivity to following context
713 _, matches = complete(line_buffer="d[]", cursor_pos=2)
713 _, matches = complete(line_buffer="d[]", cursor_pos=2)
714 nt.assert_in("'abc'", matches)
714 nt.assert_in("'abc'", matches)
715
715
716 _, matches = complete(line_buffer="d['']", cursor_pos=3)
716 _, matches = complete(line_buffer="d['']", cursor_pos=3)
717 nt.assert_in("abc", matches)
717 nt.assert_in("abc", matches)
718 nt.assert_not_in("abc'", matches)
718 nt.assert_not_in("abc'", matches)
719 nt.assert_not_in("abc']", matches)
719 nt.assert_not_in("abc']", matches)
720
720
721 # check multiple solutions are correctly returned and that noise is not
721 # check multiple solutions are correctly returned and that noise is not
722 ip.user_ns['d'] = {'abc': None, 'abd': None, 'bad': None, object(): None,
722 ip.user_ns['d'] = {'abc': None, 'abd': None, 'bad': None, object(): None,
723 5: None}
723 5: None}
724
724
725 _, matches = complete(line_buffer="d['a")
725 _, matches = complete(line_buffer="d['a")
726 nt.assert_in("abc", matches)
726 nt.assert_in("abc", matches)
727 nt.assert_in("abd", matches)
727 nt.assert_in("abd", matches)
728 nt.assert_not_in("bad", matches)
728 nt.assert_not_in("bad", matches)
729 assert not any(m.endswith((']', '"', "'")) for m in matches), matches
729 assert not any(m.endswith((']', '"', "'")) for m in matches), matches
730
730
731 # check escaping and whitespace
731 # check escaping and whitespace
732 ip.user_ns['d'] = {'a\nb': None, 'a\'b': None, 'a"b': None, 'a word': None}
732 ip.user_ns['d'] = {'a\nb': None, 'a\'b': None, 'a"b': None, 'a word': None}
733 _, matches = complete(line_buffer="d['a")
733 _, matches = complete(line_buffer="d['a")
734 nt.assert_in("a\\nb", matches)
734 nt.assert_in("a\\nb", matches)
735 nt.assert_in("a\\'b", matches)
735 nt.assert_in("a\\'b", matches)
736 nt.assert_in("a\"b", matches)
736 nt.assert_in("a\"b", matches)
737 nt.assert_in("a word", matches)
737 nt.assert_in("a word", matches)
738 assert not any(m.endswith((']', '"', "'")) for m in matches), matches
738 assert not any(m.endswith((']', '"', "'")) for m in matches), matches
739
739
740 # - can complete on non-initial word of the string
740 # - can complete on non-initial word of the string
741 _, matches = complete(line_buffer="d['a w")
741 _, matches = complete(line_buffer="d['a w")
742 nt.assert_in("word", matches)
742 nt.assert_in("word", matches)
743
743
744 # - understands quote escaping
744 # - understands quote escaping
745 _, matches = complete(line_buffer="d['a\\'")
745 _, matches = complete(line_buffer="d['a\\'")
746 nt.assert_in("b", matches)
746 nt.assert_in("b", matches)
747
747
748 # - default quoting should work like repr
748 # - default quoting should work like repr
749 _, matches = complete(line_buffer="d[")
749 _, matches = complete(line_buffer="d[")
750 nt.assert_in("\"a'b\"", matches)
750 nt.assert_in("\"a'b\"", matches)
751
751
752 # - when opening quote with ", possible to match with unescaped apostrophe
752 # - when opening quote with ", possible to match with unescaped apostrophe
753 _, matches = complete(line_buffer="d[\"a'")
753 _, matches = complete(line_buffer="d[\"a'")
754 nt.assert_in("b", matches)
754 nt.assert_in("b", matches)
755
755
756 # need to not split at delims that readline won't split at
756 # need to not split at delims that readline won't split at
757 if '-' not in ip.Completer.splitter.delims:
757 if '-' not in ip.Completer.splitter.delims:
758 ip.user_ns['d'] = {'before-after': None}
758 ip.user_ns['d'] = {'before-after': None}
759 _, matches = complete(line_buffer="d['before-af")
759 _, matches = complete(line_buffer="d['before-af")
760 nt.assert_in('before-after', matches)
760 nt.assert_in('before-after', matches)
761
761
762 def test_dict_key_completion_contexts():
762 def test_dict_key_completion_contexts():
763 """Test expression contexts in which dict key completion occurs"""
763 """Test expression contexts in which dict key completion occurs"""
764 ip = get_ipython()
764 ip = get_ipython()
765 complete = ip.Completer.complete
765 complete = ip.Completer.complete
766 d = {'abc': None}
766 d = {'abc': None}
767 ip.user_ns['d'] = d
767 ip.user_ns['d'] = d
768
768
769 class C:
769 class C:
770 data = d
770 data = d
771 ip.user_ns['C'] = C
771 ip.user_ns['C'] = C
772 ip.user_ns['get'] = lambda: d
772 ip.user_ns['get'] = lambda: d
773
773
774 def assert_no_completion(**kwargs):
774 def assert_no_completion(**kwargs):
775 _, matches = complete(**kwargs)
775 _, matches = complete(**kwargs)
776 nt.assert_not_in('abc', matches)
776 nt.assert_not_in('abc', matches)
777 nt.assert_not_in('abc\'', matches)
777 nt.assert_not_in('abc\'', matches)
778 nt.assert_not_in('abc\']', matches)
778 nt.assert_not_in('abc\']', matches)
779 nt.assert_not_in('\'abc\'', matches)
779 nt.assert_not_in('\'abc\'', matches)
780 nt.assert_not_in('\'abc\']', matches)
780 nt.assert_not_in('\'abc\']', matches)
781
781
782 def assert_completion(**kwargs):
782 def assert_completion(**kwargs):
783 _, matches = complete(**kwargs)
783 _, matches = complete(**kwargs)
784 nt.assert_in("'abc'", matches)
784 nt.assert_in("'abc'", matches)
785 nt.assert_not_in("'abc']", matches)
785 nt.assert_not_in("'abc']", matches)
786
786
787 # no completion after string closed, even if reopened
787 # no completion after string closed, even if reopened
788 assert_no_completion(line_buffer="d['a'")
788 assert_no_completion(line_buffer="d['a'")
789 assert_no_completion(line_buffer="d[\"a\"")
789 assert_no_completion(line_buffer="d[\"a\"")
790 assert_no_completion(line_buffer="d['a' + ")
790 assert_no_completion(line_buffer="d['a' + ")
791 assert_no_completion(line_buffer="d['a' + '")
791 assert_no_completion(line_buffer="d['a' + '")
792
792
793 # completion in non-trivial expressions
793 # completion in non-trivial expressions
794 assert_completion(line_buffer="+ d[")
794 assert_completion(line_buffer="+ d[")
795 assert_completion(line_buffer="(d[")
795 assert_completion(line_buffer="(d[")
796 assert_completion(line_buffer="C.data[")
796 assert_completion(line_buffer="C.data[")
797
797
798 # greedy flag
798 # greedy flag
799 def assert_completion(**kwargs):
799 def assert_completion(**kwargs):
800 _, matches = complete(**kwargs)
800 _, matches = complete(**kwargs)
801 nt.assert_in("get()['abc']", matches)
801 nt.assert_in("get()['abc']", matches)
802
802
803 assert_no_completion(line_buffer="get()[")
803 assert_no_completion(line_buffer="get()[")
804 with greedy_completion():
804 with greedy_completion():
805 assert_completion(line_buffer="get()[")
805 assert_completion(line_buffer="get()[")
806 assert_completion(line_buffer="get()['")
806 assert_completion(line_buffer="get()['")
807 assert_completion(line_buffer="get()['a")
807 assert_completion(line_buffer="get()['a")
808 assert_completion(line_buffer="get()['ab")
808 assert_completion(line_buffer="get()['ab")
809 assert_completion(line_buffer="get()['abc")
809 assert_completion(line_buffer="get()['abc")
810
810
811
811
812
812
813 def test_dict_key_completion_bytes():
813 def test_dict_key_completion_bytes():
814 """Test handling of bytes in dict key completion"""
814 """Test handling of bytes in dict key completion"""
815 ip = get_ipython()
815 ip = get_ipython()
816 complete = ip.Completer.complete
816 complete = ip.Completer.complete
817
817
818 ip.user_ns['d'] = {'abc': None, b'abd': None}
818 ip.user_ns['d'] = {'abc': None, b'abd': None}
819
819
820 _, matches = complete(line_buffer="d[")
820 _, matches = complete(line_buffer="d[")
821 nt.assert_in("'abc'", matches)
821 nt.assert_in("'abc'", matches)
822 nt.assert_in("b'abd'", matches)
822 nt.assert_in("b'abd'", matches)
823
823
824 if False: # not currently implemented
824 if False: # not currently implemented
825 _, matches = complete(line_buffer="d[b")
825 _, matches = complete(line_buffer="d[b")
826 nt.assert_in("b'abd'", matches)
826 nt.assert_in("b'abd'", matches)
827 nt.assert_not_in("b'abc'", matches)
827 nt.assert_not_in("b'abc'", matches)
828
828
829 _, matches = complete(line_buffer="d[b'")
829 _, matches = complete(line_buffer="d[b'")
830 nt.assert_in("abd", matches)
830 nt.assert_in("abd", matches)
831 nt.assert_not_in("abc", matches)
831 nt.assert_not_in("abc", matches)
832
832
833 _, matches = complete(line_buffer="d[B'")
833 _, matches = complete(line_buffer="d[B'")
834 nt.assert_in("abd", matches)
834 nt.assert_in("abd", matches)
835 nt.assert_not_in("abc", matches)
835 nt.assert_not_in("abc", matches)
836
836
837 _, matches = complete(line_buffer="d['")
837 _, matches = complete(line_buffer="d['")
838 nt.assert_in("abc", matches)
838 nt.assert_in("abc", matches)
839 nt.assert_not_in("abd", matches)
839 nt.assert_not_in("abd", matches)
840
840
841
841
842 def test_dict_key_completion_unicode_py3():
842 def test_dict_key_completion_unicode_py3():
843 """Test handling of unicode in dict key completion"""
843 """Test handling of unicode in dict key completion"""
844 ip = get_ipython()
844 ip = get_ipython()
845 complete = ip.Completer.complete
845 complete = ip.Completer.complete
846
846
847 ip.user_ns['d'] = {u'a\u05d0': None}
847 ip.user_ns['d'] = {u'a\u05d0': None}
848
848
849 # query using escape
849 # query using escape
850 if sys.platform != 'win32':
850 if sys.platform != 'win32':
851 # Known failure on Windows
851 # Known failure on Windows
852 _, matches = complete(line_buffer="d['a\\u05d0")
852 _, matches = complete(line_buffer="d['a\\u05d0")
853 nt.assert_in("u05d0", matches) # tokenized after \\
853 nt.assert_in("u05d0", matches) # tokenized after \\
854
854
855 # query using character
855 # query using character
856 _, matches = complete(line_buffer="d['a\u05d0")
856 _, matches = complete(line_buffer="d['a\u05d0")
857 nt.assert_in(u"a\u05d0", matches)
857 nt.assert_in(u"a\u05d0", matches)
858
858
859 with greedy_completion():
859 with greedy_completion():
860 # query using escape
860 # query using escape
861 _, matches = complete(line_buffer="d['a\\u05d0")
861 _, matches = complete(line_buffer="d['a\\u05d0")
862 nt.assert_in("d['a\\u05d0']", matches) # tokenized after \\
862 nt.assert_in("d['a\\u05d0']", matches) # tokenized after \\
863
863
864 # query using character
864 # query using character
865 _, matches = complete(line_buffer="d['a\u05d0")
865 _, matches = complete(line_buffer="d['a\u05d0")
866 nt.assert_in(u"d['a\u05d0']", matches)
866 nt.assert_in(u"d['a\u05d0']", matches)
867
867
868
868
869
869
870 @dec.skip_without('numpy')
870 @dec.skip_without('numpy')
871 def test_struct_array_key_completion():
871 def test_struct_array_key_completion():
872 """Test dict key completion applies to numpy struct arrays"""
872 """Test dict key completion applies to numpy struct arrays"""
873 import numpy
873 import numpy
874 ip = get_ipython()
874 ip = get_ipython()
875 complete = ip.Completer.complete
875 complete = ip.Completer.complete
876 ip.user_ns['d'] = numpy.array([], dtype=[('hello', 'f'), ('world', 'f')])
876 ip.user_ns['d'] = numpy.array([], dtype=[('hello', 'f'), ('world', 'f')])
877 _, matches = complete(line_buffer="d['")
877 _, matches = complete(line_buffer="d['")
878 nt.assert_in("hello", matches)
878 nt.assert_in("hello", matches)
879 nt.assert_in("world", matches)
879 nt.assert_in("world", matches)
880 # complete on the numpy struct itself
880 # complete on the numpy struct itself
881 dt = numpy.dtype([('my_head', [('my_dt', '>u4'), ('my_df', '>u4')]),
881 dt = numpy.dtype([('my_head', [('my_dt', '>u4'), ('my_df', '>u4')]),
882 ('my_data', '>f4', 5)])
882 ('my_data', '>f4', 5)])
883 x = numpy.zeros(2, dtype=dt)
883 x = numpy.zeros(2, dtype=dt)
884 ip.user_ns['d'] = x[1]
884 ip.user_ns['d'] = x[1]
885 _, matches = complete(line_buffer="d['")
885 _, matches = complete(line_buffer="d['")
886 nt.assert_in("my_head", matches)
886 nt.assert_in("my_head", matches)
887 nt.assert_in("my_data", matches)
887 nt.assert_in("my_data", matches)
888 # complete on a nested level
888 # complete on a nested level
889 with greedy_completion():
889 with greedy_completion():
890 ip.user_ns['d'] = numpy.zeros(2, dtype=dt)
890 ip.user_ns['d'] = numpy.zeros(2, dtype=dt)
891 _, matches = complete(line_buffer="d[1]['my_head']['")
891 _, matches = complete(line_buffer="d[1]['my_head']['")
892 nt.assert_true(any(["my_dt" in m for m in matches]))
892 nt.assert_true(any(["my_dt" in m for m in matches]))
893 nt.assert_true(any(["my_df" in m for m in matches]))
893 nt.assert_true(any(["my_df" in m for m in matches]))
894
894
895
895
896 @dec.skip_without('pandas')
896 @dec.skip_without('pandas')
897 def test_dataframe_key_completion():
897 def test_dataframe_key_completion():
898 """Test dict key completion applies to pandas DataFrames"""
898 """Test dict key completion applies to pandas DataFrames"""
899 import pandas
899 import pandas
900 ip = get_ipython()
900 ip = get_ipython()
901 complete = ip.Completer.complete
901 complete = ip.Completer.complete
902 ip.user_ns['d'] = pandas.DataFrame({'hello': [1], 'world': [2]})
902 ip.user_ns['d'] = pandas.DataFrame({'hello': [1], 'world': [2]})
903 _, matches = complete(line_buffer="d['")
903 _, matches = complete(line_buffer="d['")
904 nt.assert_in("hello", matches)
904 nt.assert_in("hello", matches)
905 nt.assert_in("world", matches)
905 nt.assert_in("world", matches)
906
906
907
907
908 def test_dict_key_completion_invalids():
908 def test_dict_key_completion_invalids():
909 """Smoke test cases dict key completion can't handle"""
909 """Smoke test cases dict key completion can't handle"""
910 ip = get_ipython()
910 ip = get_ipython()
911 complete = ip.Completer.complete
911 complete = ip.Completer.complete
912
912
913 ip.user_ns['no_getitem'] = None
913 ip.user_ns['no_getitem'] = None
914 ip.user_ns['no_keys'] = []
914 ip.user_ns['no_keys'] = []
915 ip.user_ns['cant_call_keys'] = dict
915 ip.user_ns['cant_call_keys'] = dict
916 ip.user_ns['empty'] = {}
916 ip.user_ns['empty'] = {}
917 ip.user_ns['d'] = {'abc': 5}
917 ip.user_ns['d'] = {'abc': 5}
918
918
919 _, matches = complete(line_buffer="no_getitem['")
919 _, matches = complete(line_buffer="no_getitem['")
920 _, matches = complete(line_buffer="no_keys['")
920 _, matches = complete(line_buffer="no_keys['")
921 _, matches = complete(line_buffer="cant_call_keys['")
921 _, matches = complete(line_buffer="cant_call_keys['")
922 _, matches = complete(line_buffer="empty['")
922 _, matches = complete(line_buffer="empty['")
923 _, matches = complete(line_buffer="name_error['")
923 _, matches = complete(line_buffer="name_error['")
924 _, matches = complete(line_buffer="d['\\") # incomplete escape
924 _, matches = complete(line_buffer="d['\\") # incomplete escape
925
925
926 class KeyCompletable(object):
926 class KeyCompletable(object):
927 def __init__(self, things=()):
927 def __init__(self, things=()):
928 self.things = things
928 self.things = things
929
929
930 def _ipython_key_completions_(self):
930 def _ipython_key_completions_(self):
931 return list(self.things)
931 return list(self.things)
932
932
933 def test_object_key_completion():
933 def test_object_key_completion():
934 ip = get_ipython()
934 ip = get_ipython()
935 ip.user_ns['key_completable'] = KeyCompletable(['qwerty', 'qwick'])
935 ip.user_ns['key_completable'] = KeyCompletable(['qwerty', 'qwick'])
936
936
937 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
937 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
938 nt.assert_in('qwerty', matches)
938 nt.assert_in('qwerty', matches)
939 nt.assert_in('qwick', matches)
939 nt.assert_in('qwick', matches)
940
940
941
941
942 class NamedInstanceMetaclass(type):
943 def __getitem__(cls, item):
944 return cls.get_instance(item)
945
946 class NamedInstanceClass(object, metaclass=NamedInstanceMetaclass):
947 def __init__(self, name):
948 if not hasattr(self.__class__, 'instances'):
949 self.__class__.instances = {}
950 self.__class__.instances[name] = self
951
952 @classmethod
953 def _ipython_key_completions_(cls):
954 return cls.instances.keys()
955
956 @classmethod
957 def get_instance(cls, name):
958 return cls.instances[name]
959
960 def test_class_key_completion():
961 ip = get_ipython()
962 NamedInstanceClass('qwerty')
963 NamedInstanceClass('qwick')
964 ip.user_ns['named_instance_class'] = NamedInstanceClass
965
966 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
967 nt.assert_in('qwerty', matches)
968 nt.assert_in('qwick', matches)
969
942 def test_tryimport():
970 def test_tryimport():
943 """
971 """
944 Test that try-import don't crash on trailing dot, and import modules before
972 Test that try-import don't crash on trailing dot, and import modules before
945 """
973 """
946 from IPython.core.completerlib import try_import
974 from IPython.core.completerlib import try_import
947 assert(try_import("IPython."))
975 assert(try_import("IPython."))
948
976
949
977
950 def test_aimport_module_completer():
978 def test_aimport_module_completer():
951 ip = get_ipython()
979 ip = get_ipython()
952 _, matches = ip.complete('i', '%aimport i')
980 _, matches = ip.complete('i', '%aimport i')
953 nt.assert_in('io', matches)
981 nt.assert_in('io', matches)
954 nt.assert_not_in('int', matches)
982 nt.assert_not_in('int', matches)
955
983
956 def test_nested_import_module_completer():
984 def test_nested_import_module_completer():
957 ip = get_ipython()
985 ip = get_ipython()
958 _, matches = ip.complete(None, 'import IPython.co', 17)
986 _, matches = ip.complete(None, 'import IPython.co', 17)
959 nt.assert_in('IPython.core', matches)
987 nt.assert_in('IPython.core', matches)
960 nt.assert_not_in('import IPython.core', matches)
988 nt.assert_not_in('import IPython.core', matches)
961 nt.assert_not_in('IPython.display', matches)
989 nt.assert_not_in('IPython.display', matches)
962
990
963 def test_import_module_completer():
991 def test_import_module_completer():
964 ip = get_ipython()
992 ip = get_ipython()
965 _, matches = ip.complete('i', 'import i')
993 _, matches = ip.complete('i', 'import i')
966 nt.assert_in('io', matches)
994 nt.assert_in('io', matches)
967 nt.assert_not_in('int', matches)
995 nt.assert_not_in('int', matches)
968
996
969 def test_from_module_completer():
997 def test_from_module_completer():
970 ip = get_ipython()
998 ip = get_ipython()
971 _, matches = ip.complete('B', 'from io import B', 16)
999 _, matches = ip.complete('B', 'from io import B', 16)
972 nt.assert_in('BytesIO', matches)
1000 nt.assert_in('BytesIO', matches)
973 nt.assert_not_in('BaseException', matches)
1001 nt.assert_not_in('BaseException', matches)
974
1002
975 def test_snake_case_completion():
1003 def test_snake_case_completion():
976 ip = get_ipython()
1004 ip = get_ipython()
977 ip.user_ns['some_three'] = 3
1005 ip.user_ns['some_three'] = 3
978 ip.user_ns['some_four'] = 4
1006 ip.user_ns['some_four'] = 4
979 _, matches = ip.complete("s_", "print(s_f")
1007 _, matches = ip.complete("s_", "print(s_f")
980 nt.assert_in('some_three', matches)
1008 nt.assert_in('some_three', matches)
981 nt.assert_in('some_four', matches)
1009 nt.assert_in('some_four', matches)
@@ -1,83 +1,84 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A fancy version of Python's builtin :func:`dir` function.
2 """A fancy version of Python's builtin :func:`dir` function.
3 """
3 """
4
4
5 # Copyright (c) IPython Development Team.
5 # Copyright (c) IPython Development Team.
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7
7
8 import inspect
8 import inspect
9 import types
9
10
10
11
11 def safe_hasattr(obj, attr):
12 def safe_hasattr(obj, attr):
12 """In recent versions of Python, hasattr() only catches AttributeError.
13 """In recent versions of Python, hasattr() only catches AttributeError.
13 This catches all errors.
14 This catches all errors.
14 """
15 """
15 try:
16 try:
16 getattr(obj, attr)
17 getattr(obj, attr)
17 return True
18 return True
18 except:
19 except:
19 return False
20 return False
20
21
21
22
22 def dir2(obj):
23 def dir2(obj):
23 """dir2(obj) -> list of strings
24 """dir2(obj) -> list of strings
24
25
25 Extended version of the Python builtin dir(), which does a few extra
26 Extended version of the Python builtin dir(), which does a few extra
26 checks.
27 checks.
27
28
28 This version is guaranteed to return only a list of true strings, whereas
29 This version is guaranteed to return only a list of true strings, whereas
29 dir() returns anything that objects inject into themselves, even if they
30 dir() returns anything that objects inject into themselves, even if they
30 are later not really valid for attribute access (many extension libraries
31 are later not really valid for attribute access (many extension libraries
31 have such bugs).
32 have such bugs).
32 """
33 """
33
34
34 # Start building the attribute list via dir(), and then complete it
35 # Start building the attribute list via dir(), and then complete it
35 # with a few extra special-purpose calls.
36 # with a few extra special-purpose calls.
36
37
37 try:
38 try:
38 words = set(dir(obj))
39 words = set(dir(obj))
39 except Exception:
40 except Exception:
40 # TypeError: dir(obj) does not return a list
41 # TypeError: dir(obj) does not return a list
41 words = set()
42 words = set()
42
43
43 if safe_hasattr(obj, '__class__'):
44 if safe_hasattr(obj, '__class__'):
44 words |= set(dir(obj.__class__))
45 words |= set(dir(obj.__class__))
45
46
46 # filter out non-string attributes which may be stuffed by dir() calls
47 # filter out non-string attributes which may be stuffed by dir() calls
47 # and poor coding in third-party modules
48 # and poor coding in third-party modules
48
49
49 words = [w for w in words if isinstance(w, str)]
50 words = [w for w in words if isinstance(w, str)]
50 return sorted(words)
51 return sorted(words)
51
52
52
53
53 def get_real_method(obj, name):
54 def get_real_method(obj, name):
54 """Like getattr, but with a few extra sanity checks:
55 """Like getattr, but with a few extra sanity checks:
55
56
56 - If obj is a class, ignore its methods
57 - If obj is a class, ignore everything except class methods
57 - Check if obj is a proxy that claims to have all attributes
58 - Check if obj is a proxy that claims to have all attributes
58 - Catch attribute access failing with any exception
59 - Catch attribute access failing with any exception
59 - Check that the attribute is a callable object
60 - Check that the attribute is a callable object
60
61
61 Returns the method or None.
62 Returns the method or None.
62 """
63 """
63 if inspect.isclass(obj):
64 return None
65
66 try:
64 try:
67 canary = getattr(obj, '_ipython_canary_method_should_not_exist_', None)
65 canary = getattr(obj, '_ipython_canary_method_should_not_exist_', None)
68 except Exception:
66 except Exception:
69 return None
67 return None
70
68
71 if canary is not None:
69 if canary is not None:
72 # It claimed to have an attribute it should never have
70 # It claimed to have an attribute it should never have
73 return None
71 return None
74
72
75 try:
73 try:
76 m = getattr(obj, name, None)
74 m = getattr(obj, name, None)
77 except Exception:
75 except Exception:
78 return None
76 return None
79
77
78 if inspect.isclass(obj) and not isinstance(m, types.MethodType):
79 return None
80
80 if callable(m):
81 if callable(m):
81 return m
82 return m
82
83
83 return None
84 return None
General Comments 0
You need to be logged in to leave comments. Login now