##// END OF EJS Templates
Fix a couple of types annotation and actual types errors....
Matthias Bussonnier -
Show More
@@ -1,1933 +1,1933 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Completion for IPython.
2 """Completion for IPython.
3
3
4 This module started as fork of the rlcompleter module in the Python standard
4 This module started as fork of the rlcompleter module in the Python standard
5 library. The original enhancements made to rlcompleter have been sent
5 library. The original enhancements made to rlcompleter have been sent
6 upstream and were accepted as of Python 2.3,
6 upstream and were accepted as of Python 2.3,
7
7
8 This module now support a wide variety of completion mechanism both available
8 This module now support a wide variety of completion mechanism both available
9 for normal classic Python code, as well as completer for IPython specific
9 for normal classic Python code, as well as completer for IPython specific
10 Syntax like magics.
10 Syntax like magics.
11
11
12 Latex and Unicode completion
12 Latex and Unicode completion
13 ============================
13 ============================
14
14
15 IPython and compatible frontends not only can complete your code, but can help
15 IPython and compatible frontends not only can complete your code, but can help
16 you to input a wide range of characters. In particular we allow you to insert
16 you to input a wide range of characters. In particular we allow you to insert
17 a unicode character using the tab completion mechanism.
17 a unicode character using the tab completion mechanism.
18
18
19 Forward latex/unicode completion
19 Forward latex/unicode completion
20 --------------------------------
20 --------------------------------
21
21
22 Forward completion allows you to easily type a unicode character using its latex
22 Forward completion allows you to easily type a unicode character using its latex
23 name, or unicode long description. To do so type a backslash follow by the
23 name, or unicode long description. To do so type a backslash follow by the
24 relevant name and press tab:
24 relevant name and press tab:
25
25
26
26
27 Using latex completion:
27 Using latex completion:
28
28
29 .. code::
29 .. code::
30
30
31 \\alpha<tab>
31 \\alpha<tab>
32 Ξ±
32 Ξ±
33
33
34 or using unicode completion:
34 or using unicode completion:
35
35
36
36
37 .. code::
37 .. code::
38
38
39 \\greek small letter alpha<tab>
39 \\greek small letter alpha<tab>
40 Ξ±
40 Ξ±
41
41
42
42
43 Only valid Python identifiers will complete. Combining characters (like arrow or
43 Only valid Python identifiers will complete. Combining characters (like arrow or
44 dots) are also available, unlike latex they need to be put after the their
44 dots) are also available, unlike latex they need to be put after the their
45 counterpart that is to say, `F\\\\vec<tab>` is correct, not `\\\\vec<tab>F`.
45 counterpart that is to say, `F\\\\vec<tab>` is correct, not `\\\\vec<tab>F`.
46
46
47 Some browsers are known to display combining characters incorrectly.
47 Some browsers are known to display combining characters incorrectly.
48
48
49 Backward latex completion
49 Backward latex completion
50 -------------------------
50 -------------------------
51
51
52 It is sometime challenging to know how to type a character, if you are using
52 It is sometime challenging to know how to type a character, if you are using
53 IPython, or any compatible frontend you can prepend backslash to the character
53 IPython, or any compatible frontend you can prepend backslash to the character
54 and press `<tab>` to expand it to its latex form.
54 and press `<tab>` to expand it to its latex form.
55
55
56 .. code::
56 .. code::
57
57
58 \\Ξ±<tab>
58 \\Ξ±<tab>
59 \\alpha
59 \\alpha
60
60
61
61
62 Both forward and backward completions can be deactivated by setting the
62 Both forward and backward completions can be deactivated by setting the
63 ``Completer.backslash_combining_completions`` option to ``False``.
63 ``Completer.backslash_combining_completions`` option to ``False``.
64
64
65
65
66 Experimental
66 Experimental
67 ============
67 ============
68
68
69 Starting with IPython 6.0, this module can make use of the Jedi library to
69 Starting with IPython 6.0, this module can make use of the Jedi library to
70 generate completions both using static analysis of the code, and dynamically
70 generate completions both using static analysis of the code, and dynamically
71 inspecting multiple namespaces. The APIs attached to this new mechanism is
71 inspecting multiple namespaces. The APIs attached to this new mechanism is
72 unstable and will raise unless use in an :any:`provisionalcompleter` context
72 unstable and will raise unless use in an :any:`provisionalcompleter` context
73 manager.
73 manager.
74
74
75 You will find that the following are experimental:
75 You will find that the following are experimental:
76
76
77 - :any:`provisionalcompleter`
77 - :any:`provisionalcompleter`
78 - :any:`IPCompleter.completions`
78 - :any:`IPCompleter.completions`
79 - :any:`Completion`
79 - :any:`Completion`
80 - :any:`rectify_completions`
80 - :any:`rectify_completions`
81
81
82 .. note::
82 .. note::
83
83
84 better name for :any:`rectify_completions` ?
84 better name for :any:`rectify_completions` ?
85
85
86 We welcome any feedback on these new API, and we also encourage you to try this
86 We welcome any feedback on these new API, and we also encourage you to try this
87 module in debug mode (start IPython with ``--Completer.debug=True``) in order
87 module in debug mode (start IPython with ``--Completer.debug=True``) in order
88 to have extra logging information is :any:`jedi` is crashing, or if current
88 to have extra logging information is :any:`jedi` is crashing, or if current
89 IPython completer pending deprecations are returning results not yet handled
89 IPython completer pending deprecations are returning results not yet handled
90 by :any:`jedi`.
90 by :any:`jedi`.
91
91
92 Using Jedi for tab completion allow snippets like the following to work without
92 Using Jedi for tab completion allow snippets like the following to work without
93 having to execute any code:
93 having to execute any code:
94
94
95 >>> myvar = ['hello', 42]
95 >>> myvar = ['hello', 42]
96 ... myvar[1].bi<tab>
96 ... myvar[1].bi<tab>
97
97
98 Tab completion will be able to infer that ``myvar[1]`` is a real number without
98 Tab completion will be able to infer that ``myvar[1]`` is a real number without
99 executing any code unlike the previously available ``IPCompleter.greedy``
99 executing any code unlike the previously available ``IPCompleter.greedy``
100 option.
100 option.
101
101
102 Be sure to update :any:`jedi` to the latest stable version or to try the
102 Be sure to update :any:`jedi` to the latest stable version or to try the
103 current development version to get better completions.
103 current development version to get better completions.
104 """
104 """
105
105
106 # skip module docstests
106 # skip module docstests
107 skip_doctest = True
107 skip_doctest = True
108
108
109 # Copyright (c) IPython Development Team.
109 # Copyright (c) IPython Development Team.
110 # Distributed under the terms of the Modified BSD License.
110 # Distributed under the terms of the Modified BSD License.
111 #
111 #
112 # Some of this code originated from rlcompleter in the Python standard library
112 # Some of this code originated from rlcompleter in the Python standard library
113 # Copyright (C) 2001 Python Software Foundation, www.python.org
113 # Copyright (C) 2001 Python Software Foundation, www.python.org
114
114
115
115
116 import __main__
116 import __main__
117 import builtins as builtin_mod
117 import builtins as builtin_mod
118 import glob
118 import glob
119 import time
119 import time
120 import inspect
120 import inspect
121 import itertools
121 import itertools
122 import keyword
122 import keyword
123 import os
123 import os
124 import re
124 import re
125 import sys
125 import sys
126 import unicodedata
126 import unicodedata
127 import string
127 import string
128 import warnings
128 import warnings
129
129
130 from contextlib import contextmanager
130 from contextlib import contextmanager
131 from importlib import import_module
131 from importlib import import_module
132 from typing import Iterator, List
132 from typing import Iterator, List, Tuple, Iterable, Union
133 from types import SimpleNamespace
133 from types import SimpleNamespace
134
134
135 from traitlets.config.configurable import Configurable
135 from traitlets.config.configurable import Configurable
136 from IPython.core.error import TryNext
136 from IPython.core.error import TryNext
137 from IPython.core.inputsplitter import ESC_MAGIC
137 from IPython.core.inputsplitter import ESC_MAGIC
138 from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol
138 from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol
139 from IPython.utils import generics
139 from IPython.utils import generics
140 from IPython.utils.dir2 import dir2, get_real_method
140 from IPython.utils.dir2 import dir2, get_real_method
141 from IPython.utils.process import arg_split
141 from IPython.utils.process import arg_split
142 from traitlets import Bool, Enum, observe, Int
142 from traitlets import Bool, Enum, observe, Int
143
143
144 try:
144 try:
145 import jedi
145 import jedi
146 import jedi.api.helpers
146 import jedi.api.helpers
147 JEDI_INSTALLED = True
147 JEDI_INSTALLED = True
148 except ImportError:
148 except ImportError:
149 JEDI_INSTALLED = False
149 JEDI_INSTALLED = False
150 #-----------------------------------------------------------------------------
150 #-----------------------------------------------------------------------------
151 # Globals
151 # Globals
152 #-----------------------------------------------------------------------------
152 #-----------------------------------------------------------------------------
153
153
154 # Public API
154 # Public API
155 __all__ = ['Completer','IPCompleter']
155 __all__ = ['Completer','IPCompleter']
156
156
157 if sys.platform == 'win32':
157 if sys.platform == 'win32':
158 PROTECTABLES = ' '
158 PROTECTABLES = ' '
159 else:
159 else:
160 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
160 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
161
161
162
162
163 _deprecation_readline_sentinel = object()
163 _deprecation_readline_sentinel = object()
164
164
165
165
166 class ProvisionalCompleterWarning(FutureWarning):
166 class ProvisionalCompleterWarning(FutureWarning):
167 """
167 """
168 Exception raise by an experimental feature in this module.
168 Exception raise by an experimental feature in this module.
169
169
170 Wrap code in :any:`provisionalcompleter` context manager if you
170 Wrap code in :any:`provisionalcompleter` context manager if you
171 are certain you want to use an unstable feature.
171 are certain you want to use an unstable feature.
172 """
172 """
173 pass
173 pass
174
174
175 warnings.filterwarnings('error', category=ProvisionalCompleterWarning)
175 warnings.filterwarnings('error', category=ProvisionalCompleterWarning)
176
176
177 @contextmanager
177 @contextmanager
178 def provisionalcompleter(action='ignore'):
178 def provisionalcompleter(action='ignore'):
179 """
179 """
180
180
181
181
182 This contest manager has to be used in any place where unstable completer
182 This contest manager has to be used in any place where unstable completer
183 behavior and API may be called.
183 behavior and API may be called.
184
184
185 >>> with provisionalcompleter():
185 >>> with provisionalcompleter():
186 ... completer.do_experimetal_things() # works
186 ... completer.do_experimetal_things() # works
187
187
188 >>> completer.do_experimental_things() # raises.
188 >>> completer.do_experimental_things() # raises.
189
189
190 .. note:: Unstable
190 .. note:: Unstable
191
191
192 By using this context manager you agree that the API in use may change
192 By using this context manager you agree that the API in use may change
193 without warning, and that you won't complain if they do so.
193 without warning, and that you won't complain if they do so.
194
194
195 You also understand that if the API is not to you liking you should report
195 You also understand that if the API is not to you liking you should report
196 a bug to explain your use case upstream and improve the API and will loose
196 a bug to explain your use case upstream and improve the API and will loose
197 credibility if you complain after the API is make stable.
197 credibility if you complain after the API is make stable.
198
198
199 We'll be happy to get your feedback , feature request and improvement on
199 We'll be happy to get your feedback , feature request and improvement on
200 any of the unstable APIs !
200 any of the unstable APIs !
201 """
201 """
202 with warnings.catch_warnings():
202 with warnings.catch_warnings():
203 warnings.filterwarnings(action, category=ProvisionalCompleterWarning)
203 warnings.filterwarnings(action, category=ProvisionalCompleterWarning)
204 yield
204 yield
205
205
206
206
207 def has_open_quotes(s):
207 def has_open_quotes(s):
208 """Return whether a string has open quotes.
208 """Return whether a string has open quotes.
209
209
210 This simply counts whether the number of quote characters of either type in
210 This simply counts whether the number of quote characters of either type in
211 the string is odd.
211 the string is odd.
212
212
213 Returns
213 Returns
214 -------
214 -------
215 If there is an open quote, the quote character is returned. Else, return
215 If there is an open quote, the quote character is returned. Else, return
216 False.
216 False.
217 """
217 """
218 # We check " first, then ', so complex cases with nested quotes will get
218 # We check " first, then ', so complex cases with nested quotes will get
219 # the " to take precedence.
219 # the " to take precedence.
220 if s.count('"') % 2:
220 if s.count('"') % 2:
221 return '"'
221 return '"'
222 elif s.count("'") % 2:
222 elif s.count("'") % 2:
223 return "'"
223 return "'"
224 else:
224 else:
225 return False
225 return False
226
226
227
227
228 def protect_filename(s, protectables=PROTECTABLES):
228 def protect_filename(s, protectables=PROTECTABLES):
229 """Escape a string to protect certain characters."""
229 """Escape a string to protect certain characters."""
230 if set(s) & set(protectables):
230 if set(s) & set(protectables):
231 if sys.platform == "win32":
231 if sys.platform == "win32":
232 return '"' + s + '"'
232 return '"' + s + '"'
233 else:
233 else:
234 return "".join(("\\" + c if c in protectables else c) for c in s)
234 return "".join(("\\" + c if c in protectables else c) for c in s)
235 else:
235 else:
236 return s
236 return s
237
237
238
238
239 def expand_user(path):
239 def expand_user(path):
240 """Expand ``~``-style usernames in strings.
240 """Expand ``~``-style usernames in strings.
241
241
242 This is similar to :func:`os.path.expanduser`, but it computes and returns
242 This is similar to :func:`os.path.expanduser`, but it computes and returns
243 extra information that will be useful if the input was being used in
243 extra information that will be useful if the input was being used in
244 computing completions, and you wish to return the completions with the
244 computing completions, and you wish to return the completions with the
245 original '~' instead of its expanded value.
245 original '~' instead of its expanded value.
246
246
247 Parameters
247 Parameters
248 ----------
248 ----------
249 path : str
249 path : str
250 String to be expanded. If no ~ is present, the output is the same as the
250 String to be expanded. If no ~ is present, the output is the same as the
251 input.
251 input.
252
252
253 Returns
253 Returns
254 -------
254 -------
255 newpath : str
255 newpath : str
256 Result of ~ expansion in the input path.
256 Result of ~ expansion in the input path.
257 tilde_expand : bool
257 tilde_expand : bool
258 Whether any expansion was performed or not.
258 Whether any expansion was performed or not.
259 tilde_val : str
259 tilde_val : str
260 The value that ~ was replaced with.
260 The value that ~ was replaced with.
261 """
261 """
262 # Default values
262 # Default values
263 tilde_expand = False
263 tilde_expand = False
264 tilde_val = ''
264 tilde_val = ''
265 newpath = path
265 newpath = path
266
266
267 if path.startswith('~'):
267 if path.startswith('~'):
268 tilde_expand = True
268 tilde_expand = True
269 rest = len(path)-1
269 rest = len(path)-1
270 newpath = os.path.expanduser(path)
270 newpath = os.path.expanduser(path)
271 if rest:
271 if rest:
272 tilde_val = newpath[:-rest]
272 tilde_val = newpath[:-rest]
273 else:
273 else:
274 tilde_val = newpath
274 tilde_val = newpath
275
275
276 return newpath, tilde_expand, tilde_val
276 return newpath, tilde_expand, tilde_val
277
277
278
278
279 def compress_user(path, tilde_expand, tilde_val):
279 def compress_user(path, tilde_expand, tilde_val):
280 """Does the opposite of expand_user, with its outputs.
280 """Does the opposite of expand_user, with its outputs.
281 """
281 """
282 if tilde_expand:
282 if tilde_expand:
283 return path.replace(tilde_val, '~')
283 return path.replace(tilde_val, '~')
284 else:
284 else:
285 return path
285 return path
286
286
287
287
288 def completions_sorting_key(word):
288 def completions_sorting_key(word):
289 """key for sorting completions
289 """key for sorting completions
290
290
291 This does several things:
291 This does several things:
292
292
293 - Lowercase all completions, so they are sorted alphabetically with
293 - Lowercase all completions, so they are sorted alphabetically with
294 upper and lower case words mingled
294 upper and lower case words mingled
295 - Demote any completions starting with underscores to the end
295 - Demote any completions starting with underscores to the end
296 - Insert any %magic and %%cellmagic completions in the alphabetical order
296 - Insert any %magic and %%cellmagic completions in the alphabetical order
297 by their name
297 by their name
298 """
298 """
299 # Case insensitive sort
299 # Case insensitive sort
300 word = word.lower()
300 word = word.lower()
301
301
302 prio1, prio2 = 0, 0
302 prio1, prio2 = 0, 0
303
303
304 if word.startswith('__'):
304 if word.startswith('__'):
305 prio1 = 2
305 prio1 = 2
306 elif word.startswith('_'):
306 elif word.startswith('_'):
307 prio1 = 1
307 prio1 = 1
308
308
309 if word.endswith('='):
309 if word.endswith('='):
310 prio1 = -1
310 prio1 = -1
311
311
312 if word.startswith('%%'):
312 if word.startswith('%%'):
313 # If there's another % in there, this is something else, so leave it alone
313 # If there's another % in there, this is something else, so leave it alone
314 if not "%" in word[2:]:
314 if not "%" in word[2:]:
315 word = word[2:]
315 word = word[2:]
316 prio2 = 2
316 prio2 = 2
317 elif word.startswith('%'):
317 elif word.startswith('%'):
318 if not "%" in word[1:]:
318 if not "%" in word[1:]:
319 word = word[1:]
319 word = word[1:]
320 prio2 = 1
320 prio2 = 1
321
321
322 return prio1, word, prio2
322 return prio1, word, prio2
323
323
324
324
325 class _FakeJediCompletion:
325 class _FakeJediCompletion:
326 """
326 """
327 This is a workaround to communicate to the UI that Jedi has crashed and to
327 This is a workaround to communicate to the UI that Jedi has crashed and to
328 report a bug. Will be used only id :any:`IPCompleter.debug` is set to true.
328 report a bug. Will be used only id :any:`IPCompleter.debug` is set to true.
329
329
330 Added in IPython 6.0 so should likely be removed for 7.0
330 Added in IPython 6.0 so should likely be removed for 7.0
331
331
332 """
332 """
333
333
334 def __init__(self, name):
334 def __init__(self, name):
335
335
336 self.name = name
336 self.name = name
337 self.complete = name
337 self.complete = name
338 self.type = 'crashed'
338 self.type = 'crashed'
339 self.name_with_symbols = name
339 self.name_with_symbols = name
340
340
341 def __repr__(self):
341 def __repr__(self):
342 return '<Fake completion object jedi has crashed>'
342 return '<Fake completion object jedi has crashed>'
343
343
344
344
345 class Completion:
345 class Completion:
346 """
346 """
347 Completion object used and return by IPython completers.
347 Completion object used and return by IPython completers.
348
348
349 .. warning:: Unstable
349 .. warning:: Unstable
350
350
351 This function is unstable, API may change without warning.
351 This function is unstable, API may change without warning.
352 It will also raise unless use in proper context manager.
352 It will also raise unless use in proper context manager.
353
353
354 This act as a middle ground :any:`Completion` object between the
354 This act as a middle ground :any:`Completion` object between the
355 :any:`jedi.api.classes.Completion` object and the Prompt Toolkit completion
355 :any:`jedi.api.classes.Completion` object and the Prompt Toolkit completion
356 object. While Jedi need a lot of information about evaluator and how the
356 object. While Jedi need a lot of information about evaluator and how the
357 code should be ran/inspected, PromptToolkit (and other frontend) mostly
357 code should be ran/inspected, PromptToolkit (and other frontend) mostly
358 need user facing information.
358 need user facing information.
359
359
360 - Which range should be replaced replaced by what.
360 - Which range should be replaced replaced by what.
361 - Some metadata (like completion type), or meta informations to displayed to
361 - Some metadata (like completion type), or meta informations to displayed to
362 the use user.
362 the use user.
363
363
364 For debugging purpose we can also store the origin of the completion (``jedi``,
364 For debugging purpose we can also store the origin of the completion (``jedi``,
365 ``IPython.python_matches``, ``IPython.magics_matches``...).
365 ``IPython.python_matches``, ``IPython.magics_matches``...).
366 """
366 """
367
367
368 def __init__(self, start: int, end: int, text: str, *, type: str=None, _origin=''):
368 def __init__(self, start: int, end: int, text: str, *, type: str=None, _origin='') -> None:
369 warnings.warn("``Completion`` is a provisional API (as of IPython 6.0). "
369 warnings.warn("``Completion`` is a provisional API (as of IPython 6.0). "
370 "It may change without warnings. "
370 "It may change without warnings. "
371 "Use in corresponding context manager.",
371 "Use in corresponding context manager.",
372 category=ProvisionalCompleterWarning, stacklevel=2)
372 category=ProvisionalCompleterWarning, stacklevel=2)
373
373
374 self.start = start
374 self.start = start
375 self.end = end
375 self.end = end
376 self.text = text
376 self.text = text
377 self.type = type
377 self.type = type
378 self._origin = _origin
378 self._origin = _origin
379
379
380 def __repr__(self):
380 def __repr__(self):
381 return '<Completion start=%s end=%s text=%r type=%r>' % (self.start, self.end, self.text, self.type or '?')
381 return '<Completion start=%s end=%s text=%r type=%r>' % (self.start, self.end, self.text, self.type or '?')
382
382
383 def __eq__(self, other)->Bool:
383 def __eq__(self, other)->Bool:
384 """
384 """
385 Equality and hash do not hash the type (as some completer may not be
385 Equality and hash do not hash the type (as some completer may not be
386 able to infer the type), but are use to (partially) de-duplicate
386 able to infer the type), but are use to (partially) de-duplicate
387 completion.
387 completion.
388
388
389 Completely de-duplicating completion is a bit tricker that just
389 Completely de-duplicating completion is a bit tricker that just
390 comparing as it depends on surrounding text, which Completions are not
390 comparing as it depends on surrounding text, which Completions are not
391 aware of.
391 aware of.
392 """
392 """
393 return self.start == other.start and \
393 return self.start == other.start and \
394 self.end == other.end and \
394 self.end == other.end and \
395 self.text == other.text
395 self.text == other.text
396
396
397 def __hash__(self):
397 def __hash__(self):
398 return hash((self.start, self.end, self.text))
398 return hash((self.start, self.end, self.text))
399
399
400
400
401 _IC = Iterator[Completion]
401 _IC = Iterable[Completion]
402
402
403
403
404 def _deduplicate_completions(text: str, completions: _IC)-> _IC:
404 def _deduplicate_completions(text: str, completions: _IC)-> _IC:
405 """
405 """
406 Deduplicate a set of completions.
406 Deduplicate a set of completions.
407
407
408 .. warning:: Unstable
408 .. warning:: Unstable
409
409
410 This function is unstable, API may change without warning.
410 This function is unstable, API may change without warning.
411
411
412 Parameters
412 Parameters
413 ----------
413 ----------
414 text: str
414 text: str
415 text that should be completed.
415 text that should be completed.
416 completions: Iterator[Completion]
416 completions: Iterator[Completion]
417 iterator over the completions to deduplicate
417 iterator over the completions to deduplicate
418
418
419
419
420 Completions coming from multiple sources, may be different but end up having
420 Completions coming from multiple sources, may be different but end up having
421 the same effect when applied to ``text``. If this is the case, this will
421 the same effect when applied to ``text``. If this is the case, this will
422 consider completions as equal and only emit the first encountered.
422 consider completions as equal and only emit the first encountered.
423
423
424 Not folded in `completions()` yet for debugging purpose, and to detect when
424 Not folded in `completions()` yet for debugging purpose, and to detect when
425 the IPython completer does return things that Jedi does not, but should be
425 the IPython completer does return things that Jedi does not, but should be
426 at some point.
426 at some point.
427 """
427 """
428 completions = list(completions)
428 completions = list(completions)
429 if not completions:
429 if not completions:
430 return
430 return
431
431
432 new_start = min(c.start for c in completions)
432 new_start = min(c.start for c in completions)
433 new_end = max(c.end for c in completions)
433 new_end = max(c.end for c in completions)
434
434
435 seen = set()
435 seen = set()
436 for c in completions:
436 for c in completions:
437 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
437 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
438 if new_text not in seen:
438 if new_text not in seen:
439 yield c
439 yield c
440 seen.add(new_text)
440 seen.add(new_text)
441
441
442
442
443 def rectify_completions(text: str, completions: _IC, *, _debug=False)->_IC:
443 def rectify_completions(text: str, completions: _IC, *, _debug=False)->_IC:
444 """
444 """
445 Rectify a set of completions to all have the same ``start`` and ``end``
445 Rectify a set of completions to all have the same ``start`` and ``end``
446
446
447 .. warning:: Unstable
447 .. warning:: Unstable
448
448
449 This function is unstable, API may change without warning.
449 This function is unstable, API may change without warning.
450 It will also raise unless use in proper context manager.
450 It will also raise unless use in proper context manager.
451
451
452 Parameters
452 Parameters
453 ----------
453 ----------
454 text: str
454 text: str
455 text that should be completed.
455 text that should be completed.
456 completions: Iterator[Completion]
456 completions: Iterator[Completion]
457 iterator over the completions to rectify
457 iterator over the completions to rectify
458
458
459
459
460 :any:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though
460 :any:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though
461 the Jupyter Protocol requires them to behave like so. This will readjust
461 the Jupyter Protocol requires them to behave like so. This will readjust
462 the completion to have the same ``start`` and ``end`` by padding both
462 the completion to have the same ``start`` and ``end`` by padding both
463 extremities with surrounding text.
463 extremities with surrounding text.
464
464
465 During stabilisation should support a ``_debug`` option to log which
465 During stabilisation should support a ``_debug`` option to log which
466 completion are return by the IPython completer and not found in Jedi in
466 completion are return by the IPython completer and not found in Jedi in
467 order to make upstream bug report.
467 order to make upstream bug report.
468 """
468 """
469 warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). "
469 warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). "
470 "It may change without warnings. "
470 "It may change without warnings. "
471 "Use in corresponding context manager.",
471 "Use in corresponding context manager.",
472 category=ProvisionalCompleterWarning, stacklevel=2)
472 category=ProvisionalCompleterWarning, stacklevel=2)
473
473
474 completions = list(completions)
474 completions = list(completions)
475 if not completions:
475 if not completions:
476 return
476 return
477 starts = (c.start for c in completions)
477 starts = (c.start for c in completions)
478 ends = (c.end for c in completions)
478 ends = (c.end for c in completions)
479
479
480 new_start = min(starts)
480 new_start = min(starts)
481 new_end = max(ends)
481 new_end = max(ends)
482
482
483 seen_jedi = set()
483 seen_jedi = set()
484 seen_python_matches = set()
484 seen_python_matches = set()
485 for c in completions:
485 for c in completions:
486 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
486 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
487 if c._origin == 'jedi':
487 if c._origin == 'jedi':
488 seen_jedi.add(new_text)
488 seen_jedi.add(new_text)
489 elif c._origin == 'IPCompleter.python_matches':
489 elif c._origin == 'IPCompleter.python_matches':
490 seen_python_matches.add(new_text)
490 seen_python_matches.add(new_text)
491 yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin)
491 yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin)
492 diff = seen_python_matches.difference(seen_jedi)
492 diff = seen_python_matches.difference(seen_jedi)
493 if diff and _debug:
493 if diff and _debug:
494 print('IPython.python matches have extras:', diff)
494 print('IPython.python matches have extras:', diff)
495
495
496
496
497 if sys.platform == 'win32':
497 if sys.platform == 'win32':
498 DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?'
498 DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?'
499 else:
499 else:
500 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
500 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
501
501
502 GREEDY_DELIMS = ' =\r\n'
502 GREEDY_DELIMS = ' =\r\n'
503
503
504
504
505 class CompletionSplitter(object):
505 class CompletionSplitter(object):
506 """An object to split an input line in a manner similar to readline.
506 """An object to split an input line in a manner similar to readline.
507
507
508 By having our own implementation, we can expose readline-like completion in
508 By having our own implementation, we can expose readline-like completion in
509 a uniform manner to all frontends. This object only needs to be given the
509 a uniform manner to all frontends. This object only needs to be given the
510 line of text to be split and the cursor position on said line, and it
510 line of text to be split and the cursor position on said line, and it
511 returns the 'word' to be completed on at the cursor after splitting the
511 returns the 'word' to be completed on at the cursor after splitting the
512 entire line.
512 entire line.
513
513
514 What characters are used as splitting delimiters can be controlled by
514 What characters are used as splitting delimiters can be controlled by
515 setting the ``delims`` attribute (this is a property that internally
515 setting the ``delims`` attribute (this is a property that internally
516 automatically builds the necessary regular expression)"""
516 automatically builds the necessary regular expression)"""
517
517
518 # Private interface
518 # Private interface
519
519
520 # A string of delimiter characters. The default value makes sense for
520 # A string of delimiter characters. The default value makes sense for
521 # IPython's most typical usage patterns.
521 # IPython's most typical usage patterns.
522 _delims = DELIMS
522 _delims = DELIMS
523
523
524 # The expression (a normal string) to be compiled into a regular expression
524 # The expression (a normal string) to be compiled into a regular expression
525 # for actual splitting. We store it as an attribute mostly for ease of
525 # for actual splitting. We store it as an attribute mostly for ease of
526 # debugging, since this type of code can be so tricky to debug.
526 # debugging, since this type of code can be so tricky to debug.
527 _delim_expr = None
527 _delim_expr = None
528
528
529 # The regular expression that does the actual splitting
529 # The regular expression that does the actual splitting
530 _delim_re = None
530 _delim_re = None
531
531
532 def __init__(self, delims=None):
532 def __init__(self, delims=None):
533 delims = CompletionSplitter._delims if delims is None else delims
533 delims = CompletionSplitter._delims if delims is None else delims
534 self.delims = delims
534 self.delims = delims
535
535
536 @property
536 @property
537 def delims(self):
537 def delims(self):
538 """Return the string of delimiter characters."""
538 """Return the string of delimiter characters."""
539 return self._delims
539 return self._delims
540
540
541 @delims.setter
541 @delims.setter
542 def delims(self, delims):
542 def delims(self, delims):
543 """Set the delimiters for line splitting."""
543 """Set the delimiters for line splitting."""
544 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
544 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
545 self._delim_re = re.compile(expr)
545 self._delim_re = re.compile(expr)
546 self._delims = delims
546 self._delims = delims
547 self._delim_expr = expr
547 self._delim_expr = expr
548
548
549 def split_line(self, line, cursor_pos=None):
549 def split_line(self, line, cursor_pos=None):
550 """Split a line of text with a cursor at the given position.
550 """Split a line of text with a cursor at the given position.
551 """
551 """
552 l = line if cursor_pos is None else line[:cursor_pos]
552 l = line if cursor_pos is None else line[:cursor_pos]
553 return self._delim_re.split(l)[-1]
553 return self._delim_re.split(l)[-1]
554
554
555
555
556
556
557 class Completer(Configurable):
557 class Completer(Configurable):
558
558
559 greedy = Bool(False,
559 greedy = Bool(False,
560 help="""Activate greedy completion
560 help="""Activate greedy completion
561 PENDING DEPRECTION. this is now mostly taken care of with Jedi.
561 PENDING DEPRECTION. this is now mostly taken care of with Jedi.
562
562
563 This will enable completion on elements of lists, results of function calls, etc.,
563 This will enable completion on elements of lists, results of function calls, etc.,
564 but can be unsafe because the code is actually evaluated on TAB.
564 but can be unsafe because the code is actually evaluated on TAB.
565 """
565 """
566 ).tag(config=True)
566 ).tag(config=True)
567
567
568 use_jedi = Bool(default_value=JEDI_INSTALLED,
568 use_jedi = Bool(default_value=JEDI_INSTALLED,
569 help="Experimental: Use Jedi to generate autocompletions. "
569 help="Experimental: Use Jedi to generate autocompletions. "
570 "Default to True if jedi is installed").tag(config=True)
570 "Default to True if jedi is installed").tag(config=True)
571
571
572 jedi_compute_type_timeout = Int(default_value=400,
572 jedi_compute_type_timeout = Int(default_value=400,
573 help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types.
573 help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types.
574 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
574 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
575 performance by preventing jedi to build its cache.
575 performance by preventing jedi to build its cache.
576 """).tag(config=True)
576 """).tag(config=True)
577
577
578 debug = Bool(default_value=False,
578 debug = Bool(default_value=False,
579 help='Enable debug for the Completer. Mostly print extra '
579 help='Enable debug for the Completer. Mostly print extra '
580 'information for experimental jedi integration.')\
580 'information for experimental jedi integration.')\
581 .tag(config=True)
581 .tag(config=True)
582
582
583 backslash_combining_completions = Bool(True,
583 backslash_combining_completions = Bool(True,
584 help="Enable unicode completions, e.g. \\alpha<tab> . "
584 help="Enable unicode completions, e.g. \\alpha<tab> . "
585 "Includes completion of latex commands, unicode names, and expanding "
585 "Includes completion of latex commands, unicode names, and expanding "
586 "unicode characters back to latex commands.").tag(config=True)
586 "unicode characters back to latex commands.").tag(config=True)
587
587
588
588
589
589
590 def __init__(self, namespace=None, global_namespace=None, **kwargs):
590 def __init__(self, namespace=None, global_namespace=None, **kwargs):
591 """Create a new completer for the command line.
591 """Create a new completer for the command line.
592
592
593 Completer(namespace=ns, global_namespace=ns2) -> completer instance.
593 Completer(namespace=ns, global_namespace=ns2) -> completer instance.
594
594
595 If unspecified, the default namespace where completions are performed
595 If unspecified, the default namespace where completions are performed
596 is __main__ (technically, __main__.__dict__). Namespaces should be
596 is __main__ (technically, __main__.__dict__). Namespaces should be
597 given as dictionaries.
597 given as dictionaries.
598
598
599 An optional second namespace can be given. This allows the completer
599 An optional second namespace can be given. This allows the completer
600 to handle cases where both the local and global scopes need to be
600 to handle cases where both the local and global scopes need to be
601 distinguished.
601 distinguished.
602 """
602 """
603
603
604 # Don't bind to namespace quite yet, but flag whether the user wants a
604 # Don't bind to namespace quite yet, but flag whether the user wants a
605 # specific namespace or to use __main__.__dict__. This will allow us
605 # specific namespace or to use __main__.__dict__. This will allow us
606 # to bind to __main__.__dict__ at completion time, not now.
606 # to bind to __main__.__dict__ at completion time, not now.
607 if namespace is None:
607 if namespace is None:
608 self.use_main_ns = True
608 self.use_main_ns = True
609 else:
609 else:
610 self.use_main_ns = False
610 self.use_main_ns = False
611 self.namespace = namespace
611 self.namespace = namespace
612
612
613 # The global namespace, if given, can be bound directly
613 # The global namespace, if given, can be bound directly
614 if global_namespace is None:
614 if global_namespace is None:
615 self.global_namespace = {}
615 self.global_namespace = {}
616 else:
616 else:
617 self.global_namespace = global_namespace
617 self.global_namespace = global_namespace
618
618
619 super(Completer, self).__init__(**kwargs)
619 super(Completer, self).__init__(**kwargs)
620
620
621 def complete(self, text, state):
621 def complete(self, text, state):
622 """Return the next possible completion for 'text'.
622 """Return the next possible completion for 'text'.
623
623
624 This is called successively with state == 0, 1, 2, ... until it
624 This is called successively with state == 0, 1, 2, ... until it
625 returns None. The completion should begin with 'text'.
625 returns None. The completion should begin with 'text'.
626
626
627 """
627 """
628 if self.use_main_ns:
628 if self.use_main_ns:
629 self.namespace = __main__.__dict__
629 self.namespace = __main__.__dict__
630
630
631 if state == 0:
631 if state == 0:
632 if "." in text:
632 if "." in text:
633 self.matches = self.attr_matches(text)
633 self.matches = self.attr_matches(text)
634 else:
634 else:
635 self.matches = self.global_matches(text)
635 self.matches = self.global_matches(text)
636 try:
636 try:
637 return self.matches[state]
637 return self.matches[state]
638 except IndexError:
638 except IndexError:
639 return None
639 return None
640
640
641 def global_matches(self, text):
641 def global_matches(self, text):
642 """Compute matches when text is a simple name.
642 """Compute matches when text is a simple name.
643
643
644 Return a list of all keywords, built-in functions and names currently
644 Return a list of all keywords, built-in functions and names currently
645 defined in self.namespace or self.global_namespace that match.
645 defined in self.namespace or self.global_namespace that match.
646
646
647 """
647 """
648 matches = []
648 matches = []
649 match_append = matches.append
649 match_append = matches.append
650 n = len(text)
650 n = len(text)
651 for lst in [keyword.kwlist,
651 for lst in [keyword.kwlist,
652 builtin_mod.__dict__.keys(),
652 builtin_mod.__dict__.keys(),
653 self.namespace.keys(),
653 self.namespace.keys(),
654 self.global_namespace.keys()]:
654 self.global_namespace.keys()]:
655 for word in lst:
655 for word in lst:
656 if word[:n] == text and word != "__builtins__":
656 if word[:n] == text and word != "__builtins__":
657 match_append(word)
657 match_append(word)
658
658
659 snake_case_re = re.compile(r"[^_]+(_[^_]+)+?\Z")
659 snake_case_re = re.compile(r"[^_]+(_[^_]+)+?\Z")
660 for lst in [self.namespace.keys(),
660 for lst in [self.namespace.keys(),
661 self.global_namespace.keys()]:
661 self.global_namespace.keys()]:
662 shortened = {"_".join([sub[0] for sub in word.split('_')]) : word
662 shortened = {"_".join([sub[0] for sub in word.split('_')]) : word
663 for word in lst if snake_case_re.match(word)}
663 for word in lst if snake_case_re.match(word)}
664 for word in shortened.keys():
664 for word in shortened.keys():
665 if word[:n] == text and word != "__builtins__":
665 if word[:n] == text and word != "__builtins__":
666 match_append(shortened[word])
666 match_append(shortened[word])
667 return matches
667 return matches
668
668
669 def attr_matches(self, text):
669 def attr_matches(self, text):
670 """Compute matches when text contains a dot.
670 """Compute matches when text contains a dot.
671
671
672 Assuming the text is of the form NAME.NAME....[NAME], and is
672 Assuming the text is of the form NAME.NAME....[NAME], and is
673 evaluatable in self.namespace or self.global_namespace, it will be
673 evaluatable in self.namespace or self.global_namespace, it will be
674 evaluated and its attributes (as revealed by dir()) are used as
674 evaluated and its attributes (as revealed by dir()) are used as
675 possible completions. (For class instances, class members are are
675 possible completions. (For class instances, class members are are
676 also considered.)
676 also considered.)
677
677
678 WARNING: this can still invoke arbitrary C code, if an object
678 WARNING: this can still invoke arbitrary C code, if an object
679 with a __getattr__ hook is evaluated.
679 with a __getattr__ hook is evaluated.
680
680
681 """
681 """
682
682
683 # Another option, seems to work great. Catches things like ''.<tab>
683 # Another option, seems to work great. Catches things like ''.<tab>
684 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
684 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
685
685
686 if m:
686 if m:
687 expr, attr = m.group(1, 3)
687 expr, attr = m.group(1, 3)
688 elif self.greedy:
688 elif self.greedy:
689 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
689 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
690 if not m2:
690 if not m2:
691 return []
691 return []
692 expr, attr = m2.group(1,2)
692 expr, attr = m2.group(1,2)
693 else:
693 else:
694 return []
694 return []
695
695
696 try:
696 try:
697 obj = eval(expr, self.namespace)
697 obj = eval(expr, self.namespace)
698 except:
698 except:
699 try:
699 try:
700 obj = eval(expr, self.global_namespace)
700 obj = eval(expr, self.global_namespace)
701 except:
701 except:
702 return []
702 return []
703
703
704 if self.limit_to__all__ and hasattr(obj, '__all__'):
704 if self.limit_to__all__ and hasattr(obj, '__all__'):
705 words = get__all__entries(obj)
705 words = get__all__entries(obj)
706 else:
706 else:
707 words = dir2(obj)
707 words = dir2(obj)
708
708
709 try:
709 try:
710 words = generics.complete_object(obj, words)
710 words = generics.complete_object(obj, words)
711 except TryNext:
711 except TryNext:
712 pass
712 pass
713 except AssertionError:
713 except AssertionError:
714 raise
714 raise
715 except Exception:
715 except Exception:
716 # Silence errors from completion function
716 # Silence errors from completion function
717 #raise # dbg
717 #raise # dbg
718 pass
718 pass
719 # Build match list to return
719 # Build match list to return
720 n = len(attr)
720 n = len(attr)
721 return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ]
721 return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ]
722
722
723
723
724 def get__all__entries(obj):
724 def get__all__entries(obj):
725 """returns the strings in the __all__ attribute"""
725 """returns the strings in the __all__ attribute"""
726 try:
726 try:
727 words = getattr(obj, '__all__')
727 words = getattr(obj, '__all__')
728 except:
728 except:
729 return []
729 return []
730
730
731 return [w for w in words if isinstance(w, str)]
731 return [w for w in words if isinstance(w, str)]
732
732
733
733
734 def match_dict_keys(keys: List[str], prefix: str, delims: str):
734 def match_dict_keys(keys: List[str], prefix: str, delims: str):
735 """Used by dict_key_matches, matching the prefix to a list of keys
735 """Used by dict_key_matches, matching the prefix to a list of keys
736
736
737 Parameters
737 Parameters
738 ==========
738 ==========
739 keys:
739 keys:
740 list of keys in dictionary currently being completed.
740 list of keys in dictionary currently being completed.
741 prefix:
741 prefix:
742 Part of the text already typed by the user. e.g. `mydict[b'fo`
742 Part of the text already typed by the user. e.g. `mydict[b'fo`
743 delims:
743 delims:
744 String of delimiters to consider when finding the current key.
744 String of delimiters to consider when finding the current key.
745
745
746 Returns
746 Returns
747 =======
747 =======
748
748
749 A tuple of three elements: ``quote``, ``token_start``, ``matched``, with
749 A tuple of three elements: ``quote``, ``token_start``, ``matched``, with
750 ``quote`` being the quote that need to be used to close current string.
750 ``quote`` being the quote that need to be used to close current string.
751 ``token_start`` the position where the replacement should start occurring,
751 ``token_start`` the position where the replacement should start occurring,
752 ``matches`` a list of replacement/completion
752 ``matches`` a list of replacement/completion
753
753
754 """
754 """
755 if not prefix:
755 if not prefix:
756 return None, 0, [repr(k) for k in keys
756 return None, 0, [repr(k) for k in keys
757 if isinstance(k, (str, bytes))]
757 if isinstance(k, (str, bytes))]
758 quote_match = re.search('["\']', prefix)
758 quote_match = re.search('["\']', prefix)
759 quote = quote_match.group()
759 quote = quote_match.group()
760 try:
760 try:
761 prefix_str = eval(prefix + quote, {})
761 prefix_str = eval(prefix + quote, {})
762 except Exception:
762 except Exception:
763 return None, 0, []
763 return None, 0, []
764
764
765 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
765 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
766 token_match = re.search(pattern, prefix, re.UNICODE)
766 token_match = re.search(pattern, prefix, re.UNICODE)
767 token_start = token_match.start()
767 token_start = token_match.start()
768 token_prefix = token_match.group()
768 token_prefix = token_match.group()
769
769
770 matched = []
770 matched = []
771 for key in keys:
771 for key in keys:
772 try:
772 try:
773 if not key.startswith(prefix_str):
773 if not key.startswith(prefix_str):
774 continue
774 continue
775 except (AttributeError, TypeError, UnicodeError):
775 except (AttributeError, TypeError, UnicodeError):
776 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa
776 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa
777 continue
777 continue
778
778
779 # reformat remainder of key to begin with prefix
779 # reformat remainder of key to begin with prefix
780 rem = key[len(prefix_str):]
780 rem = key[len(prefix_str):]
781 # force repr wrapped in '
781 # force repr wrapped in '
782 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
782 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
783 if rem_repr.startswith('u') and prefix[0] not in 'uU':
783 if rem_repr.startswith('u') and prefix[0] not in 'uU':
784 # Found key is unicode, but prefix is Py2 string.
784 # Found key is unicode, but prefix is Py2 string.
785 # Therefore attempt to interpret key as string.
785 # Therefore attempt to interpret key as string.
786 try:
786 try:
787 rem_repr = repr(rem.encode('ascii') + '"')
787 rem_repr = repr(rem.encode('ascii') + '"')
788 except UnicodeEncodeError:
788 except UnicodeEncodeError:
789 continue
789 continue
790
790
791 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
791 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
792 if quote == '"':
792 if quote == '"':
793 # The entered prefix is quoted with ",
793 # The entered prefix is quoted with ",
794 # but the match is quoted with '.
794 # but the match is quoted with '.
795 # A contained " hence needs escaping for comparison:
795 # A contained " hence needs escaping for comparison:
796 rem_repr = rem_repr.replace('"', '\\"')
796 rem_repr = rem_repr.replace('"', '\\"')
797
797
798 # then reinsert prefix from start of token
798 # then reinsert prefix from start of token
799 matched.append('%s%s' % (token_prefix, rem_repr))
799 matched.append('%s%s' % (token_prefix, rem_repr))
800 return quote, token_start, matched
800 return quote, token_start, matched
801
801
802
802
803 def cursor_to_position(text:int, line:int, column:int)->int:
803 def cursor_to_position(text:str, line:int, column:int)->int:
804 """
804 """
805
805
806 Convert the (line,column) position of the cursor in text to an offset in a
806 Convert the (line,column) position of the cursor in text to an offset in a
807 string.
807 string.
808
808
809 Parameters
809 Parameters
810 ----------
810 ----------
811
811
812 text : str
812 text : str
813 The text in which to calculate the cursor offset
813 The text in which to calculate the cursor offset
814 line : int
814 line : int
815 Line of the cursor; 0-indexed
815 Line of the cursor; 0-indexed
816 column : int
816 column : int
817 Column of the cursor 0-indexed
817 Column of the cursor 0-indexed
818
818
819 Return
819 Return
820 ------
820 ------
821 Position of the cursor in ``text``, 0-indexed.
821 Position of the cursor in ``text``, 0-indexed.
822
822
823 See Also
823 See Also
824 --------
824 --------
825 position_to_cursor: reciprocal of this function
825 position_to_cursor: reciprocal of this function
826
826
827 """
827 """
828 lines = text.split('\n')
828 lines = text.split('\n')
829 assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines)))
829 assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines)))
830
830
831 return sum(len(l) + 1 for l in lines[:line]) + column
831 return sum(len(l) + 1 for l in lines[:line]) + column
832
832
833 def position_to_cursor(text:str, offset:int)->(int, int):
833 def position_to_cursor(text:str, offset:int)->Tuple[int, int]:
834 """
834 """
835 Convert the position of the cursor in text (0 indexed) to a line
835 Convert the position of the cursor in text (0 indexed) to a line
836 number(0-indexed) and a column number (0-indexed) pair
836 number(0-indexed) and a column number (0-indexed) pair
837
837
838 Position should be a valid position in ``text``.
838 Position should be a valid position in ``text``.
839
839
840 Parameters
840 Parameters
841 ----------
841 ----------
842
842
843 text : str
843 text : str
844 The text in which to calculate the cursor offset
844 The text in which to calculate the cursor offset
845 offset : int
845 offset : int
846 Position of the cursor in ``text``, 0-indexed.
846 Position of the cursor in ``text``, 0-indexed.
847
847
848 Return
848 Return
849 ------
849 ------
850 (line, column) : (int, int)
850 (line, column) : (int, int)
851 Line of the cursor; 0-indexed, column of the cursor 0-indexed
851 Line of the cursor; 0-indexed, column of the cursor 0-indexed
852
852
853
853
854 See Also
854 See Also
855 --------
855 --------
856 cursor_to_position : reciprocal of this function
856 cursor_to_position : reciprocal of this function
857
857
858
858
859 """
859 """
860
860
861 assert 0 < offset <= len(text) , "0 < %s <= %s" % (offset , len(text))
861 assert 0 < offset <= len(text) , "0 < %s <= %s" % (offset , len(text))
862
862
863 before = text[:offset]
863 before = text[:offset]
864 blines = before.split('\n') # ! splitnes trim trailing \n
864 blines = before.split('\n') # ! splitnes trim trailing \n
865 line = before.count('\n')
865 line = before.count('\n')
866 col = len(blines[-1])
866 col = len(blines[-1])
867 return line, col
867 return line, col
868
868
869
869
870 def _safe_isinstance(obj, module, class_name):
870 def _safe_isinstance(obj, module, class_name):
871 """Checks if obj is an instance of module.class_name if loaded
871 """Checks if obj is an instance of module.class_name if loaded
872 """
872 """
873 return (module in sys.modules and
873 return (module in sys.modules and
874 isinstance(obj, getattr(import_module(module), class_name)))
874 isinstance(obj, getattr(import_module(module), class_name)))
875
875
876
876
877 def back_unicode_name_matches(text):
877 def back_unicode_name_matches(text):
878 u"""Match unicode characters back to unicode name
878 u"""Match unicode characters back to unicode name
879
879
880 This does ``β˜ƒ`` -> ``\\snowman``
880 This does ``β˜ƒ`` -> ``\\snowman``
881
881
882 Note that snowman is not a valid python3 combining character but will be expanded.
882 Note that snowman is not a valid python3 combining character but will be expanded.
883 Though it will not recombine back to the snowman character by the completion machinery.
883 Though it will not recombine back to the snowman character by the completion machinery.
884
884
885 This will not either back-complete standard sequences like \\n, \\b ...
885 This will not either back-complete standard sequences like \\n, \\b ...
886
886
887 Used on Python 3 only.
887 Used on Python 3 only.
888 """
888 """
889 if len(text)<2:
889 if len(text)<2:
890 return u'', ()
890 return u'', ()
891 maybe_slash = text[-2]
891 maybe_slash = text[-2]
892 if maybe_slash != '\\':
892 if maybe_slash != '\\':
893 return u'', ()
893 return u'', ()
894
894
895 char = text[-1]
895 char = text[-1]
896 # no expand on quote for completion in strings.
896 # no expand on quote for completion in strings.
897 # nor backcomplete standard ascii keys
897 # nor backcomplete standard ascii keys
898 if char in string.ascii_letters or char in ['"',"'"]:
898 if char in string.ascii_letters or char in ['"',"'"]:
899 return u'', ()
899 return u'', ()
900 try :
900 try :
901 unic = unicodedata.name(char)
901 unic = unicodedata.name(char)
902 return '\\'+char,['\\'+unic]
902 return '\\'+char,['\\'+unic]
903 except KeyError:
903 except KeyError:
904 pass
904 pass
905 return u'', ()
905 return u'', ()
906
906
907 def back_latex_name_matches(text:str):
907 def back_latex_name_matches(text:str):
908 """Match latex characters back to unicode name
908 """Match latex characters back to unicode name
909
909
910 This does ``\\β„΅`` -> ``\\aleph``
910 This does ``\\β„΅`` -> ``\\aleph``
911
911
912 Used on Python 3 only.
912 Used on Python 3 only.
913 """
913 """
914 if len(text)<2:
914 if len(text)<2:
915 return u'', ()
915 return u'', ()
916 maybe_slash = text[-2]
916 maybe_slash = text[-2]
917 if maybe_slash != '\\':
917 if maybe_slash != '\\':
918 return u'', ()
918 return u'', ()
919
919
920
920
921 char = text[-1]
921 char = text[-1]
922 # no expand on quote for completion in strings.
922 # no expand on quote for completion in strings.
923 # nor backcomplete standard ascii keys
923 # nor backcomplete standard ascii keys
924 if char in string.ascii_letters or char in ['"',"'"]:
924 if char in string.ascii_letters or char in ['"',"'"]:
925 return u'', ()
925 return u'', ()
926 try :
926 try :
927 latex = reverse_latex_symbol[char]
927 latex = reverse_latex_symbol[char]
928 # '\\' replace the \ as well
928 # '\\' replace the \ as well
929 return '\\'+char,[latex]
929 return '\\'+char,[latex]
930 except KeyError:
930 except KeyError:
931 pass
931 pass
932 return u'', ()
932 return u'', ()
933
933
934
934
935 class IPCompleter(Completer):
935 class IPCompleter(Completer):
936 """Extension of the completer class with IPython-specific features"""
936 """Extension of the completer class with IPython-specific features"""
937
937
938 @observe('greedy')
938 @observe('greedy')
939 def _greedy_changed(self, change):
939 def _greedy_changed(self, change):
940 """update the splitter and readline delims when greedy is changed"""
940 """update the splitter and readline delims when greedy is changed"""
941 if change['new']:
941 if change['new']:
942 self.splitter.delims = GREEDY_DELIMS
942 self.splitter.delims = GREEDY_DELIMS
943 else:
943 else:
944 self.splitter.delims = DELIMS
944 self.splitter.delims = DELIMS
945
945
946 merge_completions = Bool(True,
946 merge_completions = Bool(True,
947 help="""Whether to merge completion results into a single list
947 help="""Whether to merge completion results into a single list
948
948
949 If False, only the completion results from the first non-empty
949 If False, only the completion results from the first non-empty
950 completer will be returned.
950 completer will be returned.
951 """
951 """
952 ).tag(config=True)
952 ).tag(config=True)
953 omit__names = Enum((0,1,2), default_value=2,
953 omit__names = Enum((0,1,2), default_value=2,
954 help="""Instruct the completer to omit private method names
954 help="""Instruct the completer to omit private method names
955
955
956 Specifically, when completing on ``object.<tab>``.
956 Specifically, when completing on ``object.<tab>``.
957
957
958 When 2 [default]: all names that start with '_' will be excluded.
958 When 2 [default]: all names that start with '_' will be excluded.
959
959
960 When 1: all 'magic' names (``__foo__``) will be excluded.
960 When 1: all 'magic' names (``__foo__``) will be excluded.
961
961
962 When 0: nothing will be excluded.
962 When 0: nothing will be excluded.
963 """
963 """
964 ).tag(config=True)
964 ).tag(config=True)
965 limit_to__all__ = Bool(False,
965 limit_to__all__ = Bool(False,
966 help="""
966 help="""
967 DEPRECATED as of version 5.0.
967 DEPRECATED as of version 5.0.
968
968
969 Instruct the completer to use __all__ for the completion
969 Instruct the completer to use __all__ for the completion
970
970
971 Specifically, when completing on ``object.<tab>``.
971 Specifically, when completing on ``object.<tab>``.
972
972
973 When True: only those names in obj.__all__ will be included.
973 When True: only those names in obj.__all__ will be included.
974
974
975 When False [default]: the __all__ attribute is ignored
975 When False [default]: the __all__ attribute is ignored
976 """,
976 """,
977 ).tag(config=True)
977 ).tag(config=True)
978
978
979 @observe('limit_to__all__')
979 @observe('limit_to__all__')
980 def _limit_to_all_changed(self, change):
980 def _limit_to_all_changed(self, change):
981 warnings.warn('`IPython.core.IPCompleter.limit_to__all__` configuration '
981 warnings.warn('`IPython.core.IPCompleter.limit_to__all__` configuration '
982 'value has been deprecated since IPython 5.0, will be made to have '
982 'value has been deprecated since IPython 5.0, will be made to have '
983 'no effects and then removed in future version of IPython.',
983 'no effects and then removed in future version of IPython.',
984 UserWarning)
984 UserWarning)
985
985
986 def __init__(self, shell=None, namespace=None, global_namespace=None,
986 def __init__(self, shell=None, namespace=None, global_namespace=None,
987 use_readline=_deprecation_readline_sentinel, config=None, **kwargs):
987 use_readline=_deprecation_readline_sentinel, config=None, **kwargs):
988 """IPCompleter() -> completer
988 """IPCompleter() -> completer
989
989
990 Return a completer object.
990 Return a completer object.
991
991
992 Parameters
992 Parameters
993 ----------
993 ----------
994
994
995 shell
995 shell
996 a pointer to the ipython shell itself. This is needed
996 a pointer to the ipython shell itself. This is needed
997 because this completer knows about magic functions, and those can
997 because this completer knows about magic functions, and those can
998 only be accessed via the ipython instance.
998 only be accessed via the ipython instance.
999
999
1000 namespace : dict, optional
1000 namespace : dict, optional
1001 an optional dict where completions are performed.
1001 an optional dict where completions are performed.
1002
1002
1003 global_namespace : dict, optional
1003 global_namespace : dict, optional
1004 secondary optional dict for completions, to
1004 secondary optional dict for completions, to
1005 handle cases (such as IPython embedded inside functions) where
1005 handle cases (such as IPython embedded inside functions) where
1006 both Python scopes are visible.
1006 both Python scopes are visible.
1007
1007
1008 use_readline : bool, optional
1008 use_readline : bool, optional
1009 DEPRECATED, ignored since IPython 6.0, will have no effects
1009 DEPRECATED, ignored since IPython 6.0, will have no effects
1010 """
1010 """
1011
1011
1012 self.magic_escape = ESC_MAGIC
1012 self.magic_escape = ESC_MAGIC
1013 self.splitter = CompletionSplitter()
1013 self.splitter = CompletionSplitter()
1014
1014
1015 if use_readline is not _deprecation_readline_sentinel:
1015 if use_readline is not _deprecation_readline_sentinel:
1016 warnings.warn('The `use_readline` parameter is deprecated and ignored since IPython 6.0.',
1016 warnings.warn('The `use_readline` parameter is deprecated and ignored since IPython 6.0.',
1017 DeprecationWarning, stacklevel=2)
1017 DeprecationWarning, stacklevel=2)
1018
1018
1019 # _greedy_changed() depends on splitter and readline being defined:
1019 # _greedy_changed() depends on splitter and readline being defined:
1020 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
1020 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
1021 config=config, **kwargs)
1021 config=config, **kwargs)
1022
1022
1023 # List where completion matches will be stored
1023 # List where completion matches will be stored
1024 self.matches = []
1024 self.matches = []
1025 self.shell = shell
1025 self.shell = shell
1026 # Regexp to split filenames with spaces in them
1026 # Regexp to split filenames with spaces in them
1027 self.space_name_re = re.compile(r'([^\\] )')
1027 self.space_name_re = re.compile(r'([^\\] )')
1028 # Hold a local ref. to glob.glob for speed
1028 # Hold a local ref. to glob.glob for speed
1029 self.glob = glob.glob
1029 self.glob = glob.glob
1030
1030
1031 # Determine if we are running on 'dumb' terminals, like (X)Emacs
1031 # Determine if we are running on 'dumb' terminals, like (X)Emacs
1032 # buffers, to avoid completion problems.
1032 # buffers, to avoid completion problems.
1033 term = os.environ.get('TERM','xterm')
1033 term = os.environ.get('TERM','xterm')
1034 self.dumb_terminal = term in ['dumb','emacs']
1034 self.dumb_terminal = term in ['dumb','emacs']
1035
1035
1036 # Special handling of backslashes needed in win32 platforms
1036 # Special handling of backslashes needed in win32 platforms
1037 if sys.platform == "win32":
1037 if sys.platform == "win32":
1038 self.clean_glob = self._clean_glob_win32
1038 self.clean_glob = self._clean_glob_win32
1039 else:
1039 else:
1040 self.clean_glob = self._clean_glob
1040 self.clean_glob = self._clean_glob
1041
1041
1042 #regexp to parse docstring for function signature
1042 #regexp to parse docstring for function signature
1043 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1043 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1044 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1044 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1045 #use this if positional argument name is also needed
1045 #use this if positional argument name is also needed
1046 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
1046 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
1047
1047
1048 # All active matcher routines for completion
1048 # All active matcher routines for completion
1049 self.matchers = [
1049 self.matchers = [
1050 self.python_matches,
1050 self.python_matches,
1051 self.file_matches,
1051 self.file_matches,
1052 self.magic_config_matches,
1052 self.magic_config_matches,
1053 self.magic_matches,
1053 self.magic_matches,
1054 self.python_func_kw_matches,
1054 self.python_func_kw_matches,
1055 self.dict_key_matches,
1055 self.dict_key_matches,
1056 ]
1056 ]
1057
1057
1058 # This is set externally by InteractiveShell
1058 # This is set externally by InteractiveShell
1059 self.custom_completers = None
1059 self.custom_completers = None
1060
1060
1061 def all_completions(self, text):
1061 def all_completions(self, text):
1062 """
1062 """
1063 Wrapper around the complete method for the benefit of emacs.
1063 Wrapper around the complete method for the benefit of emacs.
1064 """
1064 """
1065 return self.complete(text)[1]
1065 return self.complete(text)[1]
1066
1066
1067 def _clean_glob(self, text):
1067 def _clean_glob(self, text):
1068 return self.glob("%s*" % text)
1068 return self.glob("%s*" % text)
1069
1069
1070 def _clean_glob_win32(self,text):
1070 def _clean_glob_win32(self,text):
1071 return [f.replace("\\","/")
1071 return [f.replace("\\","/")
1072 for f in self.glob("%s*" % text)]
1072 for f in self.glob("%s*" % text)]
1073
1073
1074 def file_matches(self, text):
1074 def file_matches(self, text):
1075 """Match filenames, expanding ~USER type strings.
1075 """Match filenames, expanding ~USER type strings.
1076
1076
1077 Most of the seemingly convoluted logic in this completer is an
1077 Most of the seemingly convoluted logic in this completer is an
1078 attempt to handle filenames with spaces in them. And yet it's not
1078 attempt to handle filenames with spaces in them. And yet it's not
1079 quite perfect, because Python's readline doesn't expose all of the
1079 quite perfect, because Python's readline doesn't expose all of the
1080 GNU readline details needed for this to be done correctly.
1080 GNU readline details needed for this to be done correctly.
1081
1081
1082 For a filename with a space in it, the printed completions will be
1082 For a filename with a space in it, the printed completions will be
1083 only the parts after what's already been typed (instead of the
1083 only the parts after what's already been typed (instead of the
1084 full completions, as is normally done). I don't think with the
1084 full completions, as is normally done). I don't think with the
1085 current (as of Python 2.3) Python readline it's possible to do
1085 current (as of Python 2.3) Python readline it's possible to do
1086 better."""
1086 better."""
1087
1087
1088 # chars that require escaping with backslash - i.e. chars
1088 # chars that require escaping with backslash - i.e. chars
1089 # that readline treats incorrectly as delimiters, but we
1089 # that readline treats incorrectly as delimiters, but we
1090 # don't want to treat as delimiters in filename matching
1090 # don't want to treat as delimiters in filename matching
1091 # when escaped with backslash
1091 # when escaped with backslash
1092 if text.startswith('!'):
1092 if text.startswith('!'):
1093 text = text[1:]
1093 text = text[1:]
1094 text_prefix = u'!'
1094 text_prefix = u'!'
1095 else:
1095 else:
1096 text_prefix = u''
1096 text_prefix = u''
1097
1097
1098 text_until_cursor = self.text_until_cursor
1098 text_until_cursor = self.text_until_cursor
1099 # track strings with open quotes
1099 # track strings with open quotes
1100 open_quotes = has_open_quotes(text_until_cursor)
1100 open_quotes = has_open_quotes(text_until_cursor)
1101
1101
1102 if '(' in text_until_cursor or '[' in text_until_cursor:
1102 if '(' in text_until_cursor or '[' in text_until_cursor:
1103 lsplit = text
1103 lsplit = text
1104 else:
1104 else:
1105 try:
1105 try:
1106 # arg_split ~ shlex.split, but with unicode bugs fixed by us
1106 # arg_split ~ shlex.split, but with unicode bugs fixed by us
1107 lsplit = arg_split(text_until_cursor)[-1]
1107 lsplit = arg_split(text_until_cursor)[-1]
1108 except ValueError:
1108 except ValueError:
1109 # typically an unmatched ", or backslash without escaped char.
1109 # typically an unmatched ", or backslash without escaped char.
1110 if open_quotes:
1110 if open_quotes:
1111 lsplit = text_until_cursor.split(open_quotes)[-1]
1111 lsplit = text_until_cursor.split(open_quotes)[-1]
1112 else:
1112 else:
1113 return []
1113 return []
1114 except IndexError:
1114 except IndexError:
1115 # tab pressed on empty line
1115 # tab pressed on empty line
1116 lsplit = ""
1116 lsplit = ""
1117
1117
1118 if not open_quotes and lsplit != protect_filename(lsplit):
1118 if not open_quotes and lsplit != protect_filename(lsplit):
1119 # if protectables are found, do matching on the whole escaped name
1119 # if protectables are found, do matching on the whole escaped name
1120 has_protectables = True
1120 has_protectables = True
1121 text0,text = text,lsplit
1121 text0,text = text,lsplit
1122 else:
1122 else:
1123 has_protectables = False
1123 has_protectables = False
1124 text = os.path.expanduser(text)
1124 text = os.path.expanduser(text)
1125
1125
1126 if text == "":
1126 if text == "":
1127 return [text_prefix + protect_filename(f) for f in self.glob("*")]
1127 return [text_prefix + protect_filename(f) for f in self.glob("*")]
1128
1128
1129 # Compute the matches from the filesystem
1129 # Compute the matches from the filesystem
1130 if sys.platform == 'win32':
1130 if sys.platform == 'win32':
1131 m0 = self.clean_glob(text)
1131 m0 = self.clean_glob(text)
1132 else:
1132 else:
1133 m0 = self.clean_glob(text.replace('\\', ''))
1133 m0 = self.clean_glob(text.replace('\\', ''))
1134
1134
1135 if has_protectables:
1135 if has_protectables:
1136 # If we had protectables, we need to revert our changes to the
1136 # If we had protectables, we need to revert our changes to the
1137 # beginning of filename so that we don't double-write the part
1137 # beginning of filename so that we don't double-write the part
1138 # of the filename we have so far
1138 # of the filename we have so far
1139 len_lsplit = len(lsplit)
1139 len_lsplit = len(lsplit)
1140 matches = [text_prefix + text0 +
1140 matches = [text_prefix + text0 +
1141 protect_filename(f[len_lsplit:]) for f in m0]
1141 protect_filename(f[len_lsplit:]) for f in m0]
1142 else:
1142 else:
1143 if open_quotes:
1143 if open_quotes:
1144 # if we have a string with an open quote, we don't need to
1144 # if we have a string with an open quote, we don't need to
1145 # protect the names beyond the quote (and we _shouldn't_, as
1145 # protect the names beyond the quote (and we _shouldn't_, as
1146 # it would cause bugs when the filesystem call is made).
1146 # it would cause bugs when the filesystem call is made).
1147 matches = m0 if sys.platform == "win32" else\
1147 matches = m0 if sys.platform == "win32" else\
1148 [protect_filename(f, open_quotes) for f in m0]
1148 [protect_filename(f, open_quotes) for f in m0]
1149 else:
1149 else:
1150 matches = [text_prefix +
1150 matches = [text_prefix +
1151 protect_filename(f) for f in m0]
1151 protect_filename(f) for f in m0]
1152
1152
1153 # Mark directories in input list by appending '/' to their names.
1153 # Mark directories in input list by appending '/' to their names.
1154 return [x+'/' if os.path.isdir(x) else x for x in matches]
1154 return [x+'/' if os.path.isdir(x) else x for x in matches]
1155
1155
1156 def magic_matches(self, text):
1156 def magic_matches(self, text):
1157 """Match magics"""
1157 """Match magics"""
1158 # Get all shell magics now rather than statically, so magics loaded at
1158 # Get all shell magics now rather than statically, so magics loaded at
1159 # runtime show up too.
1159 # runtime show up too.
1160 lsm = self.shell.magics_manager.lsmagic()
1160 lsm = self.shell.magics_manager.lsmagic()
1161 line_magics = lsm['line']
1161 line_magics = lsm['line']
1162 cell_magics = lsm['cell']
1162 cell_magics = lsm['cell']
1163 pre = self.magic_escape
1163 pre = self.magic_escape
1164 pre2 = pre+pre
1164 pre2 = pre+pre
1165
1165
1166 # Completion logic:
1166 # Completion logic:
1167 # - user gives %%: only do cell magics
1167 # - user gives %%: only do cell magics
1168 # - user gives %: do both line and cell magics
1168 # - user gives %: do both line and cell magics
1169 # - no prefix: do both
1169 # - no prefix: do both
1170 # In other words, line magics are skipped if the user gives %% explicitly
1170 # In other words, line magics are skipped if the user gives %% explicitly
1171 #
1171 #
1172 # We also exclude magics that match any currently visible names:
1172 # We also exclude magics that match any currently visible names:
1173 # https://github.com/ipython/ipython/issues/4877
1173 # https://github.com/ipython/ipython/issues/4877
1174 bare_text = text.lstrip(pre)
1174 bare_text = text.lstrip(pre)
1175 global_matches = self.global_matches(bare_text)
1175 global_matches = self.global_matches(bare_text)
1176 matches = lambda magic: magic.startswith(bare_text) \
1176 matches = lambda magic: magic.startswith(bare_text) \
1177 and magic not in global_matches
1177 and magic not in global_matches
1178 comp = [ pre2+m for m in cell_magics if matches(m)]
1178 comp = [ pre2+m for m in cell_magics if matches(m)]
1179 if not text.startswith(pre2):
1179 if not text.startswith(pre2):
1180 comp += [ pre+m for m in line_magics if matches(m)]
1180 comp += [ pre+m for m in line_magics if matches(m)]
1181
1181
1182 return comp
1182 return comp
1183
1183
1184 def magic_config_matches(self, text):
1184 def magic_config_matches(self, text):
1185 """ Match class names and attributes for %config magic """
1185 """ Match class names and attributes for %config magic """
1186 # use line buffer instead of text (which is a word)
1186 # use line buffer instead of text (which is a word)
1187 texts = self.line_buffer.strip().split()
1187 texts = self.line_buffer.strip().split()
1188
1188
1189 if len(texts) > 0 and \
1189 if len(texts) > 0 and \
1190 ('config'.startswith(texts[0]) or '%config'.startswith(texts[0])):
1190 ('config'.startswith(texts[0]) or '%config'.startswith(texts[0])):
1191 # get all configuration classes
1191 # get all configuration classes
1192 classes = sorted(set([ c for c in self.shell.configurables
1192 classes = sorted(set([ c for c in self.shell.configurables
1193 if c.__class__.class_traits(config=True)
1193 if c.__class__.class_traits(config=True)
1194 ]), key=lambda x: x.__class__.__name__)
1194 ]), key=lambda x: x.__class__.__name__)
1195 classnames = [ c.__class__.__name__ for c in classes ]
1195 classnames = [ c.__class__.__name__ for c in classes ]
1196
1196
1197 # return all classnames if config or %config is given
1197 # return all classnames if config or %config is given
1198 if len(texts) == 1:
1198 if len(texts) == 1:
1199 return classnames
1199 return classnames
1200
1200
1201 # match classname
1201 # match classname
1202 classname_texts = texts[1].split('.')
1202 classname_texts = texts[1].split('.')
1203 classname = classname_texts[0]
1203 classname = classname_texts[0]
1204 classname_matches = [ c for c in classnames
1204 classname_matches = [ c for c in classnames
1205 if c.startswith(classname) ]
1205 if c.startswith(classname) ]
1206
1206
1207 # return matched classes or the matched class with attributes
1207 # return matched classes or the matched class with attributes
1208 if texts[1].find('.') < 0:
1208 if texts[1].find('.') < 0:
1209 return classname_matches
1209 return classname_matches
1210 elif len(classname_matches) == 1 and \
1210 elif len(classname_matches) == 1 and \
1211 classname_matches[0] == classname:
1211 classname_matches[0] == classname:
1212 cls = classes[classnames.index(classname)].__class__
1212 cls = classes[classnames.index(classname)].__class__
1213 help = cls.class_get_help()
1213 help = cls.class_get_help()
1214 # strip leading '--' from cl-args:
1214 # strip leading '--' from cl-args:
1215 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
1215 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
1216 return [ attr.split('=')[0]
1216 return [ attr.split('=')[0]
1217 for attr in help.strip().splitlines()
1217 for attr in help.strip().splitlines()
1218 if attr.startswith(texts[1]) ]
1218 if attr.startswith(texts[1]) ]
1219 return []
1219 return []
1220
1220
1221 def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str):
1221 def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str):
1222 """
1222 """
1223
1223
1224 Return a list of :any:`jedi.api.Completions` object from a ``text`` and
1224 Return a list of :any:`jedi.api.Completions` object from a ``text`` and
1225 cursor position.
1225 cursor position.
1226
1226
1227 Parameters
1227 Parameters
1228 ----------
1228 ----------
1229 cursor_column : int
1229 cursor_column : int
1230 column position of the cursor in ``text``, 0-indexed.
1230 column position of the cursor in ``text``, 0-indexed.
1231 cursor_line : int
1231 cursor_line : int
1232 line position of the cursor in ``text``, 0-indexed
1232 line position of the cursor in ``text``, 0-indexed
1233 text : str
1233 text : str
1234 text to complete
1234 text to complete
1235
1235
1236 Debugging
1236 Debugging
1237 ---------
1237 ---------
1238
1238
1239 If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion`
1239 If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion`
1240 object containing a string with the Jedi debug information attached.
1240 object containing a string with the Jedi debug information attached.
1241 """
1241 """
1242 namespaces = [self.namespace]
1242 namespaces = [self.namespace]
1243 if self.global_namespace is not None:
1243 if self.global_namespace is not None:
1244 namespaces.append(self.global_namespace)
1244 namespaces.append(self.global_namespace)
1245
1245
1246 completion_filter = lambda x:x
1246 completion_filter = lambda x:x
1247 # cursor_pos is an it, jedi wants line and column
1247 # cursor_pos is an it, jedi wants line and column
1248 offset = cursor_to_position(text, cursor_line, cursor_column)
1248 offset = cursor_to_position(text, cursor_line, cursor_column)
1249 # filter output if we are completing for object members
1249 # filter output if we are completing for object members
1250 if offset:
1250 if offset:
1251 pre = text[offset-1]
1251 pre = text[offset-1]
1252 if pre == '.':
1252 if pre == '.':
1253 if self.omit__names == 2:
1253 if self.omit__names == 2:
1254 completion_filter = lambda c:not c.name.startswith('_')
1254 completion_filter = lambda c:not c.name.startswith('_')
1255 elif self.omit__names == 1:
1255 elif self.omit__names == 1:
1256 completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__'))
1256 completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__'))
1257 elif self.omit__names == 0:
1257 elif self.omit__names == 0:
1258 completion_filter = lambda x:x
1258 completion_filter = lambda x:x
1259 else:
1259 else:
1260 raise ValueError("Don't understand self.omit__names == {}".format(self.omit__names))
1260 raise ValueError("Don't understand self.omit__names == {}".format(self.omit__names))
1261
1261
1262 interpreter = jedi.Interpreter(
1262 interpreter = jedi.Interpreter(
1263 text, namespaces, column=cursor_column, line=cursor_line + 1)
1263 text, namespaces, column=cursor_column, line=cursor_line + 1)
1264
1264
1265 try_jedi = False
1265 try_jedi = False
1266
1266
1267 try:
1267 try:
1268 # should we check the type of the node is Error ?
1268 # should we check the type of the node is Error ?
1269 from jedi.parser.tree import ErrorLeaf
1269 from jedi.parser.tree import ErrorLeaf
1270 next_to_last_tree = interpreter._get_module().tree_node.children[-2]
1270 next_to_last_tree = interpreter._get_module().tree_node.children[-2]
1271 completing_string = False
1271 completing_string = False
1272 if isinstance(next_to_last_tree, ErrorLeaf):
1272 if isinstance(next_to_last_tree, ErrorLeaf):
1273 completing_string = interpreter._get_module().tree_node.children[-2].value[0] in {'"', "'"}
1273 completing_string = interpreter._get_module().tree_node.children[-2].value[0] in {'"', "'"}
1274 # if we are in a string jedi is likely not the right candidate for
1274 # if we are in a string jedi is likely not the right candidate for
1275 # now. Skip it.
1275 # now. Skip it.
1276 try_jedi = not completing_string
1276 try_jedi = not completing_string
1277 except Exception as e:
1277 except Exception as e:
1278 # many of things can go wrong, we are using private API just don't crash.
1278 # many of things can go wrong, we are using private API just don't crash.
1279 if self.debug:
1279 if self.debug:
1280 print("Error detecting if completing a non-finished string :", e, '|')
1280 print("Error detecting if completing a non-finished string :", e, '|')
1281
1281
1282 if not try_jedi:
1282 if not try_jedi:
1283 return []
1283 return []
1284 try:
1284 try:
1285 return filter(completion_filter, interpreter.completions())
1285 return filter(completion_filter, interpreter.completions())
1286 except Exception as e:
1286 except Exception as e:
1287 if self.debug:
1287 if self.debug:
1288 return [_FakeJediCompletion('Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' % (e))]
1288 return [_FakeJediCompletion('Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' % (e))]
1289 else:
1289 else:
1290 return []
1290 return []
1291
1291
1292 def python_matches(self, text):
1292 def python_matches(self, text):
1293 """Match attributes or global python names"""
1293 """Match attributes or global python names"""
1294 if "." in text:
1294 if "." in text:
1295 try:
1295 try:
1296 matches = self.attr_matches(text)
1296 matches = self.attr_matches(text)
1297 if text.endswith('.') and self.omit__names:
1297 if text.endswith('.') and self.omit__names:
1298 if self.omit__names == 1:
1298 if self.omit__names == 1:
1299 # true if txt is _not_ a __ name, false otherwise:
1299 # true if txt is _not_ a __ name, false otherwise:
1300 no__name = (lambda txt:
1300 no__name = (lambda txt:
1301 re.match(r'.*\.__.*?__',txt) is None)
1301 re.match(r'.*\.__.*?__',txt) is None)
1302 else:
1302 else:
1303 # true if txt is _not_ a _ name, false otherwise:
1303 # true if txt is _not_ a _ name, false otherwise:
1304 no__name = (lambda txt:
1304 no__name = (lambda txt:
1305 re.match(r'\._.*?',txt[txt.rindex('.'):]) is None)
1305 re.match(r'\._.*?',txt[txt.rindex('.'):]) is None)
1306 matches = filter(no__name, matches)
1306 matches = filter(no__name, matches)
1307 except NameError:
1307 except NameError:
1308 # catches <undefined attributes>.<tab>
1308 # catches <undefined attributes>.<tab>
1309 matches = []
1309 matches = []
1310 else:
1310 else:
1311 matches = self.global_matches(text)
1311 matches = self.global_matches(text)
1312 return matches
1312 return matches
1313
1313
1314 def _default_arguments_from_docstring(self, doc):
1314 def _default_arguments_from_docstring(self, doc):
1315 """Parse the first line of docstring for call signature.
1315 """Parse the first line of docstring for call signature.
1316
1316
1317 Docstring should be of the form 'min(iterable[, key=func])\n'.
1317 Docstring should be of the form 'min(iterable[, key=func])\n'.
1318 It can also parse cython docstring of the form
1318 It can also parse cython docstring of the form
1319 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
1319 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
1320 """
1320 """
1321 if doc is None:
1321 if doc is None:
1322 return []
1322 return []
1323
1323
1324 #care only the firstline
1324 #care only the firstline
1325 line = doc.lstrip().splitlines()[0]
1325 line = doc.lstrip().splitlines()[0]
1326
1326
1327 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1327 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1328 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
1328 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
1329 sig = self.docstring_sig_re.search(line)
1329 sig = self.docstring_sig_re.search(line)
1330 if sig is None:
1330 if sig is None:
1331 return []
1331 return []
1332 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
1332 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
1333 sig = sig.groups()[0].split(',')
1333 sig = sig.groups()[0].split(',')
1334 ret = []
1334 ret = []
1335 for s in sig:
1335 for s in sig:
1336 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1336 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1337 ret += self.docstring_kwd_re.findall(s)
1337 ret += self.docstring_kwd_re.findall(s)
1338 return ret
1338 return ret
1339
1339
1340 def _default_arguments(self, obj):
1340 def _default_arguments(self, obj):
1341 """Return the list of default arguments of obj if it is callable,
1341 """Return the list of default arguments of obj if it is callable,
1342 or empty list otherwise."""
1342 or empty list otherwise."""
1343 call_obj = obj
1343 call_obj = obj
1344 ret = []
1344 ret = []
1345 if inspect.isbuiltin(obj):
1345 if inspect.isbuiltin(obj):
1346 pass
1346 pass
1347 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
1347 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
1348 if inspect.isclass(obj):
1348 if inspect.isclass(obj):
1349 #for cython embededsignature=True the constructor docstring
1349 #for cython embededsignature=True the constructor docstring
1350 #belongs to the object itself not __init__
1350 #belongs to the object itself not __init__
1351 ret += self._default_arguments_from_docstring(
1351 ret += self._default_arguments_from_docstring(
1352 getattr(obj, '__doc__', ''))
1352 getattr(obj, '__doc__', ''))
1353 # for classes, check for __init__,__new__
1353 # for classes, check for __init__,__new__
1354 call_obj = (getattr(obj, '__init__', None) or
1354 call_obj = (getattr(obj, '__init__', None) or
1355 getattr(obj, '__new__', None))
1355 getattr(obj, '__new__', None))
1356 # for all others, check if they are __call__able
1356 # for all others, check if they are __call__able
1357 elif hasattr(obj, '__call__'):
1357 elif hasattr(obj, '__call__'):
1358 call_obj = obj.__call__
1358 call_obj = obj.__call__
1359 ret += self._default_arguments_from_docstring(
1359 ret += self._default_arguments_from_docstring(
1360 getattr(call_obj, '__doc__', ''))
1360 getattr(call_obj, '__doc__', ''))
1361
1361
1362 _keeps = (inspect.Parameter.KEYWORD_ONLY,
1362 _keeps = (inspect.Parameter.KEYWORD_ONLY,
1363 inspect.Parameter.POSITIONAL_OR_KEYWORD)
1363 inspect.Parameter.POSITIONAL_OR_KEYWORD)
1364
1364
1365 try:
1365 try:
1366 sig = inspect.signature(call_obj)
1366 sig = inspect.signature(call_obj)
1367 ret.extend(k for k, v in sig.parameters.items() if
1367 ret.extend(k for k, v in sig.parameters.items() if
1368 v.kind in _keeps)
1368 v.kind in _keeps)
1369 except ValueError:
1369 except ValueError:
1370 pass
1370 pass
1371
1371
1372 return list(set(ret))
1372 return list(set(ret))
1373
1373
1374 def python_func_kw_matches(self,text):
1374 def python_func_kw_matches(self,text):
1375 """Match named parameters (kwargs) of the last open function"""
1375 """Match named parameters (kwargs) of the last open function"""
1376
1376
1377 if "." in text: # a parameter cannot be dotted
1377 if "." in text: # a parameter cannot be dotted
1378 return []
1378 return []
1379 try: regexp = self.__funcParamsRegex
1379 try: regexp = self.__funcParamsRegex
1380 except AttributeError:
1380 except AttributeError:
1381 regexp = self.__funcParamsRegex = re.compile(r'''
1381 regexp = self.__funcParamsRegex = re.compile(r'''
1382 '.*?(?<!\\)' | # single quoted strings or
1382 '.*?(?<!\\)' | # single quoted strings or
1383 ".*?(?<!\\)" | # double quoted strings or
1383 ".*?(?<!\\)" | # double quoted strings or
1384 \w+ | # identifier
1384 \w+ | # identifier
1385 \S # other characters
1385 \S # other characters
1386 ''', re.VERBOSE | re.DOTALL)
1386 ''', re.VERBOSE | re.DOTALL)
1387 # 1. find the nearest identifier that comes before an unclosed
1387 # 1. find the nearest identifier that comes before an unclosed
1388 # parenthesis before the cursor
1388 # parenthesis before the cursor
1389 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
1389 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
1390 tokens = regexp.findall(self.text_until_cursor)
1390 tokens = regexp.findall(self.text_until_cursor)
1391 iterTokens = reversed(tokens); openPar = 0
1391 iterTokens = reversed(tokens); openPar = 0
1392
1392
1393 for token in iterTokens:
1393 for token in iterTokens:
1394 if token == ')':
1394 if token == ')':
1395 openPar -= 1
1395 openPar -= 1
1396 elif token == '(':
1396 elif token == '(':
1397 openPar += 1
1397 openPar += 1
1398 if openPar > 0:
1398 if openPar > 0:
1399 # found the last unclosed parenthesis
1399 # found the last unclosed parenthesis
1400 break
1400 break
1401 else:
1401 else:
1402 return []
1402 return []
1403 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
1403 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
1404 ids = []
1404 ids = []
1405 isId = re.compile(r'\w+$').match
1405 isId = re.compile(r'\w+$').match
1406
1406
1407 while True:
1407 while True:
1408 try:
1408 try:
1409 ids.append(next(iterTokens))
1409 ids.append(next(iterTokens))
1410 if not isId(ids[-1]):
1410 if not isId(ids[-1]):
1411 ids.pop(); break
1411 ids.pop(); break
1412 if not next(iterTokens) == '.':
1412 if not next(iterTokens) == '.':
1413 break
1413 break
1414 except StopIteration:
1414 except StopIteration:
1415 break
1415 break
1416
1416
1417 # Find all named arguments already assigned to, as to avoid suggesting
1417 # Find all named arguments already assigned to, as to avoid suggesting
1418 # them again
1418 # them again
1419 usedNamedArgs = set()
1419 usedNamedArgs = set()
1420 par_level = -1
1420 par_level = -1
1421 for token, next_token in zip(tokens, tokens[1:]):
1421 for token, next_token in zip(tokens, tokens[1:]):
1422 if token == '(':
1422 if token == '(':
1423 par_level += 1
1423 par_level += 1
1424 elif token == ')':
1424 elif token == ')':
1425 par_level -= 1
1425 par_level -= 1
1426
1426
1427 if par_level != 0:
1427 if par_level != 0:
1428 continue
1428 continue
1429
1429
1430 if next_token != '=':
1430 if next_token != '=':
1431 continue
1431 continue
1432
1432
1433 usedNamedArgs.add(token)
1433 usedNamedArgs.add(token)
1434
1434
1435 # lookup the candidate callable matches either using global_matches
1435 # lookup the candidate callable matches either using global_matches
1436 # or attr_matches for dotted names
1436 # or attr_matches for dotted names
1437 if len(ids) == 1:
1437 if len(ids) == 1:
1438 callableMatches = self.global_matches(ids[0])
1438 callableMatches = self.global_matches(ids[0])
1439 else:
1439 else:
1440 callableMatches = self.attr_matches('.'.join(ids[::-1]))
1440 callableMatches = self.attr_matches('.'.join(ids[::-1]))
1441 argMatches = []
1441 argMatches = []
1442 for callableMatch in callableMatches:
1442 for callableMatch in callableMatches:
1443 try:
1443 try:
1444 namedArgs = self._default_arguments(eval(callableMatch,
1444 namedArgs = self._default_arguments(eval(callableMatch,
1445 self.namespace))
1445 self.namespace))
1446 except:
1446 except:
1447 continue
1447 continue
1448
1448
1449 # Remove used named arguments from the list, no need to show twice
1449 # Remove used named arguments from the list, no need to show twice
1450 for namedArg in set(namedArgs) - usedNamedArgs:
1450 for namedArg in set(namedArgs) - usedNamedArgs:
1451 if namedArg.startswith(text):
1451 if namedArg.startswith(text):
1452 argMatches.append(u"%s=" %namedArg)
1452 argMatches.append(u"%s=" %namedArg)
1453 return argMatches
1453 return argMatches
1454
1454
1455 def dict_key_matches(self, text):
1455 def dict_key_matches(self, text):
1456 "Match string keys in a dictionary, after e.g. 'foo[' "
1456 "Match string keys in a dictionary, after e.g. 'foo[' "
1457 def get_keys(obj):
1457 def get_keys(obj):
1458 # Objects can define their own completions by defining an
1458 # Objects can define their own completions by defining an
1459 # _ipy_key_completions_() method.
1459 # _ipy_key_completions_() method.
1460 method = get_real_method(obj, '_ipython_key_completions_')
1460 method = get_real_method(obj, '_ipython_key_completions_')
1461 if method is not None:
1461 if method is not None:
1462 return method()
1462 return method()
1463
1463
1464 # Special case some common in-memory dict-like types
1464 # Special case some common in-memory dict-like types
1465 if isinstance(obj, dict) or\
1465 if isinstance(obj, dict) or\
1466 _safe_isinstance(obj, 'pandas', 'DataFrame'):
1466 _safe_isinstance(obj, 'pandas', 'DataFrame'):
1467 try:
1467 try:
1468 return list(obj.keys())
1468 return list(obj.keys())
1469 except Exception:
1469 except Exception:
1470 return []
1470 return []
1471 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
1471 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
1472 _safe_isinstance(obj, 'numpy', 'void'):
1472 _safe_isinstance(obj, 'numpy', 'void'):
1473 return obj.dtype.names or []
1473 return obj.dtype.names or []
1474 return []
1474 return []
1475
1475
1476 try:
1476 try:
1477 regexps = self.__dict_key_regexps
1477 regexps = self.__dict_key_regexps
1478 except AttributeError:
1478 except AttributeError:
1479 dict_key_re_fmt = r'''(?x)
1479 dict_key_re_fmt = r'''(?x)
1480 ( # match dict-referring expression wrt greedy setting
1480 ( # match dict-referring expression wrt greedy setting
1481 %s
1481 %s
1482 )
1482 )
1483 \[ # open bracket
1483 \[ # open bracket
1484 \s* # and optional whitespace
1484 \s* # and optional whitespace
1485 ([uUbB]? # string prefix (r not handled)
1485 ([uUbB]? # string prefix (r not handled)
1486 (?: # unclosed string
1486 (?: # unclosed string
1487 '(?:[^']|(?<!\\)\\')*
1487 '(?:[^']|(?<!\\)\\')*
1488 |
1488 |
1489 "(?:[^"]|(?<!\\)\\")*
1489 "(?:[^"]|(?<!\\)\\")*
1490 )
1490 )
1491 )?
1491 )?
1492 $
1492 $
1493 '''
1493 '''
1494 regexps = self.__dict_key_regexps = {
1494 regexps = self.__dict_key_regexps = {
1495 False: re.compile(dict_key_re_fmt % '''
1495 False: re.compile(dict_key_re_fmt % '''
1496 # identifiers separated by .
1496 # identifiers separated by .
1497 (?!\d)\w+
1497 (?!\d)\w+
1498 (?:\.(?!\d)\w+)*
1498 (?:\.(?!\d)\w+)*
1499 '''),
1499 '''),
1500 True: re.compile(dict_key_re_fmt % '''
1500 True: re.compile(dict_key_re_fmt % '''
1501 .+
1501 .+
1502 ''')
1502 ''')
1503 }
1503 }
1504
1504
1505 match = regexps[self.greedy].search(self.text_until_cursor)
1505 match = regexps[self.greedy].search(self.text_until_cursor)
1506 if match is None:
1506 if match is None:
1507 return []
1507 return []
1508
1508
1509 expr, prefix = match.groups()
1509 expr, prefix = match.groups()
1510 try:
1510 try:
1511 obj = eval(expr, self.namespace)
1511 obj = eval(expr, self.namespace)
1512 except Exception:
1512 except Exception:
1513 try:
1513 try:
1514 obj = eval(expr, self.global_namespace)
1514 obj = eval(expr, self.global_namespace)
1515 except Exception:
1515 except Exception:
1516 return []
1516 return []
1517
1517
1518 keys = get_keys(obj)
1518 keys = get_keys(obj)
1519 if not keys:
1519 if not keys:
1520 return keys
1520 return keys
1521 closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims)
1521 closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims)
1522 if not matches:
1522 if not matches:
1523 return matches
1523 return matches
1524
1524
1525 # get the cursor position of
1525 # get the cursor position of
1526 # - the text being completed
1526 # - the text being completed
1527 # - the start of the key text
1527 # - the start of the key text
1528 # - the start of the completion
1528 # - the start of the completion
1529 text_start = len(self.text_until_cursor) - len(text)
1529 text_start = len(self.text_until_cursor) - len(text)
1530 if prefix:
1530 if prefix:
1531 key_start = match.start(2)
1531 key_start = match.start(2)
1532 completion_start = key_start + token_offset
1532 completion_start = key_start + token_offset
1533 else:
1533 else:
1534 key_start = completion_start = match.end()
1534 key_start = completion_start = match.end()
1535
1535
1536 # grab the leading prefix, to make sure all completions start with `text`
1536 # grab the leading prefix, to make sure all completions start with `text`
1537 if text_start > key_start:
1537 if text_start > key_start:
1538 leading = ''
1538 leading = ''
1539 else:
1539 else:
1540 leading = text[text_start:completion_start]
1540 leading = text[text_start:completion_start]
1541
1541
1542 # the index of the `[` character
1542 # the index of the `[` character
1543 bracket_idx = match.end(1)
1543 bracket_idx = match.end(1)
1544
1544
1545 # append closing quote and bracket as appropriate
1545 # append closing quote and bracket as appropriate
1546 # this is *not* appropriate if the opening quote or bracket is outside
1546 # this is *not* appropriate if the opening quote or bracket is outside
1547 # the text given to this method
1547 # the text given to this method
1548 suf = ''
1548 suf = ''
1549 continuation = self.line_buffer[len(self.text_until_cursor):]
1549 continuation = self.line_buffer[len(self.text_until_cursor):]
1550 if key_start > text_start and closing_quote:
1550 if key_start > text_start and closing_quote:
1551 # quotes were opened inside text, maybe close them
1551 # quotes were opened inside text, maybe close them
1552 if continuation.startswith(closing_quote):
1552 if continuation.startswith(closing_quote):
1553 continuation = continuation[len(closing_quote):]
1553 continuation = continuation[len(closing_quote):]
1554 else:
1554 else:
1555 suf += closing_quote
1555 suf += closing_quote
1556 if bracket_idx > text_start:
1556 if bracket_idx > text_start:
1557 # brackets were opened inside text, maybe close them
1557 # brackets were opened inside text, maybe close them
1558 if not continuation.startswith(']'):
1558 if not continuation.startswith(']'):
1559 suf += ']'
1559 suf += ']'
1560
1560
1561 return [leading + k + suf for k in matches]
1561 return [leading + k + suf for k in matches]
1562
1562
1563 def unicode_name_matches(self, text):
1563 def unicode_name_matches(self, text):
1564 u"""Match Latex-like syntax for unicode characters base
1564 u"""Match Latex-like syntax for unicode characters base
1565 on the name of the character.
1565 on the name of the character.
1566
1566
1567 This does ``\\GREEK SMALL LETTER ETA`` -> ``Ξ·``
1567 This does ``\\GREEK SMALL LETTER ETA`` -> ``Ξ·``
1568
1568
1569 Works only on valid python 3 identifier, or on combining characters that
1569 Works only on valid python 3 identifier, or on combining characters that
1570 will combine to form a valid identifier.
1570 will combine to form a valid identifier.
1571
1571
1572 Used on Python 3 only.
1572 Used on Python 3 only.
1573 """
1573 """
1574 slashpos = text.rfind('\\')
1574 slashpos = text.rfind('\\')
1575 if slashpos > -1:
1575 if slashpos > -1:
1576 s = text[slashpos+1:]
1576 s = text[slashpos+1:]
1577 try :
1577 try :
1578 unic = unicodedata.lookup(s)
1578 unic = unicodedata.lookup(s)
1579 # allow combining chars
1579 # allow combining chars
1580 if ('a'+unic).isidentifier():
1580 if ('a'+unic).isidentifier():
1581 return '\\'+s,[unic]
1581 return '\\'+s,[unic]
1582 except KeyError:
1582 except KeyError:
1583 pass
1583 pass
1584 return u'', []
1584 return u'', []
1585
1585
1586
1586
1587 def latex_matches(self, text):
1587 def latex_matches(self, text):
1588 u"""Match Latex syntax for unicode characters.
1588 u"""Match Latex syntax for unicode characters.
1589
1589
1590 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``Ξ±``
1590 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``Ξ±``
1591
1591
1592 Used on Python 3 only.
1592 Used on Python 3 only.
1593 """
1593 """
1594 slashpos = text.rfind('\\')
1594 slashpos = text.rfind('\\')
1595 if slashpos > -1:
1595 if slashpos > -1:
1596 s = text[slashpos:]
1596 s = text[slashpos:]
1597 if s in latex_symbols:
1597 if s in latex_symbols:
1598 # Try to complete a full latex symbol to unicode
1598 # Try to complete a full latex symbol to unicode
1599 # \\alpha -> Ξ±
1599 # \\alpha -> Ξ±
1600 return s, [latex_symbols[s]]
1600 return s, [latex_symbols[s]]
1601 else:
1601 else:
1602 # If a user has partially typed a latex symbol, give them
1602 # If a user has partially typed a latex symbol, give them
1603 # a full list of options \al -> [\aleph, \alpha]
1603 # a full list of options \al -> [\aleph, \alpha]
1604 matches = [k for k in latex_symbols if k.startswith(s)]
1604 matches = [k for k in latex_symbols if k.startswith(s)]
1605 return s, matches
1605 return s, matches
1606 return u'', []
1606 return u'', []
1607
1607
1608 def dispatch_custom_completer(self, text):
1608 def dispatch_custom_completer(self, text):
1609 if not self.custom_completers:
1609 if not self.custom_completers:
1610 return
1610 return
1611
1611
1612 line = self.line_buffer
1612 line = self.line_buffer
1613 if not line.strip():
1613 if not line.strip():
1614 return None
1614 return None
1615
1615
1616 # Create a little structure to pass all the relevant information about
1616 # Create a little structure to pass all the relevant information about
1617 # the current completion to any custom completer.
1617 # the current completion to any custom completer.
1618 event = SimpleNamespace()
1618 event = SimpleNamespace()
1619 event.line = line
1619 event.line = line
1620 event.symbol = text
1620 event.symbol = text
1621 cmd = line.split(None,1)[0]
1621 cmd = line.split(None,1)[0]
1622 event.command = cmd
1622 event.command = cmd
1623 event.text_until_cursor = self.text_until_cursor
1623 event.text_until_cursor = self.text_until_cursor
1624
1624
1625 # for foo etc, try also to find completer for %foo
1625 # for foo etc, try also to find completer for %foo
1626 if not cmd.startswith(self.magic_escape):
1626 if not cmd.startswith(self.magic_escape):
1627 try_magic = self.custom_completers.s_matches(
1627 try_magic = self.custom_completers.s_matches(
1628 self.magic_escape + cmd)
1628 self.magic_escape + cmd)
1629 else:
1629 else:
1630 try_magic = []
1630 try_magic = []
1631
1631
1632 for c in itertools.chain(self.custom_completers.s_matches(cmd),
1632 for c in itertools.chain(self.custom_completers.s_matches(cmd),
1633 try_magic,
1633 try_magic,
1634 self.custom_completers.flat_matches(self.text_until_cursor)):
1634 self.custom_completers.flat_matches(self.text_until_cursor)):
1635 try:
1635 try:
1636 res = c(event)
1636 res = c(event)
1637 if res:
1637 if res:
1638 # first, try case sensitive match
1638 # first, try case sensitive match
1639 withcase = [r for r in res if r.startswith(text)]
1639 withcase = [r for r in res if r.startswith(text)]
1640 if withcase:
1640 if withcase:
1641 return withcase
1641 return withcase
1642 # if none, then case insensitive ones are ok too
1642 # if none, then case insensitive ones are ok too
1643 text_low = text.lower()
1643 text_low = text.lower()
1644 return [r for r in res if r.lower().startswith(text_low)]
1644 return [r for r in res if r.lower().startswith(text_low)]
1645 except TryNext:
1645 except TryNext:
1646 pass
1646 pass
1647
1647
1648 return None
1648 return None
1649
1649
1650 def completions(self, text: str, offset: int)->Iterator[Completion]:
1650 def completions(self, text: str, offset: int)->Iterator[Completion]:
1651 """
1651 """
1652 Returns an iterator over the possible completions
1652 Returns an iterator over the possible completions
1653
1653
1654 .. warning:: Unstable
1654 .. warning:: Unstable
1655
1655
1656 This function is unstable, API may change without warning.
1656 This function is unstable, API may change without warning.
1657 It will also raise unless use in proper context manager.
1657 It will also raise unless use in proper context manager.
1658
1658
1659 Parameters
1659 Parameters
1660 ----------
1660 ----------
1661
1661
1662 text:str
1662 text:str
1663 Full text of the current input, multi line string.
1663 Full text of the current input, multi line string.
1664 offset:int
1664 offset:int
1665 Integer representing the position of the cursor in ``text``. Offset
1665 Integer representing the position of the cursor in ``text``. Offset
1666 is 0-based indexed.
1666 is 0-based indexed.
1667
1667
1668 Yields
1668 Yields
1669 ------
1669 ------
1670 :any:`Completion` object
1670 :any:`Completion` object
1671
1671
1672
1672
1673 The cursor on a text can either be seen as being "in between"
1673 The cursor on a text can either be seen as being "in between"
1674 characters or "On" a character depending on the interface visible to
1674 characters or "On" a character depending on the interface visible to
1675 the user. For consistency the cursor being on "in between" characters X
1675 the user. For consistency the cursor being on "in between" characters X
1676 and Y is equivalent to the cursor being "on" character Y, that is to say
1676 and Y is equivalent to the cursor being "on" character Y, that is to say
1677 the character the cursor is on is considered as being after the cursor.
1677 the character the cursor is on is considered as being after the cursor.
1678
1678
1679 Combining characters may span more that one position in the
1679 Combining characters may span more that one position in the
1680 text.
1680 text.
1681
1681
1682
1682
1683 .. note::
1683 .. note::
1684
1684
1685 If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--``
1685 If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--``
1686 fake Completion token to distinguish completion returned by Jedi
1686 fake Completion token to distinguish completion returned by Jedi
1687 and usual IPython completion.
1687 and usual IPython completion.
1688
1688
1689 .. note::
1689 .. note::
1690
1690
1691 Completions are not completely deduplicated yet. If identical
1691 Completions are not completely deduplicated yet. If identical
1692 completions are coming from different sources this function does not
1692 completions are coming from different sources this function does not
1693 ensure that each completion object will only be present once.
1693 ensure that each completion object will only be present once.
1694 """
1694 """
1695 warnings.warn("_complete is a provisional API (as of IPython 6.0). "
1695 warnings.warn("_complete is a provisional API (as of IPython 6.0). "
1696 "It may change without warnings. "
1696 "It may change without warnings. "
1697 "Use in corresponding context manager.",
1697 "Use in corresponding context manager.",
1698 category=ProvisionalCompleterWarning, stacklevel=2)
1698 category=ProvisionalCompleterWarning, stacklevel=2)
1699
1699
1700 seen = set()
1700 seen = set()
1701 for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000):
1701 for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000):
1702 if c and (c in seen):
1702 if c and (c in seen):
1703 continue
1703 continue
1704 yield c
1704 yield c
1705 seen.add(c)
1705 seen.add(c)
1706
1706
1707 def _completions(self, full_text: str, offset: int, *, _timeout)->Iterator[Completion]:
1707 def _completions(self, full_text: str, offset: int, *, _timeout)->Iterator[Completion]:
1708 """
1708 """
1709 Core completion module.Same signature as :any:`completions`, with the
1709 Core completion module.Same signature as :any:`completions`, with the
1710 extra `timeout` parameter (in seconds).
1710 extra `timeout` parameter (in seconds).
1711
1711
1712
1712
1713 Computing jedi's completion ``.type`` can be quite expensive (it is a
1713 Computing jedi's completion ``.type`` can be quite expensive (it is a
1714 lazy property) and can require some warm-up, more warm up than just
1714 lazy property) and can require some warm-up, more warm up than just
1715 computing the ``name`` of a completion. The warm-up can be :
1715 computing the ``name`` of a completion. The warm-up can be :
1716
1716
1717 - Long warm-up the first time a module is encountered after
1717 - Long warm-up the first time a module is encountered after
1718 install/update: actually build parse/inference tree.
1718 install/update: actually build parse/inference tree.
1719
1719
1720 - first time the module is encountered in a session: load tree from
1720 - first time the module is encountered in a session: load tree from
1721 disk.
1721 disk.
1722
1722
1723 We don't want to block completions for tens of seconds so we give the
1723 We don't want to block completions for tens of seconds so we give the
1724 completer a "budget" of ``_timeout`` seconds per invocation to compute
1724 completer a "budget" of ``_timeout`` seconds per invocation to compute
1725 completions types, the completions that have not yet been computed will
1725 completions types, the completions that have not yet been computed will
1726 be marked as "unknown" an will have a chance to be computed next round
1726 be marked as "unknown" an will have a chance to be computed next round
1727 are things get cached.
1727 are things get cached.
1728
1728
1729 Keep in mind that Jedi is not the only thing treating the completion so
1729 Keep in mind that Jedi is not the only thing treating the completion so
1730 keep the timeout short-ish as if we take more than 0.3 second we still
1730 keep the timeout short-ish as if we take more than 0.3 second we still
1731 have lots of processing to do.
1731 have lots of processing to do.
1732
1732
1733 """
1733 """
1734 deadline = time.monotonic() + _timeout
1734 deadline = time.monotonic() + _timeout
1735
1735
1736
1736
1737 before = full_text[:offset]
1737 before = full_text[:offset]
1738 cursor_line, cursor_column = position_to_cursor(full_text, offset)
1738 cursor_line, cursor_column = position_to_cursor(full_text, offset)
1739
1739
1740 matched_text, matches, matches_origin, jedi_matches = self._complete(
1740 matched_text, matches, matches_origin, jedi_matches = self._complete(
1741 full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column)
1741 full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column)
1742
1742
1743 iter_jm = iter(jedi_matches)
1743 iter_jm = iter(jedi_matches)
1744 if _timeout:
1744 if _timeout:
1745 for jm in iter_jm:
1745 for jm in iter_jm:
1746 try:
1746 try:
1747 type_ = jm.type
1747 type_ = jm.type
1748 except Exception:
1748 except Exception:
1749 if self.debug:
1749 if self.debug:
1750 print("Error in Jedi getting type of ", jm)
1750 print("Error in Jedi getting type of ", jm)
1751 type_ = None
1751 type_ = None
1752 delta = len(jm.name_with_symbols) - len(jm.complete)
1752 delta = len(jm.name_with_symbols) - len(jm.complete)
1753 yield Completion(start=offset - delta,
1753 yield Completion(start=offset - delta,
1754 end=offset,
1754 end=offset,
1755 text=jm.name_with_symbols,
1755 text=jm.name_with_symbols,
1756 type=type_,
1756 type=type_,
1757 _origin='jedi')
1757 _origin='jedi')
1758
1758
1759 if time.monotonic() > deadline:
1759 if time.monotonic() > deadline:
1760 break
1760 break
1761
1761
1762 for jm in iter_jm:
1762 for jm in iter_jm:
1763 delta = len(jm.name_with_symbols) - len(jm.complete)
1763 delta = len(jm.name_with_symbols) - len(jm.complete)
1764 yield Completion(start=offset - delta,
1764 yield Completion(start=offset - delta,
1765 end=offset,
1765 end=offset,
1766 text=jm.name_with_symbols,
1766 text=jm.name_with_symbols,
1767 type='<unknown>', # don't compute type for speed
1767 type='<unknown>', # don't compute type for speed
1768 _origin='jedi')
1768 _origin='jedi')
1769
1769
1770
1770
1771 start_offset = before.rfind(matched_text)
1771 start_offset = before.rfind(matched_text)
1772
1772
1773 # TODO:
1773 # TODO:
1774 # Supress this, right now just for debug.
1774 # Supress this, right now just for debug.
1775 if jedi_matches and matches and self.debug:
1775 if jedi_matches and matches and self.debug:
1776 yield Completion(start=start_offset, end=offset, text='--jedi/ipython--', _origin='debug')
1776 yield Completion(start=start_offset, end=offset, text='--jedi/ipython--', _origin='debug')
1777
1777
1778 # I'm unsure if this is always true, so let's assert and see if it
1778 # I'm unsure if this is always true, so let's assert and see if it
1779 # crash
1779 # crash
1780 assert before.endswith(matched_text)
1780 assert before.endswith(matched_text)
1781 for m, t in zip(matches, matches_origin):
1781 for m, t in zip(matches, matches_origin):
1782 yield Completion(start=start_offset, end=offset, text=m, _origin=t)
1782 yield Completion(start=start_offset, end=offset, text=m, _origin=t)
1783
1783
1784
1784
1785 def complete(self, text=None, line_buffer=None, cursor_pos=None):
1785 def complete(self, text=None, line_buffer=None, cursor_pos=None):
1786 """Find completions for the given text and line context.
1786 """Find completions for the given text and line context.
1787
1787
1788 Note that both the text and the line_buffer are optional, but at least
1788 Note that both the text and the line_buffer are optional, but at least
1789 one of them must be given.
1789 one of them must be given.
1790
1790
1791 Parameters
1791 Parameters
1792 ----------
1792 ----------
1793 text : string, optional
1793 text : string, optional
1794 Text to perform the completion on. If not given, the line buffer
1794 Text to perform the completion on. If not given, the line buffer
1795 is split using the instance's CompletionSplitter object.
1795 is split using the instance's CompletionSplitter object.
1796
1796
1797 line_buffer : string, optional
1797 line_buffer : string, optional
1798 If not given, the completer attempts to obtain the current line
1798 If not given, the completer attempts to obtain the current line
1799 buffer via readline. This keyword allows clients which are
1799 buffer via readline. This keyword allows clients which are
1800 requesting for text completions in non-readline contexts to inform
1800 requesting for text completions in non-readline contexts to inform
1801 the completer of the entire text.
1801 the completer of the entire text.
1802
1802
1803 cursor_pos : int, optional
1803 cursor_pos : int, optional
1804 Index of the cursor in the full line buffer. Should be provided by
1804 Index of the cursor in the full line buffer. Should be provided by
1805 remote frontends where kernel has no access to frontend state.
1805 remote frontends where kernel has no access to frontend state.
1806
1806
1807 Returns
1807 Returns
1808 -------
1808 -------
1809 text : str
1809 text : str
1810 Text that was actually used in the completion.
1810 Text that was actually used in the completion.
1811
1811
1812 matches : list
1812 matches : list
1813 A list of completion matches.
1813 A list of completion matches.
1814
1814
1815
1815
1816 .. note::
1816 .. note::
1817
1817
1818 This API is likely to be deprecated and replaced by
1818 This API is likely to be deprecated and replaced by
1819 :any:`IPCompleter.completions` in the future.
1819 :any:`IPCompleter.completions` in the future.
1820
1820
1821
1821
1822 """
1822 """
1823 warnings.warn('`Completer.complete` is pending deprecation since '
1823 warnings.warn('`Completer.complete` is pending deprecation since '
1824 'IPython 6.0 and will be replaced by `Completer.completions`.',
1824 'IPython 6.0 and will be replaced by `Completer.completions`.',
1825 PendingDeprecationWarning)
1825 PendingDeprecationWarning)
1826 # potential todo, FOLD the 3rd throw away argument of _complete
1826 # potential todo, FOLD the 3rd throw away argument of _complete
1827 # into the first 2 one.
1827 # into the first 2 one.
1828 return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
1828 return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
1829
1829
1830 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
1830 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
1831 full_text=None, return_jedi_results=True) -> (str, List[str], List[object]):
1831 full_text=None, return_jedi_results=True) -> Tuple[str, List[str], List[str], Iterable[_FakeJediCompletion]]:
1832 """
1832 """
1833
1833
1834 Like complete but can also returns raw jedi completions as well as the
1834 Like complete but can also returns raw jedi completions as well as the
1835 origin of the completion text. This could (and should) be made much
1835 origin of the completion text. This could (and should) be made much
1836 cleaner but that will be simpler once we drop the old (and stateful)
1836 cleaner but that will be simpler once we drop the old (and stateful)
1837 :any:`complete` API.
1837 :any:`complete` API.
1838
1838
1839
1839
1840 With current provisional API, cursor_pos act both (depending on the
1840 With current provisional API, cursor_pos act both (depending on the
1841 caller) as the offset in the ``text`` or ``line_buffer``, or as the
1841 caller) as the offset in the ``text`` or ``line_buffer``, or as the
1842 ``column`` when passing multiline strings this could/should be renamed
1842 ``column`` when passing multiline strings this could/should be renamed
1843 but would add extra noise.
1843 but would add extra noise.
1844 """
1844 """
1845
1845
1846 # if the cursor position isn't given, the only sane assumption we can
1846 # if the cursor position isn't given, the only sane assumption we can
1847 # make is that it's at the end of the line (the common case)
1847 # make is that it's at the end of the line (the common case)
1848 if cursor_pos is None:
1848 if cursor_pos is None:
1849 cursor_pos = len(line_buffer) if text is None else len(text)
1849 cursor_pos = len(line_buffer) if text is None else len(text)
1850
1850
1851 if self.use_main_ns:
1851 if self.use_main_ns:
1852 self.namespace = __main__.__dict__
1852 self.namespace = __main__.__dict__
1853
1853
1854 # if text is either None or an empty string, rely on the line buffer
1854 # if text is either None or an empty string, rely on the line buffer
1855 if (not line_buffer) and full_text:
1855 if (not line_buffer) and full_text:
1856 line_buffer = full_text.split('\n')[cursor_line]
1856 line_buffer = full_text.split('\n')[cursor_line]
1857 if not text:
1857 if not text:
1858 text = self.splitter.split_line(line_buffer, cursor_pos)
1858 text = self.splitter.split_line(line_buffer, cursor_pos)
1859
1859
1860 if self.backslash_combining_completions:
1860 if self.backslash_combining_completions:
1861 # allow deactivation of these on windows.
1861 # allow deactivation of these on windows.
1862 base_text = text if not line_buffer else line_buffer[:cursor_pos]
1862 base_text = text if not line_buffer else line_buffer[:cursor_pos]
1863 latex_text, latex_matches = self.latex_matches(base_text)
1863 latex_text, latex_matches = self.latex_matches(base_text)
1864 if latex_matches:
1864 if latex_matches:
1865 return latex_text, latex_matches, ['latex_matches']*len(latex_matches), ()
1865 return latex_text, latex_matches, ['latex_matches']*len(latex_matches), ()
1866 name_text = ''
1866 name_text = ''
1867 name_matches = []
1867 name_matches = []
1868 for meth in (self.unicode_name_matches, back_latex_name_matches, back_unicode_name_matches):
1868 for meth in (self.unicode_name_matches, back_latex_name_matches, back_unicode_name_matches):
1869 name_text, name_matches = meth(base_text)
1869 name_text, name_matches = meth(base_text)
1870 if name_text:
1870 if name_text:
1871 return name_text, name_matches, [meth.__qualname__]*len(name_matches), {}
1871 return name_text, name_matches, [meth.__qualname__]*len(name_matches), ()
1872
1872
1873
1873
1874 # If no line buffer is given, assume the input text is all there was
1874 # If no line buffer is given, assume the input text is all there was
1875 if line_buffer is None:
1875 if line_buffer is None:
1876 line_buffer = text
1876 line_buffer = text
1877
1877
1878 self.line_buffer = line_buffer
1878 self.line_buffer = line_buffer
1879 self.text_until_cursor = self.line_buffer[:cursor_pos]
1879 self.text_until_cursor = self.line_buffer[:cursor_pos]
1880
1880
1881 # Start with a clean slate of completions
1881 # Start with a clean slate of completions
1882 matches = []
1882 matches = []
1883 custom_res = self.dispatch_custom_completer(text)
1883 custom_res = self.dispatch_custom_completer(text)
1884 # FIXME: we should extend our api to return a dict with completions for
1884 # FIXME: we should extend our api to return a dict with completions for
1885 # different types of objects. The rlcomplete() method could then
1885 # different types of objects. The rlcomplete() method could then
1886 # simply collapse the dict into a list for readline, but we'd have
1886 # simply collapse the dict into a list for readline, but we'd have
1887 # richer completion semantics in other evironments.
1887 # richer completion semantics in other evironments.
1888 completions = ()
1888 completions = ()
1889 if self.use_jedi and return_jedi_results:
1889 if self.use_jedi and return_jedi_results:
1890 if not full_text:
1890 if not full_text:
1891 full_text = line_buffer
1891 full_text = line_buffer
1892 completions = self._jedi_matches(
1892 completions = self._jedi_matches(
1893 cursor_pos, cursor_line, full_text)
1893 cursor_pos, cursor_line, full_text)
1894 if custom_res is not None:
1894 if custom_res is not None:
1895 # did custom completers produce something?
1895 # did custom completers produce something?
1896 matches = [(m, 'custom') for m in custom_res]
1896 matches = [(m, 'custom') for m in custom_res]
1897 else:
1897 else:
1898 # Extend the list of completions with the results of each
1898 # Extend the list of completions with the results of each
1899 # matcher, so we return results to the user from all
1899 # matcher, so we return results to the user from all
1900 # namespaces.
1900 # namespaces.
1901 if self.merge_completions:
1901 if self.merge_completions:
1902 matches = []
1902 matches = []
1903 for matcher in self.matchers:
1903 for matcher in self.matchers:
1904 try:
1904 try:
1905 matches.extend([(m, matcher.__qualname__)
1905 matches.extend([(m, matcher.__qualname__)
1906 for m in matcher(text)])
1906 for m in matcher(text)])
1907 except:
1907 except:
1908 # Show the ugly traceback if the matcher causes an
1908 # Show the ugly traceback if the matcher causes an
1909 # exception, but do NOT crash the kernel!
1909 # exception, but do NOT crash the kernel!
1910 sys.excepthook(*sys.exc_info())
1910 sys.excepthook(*sys.exc_info())
1911 else:
1911 else:
1912 for matcher in self.matchers:
1912 for matcher in self.matchers:
1913 matches = [(m, matcher.__qualname__)
1913 matches = [(m, matcher.__qualname__)
1914 for m in matcher(text)]
1914 for m in matcher(text)]
1915 if matches:
1915 if matches:
1916 break
1916 break
1917 seen = set()
1917 seen = set()
1918 filtered_matches = set()
1918 filtered_matches = set()
1919 for m in matches:
1919 for m in matches:
1920 t, c = m
1920 t, c = m
1921 if t not in seen:
1921 if t not in seen:
1922 filtered_matches.add(m)
1922 filtered_matches.add(m)
1923 seen.add(t)
1923 seen.add(t)
1924
1924
1925 filtered_matches = sorted(
1925 _filtered_matches = sorted(
1926 set(filtered_matches), key=lambda x: completions_sorting_key(x[0]))
1926 set(filtered_matches), key=lambda x: completions_sorting_key(x[0]))
1927
1927
1928 matches = [m[0] for m in filtered_matches]
1928 _matches = [m[0] for m in _filtered_matches]
1929 origins = [m[1] for m in filtered_matches]
1929 origins = [m[1] for m in _filtered_matches]
1930
1930
1931 self.matches = matches
1931 self.matches = _matches
1932
1932
1933 return text, matches, origins, completions
1933 return text, _matches, origins, completions
@@ -1,524 +1,510 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Process Controller
2 """IPython Test Process Controller
3
3
4 This module runs one or more subprocesses which will actually run the IPython
4 This module runs one or more subprocesses which will actually run the IPython
5 test suite.
5 test suite.
6
6
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12
12
13 import argparse
13 import argparse
14 import multiprocessing.pool
14 import multiprocessing.pool
15 import os
15 import os
16 import stat
16 import stat
17 import shutil
17 import shutil
18 import signal
18 import signal
19 import sys
19 import sys
20 import subprocess
20 import subprocess
21 import time
21 import time
22
22
23 from .iptest import (
23 from .iptest import (
24 have, test_group_names as py_test_group_names, test_sections, StreamCapturer,
24 have, test_group_names as py_test_group_names, test_sections, StreamCapturer,
25 )
25 )
26 from IPython.utils.path import compress_user
26 from IPython.utils.path import compress_user
27 from IPython.utils.py3compat import bytes_to_str
27 from IPython.utils.py3compat import bytes_to_str
28 from IPython.utils.sysinfo import get_sys_info
28 from IPython.utils.sysinfo import get_sys_info
29 from IPython.utils.tempdir import TemporaryDirectory
29 from IPython.utils.tempdir import TemporaryDirectory
30
30
31 try:
31 def popen_wait(p, timeout):
32 # Python >= 3.3
32 return p.wait(timeout)
33 from subprocess import TimeoutExpired
34 def popen_wait(p, timeout):
35 return p.wait(timeout)
36 except ImportError:
37 class TimeoutExpired(Exception):
38 pass
39 def popen_wait(p, timeout):
40 """backport of Popen.wait from Python 3"""
41 for i in range(int(10 * timeout)):
42 if p.poll() is not None:
43 return
44 time.sleep(0.1)
45 if p.poll() is None:
46 raise TimeoutExpired
47
33
48 class TestController(object):
34 class TestController(object):
49 """Run tests in a subprocess
35 """Run tests in a subprocess
50 """
36 """
51 #: str, IPython test suite to be executed.
37 #: str, IPython test suite to be executed.
52 section = None
38 section = None
53 #: list, command line arguments to be executed
39 #: list, command line arguments to be executed
54 cmd = None
40 cmd = None
55 #: dict, extra environment variables to set for the subprocess
41 #: dict, extra environment variables to set for the subprocess
56 env = None
42 env = None
57 #: list, TemporaryDirectory instances to clear up when the process finishes
43 #: list, TemporaryDirectory instances to clear up when the process finishes
58 dirs = None
44 dirs = None
59 #: subprocess.Popen instance
45 #: subprocess.Popen instance
60 process = None
46 process = None
61 #: str, process stdout+stderr
47 #: str, process stdout+stderr
62 stdout = None
48 stdout = None
63
49
64 def __init__(self):
50 def __init__(self):
65 self.cmd = []
51 self.cmd = []
66 self.env = {}
52 self.env = {}
67 self.dirs = []
53 self.dirs = []
68
54
69 def setup(self):
55 def setup(self):
70 """Create temporary directories etc.
56 """Create temporary directories etc.
71
57
72 This is only called when we know the test group will be run. Things
58 This is only called when we know the test group will be run. Things
73 created here may be cleaned up by self.cleanup().
59 created here may be cleaned up by self.cleanup().
74 """
60 """
75 pass
61 pass
76
62
77 def launch(self, buffer_output=False, capture_output=False):
63 def launch(self, buffer_output=False, capture_output=False):
78 # print('*** ENV:', self.env) # dbg
64 # print('*** ENV:', self.env) # dbg
79 # print('*** CMD:', self.cmd) # dbg
65 # print('*** CMD:', self.cmd) # dbg
80 env = os.environ.copy()
66 env = os.environ.copy()
81 env.update(self.env)
67 env.update(self.env)
82 if buffer_output:
68 if buffer_output:
83 capture_output = True
69 capture_output = True
84 self.stdout_capturer = c = StreamCapturer(echo=not buffer_output)
70 self.stdout_capturer = c = StreamCapturer(echo=not buffer_output)
85 c.start()
71 c.start()
86 stdout = c.writefd if capture_output else None
72 stdout = c.writefd if capture_output else None
87 stderr = subprocess.STDOUT if capture_output else None
73 stderr = subprocess.STDOUT if capture_output else None
88 self.process = subprocess.Popen(self.cmd, stdout=stdout,
74 self.process = subprocess.Popen(self.cmd, stdout=stdout,
89 stderr=stderr, env=env)
75 stderr=stderr, env=env)
90
76
91 def wait(self):
77 def wait(self):
92 self.process.wait()
78 self.process.wait()
93 self.stdout_capturer.halt()
79 self.stdout_capturer.halt()
94 self.stdout = self.stdout_capturer.get_buffer()
80 self.stdout = self.stdout_capturer.get_buffer()
95 return self.process.returncode
81 return self.process.returncode
96
82
97 def print_extra_info(self):
83 def print_extra_info(self):
98 """Print extra information about this test run.
84 """Print extra information about this test run.
99
85
100 If we're running in parallel and showing the concise view, this is only
86 If we're running in parallel and showing the concise view, this is only
101 called if the test group fails. Otherwise, it's called before the test
87 called if the test group fails. Otherwise, it's called before the test
102 group is started.
88 group is started.
103
89
104 The base implementation does nothing, but it can be overridden by
90 The base implementation does nothing, but it can be overridden by
105 subclasses.
91 subclasses.
106 """
92 """
107 return
93 return
108
94
109 def cleanup_process(self):
95 def cleanup_process(self):
110 """Cleanup on exit by killing any leftover processes."""
96 """Cleanup on exit by killing any leftover processes."""
111 subp = self.process
97 subp = self.process
112 if subp is None or (subp.poll() is not None):
98 if subp is None or (subp.poll() is not None):
113 return # Process doesn't exist, or is already dead.
99 return # Process doesn't exist, or is already dead.
114
100
115 try:
101 try:
116 print('Cleaning up stale PID: %d' % subp.pid)
102 print('Cleaning up stale PID: %d' % subp.pid)
117 subp.kill()
103 subp.kill()
118 except: # (OSError, WindowsError) ?
104 except: # (OSError, WindowsError) ?
119 # This is just a best effort, if we fail or the process was
105 # This is just a best effort, if we fail or the process was
120 # really gone, ignore it.
106 # really gone, ignore it.
121 pass
107 pass
122 else:
108 else:
123 for i in range(10):
109 for i in range(10):
124 if subp.poll() is None:
110 if subp.poll() is None:
125 time.sleep(0.1)
111 time.sleep(0.1)
126 else:
112 else:
127 break
113 break
128
114
129 if subp.poll() is None:
115 if subp.poll() is None:
130 # The process did not die...
116 # The process did not die...
131 print('... failed. Manual cleanup may be required.')
117 print('... failed. Manual cleanup may be required.')
132
118
133 def cleanup(self):
119 def cleanup(self):
134 "Kill process if it's still alive, and clean up temporary directories"
120 "Kill process if it's still alive, and clean up temporary directories"
135 self.cleanup_process()
121 self.cleanup_process()
136 for td in self.dirs:
122 for td in self.dirs:
137 td.cleanup()
123 td.cleanup()
138
124
139 __del__ = cleanup
125 __del__ = cleanup
140
126
141
127
142 class PyTestController(TestController):
128 class PyTestController(TestController):
143 """Run Python tests using IPython.testing.iptest"""
129 """Run Python tests using IPython.testing.iptest"""
144 #: str, Python command to execute in subprocess
130 #: str, Python command to execute in subprocess
145 pycmd = None
131 pycmd = None
146
132
147 def __init__(self, section, options):
133 def __init__(self, section, options):
148 """Create new test runner."""
134 """Create new test runner."""
149 TestController.__init__(self)
135 TestController.__init__(self)
150 self.section = section
136 self.section = section
151 # pycmd is put into cmd[2] in PyTestController.launch()
137 # pycmd is put into cmd[2] in PyTestController.launch()
152 self.cmd = [sys.executable, '-c', None, section]
138 self.cmd = [sys.executable, '-c', None, section]
153 self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()"
139 self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()"
154 self.options = options
140 self.options = options
155
141
156 def setup(self):
142 def setup(self):
157 ipydir = TemporaryDirectory()
143 ipydir = TemporaryDirectory()
158 self.dirs.append(ipydir)
144 self.dirs.append(ipydir)
159 self.env['IPYTHONDIR'] = ipydir.name
145 self.env['IPYTHONDIR'] = ipydir.name
160 self.workingdir = workingdir = TemporaryDirectory()
146 self.workingdir = workingdir = TemporaryDirectory()
161 self.dirs.append(workingdir)
147 self.dirs.append(workingdir)
162 self.env['IPTEST_WORKING_DIR'] = workingdir.name
148 self.env['IPTEST_WORKING_DIR'] = workingdir.name
163 # This means we won't get odd effects from our own matplotlib config
149 # This means we won't get odd effects from our own matplotlib config
164 self.env['MPLCONFIGDIR'] = workingdir.name
150 self.env['MPLCONFIGDIR'] = workingdir.name
165 # For security reasons (http://bugs.python.org/issue16202), use
151 # For security reasons (http://bugs.python.org/issue16202), use
166 # a temporary directory to which other users have no access.
152 # a temporary directory to which other users have no access.
167 self.env['TMPDIR'] = workingdir.name
153 self.env['TMPDIR'] = workingdir.name
168
154
169 # Add a non-accessible directory to PATH (see gh-7053)
155 # Add a non-accessible directory to PATH (see gh-7053)
170 noaccess = os.path.join(self.workingdir.name, "_no_access_")
156 noaccess = os.path.join(self.workingdir.name, "_no_access_")
171 self.noaccess = noaccess
157 self.noaccess = noaccess
172 os.mkdir(noaccess, 0)
158 os.mkdir(noaccess, 0)
173
159
174 PATH = os.environ.get('PATH', '')
160 PATH = os.environ.get('PATH', '')
175 if PATH:
161 if PATH:
176 PATH = noaccess + os.pathsep + PATH
162 PATH = noaccess + os.pathsep + PATH
177 else:
163 else:
178 PATH = noaccess
164 PATH = noaccess
179 self.env['PATH'] = PATH
165 self.env['PATH'] = PATH
180
166
181 # From options:
167 # From options:
182 if self.options.xunit:
168 if self.options.xunit:
183 self.add_xunit()
169 self.add_xunit()
184 if self.options.coverage:
170 if self.options.coverage:
185 self.add_coverage()
171 self.add_coverage()
186 self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams
172 self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams
187 self.cmd.extend(self.options.extra_args)
173 self.cmd.extend(self.options.extra_args)
188
174
189 def cleanup(self):
175 def cleanup(self):
190 """
176 """
191 Make the non-accessible directory created in setup() accessible
177 Make the non-accessible directory created in setup() accessible
192 again, otherwise deleting the workingdir will fail.
178 again, otherwise deleting the workingdir will fail.
193 """
179 """
194 os.chmod(self.noaccess, stat.S_IRWXU)
180 os.chmod(self.noaccess, stat.S_IRWXU)
195 TestController.cleanup(self)
181 TestController.cleanup(self)
196
182
197 @property
183 @property
198 def will_run(self):
184 def will_run(self):
199 try:
185 try:
200 return test_sections[self.section].will_run
186 return test_sections[self.section].will_run
201 except KeyError:
187 except KeyError:
202 return True
188 return True
203
189
204 def add_xunit(self):
190 def add_xunit(self):
205 xunit_file = os.path.abspath(self.section + '.xunit.xml')
191 xunit_file = os.path.abspath(self.section + '.xunit.xml')
206 self.cmd.extend(['--with-xunit', '--xunit-file', xunit_file])
192 self.cmd.extend(['--with-xunit', '--xunit-file', xunit_file])
207
193
208 def add_coverage(self):
194 def add_coverage(self):
209 try:
195 try:
210 sources = test_sections[self.section].includes
196 sources = test_sections[self.section].includes
211 except KeyError:
197 except KeyError:
212 sources = ['IPython']
198 sources = ['IPython']
213
199
214 coverage_rc = ("[run]\n"
200 coverage_rc = ("[run]\n"
215 "data_file = {data_file}\n"
201 "data_file = {data_file}\n"
216 "source =\n"
202 "source =\n"
217 " {source}\n"
203 " {source}\n"
218 ).format(data_file=os.path.abspath('.coverage.'+self.section),
204 ).format(data_file=os.path.abspath('.coverage.'+self.section),
219 source="\n ".join(sources))
205 source="\n ".join(sources))
220 config_file = os.path.join(self.workingdir.name, '.coveragerc')
206 config_file = os.path.join(self.workingdir.name, '.coveragerc')
221 with open(config_file, 'w') as f:
207 with open(config_file, 'w') as f:
222 f.write(coverage_rc)
208 f.write(coverage_rc)
223
209
224 self.env['COVERAGE_PROCESS_START'] = config_file
210 self.env['COVERAGE_PROCESS_START'] = config_file
225 self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
211 self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
226
212
227 def launch(self, buffer_output=False):
213 def launch(self, buffer_output=False):
228 self.cmd[2] = self.pycmd
214 self.cmd[2] = self.pycmd
229 super(PyTestController, self).launch(buffer_output=buffer_output)
215 super(PyTestController, self).launch(buffer_output=buffer_output)
230
216
231
217
232 def prepare_controllers(options):
218 def prepare_controllers(options):
233 """Returns two lists of TestController instances, those to run, and those
219 """Returns two lists of TestController instances, those to run, and those
234 not to run."""
220 not to run."""
235 testgroups = options.testgroups
221 testgroups = options.testgroups
236 if not testgroups:
222 if not testgroups:
237 testgroups = py_test_group_names
223 testgroups = py_test_group_names
238
224
239 controllers = [PyTestController(name, options) for name in testgroups]
225 controllers = [PyTestController(name, options) for name in testgroups]
240
226
241 to_run = [c for c in controllers if c.will_run]
227 to_run = [c for c in controllers if c.will_run]
242 not_run = [c for c in controllers if not c.will_run]
228 not_run = [c for c in controllers if not c.will_run]
243 return to_run, not_run
229 return to_run, not_run
244
230
245 def do_run(controller, buffer_output=True):
231 def do_run(controller, buffer_output=True):
246 """Setup and run a test controller.
232 """Setup and run a test controller.
247
233
248 If buffer_output is True, no output is displayed, to avoid it appearing
234 If buffer_output is True, no output is displayed, to avoid it appearing
249 interleaved. In this case, the caller is responsible for displaying test
235 interleaved. In this case, the caller is responsible for displaying test
250 output on failure.
236 output on failure.
251
237
252 Returns
238 Returns
253 -------
239 -------
254 controller : TestController
240 controller : TestController
255 The same controller as passed in, as a convenience for using map() type
241 The same controller as passed in, as a convenience for using map() type
256 APIs.
242 APIs.
257 exitcode : int
243 exitcode : int
258 The exit code of the test subprocess. Non-zero indicates failure.
244 The exit code of the test subprocess. Non-zero indicates failure.
259 """
245 """
260 try:
246 try:
261 try:
247 try:
262 controller.setup()
248 controller.setup()
263 if not buffer_output:
249 if not buffer_output:
264 controller.print_extra_info()
250 controller.print_extra_info()
265 controller.launch(buffer_output=buffer_output)
251 controller.launch(buffer_output=buffer_output)
266 except Exception:
252 except Exception:
267 import traceback
253 import traceback
268 traceback.print_exc()
254 traceback.print_exc()
269 return controller, 1 # signal failure
255 return controller, 1 # signal failure
270
256
271 exitcode = controller.wait()
257 exitcode = controller.wait()
272 return controller, exitcode
258 return controller, exitcode
273
259
274 except KeyboardInterrupt:
260 except KeyboardInterrupt:
275 return controller, -signal.SIGINT
261 return controller, -signal.SIGINT
276 finally:
262 finally:
277 controller.cleanup()
263 controller.cleanup()
278
264
279 def report():
265 def report():
280 """Return a string with a summary report of test-related variables."""
266 """Return a string with a summary report of test-related variables."""
281 inf = get_sys_info()
267 inf = get_sys_info()
282 out = []
268 out = []
283 def _add(name, value):
269 def _add(name, value):
284 out.append((name, value))
270 out.append((name, value))
285
271
286 _add('IPython version', inf['ipython_version'])
272 _add('IPython version', inf['ipython_version'])
287 _add('IPython commit', "{} ({})".format(inf['commit_hash'], inf['commit_source']))
273 _add('IPython commit', "{} ({})".format(inf['commit_hash'], inf['commit_source']))
288 _add('IPython package', compress_user(inf['ipython_path']))
274 _add('IPython package', compress_user(inf['ipython_path']))
289 _add('Python version', inf['sys_version'].replace('\n',''))
275 _add('Python version', inf['sys_version'].replace('\n',''))
290 _add('sys.executable', compress_user(inf['sys_executable']))
276 _add('sys.executable', compress_user(inf['sys_executable']))
291 _add('Platform', inf['platform'])
277 _add('Platform', inf['platform'])
292
278
293 width = max(len(n) for (n,v) in out)
279 width = max(len(n) for (n,v) in out)
294 out = ["{:<{width}}: {}\n".format(n, v, width=width) for (n,v) in out]
280 out = ["{:<{width}}: {}\n".format(n, v, width=width) for (n,v) in out]
295
281
296 avail = []
282 avail = []
297 not_avail = []
283 not_avail = []
298
284
299 for k, is_avail in have.items():
285 for k, is_avail in have.items():
300 if is_avail:
286 if is_avail:
301 avail.append(k)
287 avail.append(k)
302 else:
288 else:
303 not_avail.append(k)
289 not_avail.append(k)
304
290
305 if avail:
291 if avail:
306 out.append('\nTools and libraries available at test time:\n')
292 out.append('\nTools and libraries available at test time:\n')
307 avail.sort()
293 avail.sort()
308 out.append(' ' + ' '.join(avail)+'\n')
294 out.append(' ' + ' '.join(avail)+'\n')
309
295
310 if not_avail:
296 if not_avail:
311 out.append('\nTools and libraries NOT available at test time:\n')
297 out.append('\nTools and libraries NOT available at test time:\n')
312 not_avail.sort()
298 not_avail.sort()
313 out.append(' ' + ' '.join(not_avail)+'\n')
299 out.append(' ' + ' '.join(not_avail)+'\n')
314
300
315 return ''.join(out)
301 return ''.join(out)
316
302
317 def run_iptestall(options):
303 def run_iptestall(options):
318 """Run the entire IPython test suite by calling nose and trial.
304 """Run the entire IPython test suite by calling nose and trial.
319
305
320 This function constructs :class:`IPTester` instances for all IPython
306 This function constructs :class:`IPTester` instances for all IPython
321 modules and package and then runs each of them. This causes the modules
307 modules and package and then runs each of them. This causes the modules
322 and packages of IPython to be tested each in their own subprocess using
308 and packages of IPython to be tested each in their own subprocess using
323 nose.
309 nose.
324
310
325 Parameters
311 Parameters
326 ----------
312 ----------
327
313
328 All parameters are passed as attributes of the options object.
314 All parameters are passed as attributes of the options object.
329
315
330 testgroups : list of str
316 testgroups : list of str
331 Run only these sections of the test suite. If empty, run all the available
317 Run only these sections of the test suite. If empty, run all the available
332 sections.
318 sections.
333
319
334 fast : int or None
320 fast : int or None
335 Run the test suite in parallel, using n simultaneous processes. If None
321 Run the test suite in parallel, using n simultaneous processes. If None
336 is passed, one process is used per CPU core. Default 1 (i.e. sequential)
322 is passed, one process is used per CPU core. Default 1 (i.e. sequential)
337
323
338 inc_slow : bool
324 inc_slow : bool
339 Include slow tests. By default, these tests aren't run.
325 Include slow tests. By default, these tests aren't run.
340
326
341 url : unicode
327 url : unicode
342 Address:port to use when running the JS tests.
328 Address:port to use when running the JS tests.
343
329
344 xunit : bool
330 xunit : bool
345 Produce Xunit XML output. This is written to multiple foo.xunit.xml files.
331 Produce Xunit XML output. This is written to multiple foo.xunit.xml files.
346
332
347 coverage : bool or str
333 coverage : bool or str
348 Measure code coverage from tests. True will store the raw coverage data,
334 Measure code coverage from tests. True will store the raw coverage data,
349 or pass 'html' or 'xml' to get reports.
335 or pass 'html' or 'xml' to get reports.
350
336
351 extra_args : list
337 extra_args : list
352 Extra arguments to pass to the test subprocesses, e.g. '-v'
338 Extra arguments to pass to the test subprocesses, e.g. '-v'
353 """
339 """
354 to_run, not_run = prepare_controllers(options)
340 to_run, not_run = prepare_controllers(options)
355
341
356 def justify(ltext, rtext, width=70, fill='-'):
342 def justify(ltext, rtext, width=70, fill='-'):
357 ltext += ' '
343 ltext += ' '
358 rtext = (' ' + rtext).rjust(width - len(ltext), fill)
344 rtext = (' ' + rtext).rjust(width - len(ltext), fill)
359 return ltext + rtext
345 return ltext + rtext
360
346
361 # Run all test runners, tracking execution time
347 # Run all test runners, tracking execution time
362 failed = []
348 failed = []
363 t_start = time.time()
349 t_start = time.time()
364
350
365 print()
351 print()
366 if options.fast == 1:
352 if options.fast == 1:
367 # This actually means sequential, i.e. with 1 job
353 # This actually means sequential, i.e. with 1 job
368 for controller in to_run:
354 for controller in to_run:
369 print('Test group:', controller.section)
355 print('Test group:', controller.section)
370 sys.stdout.flush() # Show in correct order when output is piped
356 sys.stdout.flush() # Show in correct order when output is piped
371 controller, res = do_run(controller, buffer_output=False)
357 controller, res = do_run(controller, buffer_output=False)
372 if res:
358 if res:
373 failed.append(controller)
359 failed.append(controller)
374 if res == -signal.SIGINT:
360 if res == -signal.SIGINT:
375 print("Interrupted")
361 print("Interrupted")
376 break
362 break
377 print()
363 print()
378
364
379 else:
365 else:
380 # Run tests concurrently
366 # Run tests concurrently
381 try:
367 try:
382 pool = multiprocessing.pool.ThreadPool(options.fast)
368 pool = multiprocessing.pool.ThreadPool(options.fast)
383 for (controller, res) in pool.imap_unordered(do_run, to_run):
369 for (controller, res) in pool.imap_unordered(do_run, to_run):
384 res_string = 'OK' if res == 0 else 'FAILED'
370 res_string = 'OK' if res == 0 else 'FAILED'
385 print(justify('Test group: ' + controller.section, res_string))
371 print(justify('Test group: ' + controller.section, res_string))
386 if res:
372 if res:
387 controller.print_extra_info()
373 controller.print_extra_info()
388 print(bytes_to_str(controller.stdout))
374 print(bytes_to_str(controller.stdout))
389 failed.append(controller)
375 failed.append(controller)
390 if res == -signal.SIGINT:
376 if res == -signal.SIGINT:
391 print("Interrupted")
377 print("Interrupted")
392 break
378 break
393 except KeyboardInterrupt:
379 except KeyboardInterrupt:
394 return
380 return
395
381
396 for controller in not_run:
382 for controller in not_run:
397 print(justify('Test group: ' + controller.section, 'NOT RUN'))
383 print(justify('Test group: ' + controller.section, 'NOT RUN'))
398
384
399 t_end = time.time()
385 t_end = time.time()
400 t_tests = t_end - t_start
386 t_tests = t_end - t_start
401 nrunners = len(to_run)
387 nrunners = len(to_run)
402 nfail = len(failed)
388 nfail = len(failed)
403 # summarize results
389 # summarize results
404 print('_'*70)
390 print('_'*70)
405 print('Test suite completed for system with the following information:')
391 print('Test suite completed for system with the following information:')
406 print(report())
392 print(report())
407 took = "Took %.3fs." % t_tests
393 took = "Took %.3fs." % t_tests
408 print('Status: ', end='')
394 print('Status: ', end='')
409 if not failed:
395 if not failed:
410 print('OK (%d test groups).' % nrunners, took)
396 print('OK (%d test groups).' % nrunners, took)
411 else:
397 else:
412 # If anything went wrong, point out what command to rerun manually to
398 # If anything went wrong, point out what command to rerun manually to
413 # see the actual errors and individual summary
399 # see the actual errors and individual summary
414 failed_sections = [c.section for c in failed]
400 failed_sections = [c.section for c in failed]
415 print('ERROR - {} out of {} test groups failed ({}).'.format(nfail,
401 print('ERROR - {} out of {} test groups failed ({}).'.format(nfail,
416 nrunners, ', '.join(failed_sections)), took)
402 nrunners, ', '.join(failed_sections)), took)
417 print()
403 print()
418 print('You may wish to rerun these, with:')
404 print('You may wish to rerun these, with:')
419 print(' iptest', *failed_sections)
405 print(' iptest', *failed_sections)
420 print()
406 print()
421
407
422 if options.coverage:
408 if options.coverage:
423 from coverage import coverage, CoverageException
409 from coverage import coverage, CoverageException
424 cov = coverage(data_file='.coverage')
410 cov = coverage(data_file='.coverage')
425 cov.combine()
411 cov.combine()
426 cov.save()
412 cov.save()
427
413
428 # Coverage HTML report
414 # Coverage HTML report
429 if options.coverage == 'html':
415 if options.coverage == 'html':
430 html_dir = 'ipy_htmlcov'
416 html_dir = 'ipy_htmlcov'
431 shutil.rmtree(html_dir, ignore_errors=True)
417 shutil.rmtree(html_dir, ignore_errors=True)
432 print("Writing HTML coverage report to %s/ ... " % html_dir, end="")
418 print("Writing HTML coverage report to %s/ ... " % html_dir, end="")
433 sys.stdout.flush()
419 sys.stdout.flush()
434
420
435 # Custom HTML reporter to clean up module names.
421 # Custom HTML reporter to clean up module names.
436 from coverage.html import HtmlReporter
422 from coverage.html import HtmlReporter
437 class CustomHtmlReporter(HtmlReporter):
423 class CustomHtmlReporter(HtmlReporter):
438 def find_code_units(self, morfs):
424 def find_code_units(self, morfs):
439 super(CustomHtmlReporter, self).find_code_units(morfs)
425 super(CustomHtmlReporter, self).find_code_units(morfs)
440 for cu in self.code_units:
426 for cu in self.code_units:
441 nameparts = cu.name.split(os.sep)
427 nameparts = cu.name.split(os.sep)
442 if 'IPython' not in nameparts:
428 if 'IPython' not in nameparts:
443 continue
429 continue
444 ix = nameparts.index('IPython')
430 ix = nameparts.index('IPython')
445 cu.name = '.'.join(nameparts[ix:])
431 cu.name = '.'.join(nameparts[ix:])
446
432
447 # Reimplement the html_report method with our custom reporter
433 # Reimplement the html_report method with our custom reporter
448 cov.get_data()
434 cov.get_data()
449 cov.config.from_args(omit='*{0}tests{0}*'.format(os.sep), html_dir=html_dir,
435 cov.config.from_args(omit='*{0}tests{0}*'.format(os.sep), html_dir=html_dir,
450 html_title='IPython test coverage',
436 html_title='IPython test coverage',
451 )
437 )
452 reporter = CustomHtmlReporter(cov, cov.config)
438 reporter = CustomHtmlReporter(cov, cov.config)
453 reporter.report(None)
439 reporter.report(None)
454 print('done.')
440 print('done.')
455
441
456 # Coverage XML report
442 # Coverage XML report
457 elif options.coverage == 'xml':
443 elif options.coverage == 'xml':
458 try:
444 try:
459 cov.xml_report(outfile='ipy_coverage.xml')
445 cov.xml_report(outfile='ipy_coverage.xml')
460 except CoverageException as e:
446 except CoverageException as e:
461 print('Generating coverage report failed. Are you running javascript tests only?')
447 print('Generating coverage report failed. Are you running javascript tests only?')
462 import traceback
448 import traceback
463 traceback.print_exc()
449 traceback.print_exc()
464
450
465 if failed:
451 if failed:
466 # Ensure that our exit code indicates failure
452 # Ensure that our exit code indicates failure
467 sys.exit(1)
453 sys.exit(1)
468
454
469 argparser = argparse.ArgumentParser(description='Run IPython test suite')
455 argparser = argparse.ArgumentParser(description='Run IPython test suite')
470 argparser.add_argument('testgroups', nargs='*',
456 argparser.add_argument('testgroups', nargs='*',
471 help='Run specified groups of tests. If omitted, run '
457 help='Run specified groups of tests. If omitted, run '
472 'all tests.')
458 'all tests.')
473 argparser.add_argument('--all', action='store_true',
459 argparser.add_argument('--all', action='store_true',
474 help='Include slow tests not run by default.')
460 help='Include slow tests not run by default.')
475 argparser.add_argument('--url', help="URL to use for the JS tests.")
461 argparser.add_argument('--url', help="URL to use for the JS tests.")
476 argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int,
462 argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int,
477 help='Run test sections in parallel. This starts as many '
463 help='Run test sections in parallel. This starts as many '
478 'processes as you have cores, or you can specify a number.')
464 'processes as you have cores, or you can specify a number.')
479 argparser.add_argument('--xunit', action='store_true',
465 argparser.add_argument('--xunit', action='store_true',
480 help='Produce Xunit XML results')
466 help='Produce Xunit XML results')
481 argparser.add_argument('--coverage', nargs='?', const=True, default=False,
467 argparser.add_argument('--coverage', nargs='?', const=True, default=False,
482 help="Measure test coverage. Specify 'html' or "
468 help="Measure test coverage. Specify 'html' or "
483 "'xml' to get reports.")
469 "'xml' to get reports.")
484 argparser.add_argument('--subproc-streams', default='capture',
470 argparser.add_argument('--subproc-streams', default='capture',
485 help="What to do with stdout/stderr from subprocesses. "
471 help="What to do with stdout/stderr from subprocesses. "
486 "'capture' (default), 'show' and 'discard' are the options.")
472 "'capture' (default), 'show' and 'discard' are the options.")
487
473
488 def default_options():
474 def default_options():
489 """Get an argparse Namespace object with the default arguments, to pass to
475 """Get an argparse Namespace object with the default arguments, to pass to
490 :func:`run_iptestall`.
476 :func:`run_iptestall`.
491 """
477 """
492 options = argparser.parse_args([])
478 options = argparser.parse_args([])
493 options.extra_args = []
479 options.extra_args = []
494 return options
480 return options
495
481
496 def main():
482 def main():
497 # iptest doesn't work correctly if the working directory is the
483 # iptest doesn't work correctly if the working directory is the
498 # root of the IPython source tree. Tell the user to avoid
484 # root of the IPython source tree. Tell the user to avoid
499 # frustration.
485 # frustration.
500 if os.path.exists(os.path.join(os.getcwd(),
486 if os.path.exists(os.path.join(os.getcwd(),
501 'IPython', 'testing', '__main__.py')):
487 'IPython', 'testing', '__main__.py')):
502 print("Don't run iptest from the IPython source directory",
488 print("Don't run iptest from the IPython source directory",
503 file=sys.stderr)
489 file=sys.stderr)
504 sys.exit(1)
490 sys.exit(1)
505 # Arguments after -- should be passed through to nose. Argparse treats
491 # Arguments after -- should be passed through to nose. Argparse treats
506 # everything after -- as regular positional arguments, so we separate them
492 # everything after -- as regular positional arguments, so we separate them
507 # first.
493 # first.
508 try:
494 try:
509 ix = sys.argv.index('--')
495 ix = sys.argv.index('--')
510 except ValueError:
496 except ValueError:
511 to_parse = sys.argv[1:]
497 to_parse = sys.argv[1:]
512 extra_args = []
498 extra_args = []
513 else:
499 else:
514 to_parse = sys.argv[1:ix]
500 to_parse = sys.argv[1:ix]
515 extra_args = sys.argv[ix+1:]
501 extra_args = sys.argv[ix+1:]
516
502
517 options = argparser.parse_args(to_parse)
503 options = argparser.parse_args(to_parse)
518 options.extra_args = extra_args
504 options.extra_args = extra_args
519
505
520 run_iptestall(options)
506 run_iptestall(options)
521
507
522
508
523 if __name__ == '__main__':
509 if __name__ == '__main__':
524 main()
510 main()
General Comments 0
You need to be logged in to leave comments. Login now