##// END OF EJS Templates
fix doc
Matthias Bussonnier -
Show More
@@ -1,2229 +1,2239 b''
1 """Completion for IPython.
1 """Completion for IPython.
2
2
3 This module started as fork of the rlcompleter module in the Python standard
3 This module started as fork of the rlcompleter module in the Python standard
4 library. The original enhancements made to rlcompleter have been sent
4 library. The original enhancements made to rlcompleter have been sent
5 upstream and were accepted as of Python 2.3,
5 upstream and were accepted as of Python 2.3,
6
6
7 This module now support a wide variety of completion mechanism both available
7 This module now support a wide variety of completion mechanism both available
8 for normal classic Python code, as well as completer for IPython specific
8 for normal classic Python code, as well as completer for IPython specific
9 Syntax like magics.
9 Syntax like magics.
10
10
11 Latex and Unicode completion
11 Latex and Unicode completion
12 ============================
12 ============================
13
13
14 IPython and compatible frontends not only can complete your code, but can help
14 IPython and compatible frontends not only can complete your code, but can help
15 you to input a wide range of characters. In particular we allow you to insert
15 you to input a wide range of characters. In particular we allow you to insert
16 a unicode character using the tab completion mechanism.
16 a unicode character using the tab completion mechanism.
17
17
18 Forward latex/unicode completion
18 Forward latex/unicode completion
19 --------------------------------
19 --------------------------------
20
20
21 Forward completion allows you to easily type a unicode character using its latex
21 Forward completion allows you to easily type a unicode character using its latex
22 name, or unicode long description. To do so type a backslash follow by the
22 name, or unicode long description. To do so type a backslash follow by the
23 relevant name and press tab:
23 relevant name and press tab:
24
24
25
25
26 Using latex completion:
26 Using latex completion:
27
27
28 .. code::
28 .. code::
29
29
30 \\alpha<tab>
30 \\alpha<tab>
31 Ξ±
31 Ξ±
32
32
33 or using unicode completion:
33 or using unicode completion:
34
34
35
35
36 .. code::
36 .. code::
37
37
38 \\GREEK SMALL LETTER ALPHA<tab>
38 \\GREEK SMALL LETTER ALPHA<tab>
39 Ξ±
39 Ξ±
40
40
41
41
42 Only valid Python identifiers will complete. Combining characters (like arrow or
42 Only valid Python identifiers will complete. Combining characters (like arrow or
43 dots) are also available, unlike latex they need to be put after the their
43 dots) are also available, unlike latex they need to be put after the their
44 counterpart that is to say, `F\\\\vec<tab>` is correct, not `\\\\vec<tab>F`.
44 counterpart that is to say, `F\\\\vec<tab>` is correct, not `\\\\vec<tab>F`.
45
45
46 Some browsers are known to display combining characters incorrectly.
46 Some browsers are known to display combining characters incorrectly.
47
47
48 Backward latex completion
48 Backward latex completion
49 -------------------------
49 -------------------------
50
50
51 It is sometime challenging to know how to type a character, if you are using
51 It is sometime challenging to know how to type a character, if you are using
52 IPython, or any compatible frontend you can prepend backslash to the character
52 IPython, or any compatible frontend you can prepend backslash to the character
53 and press `<tab>` to expand it to its latex form.
53 and press `<tab>` to expand it to its latex form.
54
54
55 .. code::
55 .. code::
56
56
57 \\Ξ±<tab>
57 \\Ξ±<tab>
58 \\alpha
58 \\alpha
59
59
60
60
61 Both forward and backward completions can be deactivated by setting the
61 Both forward and backward completions can be deactivated by setting the
62 ``Completer.backslash_combining_completions`` option to ``False``.
62 ``Completer.backslash_combining_completions`` option to ``False``.
63
63
64
64
65 Experimental
65 Experimental
66 ============
66 ============
67
67
68 Starting with IPython 6.0, this module can make use of the Jedi library to
68 Starting with IPython 6.0, this module can make use of the Jedi library to
69 generate completions both using static analysis of the code, and dynamically
69 generate completions both using static analysis of the code, and dynamically
70 inspecting multiple namespaces. Jedi is an autocompletion and static analysis
70 inspecting multiple namespaces. Jedi is an autocompletion and static analysis
71 for Python. The APIs attached to this new mechanism is unstable and will
71 for Python. The APIs attached to this new mechanism is unstable and will
72 raise unless use in an :any:`provisionalcompleter` context manager.
72 raise unless use in an :any:`provisionalcompleter` context manager.
73
73
74 You will find that the following are experimental:
74 You will find that the following are experimental:
75
75
76 - :any:`provisionalcompleter`
76 - :any:`provisionalcompleter`
77 - :any:`IPCompleter.completions`
77 - :any:`IPCompleter.completions`
78 - :any:`Completion`
78 - :any:`Completion`
79 - :any:`rectify_completions`
79 - :any:`rectify_completions`
80
80
81 .. note::
81 .. note::
82
82
83 better name for :any:`rectify_completions` ?
83 better name for :any:`rectify_completions` ?
84
84
85 We welcome any feedback on these new API, and we also encourage you to try this
85 We welcome any feedback on these new API, and we also encourage you to try this
86 module in debug mode (start IPython with ``--Completer.debug=True``) in order
86 module in debug mode (start IPython with ``--Completer.debug=True``) in order
87 to have extra logging information if :any:`jedi` is crashing, or if current
87 to have extra logging information if :any:`jedi` is crashing, or if current
88 IPython completer pending deprecations are returning results not yet handled
88 IPython completer pending deprecations are returning results not yet handled
89 by :any:`jedi`
89 by :any:`jedi`
90
90
91 Using Jedi for tab completion allow snippets like the following to work without
91 Using Jedi for tab completion allow snippets like the following to work without
92 having to execute any code:
92 having to execute any code:
93
93
94 >>> myvar = ['hello', 42]
94 >>> myvar = ['hello', 42]
95 ... myvar[1].bi<tab>
95 ... myvar[1].bi<tab>
96
96
97 Tab completion will be able to infer that ``myvar[1]`` is a real number without
97 Tab completion will be able to infer that ``myvar[1]`` is a real number without
98 executing any code unlike the previously available ``IPCompleter.greedy``
98 executing any code unlike the previously available ``IPCompleter.greedy``
99 option.
99 option.
100
100
101 Be sure to update :any:`jedi` to the latest stable version or to try the
101 Be sure to update :any:`jedi` to the latest stable version or to try the
102 current development version to get better completions.
102 current development version to get better completions.
103 """
103 """
104
104
105
105
106 # Copyright (c) IPython Development Team.
106 # Copyright (c) IPython Development Team.
107 # Distributed under the terms of the Modified BSD License.
107 # Distributed under the terms of the Modified BSD License.
108 #
108 #
109 # Some of this code originated from rlcompleter in the Python standard library
109 # Some of this code originated from rlcompleter in the Python standard library
110 # Copyright (C) 2001 Python Software Foundation, www.python.org
110 # Copyright (C) 2001 Python Software Foundation, www.python.org
111
111
112
112
113 import builtins as builtin_mod
113 import builtins as builtin_mod
114 import glob
114 import glob
115 import inspect
115 import inspect
116 import itertools
116 import itertools
117 import keyword
117 import keyword
118 import os
118 import os
119 import re
119 import re
120 import string
120 import string
121 import sys
121 import sys
122 import time
122 import time
123 import unicodedata
123 import unicodedata
124 import uuid
124 import uuid
125 import warnings
125 import warnings
126 from contextlib import contextmanager
126 from contextlib import contextmanager
127 from importlib import import_module
127 from importlib import import_module
128 from types import SimpleNamespace
128 from types import SimpleNamespace
129 from typing import Iterable, Iterator, List, Tuple, Union, Any, Sequence, Dict, NamedTuple, Pattern, Optional
129 from typing import Iterable, Iterator, List, Tuple, Union, Any, Sequence, Dict, NamedTuple, Pattern, Optional
130
130
131 from IPython.core.error import TryNext
131 from IPython.core.error import TryNext
132 from IPython.core.inputtransformer2 import ESC_MAGIC
132 from IPython.core.inputtransformer2 import ESC_MAGIC
133 from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol
133 from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol
134 from IPython.core.oinspect import InspectColors
134 from IPython.core.oinspect import InspectColors
135 from IPython.utils import generics
135 from IPython.utils import generics
136 from IPython.utils.dir2 import dir2, get_real_method
136 from IPython.utils.dir2 import dir2, get_real_method
137 from IPython.utils.path import ensure_dir_exists
137 from IPython.utils.path import ensure_dir_exists
138 from IPython.utils.process import arg_split
138 from IPython.utils.process import arg_split
139 from traitlets import Bool, Enum, Int, List as ListTrait, Unicode, default, observe
139 from traitlets import Bool, Enum, Int, List as ListTrait, Unicode, default, observe
140 from traitlets.config.configurable import Configurable
140 from traitlets.config.configurable import Configurable
141
141
142 import __main__
142 import __main__
143
143
144 # skip module docstests
144 # skip module docstests
145 skip_doctest = True
145 skip_doctest = True
146
146
147 try:
147 try:
148 import jedi
148 import jedi
149 jedi.settings.case_insensitive_completion = False
149 jedi.settings.case_insensitive_completion = False
150 import jedi.api.helpers
150 import jedi.api.helpers
151 import jedi.api.classes
151 import jedi.api.classes
152 JEDI_INSTALLED = True
152 JEDI_INSTALLED = True
153 except ImportError:
153 except ImportError:
154 JEDI_INSTALLED = False
154 JEDI_INSTALLED = False
155 #-----------------------------------------------------------------------------
155 #-----------------------------------------------------------------------------
156 # Globals
156 # Globals
157 #-----------------------------------------------------------------------------
157 #-----------------------------------------------------------------------------
158
158
159 # ranges where we have most of the valid unicode names. We could be more finer
159 # ranges where we have most of the valid unicode names. We could be more finer
160 # grained but is it worth it for performace While unicode have character in the
160 # grained but is it worth it for performace While unicode have character in the
161 # rage 0, 0x110000, we seem to have name for about 10% of those. (131808 as I
161 # rage 0, 0x110000, we seem to have name for about 10% of those. (131808 as I
162 # write this). With below range we cover them all, with a density of ~67%
162 # write this). With below range we cover them all, with a density of ~67%
163 # biggest next gap we consider only adds up about 1% density and there are 600
163 # biggest next gap we consider only adds up about 1% density and there are 600
164 # gaps that would need hard coding.
164 # gaps that would need hard coding.
165 _UNICODE_RANGES = [(32, 0x3134b), (0xe0001, 0xe01f0)]
165 _UNICODE_RANGES = [(32, 0x3134b), (0xe0001, 0xe01f0)]
166
166
167 # Public API
167 # Public API
168 __all__ = ['Completer','IPCompleter']
168 __all__ = ['Completer','IPCompleter']
169
169
170 if sys.platform == 'win32':
170 if sys.platform == 'win32':
171 PROTECTABLES = ' '
171 PROTECTABLES = ' '
172 else:
172 else:
173 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
173 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
174
174
175 # Protect against returning an enormous number of completions which the frontend
175 # Protect against returning an enormous number of completions which the frontend
176 # may have trouble processing.
176 # may have trouble processing.
177 MATCHES_LIMIT = 500
177 MATCHES_LIMIT = 500
178
178
179 _deprecation_readline_sentinel = object()
179 _deprecation_readline_sentinel = object()
180
180
181
181
182 class ProvisionalCompleterWarning(FutureWarning):
182 class ProvisionalCompleterWarning(FutureWarning):
183 """
183 """
184 Exception raise by an experimental feature in this module.
184 Exception raise by an experimental feature in this module.
185
185
186 Wrap code in :any:`provisionalcompleter` context manager if you
186 Wrap code in :any:`provisionalcompleter` context manager if you
187 are certain you want to use an unstable feature.
187 are certain you want to use an unstable feature.
188 """
188 """
189 pass
189 pass
190
190
191 warnings.filterwarnings('error', category=ProvisionalCompleterWarning)
191 warnings.filterwarnings('error', category=ProvisionalCompleterWarning)
192
192
193 @contextmanager
193 @contextmanager
194 def provisionalcompleter(action='ignore'):
194 def provisionalcompleter(action='ignore'):
195 """
195 """
196 This context manager has to be used in any place where unstable completer
196 This context manager has to be used in any place where unstable completer
197 behavior and API may be called.
197 behavior and API may be called.
198
198
199 >>> with provisionalcompleter():
199 >>> with provisionalcompleter():
200 ... completer.do_experimental_things() # works
200 ... completer.do_experimental_things() # works
201
201
202 >>> completer.do_experimental_things() # raises.
202 >>> completer.do_experimental_things() # raises.
203
203
204 .. note:: Unstable
204 .. note::
205
206 Unstable
205
207
206 By using this context manager you agree that the API in use may change
208 By using this context manager you agree that the API in use may change
207 without warning, and that you won't complain if they do so.
209 without warning, and that you won't complain if they do so.
208
210
209 You also understand that, if the API is not to your liking, you should report
211 You also understand that, if the API is not to your liking, you should report
210 a bug to explain your use case upstream.
212 a bug to explain your use case upstream.
211
213
212 We'll be happy to get your feedback, feature requests, and improvements on
214 We'll be happy to get your feedback, feature requests, and improvements on
213 any of the unstable APIs!
215 any of the unstable APIs!
214 """
216 """
215 with warnings.catch_warnings():
217 with warnings.catch_warnings():
216 warnings.filterwarnings(action, category=ProvisionalCompleterWarning)
218 warnings.filterwarnings(action, category=ProvisionalCompleterWarning)
217 yield
219 yield
218
220
219
221
220 def has_open_quotes(s):
222 def has_open_quotes(s):
221 """Return whether a string has open quotes.
223 """Return whether a string has open quotes.
222
224
223 This simply counts whether the number of quote characters of either type in
225 This simply counts whether the number of quote characters of either type in
224 the string is odd.
226 the string is odd.
225
227
226 Returns
228 Returns
227 -------
229 -------
228 If there is an open quote, the quote character is returned. Else, return
230 If there is an open quote, the quote character is returned. Else, return
229 False.
231 False.
230 """
232 """
231 # We check " first, then ', so complex cases with nested quotes will get
233 # We check " first, then ', so complex cases with nested quotes will get
232 # the " to take precedence.
234 # the " to take precedence.
233 if s.count('"') % 2:
235 if s.count('"') % 2:
234 return '"'
236 return '"'
235 elif s.count("'") % 2:
237 elif s.count("'") % 2:
236 return "'"
238 return "'"
237 else:
239 else:
238 return False
240 return False
239
241
240
242
241 def protect_filename(s, protectables=PROTECTABLES):
243 def protect_filename(s, protectables=PROTECTABLES):
242 """Escape a string to protect certain characters."""
244 """Escape a string to protect certain characters."""
243 if set(s) & set(protectables):
245 if set(s) & set(protectables):
244 if sys.platform == "win32":
246 if sys.platform == "win32":
245 return '"' + s + '"'
247 return '"' + s + '"'
246 else:
248 else:
247 return "".join(("\\" + c if c in protectables else c) for c in s)
249 return "".join(("\\" + c if c in protectables else c) for c in s)
248 else:
250 else:
249 return s
251 return s
250
252
251
253
252 def expand_user(path:str) -> Tuple[str, bool, str]:
254 def expand_user(path:str) -> Tuple[str, bool, str]:
253 """Expand ``~``-style usernames in strings.
255 """Expand ``~``-style usernames in strings.
254
256
255 This is similar to :func:`os.path.expanduser`, but it computes and returns
257 This is similar to :func:`os.path.expanduser`, but it computes and returns
256 extra information that will be useful if the input was being used in
258 extra information that will be useful if the input was being used in
257 computing completions, and you wish to return the completions with the
259 computing completions, and you wish to return the completions with the
258 original '~' instead of its expanded value.
260 original '~' instead of its expanded value.
259
261
260 Parameters
262 Parameters
261 ----------
263 ----------
262 path : str
264 path : str
263 String to be expanded. If no ~ is present, the output is the same as the
265 String to be expanded. If no ~ is present, the output is the same as the
264 input.
266 input.
265
267
266 Returns
268 Returns
267 -------
269 -------
268 newpath : str
270 newpath : str
269 Result of ~ expansion in the input path.
271 Result of ~ expansion in the input path.
270 tilde_expand : bool
272 tilde_expand : bool
271 Whether any expansion was performed or not.
273 Whether any expansion was performed or not.
272 tilde_val : str
274 tilde_val : str
273 The value that ~ was replaced with.
275 The value that ~ was replaced with.
274 """
276 """
275 # Default values
277 # Default values
276 tilde_expand = False
278 tilde_expand = False
277 tilde_val = ''
279 tilde_val = ''
278 newpath = path
280 newpath = path
279
281
280 if path.startswith('~'):
282 if path.startswith('~'):
281 tilde_expand = True
283 tilde_expand = True
282 rest = len(path)-1
284 rest = len(path)-1
283 newpath = os.path.expanduser(path)
285 newpath = os.path.expanduser(path)
284 if rest:
286 if rest:
285 tilde_val = newpath[:-rest]
287 tilde_val = newpath[:-rest]
286 else:
288 else:
287 tilde_val = newpath
289 tilde_val = newpath
288
290
289 return newpath, tilde_expand, tilde_val
291 return newpath, tilde_expand, tilde_val
290
292
291
293
292 def compress_user(path:str, tilde_expand:bool, tilde_val:str) -> str:
294 def compress_user(path:str, tilde_expand:bool, tilde_val:str) -> str:
293 """Does the opposite of expand_user, with its outputs.
295 """Does the opposite of expand_user, with its outputs.
294 """
296 """
295 if tilde_expand:
297 if tilde_expand:
296 return path.replace(tilde_val, '~')
298 return path.replace(tilde_val, '~')
297 else:
299 else:
298 return path
300 return path
299
301
300
302
301 def completions_sorting_key(word):
303 def completions_sorting_key(word):
302 """key for sorting completions
304 """key for sorting completions
303
305
304 This does several things:
306 This does several things:
305
307
306 - Demote any completions starting with underscores to the end
308 - Demote any completions starting with underscores to the end
307 - Insert any %magic and %%cellmagic completions in the alphabetical order
309 - Insert any %magic and %%cellmagic completions in the alphabetical order
308 by their name
310 by their name
309 """
311 """
310 prio1, prio2 = 0, 0
312 prio1, prio2 = 0, 0
311
313
312 if word.startswith('__'):
314 if word.startswith('__'):
313 prio1 = 2
315 prio1 = 2
314 elif word.startswith('_'):
316 elif word.startswith('_'):
315 prio1 = 1
317 prio1 = 1
316
318
317 if word.endswith('='):
319 if word.endswith('='):
318 prio1 = -1
320 prio1 = -1
319
321
320 if word.startswith('%%'):
322 if word.startswith('%%'):
321 # If there's another % in there, this is something else, so leave it alone
323 # If there's another % in there, this is something else, so leave it alone
322 if not "%" in word[2:]:
324 if not "%" in word[2:]:
323 word = word[2:]
325 word = word[2:]
324 prio2 = 2
326 prio2 = 2
325 elif word.startswith('%'):
327 elif word.startswith('%'):
326 if not "%" in word[1:]:
328 if not "%" in word[1:]:
327 word = word[1:]
329 word = word[1:]
328 prio2 = 1
330 prio2 = 1
329
331
330 return prio1, word, prio2
332 return prio1, word, prio2
331
333
332
334
333 class _FakeJediCompletion:
335 class _FakeJediCompletion:
334 """
336 """
335 This is a workaround to communicate to the UI that Jedi has crashed and to
337 This is a workaround to communicate to the UI that Jedi has crashed and to
336 report a bug. Will be used only id :any:`IPCompleter.debug` is set to true.
338 report a bug. Will be used only id :any:`IPCompleter.debug` is set to true.
337
339
338 Added in IPython 6.0 so should likely be removed for 7.0
340 Added in IPython 6.0 so should likely be removed for 7.0
339
341
340 """
342 """
341
343
342 def __init__(self, name):
344 def __init__(self, name):
343
345
344 self.name = name
346 self.name = name
345 self.complete = name
347 self.complete = name
346 self.type = 'crashed'
348 self.type = 'crashed'
347 self.name_with_symbols = name
349 self.name_with_symbols = name
348 self.signature = ''
350 self.signature = ''
349 self._origin = 'fake'
351 self._origin = 'fake'
350
352
351 def __repr__(self):
353 def __repr__(self):
352 return '<Fake completion object jedi has crashed>'
354 return '<Fake completion object jedi has crashed>'
353
355
354
356
355 class Completion:
357 class Completion:
356 """
358 """
357 Completion object used and return by IPython completers.
359 Completion object used and return by IPython completers.
358
360
359 .. warning:: Unstable
361 .. warning::
362
363 Unstable
360
364
361 This function is unstable, API may change without warning.
365 This function is unstable, API may change without warning.
362 It will also raise unless use in proper context manager.
366 It will also raise unless use in proper context manager.
363
367
364 This act as a middle ground :any:`Completion` object between the
368 This act as a middle ground :any:`Completion` object between the
365 :any:`jedi.api.classes.Completion` object and the Prompt Toolkit completion
369 :any:`jedi.api.classes.Completion` object and the Prompt Toolkit completion
366 object. While Jedi need a lot of information about evaluator and how the
370 object. While Jedi need a lot of information about evaluator and how the
367 code should be ran/inspected, PromptToolkit (and other frontend) mostly
371 code should be ran/inspected, PromptToolkit (and other frontend) mostly
368 need user facing information.
372 need user facing information.
369
373
370 - Which range should be replaced replaced by what.
374 - Which range should be replaced replaced by what.
371 - Some metadata (like completion type), or meta information to displayed to
375 - Some metadata (like completion type), or meta information to displayed to
372 the use user.
376 the use user.
373
377
374 For debugging purpose we can also store the origin of the completion (``jedi``,
378 For debugging purpose we can also store the origin of the completion (``jedi``,
375 ``IPython.python_matches``, ``IPython.magics_matches``...).
379 ``IPython.python_matches``, ``IPython.magics_matches``...).
376 """
380 """
377
381
378 __slots__ = ['start', 'end', 'text', 'type', 'signature', '_origin']
382 __slots__ = ['start', 'end', 'text', 'type', 'signature', '_origin']
379
383
380 def __init__(self, start: int, end: int, text: str, *, type: str=None, _origin='', signature='') -> None:
384 def __init__(self, start: int, end: int, text: str, *, type: str=None, _origin='', signature='') -> None:
381 warnings.warn("``Completion`` is a provisional API (as of IPython 6.0). "
385 warnings.warn("``Completion`` is a provisional API (as of IPython 6.0). "
382 "It may change without warnings. "
386 "It may change without warnings. "
383 "Use in corresponding context manager.",
387 "Use in corresponding context manager.",
384 category=ProvisionalCompleterWarning, stacklevel=2)
388 category=ProvisionalCompleterWarning, stacklevel=2)
385
389
386 self.start = start
390 self.start = start
387 self.end = end
391 self.end = end
388 self.text = text
392 self.text = text
389 self.type = type
393 self.type = type
390 self.signature = signature
394 self.signature = signature
391 self._origin = _origin
395 self._origin = _origin
392
396
393 def __repr__(self):
397 def __repr__(self):
394 return '<Completion start=%s end=%s text=%r type=%r, signature=%r,>' % \
398 return '<Completion start=%s end=%s text=%r type=%r, signature=%r,>' % \
395 (self.start, self.end, self.text, self.type or '?', self.signature or '?')
399 (self.start, self.end, self.text, self.type or '?', self.signature or '?')
396
400
397 def __eq__(self, other)->Bool:
401 def __eq__(self, other)->Bool:
398 """
402 """
399 Equality and hash do not hash the type (as some completer may not be
403 Equality and hash do not hash the type (as some completer may not be
400 able to infer the type), but are use to (partially) de-duplicate
404 able to infer the type), but are use to (partially) de-duplicate
401 completion.
405 completion.
402
406
403 Completely de-duplicating completion is a bit tricker that just
407 Completely de-duplicating completion is a bit tricker that just
404 comparing as it depends on surrounding text, which Completions are not
408 comparing as it depends on surrounding text, which Completions are not
405 aware of.
409 aware of.
406 """
410 """
407 return self.start == other.start and \
411 return self.start == other.start and \
408 self.end == other.end and \
412 self.end == other.end and \
409 self.text == other.text
413 self.text == other.text
410
414
411 def __hash__(self):
415 def __hash__(self):
412 return hash((self.start, self.end, self.text))
416 return hash((self.start, self.end, self.text))
413
417
414
418
415 _IC = Iterable[Completion]
419 _IC = Iterable[Completion]
416
420
417
421
418 def _deduplicate_completions(text: str, completions: _IC)-> _IC:
422 def _deduplicate_completions(text: str, completions: _IC)-> _IC:
419 """
423 """
420 Deduplicate a set of completions.
424 Deduplicate a set of completions.
421
425
422 .. warning:: Unstable
426 .. warning::
427
428 Unstable
423
429
424 This function is unstable, API may change without warning.
430 This function is unstable, API may change without warning.
425
431
426 Parameters
432 Parameters
427 ----------
433 ----------
428 text: str
434 text: str
429 text that should be completed.
435 text that should be completed.
430 completions: Iterator[Completion]
436 completions: Iterator[Completion]
431 iterator over the completions to deduplicate
437 iterator over the completions to deduplicate
432
438
433 Yields
439 Yields
434 ------
440 ------
435 `Completions` objects
441 `Completions` objects
436 Completions coming from multiple sources, may be different but end up having
442 Completions coming from multiple sources, may be different but end up having
437 the same effect when applied to ``text``. If this is the case, this will
443 the same effect when applied to ``text``. If this is the case, this will
438 consider completions as equal and only emit the first encountered.
444 consider completions as equal and only emit the first encountered.
439 Not folded in `completions()` yet for debugging purpose, and to detect when
445 Not folded in `completions()` yet for debugging purpose, and to detect when
440 the IPython completer does return things that Jedi does not, but should be
446 the IPython completer does return things that Jedi does not, but should be
441 at some point.
447 at some point.
442 """
448 """
443 completions = list(completions)
449 completions = list(completions)
444 if not completions:
450 if not completions:
445 return
451 return
446
452
447 new_start = min(c.start for c in completions)
453 new_start = min(c.start for c in completions)
448 new_end = max(c.end for c in completions)
454 new_end = max(c.end for c in completions)
449
455
450 seen = set()
456 seen = set()
451 for c in completions:
457 for c in completions:
452 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
458 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
453 if new_text not in seen:
459 if new_text not in seen:
454 yield c
460 yield c
455 seen.add(new_text)
461 seen.add(new_text)
456
462
457
463
458 def rectify_completions(text: str, completions: _IC, *, _debug=False)->_IC:
464 def rectify_completions(text: str, completions: _IC, *, _debug=False)->_IC:
459 """
465 """
460 Rectify a set of completions to all have the same ``start`` and ``end``
466 Rectify a set of completions to all have the same ``start`` and ``end``
461
467
462 .. warning:: Unstable
468 .. warning::
469
470 Unstable
463
471
464 This function is unstable, API may change without warning.
472 This function is unstable, API may change without warning.
465 It will also raise unless use in proper context manager.
473 It will also raise unless use in proper context manager.
466
474
467 Parameters
475 Parameters
468 ----------
476 ----------
469 text: str
477 text: str
470 text that should be completed.
478 text that should be completed.
471 completions: Iterator[Completion]
479 completions: Iterator[Completion]
472 iterator over the completions to rectify
480 iterator over the completions to rectify
473
481
474 Notes
482 Notes
475 -----
483 -----
476 :any:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though
484 :any:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though
477 the Jupyter Protocol requires them to behave like so. This will readjust
485 the Jupyter Protocol requires them to behave like so. This will readjust
478 the completion to have the same ``start`` and ``end`` by padding both
486 the completion to have the same ``start`` and ``end`` by padding both
479 extremities with surrounding text.
487 extremities with surrounding text.
480
488
481 During stabilisation should support a ``_debug`` option to log which
489 During stabilisation should support a ``_debug`` option to log which
482 completion are return by the IPython completer and not found in Jedi in
490 completion are return by the IPython completer and not found in Jedi in
483 order to make upstream bug report.
491 order to make upstream bug report.
484 """
492 """
485 warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). "
493 warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). "
486 "It may change without warnings. "
494 "It may change without warnings. "
487 "Use in corresponding context manager.",
495 "Use in corresponding context manager.",
488 category=ProvisionalCompleterWarning, stacklevel=2)
496 category=ProvisionalCompleterWarning, stacklevel=2)
489
497
490 completions = list(completions)
498 completions = list(completions)
491 if not completions:
499 if not completions:
492 return
500 return
493 starts = (c.start for c in completions)
501 starts = (c.start for c in completions)
494 ends = (c.end for c in completions)
502 ends = (c.end for c in completions)
495
503
496 new_start = min(starts)
504 new_start = min(starts)
497 new_end = max(ends)
505 new_end = max(ends)
498
506
499 seen_jedi = set()
507 seen_jedi = set()
500 seen_python_matches = set()
508 seen_python_matches = set()
501 for c in completions:
509 for c in completions:
502 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
510 new_text = text[new_start:c.start] + c.text + text[c.end:new_end]
503 if c._origin == 'jedi':
511 if c._origin == 'jedi':
504 seen_jedi.add(new_text)
512 seen_jedi.add(new_text)
505 elif c._origin == 'IPCompleter.python_matches':
513 elif c._origin == 'IPCompleter.python_matches':
506 seen_python_matches.add(new_text)
514 seen_python_matches.add(new_text)
507 yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin, signature=c.signature)
515 yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin, signature=c.signature)
508 diff = seen_python_matches.difference(seen_jedi)
516 diff = seen_python_matches.difference(seen_jedi)
509 if diff and _debug:
517 if diff and _debug:
510 print('IPython.python matches have extras:', diff)
518 print('IPython.python matches have extras:', diff)
511
519
512
520
513 if sys.platform == 'win32':
521 if sys.platform == 'win32':
514 DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?'
522 DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?'
515 else:
523 else:
516 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
524 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
517
525
518 GREEDY_DELIMS = ' =\r\n'
526 GREEDY_DELIMS = ' =\r\n'
519
527
520
528
521 class CompletionSplitter(object):
529 class CompletionSplitter(object):
522 """An object to split an input line in a manner similar to readline.
530 """An object to split an input line in a manner similar to readline.
523
531
524 By having our own implementation, we can expose readline-like completion in
532 By having our own implementation, we can expose readline-like completion in
525 a uniform manner to all frontends. This object only needs to be given the
533 a uniform manner to all frontends. This object only needs to be given the
526 line of text to be split and the cursor position on said line, and it
534 line of text to be split and the cursor position on said line, and it
527 returns the 'word' to be completed on at the cursor after splitting the
535 returns the 'word' to be completed on at the cursor after splitting the
528 entire line.
536 entire line.
529
537
530 What characters are used as splitting delimiters can be controlled by
538 What characters are used as splitting delimiters can be controlled by
531 setting the ``delims`` attribute (this is a property that internally
539 setting the ``delims`` attribute (this is a property that internally
532 automatically builds the necessary regular expression)"""
540 automatically builds the necessary regular expression)"""
533
541
534 # Private interface
542 # Private interface
535
543
536 # A string of delimiter characters. The default value makes sense for
544 # A string of delimiter characters. The default value makes sense for
537 # IPython's most typical usage patterns.
545 # IPython's most typical usage patterns.
538 _delims = DELIMS
546 _delims = DELIMS
539
547
540 # The expression (a normal string) to be compiled into a regular expression
548 # The expression (a normal string) to be compiled into a regular expression
541 # for actual splitting. We store it as an attribute mostly for ease of
549 # for actual splitting. We store it as an attribute mostly for ease of
542 # debugging, since this type of code can be so tricky to debug.
550 # debugging, since this type of code can be so tricky to debug.
543 _delim_expr = None
551 _delim_expr = None
544
552
545 # The regular expression that does the actual splitting
553 # The regular expression that does the actual splitting
546 _delim_re = None
554 _delim_re = None
547
555
548 def __init__(self, delims=None):
556 def __init__(self, delims=None):
549 delims = CompletionSplitter._delims if delims is None else delims
557 delims = CompletionSplitter._delims if delims is None else delims
550 self.delims = delims
558 self.delims = delims
551
559
552 @property
560 @property
553 def delims(self):
561 def delims(self):
554 """Return the string of delimiter characters."""
562 """Return the string of delimiter characters."""
555 return self._delims
563 return self._delims
556
564
557 @delims.setter
565 @delims.setter
558 def delims(self, delims):
566 def delims(self, delims):
559 """Set the delimiters for line splitting."""
567 """Set the delimiters for line splitting."""
560 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
568 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
561 self._delim_re = re.compile(expr)
569 self._delim_re = re.compile(expr)
562 self._delims = delims
570 self._delims = delims
563 self._delim_expr = expr
571 self._delim_expr = expr
564
572
565 def split_line(self, line, cursor_pos=None):
573 def split_line(self, line, cursor_pos=None):
566 """Split a line of text with a cursor at the given position.
574 """Split a line of text with a cursor at the given position.
567 """
575 """
568 l = line if cursor_pos is None else line[:cursor_pos]
576 l = line if cursor_pos is None else line[:cursor_pos]
569 return self._delim_re.split(l)[-1]
577 return self._delim_re.split(l)[-1]
570
578
571
579
572
580
573 class Completer(Configurable):
581 class Completer(Configurable):
574
582
575 greedy = Bool(False,
583 greedy = Bool(False,
576 help="""Activate greedy completion
584 help="""Activate greedy completion
577 PENDING DEPRECTION. this is now mostly taken care of with Jedi.
585 PENDING DEPRECTION. this is now mostly taken care of with Jedi.
578
586
579 This will enable completion on elements of lists, results of function calls, etc.,
587 This will enable completion on elements of lists, results of function calls, etc.,
580 but can be unsafe because the code is actually evaluated on TAB.
588 but can be unsafe because the code is actually evaluated on TAB.
581 """
589 """
582 ).tag(config=True)
590 ).tag(config=True)
583
591
584 use_jedi = Bool(default_value=JEDI_INSTALLED,
592 use_jedi = Bool(default_value=JEDI_INSTALLED,
585 help="Experimental: Use Jedi to generate autocompletions. "
593 help="Experimental: Use Jedi to generate autocompletions. "
586 "Default to True if jedi is installed.").tag(config=True)
594 "Default to True if jedi is installed.").tag(config=True)
587
595
588 jedi_compute_type_timeout = Int(default_value=400,
596 jedi_compute_type_timeout = Int(default_value=400,
589 help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types.
597 help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types.
590 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
598 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt
591 performance by preventing jedi to build its cache.
599 performance by preventing jedi to build its cache.
592 """).tag(config=True)
600 """).tag(config=True)
593
601
594 debug = Bool(default_value=False,
602 debug = Bool(default_value=False,
595 help='Enable debug for the Completer. Mostly print extra '
603 help='Enable debug for the Completer. Mostly print extra '
596 'information for experimental jedi integration.')\
604 'information for experimental jedi integration.')\
597 .tag(config=True)
605 .tag(config=True)
598
606
599 backslash_combining_completions = Bool(True,
607 backslash_combining_completions = Bool(True,
600 help="Enable unicode completions, e.g. \\alpha<tab> . "
608 help="Enable unicode completions, e.g. \\alpha<tab> . "
601 "Includes completion of latex commands, unicode names, and expanding "
609 "Includes completion of latex commands, unicode names, and expanding "
602 "unicode characters back to latex commands.").tag(config=True)
610 "unicode characters back to latex commands.").tag(config=True)
603
611
604
612
605
613
606 def __init__(self, namespace=None, global_namespace=None, **kwargs):
614 def __init__(self, namespace=None, global_namespace=None, **kwargs):
607 """Create a new completer for the command line.
615 """Create a new completer for the command line.
608
616
609 Completer(namespace=ns, global_namespace=ns2) -> completer instance.
617 Completer(namespace=ns, global_namespace=ns2) -> completer instance.
610
618
611 If unspecified, the default namespace where completions are performed
619 If unspecified, the default namespace where completions are performed
612 is __main__ (technically, __main__.__dict__). Namespaces should be
620 is __main__ (technically, __main__.__dict__). Namespaces should be
613 given as dictionaries.
621 given as dictionaries.
614
622
615 An optional second namespace can be given. This allows the completer
623 An optional second namespace can be given. This allows the completer
616 to handle cases where both the local and global scopes need to be
624 to handle cases where both the local and global scopes need to be
617 distinguished.
625 distinguished.
618 """
626 """
619
627
620 # Don't bind to namespace quite yet, but flag whether the user wants a
628 # Don't bind to namespace quite yet, but flag whether the user wants a
621 # specific namespace or to use __main__.__dict__. This will allow us
629 # specific namespace or to use __main__.__dict__. This will allow us
622 # to bind to __main__.__dict__ at completion time, not now.
630 # to bind to __main__.__dict__ at completion time, not now.
623 if namespace is None:
631 if namespace is None:
624 self.use_main_ns = True
632 self.use_main_ns = True
625 else:
633 else:
626 self.use_main_ns = False
634 self.use_main_ns = False
627 self.namespace = namespace
635 self.namespace = namespace
628
636
629 # The global namespace, if given, can be bound directly
637 # The global namespace, if given, can be bound directly
630 if global_namespace is None:
638 if global_namespace is None:
631 self.global_namespace = {}
639 self.global_namespace = {}
632 else:
640 else:
633 self.global_namespace = global_namespace
641 self.global_namespace = global_namespace
634
642
635 self.custom_matchers = []
643 self.custom_matchers = []
636
644
637 super(Completer, self).__init__(**kwargs)
645 super(Completer, self).__init__(**kwargs)
638
646
639 def complete(self, text, state):
647 def complete(self, text, state):
640 """Return the next possible completion for 'text'.
648 """Return the next possible completion for 'text'.
641
649
642 This is called successively with state == 0, 1, 2, ... until it
650 This is called successively with state == 0, 1, 2, ... until it
643 returns None. The completion should begin with 'text'.
651 returns None. The completion should begin with 'text'.
644
652
645 """
653 """
646 if self.use_main_ns:
654 if self.use_main_ns:
647 self.namespace = __main__.__dict__
655 self.namespace = __main__.__dict__
648
656
649 if state == 0:
657 if state == 0:
650 if "." in text:
658 if "." in text:
651 self.matches = self.attr_matches(text)
659 self.matches = self.attr_matches(text)
652 else:
660 else:
653 self.matches = self.global_matches(text)
661 self.matches = self.global_matches(text)
654 try:
662 try:
655 return self.matches[state]
663 return self.matches[state]
656 except IndexError:
664 except IndexError:
657 return None
665 return None
658
666
659 def global_matches(self, text):
667 def global_matches(self, text):
660 """Compute matches when text is a simple name.
668 """Compute matches when text is a simple name.
661
669
662 Return a list of all keywords, built-in functions and names currently
670 Return a list of all keywords, built-in functions and names currently
663 defined in self.namespace or self.global_namespace that match.
671 defined in self.namespace or self.global_namespace that match.
664
672
665 """
673 """
666 matches = []
674 matches = []
667 match_append = matches.append
675 match_append = matches.append
668 n = len(text)
676 n = len(text)
669 for lst in [keyword.kwlist,
677 for lst in [keyword.kwlist,
670 builtin_mod.__dict__.keys(),
678 builtin_mod.__dict__.keys(),
671 self.namespace.keys(),
679 self.namespace.keys(),
672 self.global_namespace.keys()]:
680 self.global_namespace.keys()]:
673 for word in lst:
681 for word in lst:
674 if word[:n] == text and word != "__builtins__":
682 if word[:n] == text and word != "__builtins__":
675 match_append(word)
683 match_append(word)
676
684
677 snake_case_re = re.compile(r"[^_]+(_[^_]+)+?\Z")
685 snake_case_re = re.compile(r"[^_]+(_[^_]+)+?\Z")
678 for lst in [self.namespace.keys(),
686 for lst in [self.namespace.keys(),
679 self.global_namespace.keys()]:
687 self.global_namespace.keys()]:
680 shortened = {"_".join([sub[0] for sub in word.split('_')]) : word
688 shortened = {"_".join([sub[0] for sub in word.split('_')]) : word
681 for word in lst if snake_case_re.match(word)}
689 for word in lst if snake_case_re.match(word)}
682 for word in shortened.keys():
690 for word in shortened.keys():
683 if word[:n] == text and word != "__builtins__":
691 if word[:n] == text and word != "__builtins__":
684 match_append(shortened[word])
692 match_append(shortened[word])
685 return matches
693 return matches
686
694
687 def attr_matches(self, text):
695 def attr_matches(self, text):
688 """Compute matches when text contains a dot.
696 """Compute matches when text contains a dot.
689
697
690 Assuming the text is of the form NAME.NAME....[NAME], and is
698 Assuming the text is of the form NAME.NAME....[NAME], and is
691 evaluatable in self.namespace or self.global_namespace, it will be
699 evaluatable in self.namespace or self.global_namespace, it will be
692 evaluated and its attributes (as revealed by dir()) are used as
700 evaluated and its attributes (as revealed by dir()) are used as
693 possible completions. (For class instances, class members are
701 possible completions. (For class instances, class members are
694 also considered.)
702 also considered.)
695
703
696 WARNING: this can still invoke arbitrary C code, if an object
704 WARNING: this can still invoke arbitrary C code, if an object
697 with a __getattr__ hook is evaluated.
705 with a __getattr__ hook is evaluated.
698
706
699 """
707 """
700
708
701 # Another option, seems to work great. Catches things like ''.<tab>
709 # Another option, seems to work great. Catches things like ''.<tab>
702 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
710 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
703
711
704 if m:
712 if m:
705 expr, attr = m.group(1, 3)
713 expr, attr = m.group(1, 3)
706 elif self.greedy:
714 elif self.greedy:
707 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
715 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
708 if not m2:
716 if not m2:
709 return []
717 return []
710 expr, attr = m2.group(1,2)
718 expr, attr = m2.group(1,2)
711 else:
719 else:
712 return []
720 return []
713
721
714 try:
722 try:
715 obj = eval(expr, self.namespace)
723 obj = eval(expr, self.namespace)
716 except:
724 except:
717 try:
725 try:
718 obj = eval(expr, self.global_namespace)
726 obj = eval(expr, self.global_namespace)
719 except:
727 except:
720 return []
728 return []
721
729
722 if self.limit_to__all__ and hasattr(obj, '__all__'):
730 if self.limit_to__all__ and hasattr(obj, '__all__'):
723 words = get__all__entries(obj)
731 words = get__all__entries(obj)
724 else:
732 else:
725 words = dir2(obj)
733 words = dir2(obj)
726
734
727 try:
735 try:
728 words = generics.complete_object(obj, words)
736 words = generics.complete_object(obj, words)
729 except TryNext:
737 except TryNext:
730 pass
738 pass
731 except AssertionError:
739 except AssertionError:
732 raise
740 raise
733 except Exception:
741 except Exception:
734 # Silence errors from completion function
742 # Silence errors from completion function
735 #raise # dbg
743 #raise # dbg
736 pass
744 pass
737 # Build match list to return
745 # Build match list to return
738 n = len(attr)
746 n = len(attr)
739 return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ]
747 return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ]
740
748
741
749
742 def get__all__entries(obj):
750 def get__all__entries(obj):
743 """returns the strings in the __all__ attribute"""
751 """returns the strings in the __all__ attribute"""
744 try:
752 try:
745 words = getattr(obj, '__all__')
753 words = getattr(obj, '__all__')
746 except:
754 except:
747 return []
755 return []
748
756
749 return [w for w in words if isinstance(w, str)]
757 return [w for w in words if isinstance(w, str)]
750
758
751
759
752 def match_dict_keys(keys: List[Union[str, bytes, Tuple[Union[str, bytes]]]], prefix: str, delims: str,
760 def match_dict_keys(keys: List[Union[str, bytes, Tuple[Union[str, bytes]]]], prefix: str, delims: str,
753 extra_prefix: Optional[Tuple[str, bytes]]=None) -> Tuple[str, int, List[str]]:
761 extra_prefix: Optional[Tuple[str, bytes]]=None) -> Tuple[str, int, List[str]]:
754 """Used by dict_key_matches, matching the prefix to a list of keys
762 """Used by dict_key_matches, matching the prefix to a list of keys
755
763
756 Parameters
764 Parameters
757 ----------
765 ----------
758 keys:
766 keys:
759 list of keys in dictionary currently being completed.
767 list of keys in dictionary currently being completed.
760 prefix:
768 prefix:
761 Part of the text already typed by the user. E.g. `mydict[b'fo`
769 Part of the text already typed by the user. E.g. `mydict[b'fo`
762 delims:
770 delims:
763 String of delimiters to consider when finding the current key.
771 String of delimiters to consider when finding the current key.
764 extra_prefix: optional
772 extra_prefix: optional
765 Part of the text already typed in multi-key index cases. E.g. for
773 Part of the text already typed in multi-key index cases. E.g. for
766 `mydict['foo', "bar", 'b`, this would be `('foo', 'bar')`.
774 `mydict['foo', "bar", 'b`, this would be `('foo', 'bar')`.
767
775
768 Returns
776 Returns
769 -------
777 -------
770 A tuple of three elements: ``quote``, ``token_start``, ``matched``, with
778 A tuple of three elements: ``quote``, ``token_start``, ``matched``, with
771 ``quote`` being the quote that need to be used to close current string.
779 ``quote`` being the quote that need to be used to close current string.
772 ``token_start`` the position where the replacement should start occurring,
780 ``token_start`` the position where the replacement should start occurring,
773 ``matches`` a list of replacement/completion
781 ``matches`` a list of replacement/completion
774
782
775 """
783 """
776 prefix_tuple = extra_prefix if extra_prefix else ()
784 prefix_tuple = extra_prefix if extra_prefix else ()
777 Nprefix = len(prefix_tuple)
785 Nprefix = len(prefix_tuple)
778 def filter_prefix_tuple(key):
786 def filter_prefix_tuple(key):
779 # Reject too short keys
787 # Reject too short keys
780 if len(key) <= Nprefix:
788 if len(key) <= Nprefix:
781 return False
789 return False
782 # Reject keys with non str/bytes in it
790 # Reject keys with non str/bytes in it
783 for k in key:
791 for k in key:
784 if not isinstance(k, (str, bytes)):
792 if not isinstance(k, (str, bytes)):
785 return False
793 return False
786 # Reject keys that do not match the prefix
794 # Reject keys that do not match the prefix
787 for k, pt in zip(key, prefix_tuple):
795 for k, pt in zip(key, prefix_tuple):
788 if k != pt:
796 if k != pt:
789 return False
797 return False
790 # All checks passed!
798 # All checks passed!
791 return True
799 return True
792
800
793 filtered_keys:List[Union[str,bytes]] = []
801 filtered_keys:List[Union[str,bytes]] = []
794 def _add_to_filtered_keys(key):
802 def _add_to_filtered_keys(key):
795 if isinstance(key, (str, bytes)):
803 if isinstance(key, (str, bytes)):
796 filtered_keys.append(key)
804 filtered_keys.append(key)
797
805
798 for k in keys:
806 for k in keys:
799 if isinstance(k, tuple):
807 if isinstance(k, tuple):
800 if filter_prefix_tuple(k):
808 if filter_prefix_tuple(k):
801 _add_to_filtered_keys(k[Nprefix])
809 _add_to_filtered_keys(k[Nprefix])
802 else:
810 else:
803 _add_to_filtered_keys(k)
811 _add_to_filtered_keys(k)
804
812
805 if not prefix:
813 if not prefix:
806 return '', 0, [repr(k) for k in filtered_keys]
814 return '', 0, [repr(k) for k in filtered_keys]
807 quote_match = re.search('["\']', prefix)
815 quote_match = re.search('["\']', prefix)
808 assert quote_match is not None # silence mypy
816 assert quote_match is not None # silence mypy
809 quote = quote_match.group()
817 quote = quote_match.group()
810 try:
818 try:
811 prefix_str = eval(prefix + quote, {})
819 prefix_str = eval(prefix + quote, {})
812 except Exception:
820 except Exception:
813 return '', 0, []
821 return '', 0, []
814
822
815 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
823 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$'
816 token_match = re.search(pattern, prefix, re.UNICODE)
824 token_match = re.search(pattern, prefix, re.UNICODE)
817 assert token_match is not None # silence mypy
825 assert token_match is not None # silence mypy
818 token_start = token_match.start()
826 token_start = token_match.start()
819 token_prefix = token_match.group()
827 token_prefix = token_match.group()
820
828
821 matched:List[str] = []
829 matched:List[str] = []
822 for key in filtered_keys:
830 for key in filtered_keys:
823 try:
831 try:
824 if not key.startswith(prefix_str):
832 if not key.startswith(prefix_str):
825 continue
833 continue
826 except (AttributeError, TypeError, UnicodeError):
834 except (AttributeError, TypeError, UnicodeError):
827 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa
835 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa
828 continue
836 continue
829
837
830 # reformat remainder of key to begin with prefix
838 # reformat remainder of key to begin with prefix
831 rem = key[len(prefix_str):]
839 rem = key[len(prefix_str):]
832 # force repr wrapped in '
840 # force repr wrapped in '
833 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
841 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"')
834 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
842 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
835 if quote == '"':
843 if quote == '"':
836 # The entered prefix is quoted with ",
844 # The entered prefix is quoted with ",
837 # but the match is quoted with '.
845 # but the match is quoted with '.
838 # A contained " hence needs escaping for comparison:
846 # A contained " hence needs escaping for comparison:
839 rem_repr = rem_repr.replace('"', '\\"')
847 rem_repr = rem_repr.replace('"', '\\"')
840
848
841 # then reinsert prefix from start of token
849 # then reinsert prefix from start of token
842 matched.append('%s%s' % (token_prefix, rem_repr))
850 matched.append('%s%s' % (token_prefix, rem_repr))
843 return quote, token_start, matched
851 return quote, token_start, matched
844
852
845
853
846 def cursor_to_position(text:str, line:int, column:int)->int:
854 def cursor_to_position(text:str, line:int, column:int)->int:
847 """
855 """
848 Convert the (line,column) position of the cursor in text to an offset in a
856 Convert the (line,column) position of the cursor in text to an offset in a
849 string.
857 string.
850
858
851 Parameters
859 Parameters
852 ----------
860 ----------
853 text : str
861 text : str
854 The text in which to calculate the cursor offset
862 The text in which to calculate the cursor offset
855 line : int
863 line : int
856 Line of the cursor; 0-indexed
864 Line of the cursor; 0-indexed
857 column : int
865 column : int
858 Column of the cursor 0-indexed
866 Column of the cursor 0-indexed
859
867
860 Returns
868 Returns
861 -------
869 -------
862 Position of the cursor in ``text``, 0-indexed.
870 Position of the cursor in ``text``, 0-indexed.
863
871
864 See Also
872 See Also
865 --------
873 --------
866 position_to_cursor : reciprocal of this function
874 position_to_cursor : reciprocal of this function
867
875
868 """
876 """
869 lines = text.split('\n')
877 lines = text.split('\n')
870 assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines)))
878 assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines)))
871
879
872 return sum(len(l) + 1 for l in lines[:line]) + column
880 return sum(len(l) + 1 for l in lines[:line]) + column
873
881
874 def position_to_cursor(text:str, offset:int)->Tuple[int, int]:
882 def position_to_cursor(text:str, offset:int)->Tuple[int, int]:
875 """
883 """
876 Convert the position of the cursor in text (0 indexed) to a line
884 Convert the position of the cursor in text (0 indexed) to a line
877 number(0-indexed) and a column number (0-indexed) pair
885 number(0-indexed) and a column number (0-indexed) pair
878
886
879 Position should be a valid position in ``text``.
887 Position should be a valid position in ``text``.
880
888
881 Parameters
889 Parameters
882 ----------
890 ----------
883 text : str
891 text : str
884 The text in which to calculate the cursor offset
892 The text in which to calculate the cursor offset
885 offset : int
893 offset : int
886 Position of the cursor in ``text``, 0-indexed.
894 Position of the cursor in ``text``, 0-indexed.
887
895
888 Returns
896 Returns
889 -------
897 -------
890 (line, column) : (int, int)
898 (line, column) : (int, int)
891 Line of the cursor; 0-indexed, column of the cursor 0-indexed
899 Line of the cursor; 0-indexed, column of the cursor 0-indexed
892
900
893 See Also
901 See Also
894 --------
902 --------
895 cursor_to_position : reciprocal of this function
903 cursor_to_position : reciprocal of this function
896
904
897 """
905 """
898
906
899 assert 0 <= offset <= len(text) , "0 <= %s <= %s" % (offset , len(text))
907 assert 0 <= offset <= len(text) , "0 <= %s <= %s" % (offset , len(text))
900
908
901 before = text[:offset]
909 before = text[:offset]
902 blines = before.split('\n') # ! splitnes trim trailing \n
910 blines = before.split('\n') # ! splitnes trim trailing \n
903 line = before.count('\n')
911 line = before.count('\n')
904 col = len(blines[-1])
912 col = len(blines[-1])
905 return line, col
913 return line, col
906
914
907
915
908 def _safe_isinstance(obj, module, class_name):
916 def _safe_isinstance(obj, module, class_name):
909 """Checks if obj is an instance of module.class_name if loaded
917 """Checks if obj is an instance of module.class_name if loaded
910 """
918 """
911 return (module in sys.modules and
919 return (module in sys.modules and
912 isinstance(obj, getattr(import_module(module), class_name)))
920 isinstance(obj, getattr(import_module(module), class_name)))
913
921
914 def back_unicode_name_matches(text:str) -> Tuple[str, Sequence[str]]:
922 def back_unicode_name_matches(text:str) -> Tuple[str, Sequence[str]]:
915 """Match Unicode characters back to Unicode name
923 """Match Unicode characters back to Unicode name
916
924
917 This does ``β˜ƒ`` -> ``\\snowman``
925 This does ``β˜ƒ`` -> ``\\snowman``
918
926
919 Note that snowman is not a valid python3 combining character but will be expanded.
927 Note that snowman is not a valid python3 combining character but will be expanded.
920 Though it will not recombine back to the snowman character by the completion machinery.
928 Though it will not recombine back to the snowman character by the completion machinery.
921
929
922 This will not either back-complete standard sequences like \\n, \\b ...
930 This will not either back-complete standard sequences like \\n, \\b ...
923
931
924 Returns
932 Returns
925 =======
933 =======
926
934
927 Return a tuple with two elements:
935 Return a tuple with two elements:
928
936
929 - The Unicode character that was matched (preceded with a backslash), or
937 - The Unicode character that was matched (preceded with a backslash), or
930 empty string,
938 empty string,
931 - a sequence (of 1), name for the match Unicode character, preceded by
939 - a sequence (of 1), name for the match Unicode character, preceded by
932 backslash, or empty if no match.
940 backslash, or empty if no match.
933
941
934 """
942 """
935 if len(text)<2:
943 if len(text)<2:
936 return '', ()
944 return '', ()
937 maybe_slash = text[-2]
945 maybe_slash = text[-2]
938 if maybe_slash != '\\':
946 if maybe_slash != '\\':
939 return '', ()
947 return '', ()
940
948
941 char = text[-1]
949 char = text[-1]
942 # no expand on quote for completion in strings.
950 # no expand on quote for completion in strings.
943 # nor backcomplete standard ascii keys
951 # nor backcomplete standard ascii keys
944 if char in string.ascii_letters or char in ('"',"'"):
952 if char in string.ascii_letters or char in ('"',"'"):
945 return '', ()
953 return '', ()
946 try :
954 try :
947 unic = unicodedata.name(char)
955 unic = unicodedata.name(char)
948 return '\\'+char,('\\'+unic,)
956 return '\\'+char,('\\'+unic,)
949 except KeyError:
957 except KeyError:
950 pass
958 pass
951 return '', ()
959 return '', ()
952
960
953 def back_latex_name_matches(text:str) -> Tuple[str, Sequence[str]] :
961 def back_latex_name_matches(text:str) -> Tuple[str, Sequence[str]] :
954 """Match latex characters back to unicode name
962 """Match latex characters back to unicode name
955
963
956 This does ``\\β„΅`` -> ``\\aleph``
964 This does ``\\β„΅`` -> ``\\aleph``
957
965
958 """
966 """
959 if len(text)<2:
967 if len(text)<2:
960 return '', ()
968 return '', ()
961 maybe_slash = text[-2]
969 maybe_slash = text[-2]
962 if maybe_slash != '\\':
970 if maybe_slash != '\\':
963 return '', ()
971 return '', ()
964
972
965
973
966 char = text[-1]
974 char = text[-1]
967 # no expand on quote for completion in strings.
975 # no expand on quote for completion in strings.
968 # nor backcomplete standard ascii keys
976 # nor backcomplete standard ascii keys
969 if char in string.ascii_letters or char in ('"',"'"):
977 if char in string.ascii_letters or char in ('"',"'"):
970 return '', ()
978 return '', ()
971 try :
979 try :
972 latex = reverse_latex_symbol[char]
980 latex = reverse_latex_symbol[char]
973 # '\\' replace the \ as well
981 # '\\' replace the \ as well
974 return '\\'+char,[latex]
982 return '\\'+char,[latex]
975 except KeyError:
983 except KeyError:
976 pass
984 pass
977 return '', ()
985 return '', ()
978
986
979
987
980 def _formatparamchildren(parameter) -> str:
988 def _formatparamchildren(parameter) -> str:
981 """
989 """
982 Get parameter name and value from Jedi Private API
990 Get parameter name and value from Jedi Private API
983
991
984 Jedi does not expose a simple way to get `param=value` from its API.
992 Jedi does not expose a simple way to get `param=value` from its API.
985
993
986 Parameters
994 Parameters
987 ----------
995 ----------
988 parameter:
996 parameter:
989 Jedi's function `Param`
997 Jedi's function `Param`
990
998
991 Returns
999 Returns
992 -------
1000 -------
993 A string like 'a', 'b=1', '*args', '**kwargs'
1001 A string like 'a', 'b=1', '*args', '**kwargs'
994
1002
995 """
1003 """
996 description = parameter.description
1004 description = parameter.description
997 if not description.startswith('param '):
1005 if not description.startswith('param '):
998 raise ValueError('Jedi function parameter description have change format.'
1006 raise ValueError('Jedi function parameter description have change format.'
999 'Expected "param ...", found %r".' % description)
1007 'Expected "param ...", found %r".' % description)
1000 return description[6:]
1008 return description[6:]
1001
1009
1002 def _make_signature(completion)-> str:
1010 def _make_signature(completion)-> str:
1003 """
1011 """
1004 Make the signature from a jedi completion
1012 Make the signature from a jedi completion
1005
1013
1006 Parameters
1014 Parameters
1007 ----------
1015 ----------
1008 completion: jedi.Completion
1016 completion: jedi.Completion
1009 object does not complete a function type
1017 object does not complete a function type
1010
1018
1011 Returns
1019 Returns
1012 -------
1020 -------
1013 a string consisting of the function signature, with the parenthesis but
1021 a string consisting of the function signature, with the parenthesis but
1014 without the function name. example:
1022 without the function name. example:
1015 `(a, *args, b=1, **kwargs)`
1023 `(a, *args, b=1, **kwargs)`
1016
1024
1017 """
1025 """
1018
1026
1019 # it looks like this might work on jedi 0.17
1027 # it looks like this might work on jedi 0.17
1020 if hasattr(completion, 'get_signatures'):
1028 if hasattr(completion, 'get_signatures'):
1021 signatures = completion.get_signatures()
1029 signatures = completion.get_signatures()
1022 if not signatures:
1030 if not signatures:
1023 return '(?)'
1031 return '(?)'
1024
1032
1025 c0 = completion.get_signatures()[0]
1033 c0 = completion.get_signatures()[0]
1026 return '('+c0.to_string().split('(', maxsplit=1)[1]
1034 return '('+c0.to_string().split('(', maxsplit=1)[1]
1027
1035
1028 return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures()
1036 return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures()
1029 for p in signature.defined_names()) if f])
1037 for p in signature.defined_names()) if f])
1030
1038
1031
1039
1032 class _CompleteResult(NamedTuple):
1040 class _CompleteResult(NamedTuple):
1033 matched_text : str
1041 matched_text : str
1034 matches: Sequence[str]
1042 matches: Sequence[str]
1035 matches_origin: Sequence[str]
1043 matches_origin: Sequence[str]
1036 jedi_matches: Any
1044 jedi_matches: Any
1037
1045
1038
1046
1039 class IPCompleter(Completer):
1047 class IPCompleter(Completer):
1040 """Extension of the completer class with IPython-specific features"""
1048 """Extension of the completer class with IPython-specific features"""
1041
1049
1042 __dict_key_regexps: Optional[Dict[bool,Pattern]] = None
1050 __dict_key_regexps: Optional[Dict[bool,Pattern]] = None
1043
1051
1044 @observe('greedy')
1052 @observe('greedy')
1045 def _greedy_changed(self, change):
1053 def _greedy_changed(self, change):
1046 """update the splitter and readline delims when greedy is changed"""
1054 """update the splitter and readline delims when greedy is changed"""
1047 if change['new']:
1055 if change['new']:
1048 self.splitter.delims = GREEDY_DELIMS
1056 self.splitter.delims = GREEDY_DELIMS
1049 else:
1057 else:
1050 self.splitter.delims = DELIMS
1058 self.splitter.delims = DELIMS
1051
1059
1052 dict_keys_only = Bool(False,
1060 dict_keys_only = Bool(False,
1053 help="""Whether to show dict key matches only""")
1061 help="""Whether to show dict key matches only""")
1054
1062
1055 merge_completions = Bool(True,
1063 merge_completions = Bool(True,
1056 help="""Whether to merge completion results into a single list
1064 help="""Whether to merge completion results into a single list
1057
1065
1058 If False, only the completion results from the first non-empty
1066 If False, only the completion results from the first non-empty
1059 completer will be returned.
1067 completer will be returned.
1060 """
1068 """
1061 ).tag(config=True)
1069 ).tag(config=True)
1062 omit__names = Enum((0,1,2), default_value=2,
1070 omit__names = Enum((0,1,2), default_value=2,
1063 help="""Instruct the completer to omit private method names
1071 help="""Instruct the completer to omit private method names
1064
1072
1065 Specifically, when completing on ``object.<tab>``.
1073 Specifically, when completing on ``object.<tab>``.
1066
1074
1067 When 2 [default]: all names that start with '_' will be excluded.
1075 When 2 [default]: all names that start with '_' will be excluded.
1068
1076
1069 When 1: all 'magic' names (``__foo__``) will be excluded.
1077 When 1: all 'magic' names (``__foo__``) will be excluded.
1070
1078
1071 When 0: nothing will be excluded.
1079 When 0: nothing will be excluded.
1072 """
1080 """
1073 ).tag(config=True)
1081 ).tag(config=True)
1074 limit_to__all__ = Bool(False,
1082 limit_to__all__ = Bool(False,
1075 help="""
1083 help="""
1076 DEPRECATED as of version 5.0.
1084 DEPRECATED as of version 5.0.
1077
1085
1078 Instruct the completer to use __all__ for the completion
1086 Instruct the completer to use __all__ for the completion
1079
1087
1080 Specifically, when completing on ``object.<tab>``.
1088 Specifically, when completing on ``object.<tab>``.
1081
1089
1082 When True: only those names in obj.__all__ will be included.
1090 When True: only those names in obj.__all__ will be included.
1083
1091
1084 When False [default]: the __all__ attribute is ignored
1092 When False [default]: the __all__ attribute is ignored
1085 """,
1093 """,
1086 ).tag(config=True)
1094 ).tag(config=True)
1087
1095
1088 profile_completions = Bool(
1096 profile_completions = Bool(
1089 default_value=False,
1097 default_value=False,
1090 help="If True, emit profiling data for completion subsystem using cProfile."
1098 help="If True, emit profiling data for completion subsystem using cProfile."
1091 ).tag(config=True)
1099 ).tag(config=True)
1092
1100
1093 profiler_output_dir = Unicode(
1101 profiler_output_dir = Unicode(
1094 default_value=".completion_profiles",
1102 default_value=".completion_profiles",
1095 help="Template for path at which to output profile data for completions."
1103 help="Template for path at which to output profile data for completions."
1096 ).tag(config=True)
1104 ).tag(config=True)
1097
1105
1098 @observe('limit_to__all__')
1106 @observe('limit_to__all__')
1099 def _limit_to_all_changed(self, change):
1107 def _limit_to_all_changed(self, change):
1100 warnings.warn('`IPython.core.IPCompleter.limit_to__all__` configuration '
1108 warnings.warn('`IPython.core.IPCompleter.limit_to__all__` configuration '
1101 'value has been deprecated since IPython 5.0, will be made to have '
1109 'value has been deprecated since IPython 5.0, will be made to have '
1102 'no effects and then removed in future version of IPython.',
1110 'no effects and then removed in future version of IPython.',
1103 UserWarning)
1111 UserWarning)
1104
1112
1105 def __init__(self, shell=None, namespace=None, global_namespace=None,
1113 def __init__(self, shell=None, namespace=None, global_namespace=None,
1106 use_readline=_deprecation_readline_sentinel, config=None, **kwargs):
1114 use_readline=_deprecation_readline_sentinel, config=None, **kwargs):
1107 """IPCompleter() -> completer
1115 """IPCompleter() -> completer
1108
1116
1109 Return a completer object.
1117 Return a completer object.
1110
1118
1111 Parameters
1119 Parameters
1112 ----------
1120 ----------
1113 shell
1121 shell
1114 a pointer to the ipython shell itself. This is needed
1122 a pointer to the ipython shell itself. This is needed
1115 because this completer knows about magic functions, and those can
1123 because this completer knows about magic functions, and those can
1116 only be accessed via the ipython instance.
1124 only be accessed via the ipython instance.
1117 namespace : dict, optional
1125 namespace : dict, optional
1118 an optional dict where completions are performed.
1126 an optional dict where completions are performed.
1119 global_namespace : dict, optional
1127 global_namespace : dict, optional
1120 secondary optional dict for completions, to
1128 secondary optional dict for completions, to
1121 handle cases (such as IPython embedded inside functions) where
1129 handle cases (such as IPython embedded inside functions) where
1122 both Python scopes are visible.
1130 both Python scopes are visible.
1123 use_readline : bool, optional
1131 use_readline : bool, optional
1124 DEPRECATED, ignored since IPython 6.0, will have no effects
1132 DEPRECATED, ignored since IPython 6.0, will have no effects
1125 """
1133 """
1126
1134
1127 self.magic_escape = ESC_MAGIC
1135 self.magic_escape = ESC_MAGIC
1128 self.splitter = CompletionSplitter()
1136 self.splitter = CompletionSplitter()
1129
1137
1130 if use_readline is not _deprecation_readline_sentinel:
1138 if use_readline is not _deprecation_readline_sentinel:
1131 warnings.warn('The `use_readline` parameter is deprecated and ignored since IPython 6.0.',
1139 warnings.warn('The `use_readline` parameter is deprecated and ignored since IPython 6.0.',
1132 DeprecationWarning, stacklevel=2)
1140 DeprecationWarning, stacklevel=2)
1133
1141
1134 # _greedy_changed() depends on splitter and readline being defined:
1142 # _greedy_changed() depends on splitter and readline being defined:
1135 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
1143 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
1136 config=config, **kwargs)
1144 config=config, **kwargs)
1137
1145
1138 # List where completion matches will be stored
1146 # List where completion matches will be stored
1139 self.matches = []
1147 self.matches = []
1140 self.shell = shell
1148 self.shell = shell
1141 # Regexp to split filenames with spaces in them
1149 # Regexp to split filenames with spaces in them
1142 self.space_name_re = re.compile(r'([^\\] )')
1150 self.space_name_re = re.compile(r'([^\\] )')
1143 # Hold a local ref. to glob.glob for speed
1151 # Hold a local ref. to glob.glob for speed
1144 self.glob = glob.glob
1152 self.glob = glob.glob
1145
1153
1146 # Determine if we are running on 'dumb' terminals, like (X)Emacs
1154 # Determine if we are running on 'dumb' terminals, like (X)Emacs
1147 # buffers, to avoid completion problems.
1155 # buffers, to avoid completion problems.
1148 term = os.environ.get('TERM','xterm')
1156 term = os.environ.get('TERM','xterm')
1149 self.dumb_terminal = term in ['dumb','emacs']
1157 self.dumb_terminal = term in ['dumb','emacs']
1150
1158
1151 # Special handling of backslashes needed in win32 platforms
1159 # Special handling of backslashes needed in win32 platforms
1152 if sys.platform == "win32":
1160 if sys.platform == "win32":
1153 self.clean_glob = self._clean_glob_win32
1161 self.clean_glob = self._clean_glob_win32
1154 else:
1162 else:
1155 self.clean_glob = self._clean_glob
1163 self.clean_glob = self._clean_glob
1156
1164
1157 #regexp to parse docstring for function signature
1165 #regexp to parse docstring for function signature
1158 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1166 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1159 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1167 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1160 #use this if positional argument name is also needed
1168 #use this if positional argument name is also needed
1161 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
1169 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
1162
1170
1163 self.magic_arg_matchers = [
1171 self.magic_arg_matchers = [
1164 self.magic_config_matches,
1172 self.magic_config_matches,
1165 self.magic_color_matches,
1173 self.magic_color_matches,
1166 ]
1174 ]
1167
1175
1168 # This is set externally by InteractiveShell
1176 # This is set externally by InteractiveShell
1169 self.custom_completers = None
1177 self.custom_completers = None
1170
1178
1171 # This is a list of names of unicode characters that can be completed
1179 # This is a list of names of unicode characters that can be completed
1172 # into their corresponding unicode value. The list is large, so we
1180 # into their corresponding unicode value. The list is large, so we
1173 # laziliy initialize it on first use. Consuming code should access this
1181 # laziliy initialize it on first use. Consuming code should access this
1174 # attribute through the `@unicode_names` property.
1182 # attribute through the `@unicode_names` property.
1175 self._unicode_names = None
1183 self._unicode_names = None
1176
1184
1177 @property
1185 @property
1178 def matchers(self) -> List[Any]:
1186 def matchers(self) -> List[Any]:
1179 """All active matcher routines for completion"""
1187 """All active matcher routines for completion"""
1180 if self.dict_keys_only:
1188 if self.dict_keys_only:
1181 return [self.dict_key_matches]
1189 return [self.dict_key_matches]
1182
1190
1183 if self.use_jedi:
1191 if self.use_jedi:
1184 return [
1192 return [
1185 *self.custom_matchers,
1193 *self.custom_matchers,
1186 self.file_matches,
1194 self.file_matches,
1187 self.magic_matches,
1195 self.magic_matches,
1188 self.dict_key_matches,
1196 self.dict_key_matches,
1189 ]
1197 ]
1190 else:
1198 else:
1191 return [
1199 return [
1192 *self.custom_matchers,
1200 *self.custom_matchers,
1193 self.python_matches,
1201 self.python_matches,
1194 self.file_matches,
1202 self.file_matches,
1195 self.magic_matches,
1203 self.magic_matches,
1196 self.python_func_kw_matches,
1204 self.python_func_kw_matches,
1197 self.dict_key_matches,
1205 self.dict_key_matches,
1198 ]
1206 ]
1199
1207
1200 def all_completions(self, text:str) -> List[str]:
1208 def all_completions(self, text:str) -> List[str]:
1201 """
1209 """
1202 Wrapper around the completion methods for the benefit of emacs.
1210 Wrapper around the completion methods for the benefit of emacs.
1203 """
1211 """
1204 prefix = text.rpartition('.')[0]
1212 prefix = text.rpartition('.')[0]
1205 with provisionalcompleter():
1213 with provisionalcompleter():
1206 return ['.'.join([prefix, c.text]) if prefix and self.use_jedi else c.text
1214 return ['.'.join([prefix, c.text]) if prefix and self.use_jedi else c.text
1207 for c in self.completions(text, len(text))]
1215 for c in self.completions(text, len(text))]
1208
1216
1209 return self.complete(text)[1]
1217 return self.complete(text)[1]
1210
1218
1211 def _clean_glob(self, text:str):
1219 def _clean_glob(self, text:str):
1212 return self.glob("%s*" % text)
1220 return self.glob("%s*" % text)
1213
1221
1214 def _clean_glob_win32(self, text:str):
1222 def _clean_glob_win32(self, text:str):
1215 return [f.replace("\\","/")
1223 return [f.replace("\\","/")
1216 for f in self.glob("%s*" % text)]
1224 for f in self.glob("%s*" % text)]
1217
1225
1218 def file_matches(self, text:str)->List[str]:
1226 def file_matches(self, text:str)->List[str]:
1219 """Match filenames, expanding ~USER type strings.
1227 """Match filenames, expanding ~USER type strings.
1220
1228
1221 Most of the seemingly convoluted logic in this completer is an
1229 Most of the seemingly convoluted logic in this completer is an
1222 attempt to handle filenames with spaces in them. And yet it's not
1230 attempt to handle filenames with spaces in them. And yet it's not
1223 quite perfect, because Python's readline doesn't expose all of the
1231 quite perfect, because Python's readline doesn't expose all of the
1224 GNU readline details needed for this to be done correctly.
1232 GNU readline details needed for this to be done correctly.
1225
1233
1226 For a filename with a space in it, the printed completions will be
1234 For a filename with a space in it, the printed completions will be
1227 only the parts after what's already been typed (instead of the
1235 only the parts after what's already been typed (instead of the
1228 full completions, as is normally done). I don't think with the
1236 full completions, as is normally done). I don't think with the
1229 current (as of Python 2.3) Python readline it's possible to do
1237 current (as of Python 2.3) Python readline it's possible to do
1230 better."""
1238 better."""
1231
1239
1232 # chars that require escaping with backslash - i.e. chars
1240 # chars that require escaping with backslash - i.e. chars
1233 # that readline treats incorrectly as delimiters, but we
1241 # that readline treats incorrectly as delimiters, but we
1234 # don't want to treat as delimiters in filename matching
1242 # don't want to treat as delimiters in filename matching
1235 # when escaped with backslash
1243 # when escaped with backslash
1236 if text.startswith('!'):
1244 if text.startswith('!'):
1237 text = text[1:]
1245 text = text[1:]
1238 text_prefix = u'!'
1246 text_prefix = u'!'
1239 else:
1247 else:
1240 text_prefix = u''
1248 text_prefix = u''
1241
1249
1242 text_until_cursor = self.text_until_cursor
1250 text_until_cursor = self.text_until_cursor
1243 # track strings with open quotes
1251 # track strings with open quotes
1244 open_quotes = has_open_quotes(text_until_cursor)
1252 open_quotes = has_open_quotes(text_until_cursor)
1245
1253
1246 if '(' in text_until_cursor or '[' in text_until_cursor:
1254 if '(' in text_until_cursor or '[' in text_until_cursor:
1247 lsplit = text
1255 lsplit = text
1248 else:
1256 else:
1249 try:
1257 try:
1250 # arg_split ~ shlex.split, but with unicode bugs fixed by us
1258 # arg_split ~ shlex.split, but with unicode bugs fixed by us
1251 lsplit = arg_split(text_until_cursor)[-1]
1259 lsplit = arg_split(text_until_cursor)[-1]
1252 except ValueError:
1260 except ValueError:
1253 # typically an unmatched ", or backslash without escaped char.
1261 # typically an unmatched ", or backslash without escaped char.
1254 if open_quotes:
1262 if open_quotes:
1255 lsplit = text_until_cursor.split(open_quotes)[-1]
1263 lsplit = text_until_cursor.split(open_quotes)[-1]
1256 else:
1264 else:
1257 return []
1265 return []
1258 except IndexError:
1266 except IndexError:
1259 # tab pressed on empty line
1267 # tab pressed on empty line
1260 lsplit = ""
1268 lsplit = ""
1261
1269
1262 if not open_quotes and lsplit != protect_filename(lsplit):
1270 if not open_quotes and lsplit != protect_filename(lsplit):
1263 # if protectables are found, do matching on the whole escaped name
1271 # if protectables are found, do matching on the whole escaped name
1264 has_protectables = True
1272 has_protectables = True
1265 text0,text = text,lsplit
1273 text0,text = text,lsplit
1266 else:
1274 else:
1267 has_protectables = False
1275 has_protectables = False
1268 text = os.path.expanduser(text)
1276 text = os.path.expanduser(text)
1269
1277
1270 if text == "":
1278 if text == "":
1271 return [text_prefix + protect_filename(f) for f in self.glob("*")]
1279 return [text_prefix + protect_filename(f) for f in self.glob("*")]
1272
1280
1273 # Compute the matches from the filesystem
1281 # Compute the matches from the filesystem
1274 if sys.platform == 'win32':
1282 if sys.platform == 'win32':
1275 m0 = self.clean_glob(text)
1283 m0 = self.clean_glob(text)
1276 else:
1284 else:
1277 m0 = self.clean_glob(text.replace('\\', ''))
1285 m0 = self.clean_glob(text.replace('\\', ''))
1278
1286
1279 if has_protectables:
1287 if has_protectables:
1280 # If we had protectables, we need to revert our changes to the
1288 # If we had protectables, we need to revert our changes to the
1281 # beginning of filename so that we don't double-write the part
1289 # beginning of filename so that we don't double-write the part
1282 # of the filename we have so far
1290 # of the filename we have so far
1283 len_lsplit = len(lsplit)
1291 len_lsplit = len(lsplit)
1284 matches = [text_prefix + text0 +
1292 matches = [text_prefix + text0 +
1285 protect_filename(f[len_lsplit:]) for f in m0]
1293 protect_filename(f[len_lsplit:]) for f in m0]
1286 else:
1294 else:
1287 if open_quotes:
1295 if open_quotes:
1288 # if we have a string with an open quote, we don't need to
1296 # if we have a string with an open quote, we don't need to
1289 # protect the names beyond the quote (and we _shouldn't_, as
1297 # protect the names beyond the quote (and we _shouldn't_, as
1290 # it would cause bugs when the filesystem call is made).
1298 # it would cause bugs when the filesystem call is made).
1291 matches = m0 if sys.platform == "win32" else\
1299 matches = m0 if sys.platform == "win32" else\
1292 [protect_filename(f, open_quotes) for f in m0]
1300 [protect_filename(f, open_quotes) for f in m0]
1293 else:
1301 else:
1294 matches = [text_prefix +
1302 matches = [text_prefix +
1295 protect_filename(f) for f in m0]
1303 protect_filename(f) for f in m0]
1296
1304
1297 # Mark directories in input list by appending '/' to their names.
1305 # Mark directories in input list by appending '/' to their names.
1298 return [x+'/' if os.path.isdir(x) else x for x in matches]
1306 return [x+'/' if os.path.isdir(x) else x for x in matches]
1299
1307
1300 def magic_matches(self, text:str):
1308 def magic_matches(self, text:str):
1301 """Match magics"""
1309 """Match magics"""
1302 # Get all shell magics now rather than statically, so magics loaded at
1310 # Get all shell magics now rather than statically, so magics loaded at
1303 # runtime show up too.
1311 # runtime show up too.
1304 lsm = self.shell.magics_manager.lsmagic()
1312 lsm = self.shell.magics_manager.lsmagic()
1305 line_magics = lsm['line']
1313 line_magics = lsm['line']
1306 cell_magics = lsm['cell']
1314 cell_magics = lsm['cell']
1307 pre = self.magic_escape
1315 pre = self.magic_escape
1308 pre2 = pre+pre
1316 pre2 = pre+pre
1309
1317
1310 explicit_magic = text.startswith(pre)
1318 explicit_magic = text.startswith(pre)
1311
1319
1312 # Completion logic:
1320 # Completion logic:
1313 # - user gives %%: only do cell magics
1321 # - user gives %%: only do cell magics
1314 # - user gives %: do both line and cell magics
1322 # - user gives %: do both line and cell magics
1315 # - no prefix: do both
1323 # - no prefix: do both
1316 # In other words, line magics are skipped if the user gives %% explicitly
1324 # In other words, line magics are skipped if the user gives %% explicitly
1317 #
1325 #
1318 # We also exclude magics that match any currently visible names:
1326 # We also exclude magics that match any currently visible names:
1319 # https://github.com/ipython/ipython/issues/4877, unless the user has
1327 # https://github.com/ipython/ipython/issues/4877, unless the user has
1320 # typed a %:
1328 # typed a %:
1321 # https://github.com/ipython/ipython/issues/10754
1329 # https://github.com/ipython/ipython/issues/10754
1322 bare_text = text.lstrip(pre)
1330 bare_text = text.lstrip(pre)
1323 global_matches = self.global_matches(bare_text)
1331 global_matches = self.global_matches(bare_text)
1324 if not explicit_magic:
1332 if not explicit_magic:
1325 def matches(magic):
1333 def matches(magic):
1326 """
1334 """
1327 Filter magics, in particular remove magics that match
1335 Filter magics, in particular remove magics that match
1328 a name present in global namespace.
1336 a name present in global namespace.
1329 """
1337 """
1330 return ( magic.startswith(bare_text) and
1338 return ( magic.startswith(bare_text) and
1331 magic not in global_matches )
1339 magic not in global_matches )
1332 else:
1340 else:
1333 def matches(magic):
1341 def matches(magic):
1334 return magic.startswith(bare_text)
1342 return magic.startswith(bare_text)
1335
1343
1336 comp = [ pre2+m for m in cell_magics if matches(m)]
1344 comp = [ pre2+m for m in cell_magics if matches(m)]
1337 if not text.startswith(pre2):
1345 if not text.startswith(pre2):
1338 comp += [ pre+m for m in line_magics if matches(m)]
1346 comp += [ pre+m for m in line_magics if matches(m)]
1339
1347
1340 return comp
1348 return comp
1341
1349
1342 def magic_config_matches(self, text:str) -> List[str]:
1350 def magic_config_matches(self, text:str) -> List[str]:
1343 """ Match class names and attributes for %config magic """
1351 """ Match class names and attributes for %config magic """
1344 texts = text.strip().split()
1352 texts = text.strip().split()
1345
1353
1346 if len(texts) > 0 and (texts[0] == 'config' or texts[0] == '%config'):
1354 if len(texts) > 0 and (texts[0] == 'config' or texts[0] == '%config'):
1347 # get all configuration classes
1355 # get all configuration classes
1348 classes = sorted(set([ c for c in self.shell.configurables
1356 classes = sorted(set([ c for c in self.shell.configurables
1349 if c.__class__.class_traits(config=True)
1357 if c.__class__.class_traits(config=True)
1350 ]), key=lambda x: x.__class__.__name__)
1358 ]), key=lambda x: x.__class__.__name__)
1351 classnames = [ c.__class__.__name__ for c in classes ]
1359 classnames = [ c.__class__.__name__ for c in classes ]
1352
1360
1353 # return all classnames if config or %config is given
1361 # return all classnames if config or %config is given
1354 if len(texts) == 1:
1362 if len(texts) == 1:
1355 return classnames
1363 return classnames
1356
1364
1357 # match classname
1365 # match classname
1358 classname_texts = texts[1].split('.')
1366 classname_texts = texts[1].split('.')
1359 classname = classname_texts[0]
1367 classname = classname_texts[0]
1360 classname_matches = [ c for c in classnames
1368 classname_matches = [ c for c in classnames
1361 if c.startswith(classname) ]
1369 if c.startswith(classname) ]
1362
1370
1363 # return matched classes or the matched class with attributes
1371 # return matched classes or the matched class with attributes
1364 if texts[1].find('.') < 0:
1372 if texts[1].find('.') < 0:
1365 return classname_matches
1373 return classname_matches
1366 elif len(classname_matches) == 1 and \
1374 elif len(classname_matches) == 1 and \
1367 classname_matches[0] == classname:
1375 classname_matches[0] == classname:
1368 cls = classes[classnames.index(classname)].__class__
1376 cls = classes[classnames.index(classname)].__class__
1369 help = cls.class_get_help()
1377 help = cls.class_get_help()
1370 # strip leading '--' from cl-args:
1378 # strip leading '--' from cl-args:
1371 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
1379 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
1372 return [ attr.split('=')[0]
1380 return [ attr.split('=')[0]
1373 for attr in help.strip().splitlines()
1381 for attr in help.strip().splitlines()
1374 if attr.startswith(texts[1]) ]
1382 if attr.startswith(texts[1]) ]
1375 return []
1383 return []
1376
1384
1377 def magic_color_matches(self, text:str) -> List[str] :
1385 def magic_color_matches(self, text:str) -> List[str] :
1378 """ Match color schemes for %colors magic"""
1386 """ Match color schemes for %colors magic"""
1379 texts = text.split()
1387 texts = text.split()
1380 if text.endswith(' '):
1388 if text.endswith(' '):
1381 # .split() strips off the trailing whitespace. Add '' back
1389 # .split() strips off the trailing whitespace. Add '' back
1382 # so that: '%colors ' -> ['%colors', '']
1390 # so that: '%colors ' -> ['%colors', '']
1383 texts.append('')
1391 texts.append('')
1384
1392
1385 if len(texts) == 2 and (texts[0] == 'colors' or texts[0] == '%colors'):
1393 if len(texts) == 2 and (texts[0] == 'colors' or texts[0] == '%colors'):
1386 prefix = texts[1]
1394 prefix = texts[1]
1387 return [ color for color in InspectColors.keys()
1395 return [ color for color in InspectColors.keys()
1388 if color.startswith(prefix) ]
1396 if color.startswith(prefix) ]
1389 return []
1397 return []
1390
1398
1391 def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str) -> Iterable[Any]:
1399 def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str) -> Iterable[Any]:
1392 """
1400 """
1393 Return a list of :any:`jedi.api.Completions` object from a ``text`` and
1401 Return a list of :any:`jedi.api.Completions` object from a ``text`` and
1394 cursor position.
1402 cursor position.
1395
1403
1396 Parameters
1404 Parameters
1397 ----------
1405 ----------
1398 cursor_column : int
1406 cursor_column : int
1399 column position of the cursor in ``text``, 0-indexed.
1407 column position of the cursor in ``text``, 0-indexed.
1400 cursor_line : int
1408 cursor_line : int
1401 line position of the cursor in ``text``, 0-indexed
1409 line position of the cursor in ``text``, 0-indexed
1402 text : str
1410 text : str
1403 text to complete
1411 text to complete
1404
1412
1405 Notes
1413 Notes
1406 -----
1414 -----
1407 If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion`
1415 If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion`
1408 object containing a string with the Jedi debug information attached.
1416 object containing a string with the Jedi debug information attached.
1409 """
1417 """
1410 namespaces = [self.namespace]
1418 namespaces = [self.namespace]
1411 if self.global_namespace is not None:
1419 if self.global_namespace is not None:
1412 namespaces.append(self.global_namespace)
1420 namespaces.append(self.global_namespace)
1413
1421
1414 completion_filter = lambda x:x
1422 completion_filter = lambda x:x
1415 offset = cursor_to_position(text, cursor_line, cursor_column)
1423 offset = cursor_to_position(text, cursor_line, cursor_column)
1416 # filter output if we are completing for object members
1424 # filter output if we are completing for object members
1417 if offset:
1425 if offset:
1418 pre = text[offset-1]
1426 pre = text[offset-1]
1419 if pre == '.':
1427 if pre == '.':
1420 if self.omit__names == 2:
1428 if self.omit__names == 2:
1421 completion_filter = lambda c:not c.name.startswith('_')
1429 completion_filter = lambda c:not c.name.startswith('_')
1422 elif self.omit__names == 1:
1430 elif self.omit__names == 1:
1423 completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__'))
1431 completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__'))
1424 elif self.omit__names == 0:
1432 elif self.omit__names == 0:
1425 completion_filter = lambda x:x
1433 completion_filter = lambda x:x
1426 else:
1434 else:
1427 raise ValueError("Don't understand self.omit__names == {}".format(self.omit__names))
1435 raise ValueError("Don't understand self.omit__names == {}".format(self.omit__names))
1428
1436
1429 interpreter = jedi.Interpreter(text[:offset], namespaces)
1437 interpreter = jedi.Interpreter(text[:offset], namespaces)
1430 try_jedi = True
1438 try_jedi = True
1431
1439
1432 try:
1440 try:
1433 # find the first token in the current tree -- if it is a ' or " then we are in a string
1441 # find the first token in the current tree -- if it is a ' or " then we are in a string
1434 completing_string = False
1442 completing_string = False
1435 try:
1443 try:
1436 first_child = next(c for c in interpreter._get_module().tree_node.children if hasattr(c, 'value'))
1444 first_child = next(c for c in interpreter._get_module().tree_node.children if hasattr(c, 'value'))
1437 except StopIteration:
1445 except StopIteration:
1438 pass
1446 pass
1439 else:
1447 else:
1440 # note the value may be ', ", or it may also be ''' or """, or
1448 # note the value may be ', ", or it may also be ''' or """, or
1441 # in some cases, """what/you/typed..., but all of these are
1449 # in some cases, """what/you/typed..., but all of these are
1442 # strings.
1450 # strings.
1443 completing_string = len(first_child.value) > 0 and first_child.value[0] in {"'", '"'}
1451 completing_string = len(first_child.value) > 0 and first_child.value[0] in {"'", '"'}
1444
1452
1445 # if we are in a string jedi is likely not the right candidate for
1453 # if we are in a string jedi is likely not the right candidate for
1446 # now. Skip it.
1454 # now. Skip it.
1447 try_jedi = not completing_string
1455 try_jedi = not completing_string
1448 except Exception as e:
1456 except Exception as e:
1449 # many of things can go wrong, we are using private API just don't crash.
1457 # many of things can go wrong, we are using private API just don't crash.
1450 if self.debug:
1458 if self.debug:
1451 print("Error detecting if completing a non-finished string :", e, '|')
1459 print("Error detecting if completing a non-finished string :", e, '|')
1452
1460
1453 if not try_jedi:
1461 if not try_jedi:
1454 return []
1462 return []
1455 try:
1463 try:
1456 return filter(completion_filter, interpreter.complete(column=cursor_column, line=cursor_line + 1))
1464 return filter(completion_filter, interpreter.complete(column=cursor_column, line=cursor_line + 1))
1457 except Exception as e:
1465 except Exception as e:
1458 if self.debug:
1466 if self.debug:
1459 return [_FakeJediCompletion('Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' % (e))]
1467 return [_FakeJediCompletion('Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' % (e))]
1460 else:
1468 else:
1461 return []
1469 return []
1462
1470
1463 def python_matches(self, text:str)->List[str]:
1471 def python_matches(self, text:str)->List[str]:
1464 """Match attributes or global python names"""
1472 """Match attributes or global python names"""
1465 if "." in text:
1473 if "." in text:
1466 try:
1474 try:
1467 matches = self.attr_matches(text)
1475 matches = self.attr_matches(text)
1468 if text.endswith('.') and self.omit__names:
1476 if text.endswith('.') and self.omit__names:
1469 if self.omit__names == 1:
1477 if self.omit__names == 1:
1470 # true if txt is _not_ a __ name, false otherwise:
1478 # true if txt is _not_ a __ name, false otherwise:
1471 no__name = (lambda txt:
1479 no__name = (lambda txt:
1472 re.match(r'.*\.__.*?__',txt) is None)
1480 re.match(r'.*\.__.*?__',txt) is None)
1473 else:
1481 else:
1474 # true if txt is _not_ a _ name, false otherwise:
1482 # true if txt is _not_ a _ name, false otherwise:
1475 no__name = (lambda txt:
1483 no__name = (lambda txt:
1476 re.match(r'\._.*?',txt[txt.rindex('.'):]) is None)
1484 re.match(r'\._.*?',txt[txt.rindex('.'):]) is None)
1477 matches = filter(no__name, matches)
1485 matches = filter(no__name, matches)
1478 except NameError:
1486 except NameError:
1479 # catches <undefined attributes>.<tab>
1487 # catches <undefined attributes>.<tab>
1480 matches = []
1488 matches = []
1481 else:
1489 else:
1482 matches = self.global_matches(text)
1490 matches = self.global_matches(text)
1483 return matches
1491 return matches
1484
1492
1485 def _default_arguments_from_docstring(self, doc):
1493 def _default_arguments_from_docstring(self, doc):
1486 """Parse the first line of docstring for call signature.
1494 """Parse the first line of docstring for call signature.
1487
1495
1488 Docstring should be of the form 'min(iterable[, key=func])\n'.
1496 Docstring should be of the form 'min(iterable[, key=func])\n'.
1489 It can also parse cython docstring of the form
1497 It can also parse cython docstring of the form
1490 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
1498 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
1491 """
1499 """
1492 if doc is None:
1500 if doc is None:
1493 return []
1501 return []
1494
1502
1495 #care only the firstline
1503 #care only the firstline
1496 line = doc.lstrip().splitlines()[0]
1504 line = doc.lstrip().splitlines()[0]
1497
1505
1498 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1506 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
1499 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
1507 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
1500 sig = self.docstring_sig_re.search(line)
1508 sig = self.docstring_sig_re.search(line)
1501 if sig is None:
1509 if sig is None:
1502 return []
1510 return []
1503 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
1511 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
1504 sig = sig.groups()[0].split(',')
1512 sig = sig.groups()[0].split(',')
1505 ret = []
1513 ret = []
1506 for s in sig:
1514 for s in sig:
1507 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1515 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
1508 ret += self.docstring_kwd_re.findall(s)
1516 ret += self.docstring_kwd_re.findall(s)
1509 return ret
1517 return ret
1510
1518
1511 def _default_arguments(self, obj):
1519 def _default_arguments(self, obj):
1512 """Return the list of default arguments of obj if it is callable,
1520 """Return the list of default arguments of obj if it is callable,
1513 or empty list otherwise."""
1521 or empty list otherwise."""
1514 call_obj = obj
1522 call_obj = obj
1515 ret = []
1523 ret = []
1516 if inspect.isbuiltin(obj):
1524 if inspect.isbuiltin(obj):
1517 pass
1525 pass
1518 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
1526 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
1519 if inspect.isclass(obj):
1527 if inspect.isclass(obj):
1520 #for cython embedsignature=True the constructor docstring
1528 #for cython embedsignature=True the constructor docstring
1521 #belongs to the object itself not __init__
1529 #belongs to the object itself not __init__
1522 ret += self._default_arguments_from_docstring(
1530 ret += self._default_arguments_from_docstring(
1523 getattr(obj, '__doc__', ''))
1531 getattr(obj, '__doc__', ''))
1524 # for classes, check for __init__,__new__
1532 # for classes, check for __init__,__new__
1525 call_obj = (getattr(obj, '__init__', None) or
1533 call_obj = (getattr(obj, '__init__', None) or
1526 getattr(obj, '__new__', None))
1534 getattr(obj, '__new__', None))
1527 # for all others, check if they are __call__able
1535 # for all others, check if they are __call__able
1528 elif hasattr(obj, '__call__'):
1536 elif hasattr(obj, '__call__'):
1529 call_obj = obj.__call__
1537 call_obj = obj.__call__
1530 ret += self._default_arguments_from_docstring(
1538 ret += self._default_arguments_from_docstring(
1531 getattr(call_obj, '__doc__', ''))
1539 getattr(call_obj, '__doc__', ''))
1532
1540
1533 _keeps = (inspect.Parameter.KEYWORD_ONLY,
1541 _keeps = (inspect.Parameter.KEYWORD_ONLY,
1534 inspect.Parameter.POSITIONAL_OR_KEYWORD)
1542 inspect.Parameter.POSITIONAL_OR_KEYWORD)
1535
1543
1536 try:
1544 try:
1537 sig = inspect.signature(call_obj)
1545 sig = inspect.signature(call_obj)
1538 ret.extend(k for k, v in sig.parameters.items() if
1546 ret.extend(k for k, v in sig.parameters.items() if
1539 v.kind in _keeps)
1547 v.kind in _keeps)
1540 except ValueError:
1548 except ValueError:
1541 pass
1549 pass
1542
1550
1543 return list(set(ret))
1551 return list(set(ret))
1544
1552
1545 def python_func_kw_matches(self, text):
1553 def python_func_kw_matches(self, text):
1546 """Match named parameters (kwargs) of the last open function"""
1554 """Match named parameters (kwargs) of the last open function"""
1547
1555
1548 if "." in text: # a parameter cannot be dotted
1556 if "." in text: # a parameter cannot be dotted
1549 return []
1557 return []
1550 try: regexp = self.__funcParamsRegex
1558 try: regexp = self.__funcParamsRegex
1551 except AttributeError:
1559 except AttributeError:
1552 regexp = self.__funcParamsRegex = re.compile(r'''
1560 regexp = self.__funcParamsRegex = re.compile(r'''
1553 '.*?(?<!\\)' | # single quoted strings or
1561 '.*?(?<!\\)' | # single quoted strings or
1554 ".*?(?<!\\)" | # double quoted strings or
1562 ".*?(?<!\\)" | # double quoted strings or
1555 \w+ | # identifier
1563 \w+ | # identifier
1556 \S # other characters
1564 \S # other characters
1557 ''', re.VERBOSE | re.DOTALL)
1565 ''', re.VERBOSE | re.DOTALL)
1558 # 1. find the nearest identifier that comes before an unclosed
1566 # 1. find the nearest identifier that comes before an unclosed
1559 # parenthesis before the cursor
1567 # parenthesis before the cursor
1560 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
1568 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
1561 tokens = regexp.findall(self.text_until_cursor)
1569 tokens = regexp.findall(self.text_until_cursor)
1562 iterTokens = reversed(tokens); openPar = 0
1570 iterTokens = reversed(tokens); openPar = 0
1563
1571
1564 for token in iterTokens:
1572 for token in iterTokens:
1565 if token == ')':
1573 if token == ')':
1566 openPar -= 1
1574 openPar -= 1
1567 elif token == '(':
1575 elif token == '(':
1568 openPar += 1
1576 openPar += 1
1569 if openPar > 0:
1577 if openPar > 0:
1570 # found the last unclosed parenthesis
1578 # found the last unclosed parenthesis
1571 break
1579 break
1572 else:
1580 else:
1573 return []
1581 return []
1574 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
1582 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
1575 ids = []
1583 ids = []
1576 isId = re.compile(r'\w+$').match
1584 isId = re.compile(r'\w+$').match
1577
1585
1578 while True:
1586 while True:
1579 try:
1587 try:
1580 ids.append(next(iterTokens))
1588 ids.append(next(iterTokens))
1581 if not isId(ids[-1]):
1589 if not isId(ids[-1]):
1582 ids.pop(); break
1590 ids.pop(); break
1583 if not next(iterTokens) == '.':
1591 if not next(iterTokens) == '.':
1584 break
1592 break
1585 except StopIteration:
1593 except StopIteration:
1586 break
1594 break
1587
1595
1588 # Find all named arguments already assigned to, as to avoid suggesting
1596 # Find all named arguments already assigned to, as to avoid suggesting
1589 # them again
1597 # them again
1590 usedNamedArgs = set()
1598 usedNamedArgs = set()
1591 par_level = -1
1599 par_level = -1
1592 for token, next_token in zip(tokens, tokens[1:]):
1600 for token, next_token in zip(tokens, tokens[1:]):
1593 if token == '(':
1601 if token == '(':
1594 par_level += 1
1602 par_level += 1
1595 elif token == ')':
1603 elif token == ')':
1596 par_level -= 1
1604 par_level -= 1
1597
1605
1598 if par_level != 0:
1606 if par_level != 0:
1599 continue
1607 continue
1600
1608
1601 if next_token != '=':
1609 if next_token != '=':
1602 continue
1610 continue
1603
1611
1604 usedNamedArgs.add(token)
1612 usedNamedArgs.add(token)
1605
1613
1606 argMatches = []
1614 argMatches = []
1607 try:
1615 try:
1608 callableObj = '.'.join(ids[::-1])
1616 callableObj = '.'.join(ids[::-1])
1609 namedArgs = self._default_arguments(eval(callableObj,
1617 namedArgs = self._default_arguments(eval(callableObj,
1610 self.namespace))
1618 self.namespace))
1611
1619
1612 # Remove used named arguments from the list, no need to show twice
1620 # Remove used named arguments from the list, no need to show twice
1613 for namedArg in set(namedArgs) - usedNamedArgs:
1621 for namedArg in set(namedArgs) - usedNamedArgs:
1614 if namedArg.startswith(text):
1622 if namedArg.startswith(text):
1615 argMatches.append("%s=" %namedArg)
1623 argMatches.append("%s=" %namedArg)
1616 except:
1624 except:
1617 pass
1625 pass
1618
1626
1619 return argMatches
1627 return argMatches
1620
1628
1621 @staticmethod
1629 @staticmethod
1622 def _get_keys(obj: Any) -> List[Any]:
1630 def _get_keys(obj: Any) -> List[Any]:
1623 # Objects can define their own completions by defining an
1631 # Objects can define their own completions by defining an
1624 # _ipy_key_completions_() method.
1632 # _ipy_key_completions_() method.
1625 method = get_real_method(obj, '_ipython_key_completions_')
1633 method = get_real_method(obj, '_ipython_key_completions_')
1626 if method is not None:
1634 if method is not None:
1627 return method()
1635 return method()
1628
1636
1629 # Special case some common in-memory dict-like types
1637 # Special case some common in-memory dict-like types
1630 if isinstance(obj, dict) or\
1638 if isinstance(obj, dict) or\
1631 _safe_isinstance(obj, 'pandas', 'DataFrame'):
1639 _safe_isinstance(obj, 'pandas', 'DataFrame'):
1632 try:
1640 try:
1633 return list(obj.keys())
1641 return list(obj.keys())
1634 except Exception:
1642 except Exception:
1635 return []
1643 return []
1636 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
1644 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\
1637 _safe_isinstance(obj, 'numpy', 'void'):
1645 _safe_isinstance(obj, 'numpy', 'void'):
1638 return obj.dtype.names or []
1646 return obj.dtype.names or []
1639 return []
1647 return []
1640
1648
1641 def dict_key_matches(self, text:str) -> List[str]:
1649 def dict_key_matches(self, text:str) -> List[str]:
1642 "Match string keys in a dictionary, after e.g. 'foo[' "
1650 "Match string keys in a dictionary, after e.g. 'foo[' "
1643
1651
1644
1652
1645 if self.__dict_key_regexps is not None:
1653 if self.__dict_key_regexps is not None:
1646 regexps = self.__dict_key_regexps
1654 regexps = self.__dict_key_regexps
1647 else:
1655 else:
1648 dict_key_re_fmt = r'''(?x)
1656 dict_key_re_fmt = r'''(?x)
1649 ( # match dict-referring expression wrt greedy setting
1657 ( # match dict-referring expression wrt greedy setting
1650 %s
1658 %s
1651 )
1659 )
1652 \[ # open bracket
1660 \[ # open bracket
1653 \s* # and optional whitespace
1661 \s* # and optional whitespace
1654 # Capture any number of str-like objects (e.g. "a", "b", 'c')
1662 # Capture any number of str-like objects (e.g. "a", "b", 'c')
1655 ((?:[uUbB]? # string prefix (r not handled)
1663 ((?:[uUbB]? # string prefix (r not handled)
1656 (?:
1664 (?:
1657 '(?:[^']|(?<!\\)\\')*'
1665 '(?:[^']|(?<!\\)\\')*'
1658 |
1666 |
1659 "(?:[^"]|(?<!\\)\\")*"
1667 "(?:[^"]|(?<!\\)\\")*"
1660 )
1668 )
1661 \s*,\s*
1669 \s*,\s*
1662 )*)
1670 )*)
1663 ([uUbB]? # string prefix (r not handled)
1671 ([uUbB]? # string prefix (r not handled)
1664 (?: # unclosed string
1672 (?: # unclosed string
1665 '(?:[^']|(?<!\\)\\')*
1673 '(?:[^']|(?<!\\)\\')*
1666 |
1674 |
1667 "(?:[^"]|(?<!\\)\\")*
1675 "(?:[^"]|(?<!\\)\\")*
1668 )
1676 )
1669 )?
1677 )?
1670 $
1678 $
1671 '''
1679 '''
1672 regexps = self.__dict_key_regexps = {
1680 regexps = self.__dict_key_regexps = {
1673 False: re.compile(dict_key_re_fmt % r'''
1681 False: re.compile(dict_key_re_fmt % r'''
1674 # identifiers separated by .
1682 # identifiers separated by .
1675 (?!\d)\w+
1683 (?!\d)\w+
1676 (?:\.(?!\d)\w+)*
1684 (?:\.(?!\d)\w+)*
1677 '''),
1685 '''),
1678 True: re.compile(dict_key_re_fmt % '''
1686 True: re.compile(dict_key_re_fmt % '''
1679 .+
1687 .+
1680 ''')
1688 ''')
1681 }
1689 }
1682
1690
1683 match = regexps[self.greedy].search(self.text_until_cursor)
1691 match = regexps[self.greedy].search(self.text_until_cursor)
1684
1692
1685 if match is None:
1693 if match is None:
1686 return []
1694 return []
1687
1695
1688 expr, prefix0, prefix = match.groups()
1696 expr, prefix0, prefix = match.groups()
1689 try:
1697 try:
1690 obj = eval(expr, self.namespace)
1698 obj = eval(expr, self.namespace)
1691 except Exception:
1699 except Exception:
1692 try:
1700 try:
1693 obj = eval(expr, self.global_namespace)
1701 obj = eval(expr, self.global_namespace)
1694 except Exception:
1702 except Exception:
1695 return []
1703 return []
1696
1704
1697 keys = self._get_keys(obj)
1705 keys = self._get_keys(obj)
1698 if not keys:
1706 if not keys:
1699 return keys
1707 return keys
1700
1708
1701 extra_prefix = eval(prefix0) if prefix0 != '' else None
1709 extra_prefix = eval(prefix0) if prefix0 != '' else None
1702
1710
1703 closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims, extra_prefix=extra_prefix)
1711 closing_quote, token_offset, matches = match_dict_keys(keys, prefix, self.splitter.delims, extra_prefix=extra_prefix)
1704 if not matches:
1712 if not matches:
1705 return matches
1713 return matches
1706
1714
1707 # get the cursor position of
1715 # get the cursor position of
1708 # - the text being completed
1716 # - the text being completed
1709 # - the start of the key text
1717 # - the start of the key text
1710 # - the start of the completion
1718 # - the start of the completion
1711 text_start = len(self.text_until_cursor) - len(text)
1719 text_start = len(self.text_until_cursor) - len(text)
1712 if prefix:
1720 if prefix:
1713 key_start = match.start(3)
1721 key_start = match.start(3)
1714 completion_start = key_start + token_offset
1722 completion_start = key_start + token_offset
1715 else:
1723 else:
1716 key_start = completion_start = match.end()
1724 key_start = completion_start = match.end()
1717
1725
1718 # grab the leading prefix, to make sure all completions start with `text`
1726 # grab the leading prefix, to make sure all completions start with `text`
1719 if text_start > key_start:
1727 if text_start > key_start:
1720 leading = ''
1728 leading = ''
1721 else:
1729 else:
1722 leading = text[text_start:completion_start]
1730 leading = text[text_start:completion_start]
1723
1731
1724 # the index of the `[` character
1732 # the index of the `[` character
1725 bracket_idx = match.end(1)
1733 bracket_idx = match.end(1)
1726
1734
1727 # append closing quote and bracket as appropriate
1735 # append closing quote and bracket as appropriate
1728 # this is *not* appropriate if the opening quote or bracket is outside
1736 # this is *not* appropriate if the opening quote or bracket is outside
1729 # the text given to this method
1737 # the text given to this method
1730 suf = ''
1738 suf = ''
1731 continuation = self.line_buffer[len(self.text_until_cursor):]
1739 continuation = self.line_buffer[len(self.text_until_cursor):]
1732 if key_start > text_start and closing_quote:
1740 if key_start > text_start and closing_quote:
1733 # quotes were opened inside text, maybe close them
1741 # quotes were opened inside text, maybe close them
1734 if continuation.startswith(closing_quote):
1742 if continuation.startswith(closing_quote):
1735 continuation = continuation[len(closing_quote):]
1743 continuation = continuation[len(closing_quote):]
1736 else:
1744 else:
1737 suf += closing_quote
1745 suf += closing_quote
1738 if bracket_idx > text_start:
1746 if bracket_idx > text_start:
1739 # brackets were opened inside text, maybe close them
1747 # brackets were opened inside text, maybe close them
1740 if not continuation.startswith(']'):
1748 if not continuation.startswith(']'):
1741 suf += ']'
1749 suf += ']'
1742
1750
1743 return [leading + k + suf for k in matches]
1751 return [leading + k + suf for k in matches]
1744
1752
1745 @staticmethod
1753 @staticmethod
1746 def unicode_name_matches(text:str) -> Tuple[str, List[str]] :
1754 def unicode_name_matches(text:str) -> Tuple[str, List[str]] :
1747 """Match Latex-like syntax for unicode characters base
1755 """Match Latex-like syntax for unicode characters base
1748 on the name of the character.
1756 on the name of the character.
1749
1757
1750 This does ``\\GREEK SMALL LETTER ETA`` -> ``Ξ·``
1758 This does ``\\GREEK SMALL LETTER ETA`` -> ``Ξ·``
1751
1759
1752 Works only on valid python 3 identifier, or on combining characters that
1760 Works only on valid python 3 identifier, or on combining characters that
1753 will combine to form a valid identifier.
1761 will combine to form a valid identifier.
1754 """
1762 """
1755 slashpos = text.rfind('\\')
1763 slashpos = text.rfind('\\')
1756 if slashpos > -1:
1764 if slashpos > -1:
1757 s = text[slashpos+1:]
1765 s = text[slashpos+1:]
1758 try :
1766 try :
1759 unic = unicodedata.lookup(s)
1767 unic = unicodedata.lookup(s)
1760 # allow combining chars
1768 # allow combining chars
1761 if ('a'+unic).isidentifier():
1769 if ('a'+unic).isidentifier():
1762 return '\\'+s,[unic]
1770 return '\\'+s,[unic]
1763 except KeyError:
1771 except KeyError:
1764 pass
1772 pass
1765 return '', []
1773 return '', []
1766
1774
1767
1775
1768 def latex_matches(self, text:str) -> Tuple[str, Sequence[str]]:
1776 def latex_matches(self, text:str) -> Tuple[str, Sequence[str]]:
1769 """Match Latex syntax for unicode characters.
1777 """Match Latex syntax for unicode characters.
1770
1778
1771 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``Ξ±``
1779 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``Ξ±``
1772 """
1780 """
1773 slashpos = text.rfind('\\')
1781 slashpos = text.rfind('\\')
1774 if slashpos > -1:
1782 if slashpos > -1:
1775 s = text[slashpos:]
1783 s = text[slashpos:]
1776 if s in latex_symbols:
1784 if s in latex_symbols:
1777 # Try to complete a full latex symbol to unicode
1785 # Try to complete a full latex symbol to unicode
1778 # \\alpha -> Ξ±
1786 # \\alpha -> Ξ±
1779 return s, [latex_symbols[s]]
1787 return s, [latex_symbols[s]]
1780 else:
1788 else:
1781 # If a user has partially typed a latex symbol, give them
1789 # If a user has partially typed a latex symbol, give them
1782 # a full list of options \al -> [\aleph, \alpha]
1790 # a full list of options \al -> [\aleph, \alpha]
1783 matches = [k for k in latex_symbols if k.startswith(s)]
1791 matches = [k for k in latex_symbols if k.startswith(s)]
1784 if matches:
1792 if matches:
1785 return s, matches
1793 return s, matches
1786 return '', ()
1794 return '', ()
1787
1795
1788 def dispatch_custom_completer(self, text):
1796 def dispatch_custom_completer(self, text):
1789 if not self.custom_completers:
1797 if not self.custom_completers:
1790 return
1798 return
1791
1799
1792 line = self.line_buffer
1800 line = self.line_buffer
1793 if not line.strip():
1801 if not line.strip():
1794 return None
1802 return None
1795
1803
1796 # Create a little structure to pass all the relevant information about
1804 # Create a little structure to pass all the relevant information about
1797 # the current completion to any custom completer.
1805 # the current completion to any custom completer.
1798 event = SimpleNamespace()
1806 event = SimpleNamespace()
1799 event.line = line
1807 event.line = line
1800 event.symbol = text
1808 event.symbol = text
1801 cmd = line.split(None,1)[0]
1809 cmd = line.split(None,1)[0]
1802 event.command = cmd
1810 event.command = cmd
1803 event.text_until_cursor = self.text_until_cursor
1811 event.text_until_cursor = self.text_until_cursor
1804
1812
1805 # for foo etc, try also to find completer for %foo
1813 # for foo etc, try also to find completer for %foo
1806 if not cmd.startswith(self.magic_escape):
1814 if not cmd.startswith(self.magic_escape):
1807 try_magic = self.custom_completers.s_matches(
1815 try_magic = self.custom_completers.s_matches(
1808 self.magic_escape + cmd)
1816 self.magic_escape + cmd)
1809 else:
1817 else:
1810 try_magic = []
1818 try_magic = []
1811
1819
1812 for c in itertools.chain(self.custom_completers.s_matches(cmd),
1820 for c in itertools.chain(self.custom_completers.s_matches(cmd),
1813 try_magic,
1821 try_magic,
1814 self.custom_completers.flat_matches(self.text_until_cursor)):
1822 self.custom_completers.flat_matches(self.text_until_cursor)):
1815 try:
1823 try:
1816 res = c(event)
1824 res = c(event)
1817 if res:
1825 if res:
1818 # first, try case sensitive match
1826 # first, try case sensitive match
1819 withcase = [r for r in res if r.startswith(text)]
1827 withcase = [r for r in res if r.startswith(text)]
1820 if withcase:
1828 if withcase:
1821 return withcase
1829 return withcase
1822 # if none, then case insensitive ones are ok too
1830 # if none, then case insensitive ones are ok too
1823 text_low = text.lower()
1831 text_low = text.lower()
1824 return [r for r in res if r.lower().startswith(text_low)]
1832 return [r for r in res if r.lower().startswith(text_low)]
1825 except TryNext:
1833 except TryNext:
1826 pass
1834 pass
1827 except KeyboardInterrupt:
1835 except KeyboardInterrupt:
1828 """
1836 """
1829 If custom completer take too long,
1837 If custom completer take too long,
1830 let keyboard interrupt abort and return nothing.
1838 let keyboard interrupt abort and return nothing.
1831 """
1839 """
1832 break
1840 break
1833
1841
1834 return None
1842 return None
1835
1843
1836 def completions(self, text: str, offset: int)->Iterator[Completion]:
1844 def completions(self, text: str, offset: int)->Iterator[Completion]:
1837 """
1845 """
1838 Returns an iterator over the possible completions
1846 Returns an iterator over the possible completions
1839
1847
1840 .. warning:: Unstable
1848 .. warning::
1849
1850 Unstable
1841
1851
1842 This function is unstable, API may change without warning.
1852 This function is unstable, API may change without warning.
1843 It will also raise unless use in proper context manager.
1853 It will also raise unless use in proper context manager.
1844
1854
1845 Parameters
1855 Parameters
1846 ----------
1856 ----------
1847 text:str
1857 text:str
1848 Full text of the current input, multi line string.
1858 Full text of the current input, multi line string.
1849 offset:int
1859 offset:int
1850 Integer representing the position of the cursor in ``text``. Offset
1860 Integer representing the position of the cursor in ``text``. Offset
1851 is 0-based indexed.
1861 is 0-based indexed.
1852
1862
1853 Yields
1863 Yields
1854 ------
1864 ------
1855 Completion
1865 Completion
1856
1866
1857 Notes
1867 Notes
1858 -----
1868 -----
1859 The cursor on a text can either be seen as being "in between"
1869 The cursor on a text can either be seen as being "in between"
1860 characters or "On" a character depending on the interface visible to
1870 characters or "On" a character depending on the interface visible to
1861 the user. For consistency the cursor being on "in between" characters X
1871 the user. For consistency the cursor being on "in between" characters X
1862 and Y is equivalent to the cursor being "on" character Y, that is to say
1872 and Y is equivalent to the cursor being "on" character Y, that is to say
1863 the character the cursor is on is considered as being after the cursor.
1873 the character the cursor is on is considered as being after the cursor.
1864
1874
1865 Combining characters may span more that one position in the
1875 Combining characters may span more that one position in the
1866 text.
1876 text.
1867
1877
1868 .. note::
1878 .. note::
1869
1879
1870 If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--``
1880 If ``IPCompleter.debug`` is :any:`True` will yield a ``--jedi/ipython--``
1871 fake Completion token to distinguish completion returned by Jedi
1881 fake Completion token to distinguish completion returned by Jedi
1872 and usual IPython completion.
1882 and usual IPython completion.
1873
1883
1874 .. note::
1884 .. note::
1875
1885
1876 Completions are not completely deduplicated yet. If identical
1886 Completions are not completely deduplicated yet. If identical
1877 completions are coming from different sources this function does not
1887 completions are coming from different sources this function does not
1878 ensure that each completion object will only be present once.
1888 ensure that each completion object will only be present once.
1879 """
1889 """
1880 warnings.warn("_complete is a provisional API (as of IPython 6.0). "
1890 warnings.warn("_complete is a provisional API (as of IPython 6.0). "
1881 "It may change without warnings. "
1891 "It may change without warnings. "
1882 "Use in corresponding context manager.",
1892 "Use in corresponding context manager.",
1883 category=ProvisionalCompleterWarning, stacklevel=2)
1893 category=ProvisionalCompleterWarning, stacklevel=2)
1884
1894
1885 seen = set()
1895 seen = set()
1886 profiler:Optional[cProfile.Profile]
1896 profiler:Optional[cProfile.Profile]
1887 try:
1897 try:
1888 if self.profile_completions:
1898 if self.profile_completions:
1889 import cProfile
1899 import cProfile
1890 profiler = cProfile.Profile()
1900 profiler = cProfile.Profile()
1891 profiler.enable()
1901 profiler.enable()
1892 else:
1902 else:
1893 profiler = None
1903 profiler = None
1894
1904
1895 for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000):
1905 for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000):
1896 if c and (c in seen):
1906 if c and (c in seen):
1897 continue
1907 continue
1898 yield c
1908 yield c
1899 seen.add(c)
1909 seen.add(c)
1900 except KeyboardInterrupt:
1910 except KeyboardInterrupt:
1901 """if completions take too long and users send keyboard interrupt,
1911 """if completions take too long and users send keyboard interrupt,
1902 do not crash and return ASAP. """
1912 do not crash and return ASAP. """
1903 pass
1913 pass
1904 finally:
1914 finally:
1905 if profiler is not None:
1915 if profiler is not None:
1906 profiler.disable()
1916 profiler.disable()
1907 ensure_dir_exists(self.profiler_output_dir)
1917 ensure_dir_exists(self.profiler_output_dir)
1908 output_path = os.path.join(self.profiler_output_dir, str(uuid.uuid4()))
1918 output_path = os.path.join(self.profiler_output_dir, str(uuid.uuid4()))
1909 print("Writing profiler output to", output_path)
1919 print("Writing profiler output to", output_path)
1910 profiler.dump_stats(output_path)
1920 profiler.dump_stats(output_path)
1911
1921
1912 def _completions(self, full_text: str, offset: int, *, _timeout) -> Iterator[Completion]:
1922 def _completions(self, full_text: str, offset: int, *, _timeout) -> Iterator[Completion]:
1913 """
1923 """
1914 Core completion module.Same signature as :any:`completions`, with the
1924 Core completion module.Same signature as :any:`completions`, with the
1915 extra `timeout` parameter (in seconds).
1925 extra `timeout` parameter (in seconds).
1916
1926
1917 Computing jedi's completion ``.type`` can be quite expensive (it is a
1927 Computing jedi's completion ``.type`` can be quite expensive (it is a
1918 lazy property) and can require some warm-up, more warm up than just
1928 lazy property) and can require some warm-up, more warm up than just
1919 computing the ``name`` of a completion. The warm-up can be :
1929 computing the ``name`` of a completion. The warm-up can be :
1920
1930
1921 - Long warm-up the first time a module is encountered after
1931 - Long warm-up the first time a module is encountered after
1922 install/update: actually build parse/inference tree.
1932 install/update: actually build parse/inference tree.
1923
1933
1924 - first time the module is encountered in a session: load tree from
1934 - first time the module is encountered in a session: load tree from
1925 disk.
1935 disk.
1926
1936
1927 We don't want to block completions for tens of seconds so we give the
1937 We don't want to block completions for tens of seconds so we give the
1928 completer a "budget" of ``_timeout`` seconds per invocation to compute
1938 completer a "budget" of ``_timeout`` seconds per invocation to compute
1929 completions types, the completions that have not yet been computed will
1939 completions types, the completions that have not yet been computed will
1930 be marked as "unknown" an will have a chance to be computed next round
1940 be marked as "unknown" an will have a chance to be computed next round
1931 are things get cached.
1941 are things get cached.
1932
1942
1933 Keep in mind that Jedi is not the only thing treating the completion so
1943 Keep in mind that Jedi is not the only thing treating the completion so
1934 keep the timeout short-ish as if we take more than 0.3 second we still
1944 keep the timeout short-ish as if we take more than 0.3 second we still
1935 have lots of processing to do.
1945 have lots of processing to do.
1936
1946
1937 """
1947 """
1938 deadline = time.monotonic() + _timeout
1948 deadline = time.monotonic() + _timeout
1939
1949
1940
1950
1941 before = full_text[:offset]
1951 before = full_text[:offset]
1942 cursor_line, cursor_column = position_to_cursor(full_text, offset)
1952 cursor_line, cursor_column = position_to_cursor(full_text, offset)
1943
1953
1944 matched_text, matches, matches_origin, jedi_matches = self._complete(
1954 matched_text, matches, matches_origin, jedi_matches = self._complete(
1945 full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column)
1955 full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column)
1946
1956
1947 iter_jm = iter(jedi_matches)
1957 iter_jm = iter(jedi_matches)
1948 if _timeout:
1958 if _timeout:
1949 for jm in iter_jm:
1959 for jm in iter_jm:
1950 try:
1960 try:
1951 type_ = jm.type
1961 type_ = jm.type
1952 except Exception:
1962 except Exception:
1953 if self.debug:
1963 if self.debug:
1954 print("Error in Jedi getting type of ", jm)
1964 print("Error in Jedi getting type of ", jm)
1955 type_ = None
1965 type_ = None
1956 delta = len(jm.name_with_symbols) - len(jm.complete)
1966 delta = len(jm.name_with_symbols) - len(jm.complete)
1957 if type_ == 'function':
1967 if type_ == 'function':
1958 signature = _make_signature(jm)
1968 signature = _make_signature(jm)
1959 else:
1969 else:
1960 signature = ''
1970 signature = ''
1961 yield Completion(start=offset - delta,
1971 yield Completion(start=offset - delta,
1962 end=offset,
1972 end=offset,
1963 text=jm.name_with_symbols,
1973 text=jm.name_with_symbols,
1964 type=type_,
1974 type=type_,
1965 signature=signature,
1975 signature=signature,
1966 _origin='jedi')
1976 _origin='jedi')
1967
1977
1968 if time.monotonic() > deadline:
1978 if time.monotonic() > deadline:
1969 break
1979 break
1970
1980
1971 for jm in iter_jm:
1981 for jm in iter_jm:
1972 delta = len(jm.name_with_symbols) - len(jm.complete)
1982 delta = len(jm.name_with_symbols) - len(jm.complete)
1973 yield Completion(start=offset - delta,
1983 yield Completion(start=offset - delta,
1974 end=offset,
1984 end=offset,
1975 text=jm.name_with_symbols,
1985 text=jm.name_with_symbols,
1976 type='<unknown>', # don't compute type for speed
1986 type='<unknown>', # don't compute type for speed
1977 _origin='jedi',
1987 _origin='jedi',
1978 signature='')
1988 signature='')
1979
1989
1980
1990
1981 start_offset = before.rfind(matched_text)
1991 start_offset = before.rfind(matched_text)
1982
1992
1983 # TODO:
1993 # TODO:
1984 # Suppress this, right now just for debug.
1994 # Suppress this, right now just for debug.
1985 if jedi_matches and matches and self.debug:
1995 if jedi_matches and matches and self.debug:
1986 yield Completion(start=start_offset, end=offset, text='--jedi/ipython--',
1996 yield Completion(start=start_offset, end=offset, text='--jedi/ipython--',
1987 _origin='debug', type='none', signature='')
1997 _origin='debug', type='none', signature='')
1988
1998
1989 # I'm unsure if this is always true, so let's assert and see if it
1999 # I'm unsure if this is always true, so let's assert and see if it
1990 # crash
2000 # crash
1991 assert before.endswith(matched_text)
2001 assert before.endswith(matched_text)
1992 for m, t in zip(matches, matches_origin):
2002 for m, t in zip(matches, matches_origin):
1993 yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>')
2003 yield Completion(start=start_offset, end=offset, text=m, _origin=t, signature='', type='<unknown>')
1994
2004
1995
2005
1996 def complete(self, text=None, line_buffer=None, cursor_pos=None) -> Tuple[str, Sequence[str]]:
2006 def complete(self, text=None, line_buffer=None, cursor_pos=None) -> Tuple[str, Sequence[str]]:
1997 """Find completions for the given text and line context.
2007 """Find completions for the given text and line context.
1998
2008
1999 Note that both the text and the line_buffer are optional, but at least
2009 Note that both the text and the line_buffer are optional, but at least
2000 one of them must be given.
2010 one of them must be given.
2001
2011
2002 Parameters
2012 Parameters
2003 ----------
2013 ----------
2004 text : string, optional
2014 text : string, optional
2005 Text to perform the completion on. If not given, the line buffer
2015 Text to perform the completion on. If not given, the line buffer
2006 is split using the instance's CompletionSplitter object.
2016 is split using the instance's CompletionSplitter object.
2007 line_buffer : string, optional
2017 line_buffer : string, optional
2008 If not given, the completer attempts to obtain the current line
2018 If not given, the completer attempts to obtain the current line
2009 buffer via readline. This keyword allows clients which are
2019 buffer via readline. This keyword allows clients which are
2010 requesting for text completions in non-readline contexts to inform
2020 requesting for text completions in non-readline contexts to inform
2011 the completer of the entire text.
2021 the completer of the entire text.
2012 cursor_pos : int, optional
2022 cursor_pos : int, optional
2013 Index of the cursor in the full line buffer. Should be provided by
2023 Index of the cursor in the full line buffer. Should be provided by
2014 remote frontends where kernel has no access to frontend state.
2024 remote frontends where kernel has no access to frontend state.
2015
2025
2016 Returns
2026 Returns
2017 -------
2027 -------
2018 Tuple of two items:
2028 Tuple of two items:
2019 text : str
2029 text : str
2020 Text that was actually used in the completion.
2030 Text that was actually used in the completion.
2021 matches : list
2031 matches : list
2022 A list of completion matches.
2032 A list of completion matches.
2023
2033
2024 Notes
2034 Notes
2025 -----
2035 -----
2026 This API is likely to be deprecated and replaced by
2036 This API is likely to be deprecated and replaced by
2027 :any:`IPCompleter.completions` in the future.
2037 :any:`IPCompleter.completions` in the future.
2028
2038
2029 """
2039 """
2030 warnings.warn('`Completer.complete` is pending deprecation since '
2040 warnings.warn('`Completer.complete` is pending deprecation since '
2031 'IPython 6.0 and will be replaced by `Completer.completions`.',
2041 'IPython 6.0 and will be replaced by `Completer.completions`.',
2032 PendingDeprecationWarning)
2042 PendingDeprecationWarning)
2033 # potential todo, FOLD the 3rd throw away argument of _complete
2043 # potential todo, FOLD the 3rd throw away argument of _complete
2034 # into the first 2 one.
2044 # into the first 2 one.
2035 return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
2045 return self._complete(line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0)[:2]
2036
2046
2037 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
2047 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None,
2038 full_text=None) -> _CompleteResult:
2048 full_text=None) -> _CompleteResult:
2039 """
2049 """
2040 Like complete but can also returns raw jedi completions as well as the
2050 Like complete but can also returns raw jedi completions as well as the
2041 origin of the completion text. This could (and should) be made much
2051 origin of the completion text. This could (and should) be made much
2042 cleaner but that will be simpler once we drop the old (and stateful)
2052 cleaner but that will be simpler once we drop the old (and stateful)
2043 :any:`complete` API.
2053 :any:`complete` API.
2044
2054
2045 With current provisional API, cursor_pos act both (depending on the
2055 With current provisional API, cursor_pos act both (depending on the
2046 caller) as the offset in the ``text`` or ``line_buffer``, or as the
2056 caller) as the offset in the ``text`` or ``line_buffer``, or as the
2047 ``column`` when passing multiline strings this could/should be renamed
2057 ``column`` when passing multiline strings this could/should be renamed
2048 but would add extra noise.
2058 but would add extra noise.
2049
2059
2050 Returns
2060 Returns
2051 -------
2061 -------
2052 A tuple of N elements which are (likely):
2062 A tuple of N elements which are (likely):
2053 matched_text: ? the text that the complete matched
2063 matched_text: ? the text that the complete matched
2054 matches: list of completions ?
2064 matches: list of completions ?
2055 matches_origin: ? list same lenght as matches, and where each completion came from
2065 matches_origin: ? list same lenght as matches, and where each completion came from
2056 jedi_matches: list of Jedi matches, have it's own structure.
2066 jedi_matches: list of Jedi matches, have it's own structure.
2057 """
2067 """
2058
2068
2059
2069
2060 # if the cursor position isn't given, the only sane assumption we can
2070 # if the cursor position isn't given, the only sane assumption we can
2061 # make is that it's at the end of the line (the common case)
2071 # make is that it's at the end of the line (the common case)
2062 if cursor_pos is None:
2072 if cursor_pos is None:
2063 cursor_pos = len(line_buffer) if text is None else len(text)
2073 cursor_pos = len(line_buffer) if text is None else len(text)
2064
2074
2065 if self.use_main_ns:
2075 if self.use_main_ns:
2066 self.namespace = __main__.__dict__
2076 self.namespace = __main__.__dict__
2067
2077
2068 # if text is either None or an empty string, rely on the line buffer
2078 # if text is either None or an empty string, rely on the line buffer
2069 if (not line_buffer) and full_text:
2079 if (not line_buffer) and full_text:
2070 line_buffer = full_text.split('\n')[cursor_line]
2080 line_buffer = full_text.split('\n')[cursor_line]
2071 if not text: # issue #11508: check line_buffer before calling split_line
2081 if not text: # issue #11508: check line_buffer before calling split_line
2072 text = self.splitter.split_line(line_buffer, cursor_pos) if line_buffer else ''
2082 text = self.splitter.split_line(line_buffer, cursor_pos) if line_buffer else ''
2073
2083
2074 if self.backslash_combining_completions:
2084 if self.backslash_combining_completions:
2075 # allow deactivation of these on windows.
2085 # allow deactivation of these on windows.
2076 base_text = text if not line_buffer else line_buffer[:cursor_pos]
2086 base_text = text if not line_buffer else line_buffer[:cursor_pos]
2077
2087
2078 for meth in (self.latex_matches,
2088 for meth in (self.latex_matches,
2079 self.unicode_name_matches,
2089 self.unicode_name_matches,
2080 back_latex_name_matches,
2090 back_latex_name_matches,
2081 back_unicode_name_matches,
2091 back_unicode_name_matches,
2082 self.fwd_unicode_match):
2092 self.fwd_unicode_match):
2083 name_text, name_matches = meth(base_text)
2093 name_text, name_matches = meth(base_text)
2084 if name_text:
2094 if name_text:
2085 return _CompleteResult(name_text, name_matches[:MATCHES_LIMIT], \
2095 return _CompleteResult(name_text, name_matches[:MATCHES_LIMIT], \
2086 [meth.__qualname__]*min(len(name_matches), MATCHES_LIMIT), ())
2096 [meth.__qualname__]*min(len(name_matches), MATCHES_LIMIT), ())
2087
2097
2088
2098
2089 # If no line buffer is given, assume the input text is all there was
2099 # If no line buffer is given, assume the input text is all there was
2090 if line_buffer is None:
2100 if line_buffer is None:
2091 line_buffer = text
2101 line_buffer = text
2092
2102
2093 self.line_buffer = line_buffer
2103 self.line_buffer = line_buffer
2094 self.text_until_cursor = self.line_buffer[:cursor_pos]
2104 self.text_until_cursor = self.line_buffer[:cursor_pos]
2095
2105
2096 # Do magic arg matches
2106 # Do magic arg matches
2097 for matcher in self.magic_arg_matchers:
2107 for matcher in self.magic_arg_matchers:
2098 matches = list(matcher(line_buffer))[:MATCHES_LIMIT]
2108 matches = list(matcher(line_buffer))[:MATCHES_LIMIT]
2099 if matches:
2109 if matches:
2100 origins = [matcher.__qualname__] * len(matches)
2110 origins = [matcher.__qualname__] * len(matches)
2101 return _CompleteResult(text, matches, origins, ())
2111 return _CompleteResult(text, matches, origins, ())
2102
2112
2103 # Start with a clean slate of completions
2113 # Start with a clean slate of completions
2104 matches = []
2114 matches = []
2105
2115
2106 # FIXME: we should extend our api to return a dict with completions for
2116 # FIXME: we should extend our api to return a dict with completions for
2107 # different types of objects. The rlcomplete() method could then
2117 # different types of objects. The rlcomplete() method could then
2108 # simply collapse the dict into a list for readline, but we'd have
2118 # simply collapse the dict into a list for readline, but we'd have
2109 # richer completion semantics in other environments.
2119 # richer completion semantics in other environments.
2110 completions:Iterable[Any] = []
2120 completions:Iterable[Any] = []
2111 if self.use_jedi:
2121 if self.use_jedi:
2112 if not full_text:
2122 if not full_text:
2113 full_text = line_buffer
2123 full_text = line_buffer
2114 completions = self._jedi_matches(
2124 completions = self._jedi_matches(
2115 cursor_pos, cursor_line, full_text)
2125 cursor_pos, cursor_line, full_text)
2116
2126
2117 if self.merge_completions:
2127 if self.merge_completions:
2118 matches = []
2128 matches = []
2119 for matcher in self.matchers:
2129 for matcher in self.matchers:
2120 try:
2130 try:
2121 matches.extend([(m, matcher.__qualname__)
2131 matches.extend([(m, matcher.__qualname__)
2122 for m in matcher(text)])
2132 for m in matcher(text)])
2123 except:
2133 except:
2124 # Show the ugly traceback if the matcher causes an
2134 # Show the ugly traceback if the matcher causes an
2125 # exception, but do NOT crash the kernel!
2135 # exception, but do NOT crash the kernel!
2126 sys.excepthook(*sys.exc_info())
2136 sys.excepthook(*sys.exc_info())
2127 else:
2137 else:
2128 for matcher in self.matchers:
2138 for matcher in self.matchers:
2129 matches = [(m, matcher.__qualname__)
2139 matches = [(m, matcher.__qualname__)
2130 for m in matcher(text)]
2140 for m in matcher(text)]
2131 if matches:
2141 if matches:
2132 break
2142 break
2133
2143
2134 seen = set()
2144 seen = set()
2135 filtered_matches = set()
2145 filtered_matches = set()
2136 for m in matches:
2146 for m in matches:
2137 t, c = m
2147 t, c = m
2138 if t not in seen:
2148 if t not in seen:
2139 filtered_matches.add(m)
2149 filtered_matches.add(m)
2140 seen.add(t)
2150 seen.add(t)
2141
2151
2142 _filtered_matches = sorted(filtered_matches, key=lambda x: completions_sorting_key(x[0]))
2152 _filtered_matches = sorted(filtered_matches, key=lambda x: completions_sorting_key(x[0]))
2143
2153
2144 custom_res = [(m, 'custom') for m in self.dispatch_custom_completer(text) or []]
2154 custom_res = [(m, 'custom') for m in self.dispatch_custom_completer(text) or []]
2145
2155
2146 _filtered_matches = custom_res or _filtered_matches
2156 _filtered_matches = custom_res or _filtered_matches
2147
2157
2148 _filtered_matches = _filtered_matches[:MATCHES_LIMIT]
2158 _filtered_matches = _filtered_matches[:MATCHES_LIMIT]
2149 _matches = [m[0] for m in _filtered_matches]
2159 _matches = [m[0] for m in _filtered_matches]
2150 origins = [m[1] for m in _filtered_matches]
2160 origins = [m[1] for m in _filtered_matches]
2151
2161
2152 self.matches = _matches
2162 self.matches = _matches
2153
2163
2154 return _CompleteResult(text, _matches, origins, completions)
2164 return _CompleteResult(text, _matches, origins, completions)
2155
2165
2156 def fwd_unicode_match(self, text:str) -> Tuple[str, Sequence[str]]:
2166 def fwd_unicode_match(self, text:str) -> Tuple[str, Sequence[str]]:
2157 """
2167 """
2158 Forward match a string starting with a backslash with a list of
2168 Forward match a string starting with a backslash with a list of
2159 potential Unicode completions.
2169 potential Unicode completions.
2160
2170
2161 Will compute list list of Unicode character names on first call and cache it.
2171 Will compute list list of Unicode character names on first call and cache it.
2162
2172
2163 Returns
2173 Returns
2164 -------
2174 -------
2165 At tuple with:
2175 At tuple with:
2166 - matched text (empty if no matches)
2176 - matched text (empty if no matches)
2167 - list of potential completions, empty tuple otherwise)
2177 - list of potential completions, empty tuple otherwise)
2168 """
2178 """
2169 # TODO: self.unicode_names is here a list we traverse each time with ~100k elements.
2179 # TODO: self.unicode_names is here a list we traverse each time with ~100k elements.
2170 # We could do a faster match using a Trie.
2180 # We could do a faster match using a Trie.
2171
2181
2172 # Using pygtrie the follwing seem to work:
2182 # Using pygtrie the follwing seem to work:
2173
2183
2174 # s = PrefixSet()
2184 # s = PrefixSet()
2175
2185
2176 # for c in range(0,0x10FFFF + 1):
2186 # for c in range(0,0x10FFFF + 1):
2177 # try:
2187 # try:
2178 # s.add(unicodedata.name(chr(c)))
2188 # s.add(unicodedata.name(chr(c)))
2179 # except ValueError:
2189 # except ValueError:
2180 # pass
2190 # pass
2181 # [''.join(k) for k in s.iter(prefix)]
2191 # [''.join(k) for k in s.iter(prefix)]
2182
2192
2183 # But need to be timed and adds an extra dependency.
2193 # But need to be timed and adds an extra dependency.
2184
2194
2185 slashpos = text.rfind('\\')
2195 slashpos = text.rfind('\\')
2186 # if text starts with slash
2196 # if text starts with slash
2187 if slashpos > -1:
2197 if slashpos > -1:
2188 # PERF: It's important that we don't access self._unicode_names
2198 # PERF: It's important that we don't access self._unicode_names
2189 # until we're inside this if-block. _unicode_names is lazily
2199 # until we're inside this if-block. _unicode_names is lazily
2190 # initialized, and it takes a user-noticeable amount of time to
2200 # initialized, and it takes a user-noticeable amount of time to
2191 # initialize it, so we don't want to initialize it unless we're
2201 # initialize it, so we don't want to initialize it unless we're
2192 # actually going to use it.
2202 # actually going to use it.
2193 s = text[slashpos+1:]
2203 s = text[slashpos+1:]
2194 candidates = [x for x in self.unicode_names if x.startswith(s)]
2204 candidates = [x for x in self.unicode_names if x.startswith(s)]
2195 if candidates:
2205 if candidates:
2196 return s, candidates
2206 return s, candidates
2197 else:
2207 else:
2198 return '', ()
2208 return '', ()
2199
2209
2200 # if text does not start with slash
2210 # if text does not start with slash
2201 else:
2211 else:
2202 return '', ()
2212 return '', ()
2203
2213
2204 @property
2214 @property
2205 def unicode_names(self) -> List[str]:
2215 def unicode_names(self) -> List[str]:
2206 """List of names of unicode code points that can be completed.
2216 """List of names of unicode code points that can be completed.
2207
2217
2208 The list is lazily initialized on first access.
2218 The list is lazily initialized on first access.
2209 """
2219 """
2210 if self._unicode_names is None:
2220 if self._unicode_names is None:
2211 names = []
2221 names = []
2212 for c in range(0,0x10FFFF + 1):
2222 for c in range(0,0x10FFFF + 1):
2213 try:
2223 try:
2214 names.append(unicodedata.name(chr(c)))
2224 names.append(unicodedata.name(chr(c)))
2215 except ValueError:
2225 except ValueError:
2216 pass
2226 pass
2217 self._unicode_names = _unicode_name_compute(_UNICODE_RANGES)
2227 self._unicode_names = _unicode_name_compute(_UNICODE_RANGES)
2218
2228
2219 return self._unicode_names
2229 return self._unicode_names
2220
2230
2221 def _unicode_name_compute(ranges:List[Tuple[int,int]]) -> List[str]:
2231 def _unicode_name_compute(ranges:List[Tuple[int,int]]) -> List[str]:
2222 names = []
2232 names = []
2223 for start,stop in ranges:
2233 for start,stop in ranges:
2224 for c in range(start, stop) :
2234 for c in range(start, stop) :
2225 try:
2235 try:
2226 names.append(unicodedata.name(chr(c)))
2236 names.append(unicodedata.name(chr(c)))
2227 except ValueError:
2237 except ValueError:
2228 pass
2238 pass
2229 return names
2239 return names
@@ -1,1211 +1,1211 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats."""
2 """Top-level display functions for displaying object in different formats."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from binascii import b2a_base64, hexlify
8 from binascii import b2a_base64, hexlify
9 import json
9 import json
10 import mimetypes
10 import mimetypes
11 import os
11 import os
12 import struct
12 import struct
13 import warnings
13 import warnings
14 from copy import deepcopy
14 from copy import deepcopy
15 from os.path import splitext
15 from os.path import splitext
16 from pathlib import Path, PurePath
16 from pathlib import Path, PurePath
17
17
18 from IPython.utils.py3compat import cast_unicode
18 from IPython.utils.py3compat import cast_unicode
19 from IPython.testing.skipdoctest import skip_doctest
19 from IPython.testing.skipdoctest import skip_doctest
20 from . import display_functions
20 from . import display_functions
21
21
22
22
23 __all__ = ['display_pretty', 'display_html', 'display_markdown',
23 __all__ = ['display_pretty', 'display_html', 'display_markdown',
24 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
24 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
25 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
25 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
26 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
26 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
27 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
27 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
28 'set_matplotlib_close',
28 'set_matplotlib_close',
29 'Video']
29 'Video']
30
30
31 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
31 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
32
32
33 __all__ = __all__ + _deprecated_names
33 __all__ = __all__ + _deprecated_names
34
34
35
35
36 # ----- warn to import from IPython.display -----
36 # ----- warn to import from IPython.display -----
37
37
38 from warnings import warn
38 from warnings import warn
39
39
40
40
41 def __getattr__(name):
41 def __getattr__(name):
42 if name in _deprecated_names:
42 if name in _deprecated_names:
43 warn(f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython display", DeprecationWarning, stacklevel=2)
43 warn(f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython display", DeprecationWarning, stacklevel=2)
44 return getattr(display_functions, name)
44 return getattr(display_functions, name)
45
45
46 if name in globals().keys():
46 if name in globals().keys():
47 return globals()[name]
47 return globals()[name]
48 else:
48 else:
49 raise AttributeError(f"module {__name__} has no attribute {name}")
49 raise AttributeError(f"module {__name__} has no attribute {name}")
50
50
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # utility functions
53 # utility functions
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56 def _safe_exists(path):
56 def _safe_exists(path):
57 """Check path, but don't let exceptions raise"""
57 """Check path, but don't let exceptions raise"""
58 try:
58 try:
59 return os.path.exists(path)
59 return os.path.exists(path)
60 except Exception:
60 except Exception:
61 return False
61 return False
62
62
63
63
64 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
64 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
65 """internal implementation of all display_foo methods
65 """internal implementation of all display_foo methods
66
66
67 Parameters
67 Parameters
68 ----------
68 ----------
69 mimetype : str
69 mimetype : str
70 The mimetype to be published (e.g. 'image/png')
70 The mimetype to be published (e.g. 'image/png')
71 *objs : object
71 *objs : object
72 The Python objects to display, or if raw=True raw text data to
72 The Python objects to display, or if raw=True raw text data to
73 display.
73 display.
74 raw : bool
74 raw : bool
75 Are the data objects raw data or Python objects that need to be
75 Are the data objects raw data or Python objects that need to be
76 formatted before display? [default: False]
76 formatted before display? [default: False]
77 metadata : dict (optional)
77 metadata : dict (optional)
78 Metadata to be associated with the specific mimetype output.
78 Metadata to be associated with the specific mimetype output.
79 """
79 """
80 if metadata:
80 if metadata:
81 metadata = {mimetype: metadata}
81 metadata = {mimetype: metadata}
82 if raw:
82 if raw:
83 # turn list of pngdata into list of { 'image/png': pngdata }
83 # turn list of pngdata into list of { 'image/png': pngdata }
84 objs = [ {mimetype: obj} for obj in objs ]
84 objs = [ {mimetype: obj} for obj in objs ]
85 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
85 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
86
86
87 #-----------------------------------------------------------------------------
87 #-----------------------------------------------------------------------------
88 # Main functions
88 # Main functions
89 #-----------------------------------------------------------------------------
89 #-----------------------------------------------------------------------------
90
90
91
91
92 def display_pretty(*objs, **kwargs):
92 def display_pretty(*objs, **kwargs):
93 """Display the pretty (default) representation of an object.
93 """Display the pretty (default) representation of an object.
94
94
95 Parameters
95 Parameters
96 ----------
96 ----------
97 *objs : object
97 *objs : object
98 The Python objects to display, or if raw=True raw text data to
98 The Python objects to display, or if raw=True raw text data to
99 display.
99 display.
100 raw : bool
100 raw : bool
101 Are the data objects raw data or Python objects that need to be
101 Are the data objects raw data or Python objects that need to be
102 formatted before display? [default: False]
102 formatted before display? [default: False]
103 metadata : dict (optional)
103 metadata : dict (optional)
104 Metadata to be associated with the specific mimetype output.
104 Metadata to be associated with the specific mimetype output.
105 """
105 """
106 _display_mimetype('text/plain', objs, **kwargs)
106 _display_mimetype('text/plain', objs, **kwargs)
107
107
108
108
109 def display_html(*objs, **kwargs):
109 def display_html(*objs, **kwargs):
110 """Display the HTML representation of an object.
110 """Display the HTML representation of an object.
111
111
112 Note: If raw=False and the object does not have a HTML
112 Note: If raw=False and the object does not have a HTML
113 representation, no HTML will be shown.
113 representation, no HTML will be shown.
114
114
115 Parameters
115 Parameters
116 ----------
116 ----------
117 *objs : object
117 *objs : object
118 The Python objects to display, or if raw=True raw HTML data to
118 The Python objects to display, or if raw=True raw HTML data to
119 display.
119 display.
120 raw : bool
120 raw : bool
121 Are the data objects raw data or Python objects that need to be
121 Are the data objects raw data or Python objects that need to be
122 formatted before display? [default: False]
122 formatted before display? [default: False]
123 metadata : dict (optional)
123 metadata : dict (optional)
124 Metadata to be associated with the specific mimetype output.
124 Metadata to be associated with the specific mimetype output.
125 """
125 """
126 _display_mimetype('text/html', objs, **kwargs)
126 _display_mimetype('text/html', objs, **kwargs)
127
127
128
128
129 def display_markdown(*objs, **kwargs):
129 def display_markdown(*objs, **kwargs):
130 """Displays the Markdown representation of an object.
130 """Displays the Markdown representation of an object.
131
131
132 Parameters
132 Parameters
133 ----------
133 ----------
134 *objs : object
134 *objs : object
135 The Python objects to display, or if raw=True raw markdown data to
135 The Python objects to display, or if raw=True raw markdown data to
136 display.
136 display.
137 raw : bool
137 raw : bool
138 Are the data objects raw data or Python objects that need to be
138 Are the data objects raw data or Python objects that need to be
139 formatted before display? [default: False]
139 formatted before display? [default: False]
140 metadata : dict (optional)
140 metadata : dict (optional)
141 Metadata to be associated with the specific mimetype output.
141 Metadata to be associated with the specific mimetype output.
142 """
142 """
143
143
144 _display_mimetype('text/markdown', objs, **kwargs)
144 _display_mimetype('text/markdown', objs, **kwargs)
145
145
146
146
147 def display_svg(*objs, **kwargs):
147 def display_svg(*objs, **kwargs):
148 """Display the SVG representation of an object.
148 """Display the SVG representation of an object.
149
149
150 Parameters
150 Parameters
151 ----------
151 ----------
152 *objs : object
152 *objs : object
153 The Python objects to display, or if raw=True raw svg data to
153 The Python objects to display, or if raw=True raw svg data to
154 display.
154 display.
155 raw : bool
155 raw : bool
156 Are the data objects raw data or Python objects that need to be
156 Are the data objects raw data or Python objects that need to be
157 formatted before display? [default: False]
157 formatted before display? [default: False]
158 metadata : dict (optional)
158 metadata : dict (optional)
159 Metadata to be associated with the specific mimetype output.
159 Metadata to be associated with the specific mimetype output.
160 """
160 """
161 _display_mimetype('image/svg+xml', objs, **kwargs)
161 _display_mimetype('image/svg+xml', objs, **kwargs)
162
162
163
163
164 def display_png(*objs, **kwargs):
164 def display_png(*objs, **kwargs):
165 """Display the PNG representation of an object.
165 """Display the PNG representation of an object.
166
166
167 Parameters
167 Parameters
168 ----------
168 ----------
169 *objs : object
169 *objs : object
170 The Python objects to display, or if raw=True raw png data to
170 The Python objects to display, or if raw=True raw png data to
171 display.
171 display.
172 raw : bool
172 raw : bool
173 Are the data objects raw data or Python objects that need to be
173 Are the data objects raw data or Python objects that need to be
174 formatted before display? [default: False]
174 formatted before display? [default: False]
175 metadata : dict (optional)
175 metadata : dict (optional)
176 Metadata to be associated with the specific mimetype output.
176 Metadata to be associated with the specific mimetype output.
177 """
177 """
178 _display_mimetype('image/png', objs, **kwargs)
178 _display_mimetype('image/png', objs, **kwargs)
179
179
180
180
181 def display_jpeg(*objs, **kwargs):
181 def display_jpeg(*objs, **kwargs):
182 """Display the JPEG representation of an object.
182 """Display the JPEG representation of an object.
183
183
184 Parameters
184 Parameters
185 ----------
185 ----------
186 *objs : object
186 *objs : object
187 The Python objects to display, or if raw=True raw JPEG data to
187 The Python objects to display, or if raw=True raw JPEG data to
188 display.
188 display.
189 raw : bool
189 raw : bool
190 Are the data objects raw data or Python objects that need to be
190 Are the data objects raw data or Python objects that need to be
191 formatted before display? [default: False]
191 formatted before display? [default: False]
192 metadata : dict (optional)
192 metadata : dict (optional)
193 Metadata to be associated with the specific mimetype output.
193 Metadata to be associated with the specific mimetype output.
194 """
194 """
195 _display_mimetype('image/jpeg', objs, **kwargs)
195 _display_mimetype('image/jpeg', objs, **kwargs)
196
196
197
197
198 def display_latex(*objs, **kwargs):
198 def display_latex(*objs, **kwargs):
199 """Display the LaTeX representation of an object.
199 """Display the LaTeX representation of an object.
200
200
201 Parameters
201 Parameters
202 ----------
202 ----------
203 *objs : object
203 *objs : object
204 The Python objects to display, or if raw=True raw latex data to
204 The Python objects to display, or if raw=True raw latex data to
205 display.
205 display.
206 raw : bool
206 raw : bool
207 Are the data objects raw data or Python objects that need to be
207 Are the data objects raw data or Python objects that need to be
208 formatted before display? [default: False]
208 formatted before display? [default: False]
209 metadata : dict (optional)
209 metadata : dict (optional)
210 Metadata to be associated with the specific mimetype output.
210 Metadata to be associated with the specific mimetype output.
211 """
211 """
212 _display_mimetype('text/latex', objs, **kwargs)
212 _display_mimetype('text/latex', objs, **kwargs)
213
213
214
214
215 def display_json(*objs, **kwargs):
215 def display_json(*objs, **kwargs):
216 """Display the JSON representation of an object.
216 """Display the JSON representation of an object.
217
217
218 Note that not many frontends support displaying JSON.
218 Note that not many frontends support displaying JSON.
219
219
220 Parameters
220 Parameters
221 ----------
221 ----------
222 *objs : object
222 *objs : object
223 The Python objects to display, or if raw=True raw json data to
223 The Python objects to display, or if raw=True raw json data to
224 display.
224 display.
225 raw : bool
225 raw : bool
226 Are the data objects raw data or Python objects that need to be
226 Are the data objects raw data or Python objects that need to be
227 formatted before display? [default: False]
227 formatted before display? [default: False]
228 metadata : dict (optional)
228 metadata : dict (optional)
229 Metadata to be associated with the specific mimetype output.
229 Metadata to be associated with the specific mimetype output.
230 """
230 """
231 _display_mimetype('application/json', objs, **kwargs)
231 _display_mimetype('application/json', objs, **kwargs)
232
232
233
233
234 def display_javascript(*objs, **kwargs):
234 def display_javascript(*objs, **kwargs):
235 """Display the Javascript representation of an object.
235 """Display the Javascript representation of an object.
236
236
237 Parameters
237 Parameters
238 ----------
238 ----------
239 *objs : object
239 *objs : object
240 The Python objects to display, or if raw=True raw javascript data to
240 The Python objects to display, or if raw=True raw javascript data to
241 display.
241 display.
242 raw : bool
242 raw : bool
243 Are the data objects raw data or Python objects that need to be
243 Are the data objects raw data or Python objects that need to be
244 formatted before display? [default: False]
244 formatted before display? [default: False]
245 metadata : dict (optional)
245 metadata : dict (optional)
246 Metadata to be associated with the specific mimetype output.
246 Metadata to be associated with the specific mimetype output.
247 """
247 """
248 _display_mimetype('application/javascript', objs, **kwargs)
248 _display_mimetype('application/javascript', objs, **kwargs)
249
249
250
250
251 def display_pdf(*objs, **kwargs):
251 def display_pdf(*objs, **kwargs):
252 """Display the PDF representation of an object.
252 """Display the PDF representation of an object.
253
253
254 Parameters
254 Parameters
255 ----------
255 ----------
256 *objs : object
256 *objs : object
257 The Python objects to display, or if raw=True raw javascript data to
257 The Python objects to display, or if raw=True raw javascript data to
258 display.
258 display.
259 raw : bool
259 raw : bool
260 Are the data objects raw data or Python objects that need to be
260 Are the data objects raw data or Python objects that need to be
261 formatted before display? [default: False]
261 formatted before display? [default: False]
262 metadata : dict (optional)
262 metadata : dict (optional)
263 Metadata to be associated with the specific mimetype output.
263 Metadata to be associated with the specific mimetype output.
264 """
264 """
265 _display_mimetype('application/pdf', objs, **kwargs)
265 _display_mimetype('application/pdf', objs, **kwargs)
266
266
267
267
268 #-----------------------------------------------------------------------------
268 #-----------------------------------------------------------------------------
269 # Smart classes
269 # Smart classes
270 #-----------------------------------------------------------------------------
270 #-----------------------------------------------------------------------------
271
271
272
272
273 class DisplayObject(object):
273 class DisplayObject(object):
274 """An object that wraps data to be displayed."""
274 """An object that wraps data to be displayed."""
275
275
276 _read_flags = 'r'
276 _read_flags = 'r'
277 _show_mem_addr = False
277 _show_mem_addr = False
278 metadata = None
278 metadata = None
279
279
280 def __init__(self, data=None, url=None, filename=None, metadata=None):
280 def __init__(self, data=None, url=None, filename=None, metadata=None):
281 """Create a display object given raw data.
281 """Create a display object given raw data.
282
282
283 When this object is returned by an expression or passed to the
283 When this object is returned by an expression or passed to the
284 display function, it will result in the data being displayed
284 display function, it will result in the data being displayed
285 in the frontend. The MIME type of the data should match the
285 in the frontend. The MIME type of the data should match the
286 subclasses used, so the Png subclass should be used for 'image/png'
286 subclasses used, so the Png subclass should be used for 'image/png'
287 data. If the data is a URL, the data will first be downloaded
287 data. If the data is a URL, the data will first be downloaded
288 and then displayed. If
288 and then displayed. If
289
289
290 Parameters
290 Parameters
291 ----------
291 ----------
292 data : unicode, str or bytes
292 data : unicode, str or bytes
293 The raw data or a URL or file to load the data from
293 The raw data or a URL or file to load the data from
294 url : unicode
294 url : unicode
295 A URL to download the data from.
295 A URL to download the data from.
296 filename : unicode
296 filename : unicode
297 Path to a local file to load the data from.
297 Path to a local file to load the data from.
298 metadata : dict
298 metadata : dict
299 Dict of metadata associated to be the object when displayed
299 Dict of metadata associated to be the object when displayed
300 """
300 """
301 if isinstance(data, (Path, PurePath)):
301 if isinstance(data, (Path, PurePath)):
302 data = str(data)
302 data = str(data)
303
303
304 if data is not None and isinstance(data, str):
304 if data is not None and isinstance(data, str):
305 if data.startswith('http') and url is None:
305 if data.startswith('http') and url is None:
306 url = data
306 url = data
307 filename = None
307 filename = None
308 data = None
308 data = None
309 elif _safe_exists(data) and filename is None:
309 elif _safe_exists(data) and filename is None:
310 url = None
310 url = None
311 filename = data
311 filename = data
312 data = None
312 data = None
313
313
314 self.url = url
314 self.url = url
315 self.filename = filename
315 self.filename = filename
316 # because of @data.setter methods in
316 # because of @data.setter methods in
317 # subclasses ensure url and filename are set
317 # subclasses ensure url and filename are set
318 # before assigning to self.data
318 # before assigning to self.data
319 self.data = data
319 self.data = data
320
320
321 if metadata is not None:
321 if metadata is not None:
322 self.metadata = metadata
322 self.metadata = metadata
323 elif self.metadata is None:
323 elif self.metadata is None:
324 self.metadata = {}
324 self.metadata = {}
325
325
326 self.reload()
326 self.reload()
327 self._check_data()
327 self._check_data()
328
328
329 def __repr__(self):
329 def __repr__(self):
330 if not self._show_mem_addr:
330 if not self._show_mem_addr:
331 cls = self.__class__
331 cls = self.__class__
332 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
332 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
333 else:
333 else:
334 r = super(DisplayObject, self).__repr__()
334 r = super(DisplayObject, self).__repr__()
335 return r
335 return r
336
336
337 def _check_data(self):
337 def _check_data(self):
338 """Override in subclasses if there's something to check."""
338 """Override in subclasses if there's something to check."""
339 pass
339 pass
340
340
341 def _data_and_metadata(self):
341 def _data_and_metadata(self):
342 """shortcut for returning metadata with shape information, if defined"""
342 """shortcut for returning metadata with shape information, if defined"""
343 if self.metadata:
343 if self.metadata:
344 return self.data, deepcopy(self.metadata)
344 return self.data, deepcopy(self.metadata)
345 else:
345 else:
346 return self.data
346 return self.data
347
347
348 def reload(self):
348 def reload(self):
349 """Reload the raw data from file or URL."""
349 """Reload the raw data from file or URL."""
350 if self.filename is not None:
350 if self.filename is not None:
351 with open(self.filename, self._read_flags) as f:
351 with open(self.filename, self._read_flags) as f:
352 self.data = f.read()
352 self.data = f.read()
353 elif self.url is not None:
353 elif self.url is not None:
354 # Deferred import
354 # Deferred import
355 from urllib.request import urlopen
355 from urllib.request import urlopen
356 response = urlopen(self.url)
356 response = urlopen(self.url)
357 data = response.read()
357 data = response.read()
358 # extract encoding from header, if there is one:
358 # extract encoding from header, if there is one:
359 encoding = None
359 encoding = None
360 if 'content-type' in response.headers:
360 if 'content-type' in response.headers:
361 for sub in response.headers['content-type'].split(';'):
361 for sub in response.headers['content-type'].split(';'):
362 sub = sub.strip()
362 sub = sub.strip()
363 if sub.startswith('charset'):
363 if sub.startswith('charset'):
364 encoding = sub.split('=')[-1].strip()
364 encoding = sub.split('=')[-1].strip()
365 break
365 break
366 if 'content-encoding' in response.headers:
366 if 'content-encoding' in response.headers:
367 # TODO: do deflate?
367 # TODO: do deflate?
368 if 'gzip' in response.headers['content-encoding']:
368 if 'gzip' in response.headers['content-encoding']:
369 import gzip
369 import gzip
370 from io import BytesIO
370 from io import BytesIO
371 with gzip.open(BytesIO(data), 'rt', encoding=encoding) as fp:
371 with gzip.open(BytesIO(data), 'rt', encoding=encoding) as fp:
372 encoding = None
372 encoding = None
373 data = fp.read()
373 data = fp.read()
374
374
375 # decode data, if an encoding was specified
375 # decode data, if an encoding was specified
376 # We only touch self.data once since
376 # We only touch self.data once since
377 # subclasses such as SVG have @data.setter methods
377 # subclasses such as SVG have @data.setter methods
378 # that transform self.data into ... well svg.
378 # that transform self.data into ... well svg.
379 if encoding:
379 if encoding:
380 self.data = data.decode(encoding, 'replace')
380 self.data = data.decode(encoding, 'replace')
381 else:
381 else:
382 self.data = data
382 self.data = data
383
383
384
384
385 class TextDisplayObject(DisplayObject):
385 class TextDisplayObject(DisplayObject):
386 """Validate that display data is text"""
386 """Validate that display data is text"""
387 def _check_data(self):
387 def _check_data(self):
388 if self.data is not None and not isinstance(self.data, str):
388 if self.data is not None and not isinstance(self.data, str):
389 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
389 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
390
390
391 class Pretty(TextDisplayObject):
391 class Pretty(TextDisplayObject):
392
392
393 def _repr_pretty_(self, pp, cycle):
393 def _repr_pretty_(self, pp, cycle):
394 return pp.text(self.data)
394 return pp.text(self.data)
395
395
396
396
397 class HTML(TextDisplayObject):
397 class HTML(TextDisplayObject):
398
398
399 def __init__(self, data=None, url=None, filename=None, metadata=None):
399 def __init__(self, data=None, url=None, filename=None, metadata=None):
400 def warn():
400 def warn():
401 if not data:
401 if not data:
402 return False
402 return False
403
403
404 #
404 #
405 # Avoid calling lower() on the entire data, because it could be a
405 # Avoid calling lower() on the entire data, because it could be a
406 # long string and we're only interested in its beginning and end.
406 # long string and we're only interested in its beginning and end.
407 #
407 #
408 prefix = data[:10].lower()
408 prefix = data[:10].lower()
409 suffix = data[-10:].lower()
409 suffix = data[-10:].lower()
410 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
410 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
411
411
412 if warn():
412 if warn():
413 warnings.warn("Consider using IPython.display.IFrame instead")
413 warnings.warn("Consider using IPython.display.IFrame instead")
414 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
414 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
415
415
416 def _repr_html_(self):
416 def _repr_html_(self):
417 return self._data_and_metadata()
417 return self._data_and_metadata()
418
418
419 def __html__(self):
419 def __html__(self):
420 """
420 """
421 This method exists to inform other HTML-using modules (e.g. Markupsafe,
421 This method exists to inform other HTML-using modules (e.g. Markupsafe,
422 htmltag, etc) that this object is HTML and does not need things like
422 htmltag, etc) that this object is HTML and does not need things like
423 special characters (<>&) escaped.
423 special characters (<>&) escaped.
424 """
424 """
425 return self._repr_html_()
425 return self._repr_html_()
426
426
427
427
428 class Markdown(TextDisplayObject):
428 class Markdown(TextDisplayObject):
429
429
430 def _repr_markdown_(self):
430 def _repr_markdown_(self):
431 return self._data_and_metadata()
431 return self._data_and_metadata()
432
432
433
433
434 class Math(TextDisplayObject):
434 class Math(TextDisplayObject):
435
435
436 def _repr_latex_(self):
436 def _repr_latex_(self):
437 s = r"$\displaystyle %s$" % self.data.strip('$')
437 s = r"$\displaystyle %s$" % self.data.strip('$')
438 if self.metadata:
438 if self.metadata:
439 return s, deepcopy(self.metadata)
439 return s, deepcopy(self.metadata)
440 else:
440 else:
441 return s
441 return s
442
442
443
443
444 class Latex(TextDisplayObject):
444 class Latex(TextDisplayObject):
445
445
446 def _repr_latex_(self):
446 def _repr_latex_(self):
447 return self._data_and_metadata()
447 return self._data_and_metadata()
448
448
449
449
450 class SVG(DisplayObject):
450 class SVG(DisplayObject):
451 """Embed an SVG into the display.
451 """Embed an SVG into the display.
452
452
453 Note if you just want to view a svg image via a URL use `:class:Image` with
453 Note if you just want to view a svg image via a URL use `:class:Image` with
454 a url=URL keyword argument.
454 a url=URL keyword argument.
455 """
455 """
456
456
457 _read_flags = 'rb'
457 _read_flags = 'rb'
458 # wrap data in a property, which extracts the <svg> tag, discarding
458 # wrap data in a property, which extracts the <svg> tag, discarding
459 # document headers
459 # document headers
460 _data = None
460 _data = None
461
461
462 @property
462 @property
463 def data(self):
463 def data(self):
464 return self._data
464 return self._data
465
465
466 @data.setter
466 @data.setter
467 def data(self, svg):
467 def data(self, svg):
468 if svg is None:
468 if svg is None:
469 self._data = None
469 self._data = None
470 return
470 return
471 # parse into dom object
471 # parse into dom object
472 from xml.dom import minidom
472 from xml.dom import minidom
473 x = minidom.parseString(svg)
473 x = minidom.parseString(svg)
474 # get svg tag (should be 1)
474 # get svg tag (should be 1)
475 found_svg = x.getElementsByTagName('svg')
475 found_svg = x.getElementsByTagName('svg')
476 if found_svg:
476 if found_svg:
477 svg = found_svg[0].toxml()
477 svg = found_svg[0].toxml()
478 else:
478 else:
479 # fallback on the input, trust the user
479 # fallback on the input, trust the user
480 # but this is probably an error.
480 # but this is probably an error.
481 pass
481 pass
482 svg = cast_unicode(svg)
482 svg = cast_unicode(svg)
483 self._data = svg
483 self._data = svg
484
484
485 def _repr_svg_(self):
485 def _repr_svg_(self):
486 return self._data_and_metadata()
486 return self._data_and_metadata()
487
487
488 class ProgressBar(DisplayObject):
488 class ProgressBar(DisplayObject):
489 """Progressbar supports displaying a progressbar like element
489 """Progressbar supports displaying a progressbar like element
490 """
490 """
491 def __init__(self, total):
491 def __init__(self, total):
492 """Creates a new progressbar
492 """Creates a new progressbar
493
493
494 Parameters
494 Parameters
495 ----------
495 ----------
496 total : int
496 total : int
497 maximum size of the progressbar
497 maximum size of the progressbar
498 """
498 """
499 self.total = total
499 self.total = total
500 self._progress = 0
500 self._progress = 0
501 self.html_width = '60ex'
501 self.html_width = '60ex'
502 self.text_width = 60
502 self.text_width = 60
503 self._display_id = hexlify(os.urandom(8)).decode('ascii')
503 self._display_id = hexlify(os.urandom(8)).decode('ascii')
504
504
505 def __repr__(self):
505 def __repr__(self):
506 fraction = self.progress / self.total
506 fraction = self.progress / self.total
507 filled = '=' * int(fraction * self.text_width)
507 filled = '=' * int(fraction * self.text_width)
508 rest = ' ' * (self.text_width - len(filled))
508 rest = ' ' * (self.text_width - len(filled))
509 return '[{}{}] {}/{}'.format(
509 return '[{}{}] {}/{}'.format(
510 filled, rest,
510 filled, rest,
511 self.progress, self.total,
511 self.progress, self.total,
512 )
512 )
513
513
514 def _repr_html_(self):
514 def _repr_html_(self):
515 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
515 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
516 self.html_width, self.total, self.progress)
516 self.html_width, self.total, self.progress)
517
517
518 def display(self):
518 def display(self):
519 display(self, display_id=self._display_id)
519 display(self, display_id=self._display_id)
520
520
521 def update(self):
521 def update(self):
522 display(self, display_id=self._display_id, update=True)
522 display(self, display_id=self._display_id, update=True)
523
523
524 @property
524 @property
525 def progress(self):
525 def progress(self):
526 return self._progress
526 return self._progress
527
527
528 @progress.setter
528 @progress.setter
529 def progress(self, value):
529 def progress(self, value):
530 self._progress = value
530 self._progress = value
531 self.update()
531 self.update()
532
532
533 def __iter__(self):
533 def __iter__(self):
534 self.display()
534 self.display()
535 self._progress = -1 # First iteration is 0
535 self._progress = -1 # First iteration is 0
536 return self
536 return self
537
537
538 def __next__(self):
538 def __next__(self):
539 """Returns current value and increments display by one."""
539 """Returns current value and increments display by one."""
540 self.progress += 1
540 self.progress += 1
541 if self.progress < self.total:
541 if self.progress < self.total:
542 return self.progress
542 return self.progress
543 else:
543 else:
544 raise StopIteration()
544 raise StopIteration()
545
545
546 class JSON(DisplayObject):
546 class JSON(DisplayObject):
547 """JSON expects a JSON-able dict or list
547 """JSON expects a JSON-able dict or list
548
548
549 not an already-serialized JSON string.
549 not an already-serialized JSON string.
550
550
551 Scalar types (None, number, string) are not allowed, only dict or list containers.
551 Scalar types (None, number, string) are not allowed, only dict or list containers.
552 """
552 """
553 # wrap data in a property, which warns about passing already-serialized JSON
553 # wrap data in a property, which warns about passing already-serialized JSON
554 _data = None
554 _data = None
555 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
555 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
556 """Create a JSON display object given raw data.
556 """Create a JSON display object given raw data.
557
557
558 Parameters
558 Parameters
559 ----------
559 ----------
560 data : dict or list
560 data : dict or list
561 JSON data to display. Not an already-serialized JSON string.
561 JSON data to display. Not an already-serialized JSON string.
562 Scalar types (None, number, string) are not allowed, only dict
562 Scalar types (None, number, string) are not allowed, only dict
563 or list containers.
563 or list containers.
564 url : unicode
564 url : unicode
565 A URL to download the data from.
565 A URL to download the data from.
566 filename : unicode
566 filename : unicode
567 Path to a local file to load the data from.
567 Path to a local file to load the data from.
568 expanded : boolean
568 expanded : boolean
569 Metadata to control whether a JSON display component is expanded.
569 Metadata to control whether a JSON display component is expanded.
570 metadata : dict
570 metadata : dict
571 Specify extra metadata to attach to the json display object.
571 Specify extra metadata to attach to the json display object.
572 root : str
572 root : str
573 The name of the root element of the JSON tree
573 The name of the root element of the JSON tree
574 """
574 """
575 self.metadata = {
575 self.metadata = {
576 'expanded': expanded,
576 'expanded': expanded,
577 'root': root,
577 'root': root,
578 }
578 }
579 if metadata:
579 if metadata:
580 self.metadata.update(metadata)
580 self.metadata.update(metadata)
581 if kwargs:
581 if kwargs:
582 self.metadata.update(kwargs)
582 self.metadata.update(kwargs)
583 super(JSON, self).__init__(data=data, url=url, filename=filename)
583 super(JSON, self).__init__(data=data, url=url, filename=filename)
584
584
585 def _check_data(self):
585 def _check_data(self):
586 if self.data is not None and not isinstance(self.data, (dict, list)):
586 if self.data is not None and not isinstance(self.data, (dict, list)):
587 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
587 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
588
588
589 @property
589 @property
590 def data(self):
590 def data(self):
591 return self._data
591 return self._data
592
592
593 @data.setter
593 @data.setter
594 def data(self, data):
594 def data(self, data):
595 if isinstance(data, (Path, PurePath)):
595 if isinstance(data, (Path, PurePath)):
596 data = str(data)
596 data = str(data)
597
597
598 if isinstance(data, str):
598 if isinstance(data, str):
599 if self.filename is None and self.url is None:
599 if self.filename is None and self.url is None:
600 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
600 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
601 data = json.loads(data)
601 data = json.loads(data)
602 self._data = data
602 self._data = data
603
603
604 def _data_and_metadata(self):
604 def _data_and_metadata(self):
605 return self.data, self.metadata
605 return self.data, self.metadata
606
606
607 def _repr_json_(self):
607 def _repr_json_(self):
608 return self._data_and_metadata()
608 return self._data_and_metadata()
609
609
610 _css_t = """var link = document.createElement("link");
610 _css_t = """var link = document.createElement("link");
611 link.ref = "stylesheet";
611 link.ref = "stylesheet";
612 link.type = "text/css";
612 link.type = "text/css";
613 link.href = "%s";
613 link.href = "%s";
614 document.head.appendChild(link);
614 document.head.appendChild(link);
615 """
615 """
616
616
617 _lib_t1 = """new Promise(function(resolve, reject) {
617 _lib_t1 = """new Promise(function(resolve, reject) {
618 var script = document.createElement("script");
618 var script = document.createElement("script");
619 script.onload = resolve;
619 script.onload = resolve;
620 script.onerror = reject;
620 script.onerror = reject;
621 script.src = "%s";
621 script.src = "%s";
622 document.head.appendChild(script);
622 document.head.appendChild(script);
623 }).then(() => {
623 }).then(() => {
624 """
624 """
625
625
626 _lib_t2 = """
626 _lib_t2 = """
627 });"""
627 });"""
628
628
629 class GeoJSON(JSON):
629 class GeoJSON(JSON):
630 """GeoJSON expects JSON-able dict
630 """GeoJSON expects JSON-able dict
631
631
632 not an already-serialized JSON string.
632 not an already-serialized JSON string.
633
633
634 Scalar types (None, number, string) are not allowed, only dict containers.
634 Scalar types (None, number, string) are not allowed, only dict containers.
635 """
635 """
636
636
637 def __init__(self, *args, **kwargs):
637 def __init__(self, *args, **kwargs):
638 """Create a GeoJSON display object given raw data.
638 """Create a GeoJSON display object given raw data.
639
639
640 Parameters
640 Parameters
641 ----------
641 ----------
642 data : dict or list
642 data : dict or list
643 VegaLite data. Not an already-serialized JSON string.
643 VegaLite data. Not an already-serialized JSON string.
644 Scalar types (None, number, string) are not allowed, only dict
644 Scalar types (None, number, string) are not allowed, only dict
645 or list containers.
645 or list containers.
646 url_template : string
646 url_template : string
647 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
647 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
648 layer_options : dict
648 layer_options : dict
649 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
649 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
650 url : unicode
650 url : unicode
651 A URL to download the data from.
651 A URL to download the data from.
652 filename : unicode
652 filename : unicode
653 Path to a local file to load the data from.
653 Path to a local file to load the data from.
654 metadata : dict
654 metadata : dict
655 Specify extra metadata to attach to the json display object.
655 Specify extra metadata to attach to the json display object.
656
656
657 Examples
657 Examples
658 --------
658 --------
659 The following will display an interactive map of Mars with a point of
659 The following will display an interactive map of Mars with a point of
660 interest on frontend that do support GeoJSON display.
660 interest on frontend that do support GeoJSON display.
661
661
662 >>> from IPython.display import GeoJSON
662 >>> from IPython.display import GeoJSON
663
663
664 >>> GeoJSON(data={
664 >>> GeoJSON(data={
665 ... "type": "Feature",
665 ... "type": "Feature",
666 ... "geometry": {
666 ... "geometry": {
667 ... "type": "Point",
667 ... "type": "Point",
668 ... "coordinates": [-81.327, 296.038]
668 ... "coordinates": [-81.327, 296.038]
669 ... }
669 ... }
670 ... },
670 ... },
671 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
671 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
672 ... layer_options={
672 ... layer_options={
673 ... "basemap_id": "celestia_mars-shaded-16k_global",
673 ... "basemap_id": "celestia_mars-shaded-16k_global",
674 ... "attribution" : "Celestia/praesepe",
674 ... "attribution" : "Celestia/praesepe",
675 ... "minZoom" : 0,
675 ... "minZoom" : 0,
676 ... "maxZoom" : 18,
676 ... "maxZoom" : 18,
677 ... })
677 ... })
678 <IPython.core.display.GeoJSON object>
678 <IPython.core.display.GeoJSON object>
679
679
680 In the terminal IPython, you will only see the text representation of
680 In the terminal IPython, you will only see the text representation of
681 the GeoJSON object.
681 the GeoJSON object.
682
682
683 """
683 """
684
684
685 super(GeoJSON, self).__init__(*args, **kwargs)
685 super(GeoJSON, self).__init__(*args, **kwargs)
686
686
687
687
688 def _ipython_display_(self):
688 def _ipython_display_(self):
689 bundle = {
689 bundle = {
690 'application/geo+json': self.data,
690 'application/geo+json': self.data,
691 'text/plain': '<IPython.display.GeoJSON object>'
691 'text/plain': '<IPython.display.GeoJSON object>'
692 }
692 }
693 metadata = {
693 metadata = {
694 'application/geo+json': self.metadata
694 'application/geo+json': self.metadata
695 }
695 }
696 display(bundle, metadata=metadata, raw=True)
696 display(bundle, metadata=metadata, raw=True)
697
697
698 class Javascript(TextDisplayObject):
698 class Javascript(TextDisplayObject):
699
699
700 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
700 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
701 """Create a Javascript display object given raw data.
701 """Create a Javascript display object given raw data.
702
702
703 When this object is returned by an expression or passed to the
703 When this object is returned by an expression or passed to the
704 display function, it will result in the data being displayed
704 display function, it will result in the data being displayed
705 in the frontend. If the data is a URL, the data will first be
705 in the frontend. If the data is a URL, the data will first be
706 downloaded and then displayed.
706 downloaded and then displayed.
707
707
708 In the Notebook, the containing element will be available as `element`,
708 In the Notebook, the containing element will be available as `element`,
709 and jQuery will be available. Content appended to `element` will be
709 and jQuery will be available. Content appended to `element` will be
710 visible in the output area.
710 visible in the output area.
711
711
712 Parameters
712 Parameters
713 ----------
713 ----------
714 data : unicode, str or bytes
714 data : unicode, str or bytes
715 The Javascript source code or a URL to download it from.
715 The Javascript source code or a URL to download it from.
716 url : unicode
716 url : unicode
717 A URL to download the data from.
717 A URL to download the data from.
718 filename : unicode
718 filename : unicode
719 Path to a local file to load the data from.
719 Path to a local file to load the data from.
720 lib : list or str
720 lib : list or str
721 A sequence of Javascript library URLs to load asynchronously before
721 A sequence of Javascript library URLs to load asynchronously before
722 running the source code. The full URLs of the libraries should
722 running the source code. The full URLs of the libraries should
723 be given. A single Javascript library URL can also be given as a
723 be given. A single Javascript library URL can also be given as a
724 string.
724 string.
725 css : list or str
725 css : list or str
726 A sequence of css files to load before running the source code.
726 A sequence of css files to load before running the source code.
727 The full URLs of the css files should be given. A single css URL
727 The full URLs of the css files should be given. A single css URL
728 can also be given as a string.
728 can also be given as a string.
729 """
729 """
730 if isinstance(lib, str):
730 if isinstance(lib, str):
731 lib = [lib]
731 lib = [lib]
732 elif lib is None:
732 elif lib is None:
733 lib = []
733 lib = []
734 if isinstance(css, str):
734 if isinstance(css, str):
735 css = [css]
735 css = [css]
736 elif css is None:
736 elif css is None:
737 css = []
737 css = []
738 if not isinstance(lib, (list,tuple)):
738 if not isinstance(lib, (list,tuple)):
739 raise TypeError('expected sequence, got: %r' % lib)
739 raise TypeError('expected sequence, got: %r' % lib)
740 if not isinstance(css, (list,tuple)):
740 if not isinstance(css, (list,tuple)):
741 raise TypeError('expected sequence, got: %r' % css)
741 raise TypeError('expected sequence, got: %r' % css)
742 self.lib = lib
742 self.lib = lib
743 self.css = css
743 self.css = css
744 super(Javascript, self).__init__(data=data, url=url, filename=filename)
744 super(Javascript, self).__init__(data=data, url=url, filename=filename)
745
745
746 def _repr_javascript_(self):
746 def _repr_javascript_(self):
747 r = ''
747 r = ''
748 for c in self.css:
748 for c in self.css:
749 r += _css_t % c
749 r += _css_t % c
750 for l in self.lib:
750 for l in self.lib:
751 r += _lib_t1 % l
751 r += _lib_t1 % l
752 r += self.data
752 r += self.data
753 r += _lib_t2*len(self.lib)
753 r += _lib_t2*len(self.lib)
754 return r
754 return r
755
755
756 # constants for identifying png/jpeg data
756 # constants for identifying png/jpeg data
757 _PNG = b'\x89PNG\r\n\x1a\n'
757 _PNG = b'\x89PNG\r\n\x1a\n'
758 _JPEG = b'\xff\xd8'
758 _JPEG = b'\xff\xd8'
759
759
760 def _pngxy(data):
760 def _pngxy(data):
761 """read the (width, height) from a PNG header"""
761 """read the (width, height) from a PNG header"""
762 ihdr = data.index(b'IHDR')
762 ihdr = data.index(b'IHDR')
763 # next 8 bytes are width/height
763 # next 8 bytes are width/height
764 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
764 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
765
765
766 def _jpegxy(data):
766 def _jpegxy(data):
767 """read the (width, height) from a JPEG header"""
767 """read the (width, height) from a JPEG header"""
768 # adapted from http://www.64lines.com/jpeg-width-height
768 # adapted from http://www.64lines.com/jpeg-width-height
769
769
770 idx = 4
770 idx = 4
771 while True:
771 while True:
772 block_size = struct.unpack('>H', data[idx:idx+2])[0]
772 block_size = struct.unpack('>H', data[idx:idx+2])[0]
773 idx = idx + block_size
773 idx = idx + block_size
774 if data[idx:idx+2] == b'\xFF\xC0':
774 if data[idx:idx+2] == b'\xFF\xC0':
775 # found Start of Frame
775 # found Start of Frame
776 iSOF = idx
776 iSOF = idx
777 break
777 break
778 else:
778 else:
779 # read another block
779 # read another block
780 idx += 2
780 idx += 2
781
781
782 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
782 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
783 return w, h
783 return w, h
784
784
785 def _gifxy(data):
785 def _gifxy(data):
786 """read the (width, height) from a GIF header"""
786 """read the (width, height) from a GIF header"""
787 return struct.unpack('<HH', data[6:10])
787 return struct.unpack('<HH', data[6:10])
788
788
789
789
790 class Image(DisplayObject):
790 class Image(DisplayObject):
791
791
792 _read_flags = 'rb'
792 _read_flags = 'rb'
793 _FMT_JPEG = u'jpeg'
793 _FMT_JPEG = u'jpeg'
794 _FMT_PNG = u'png'
794 _FMT_PNG = u'png'
795 _FMT_GIF = u'gif'
795 _FMT_GIF = u'gif'
796 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
796 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
797 _MIMETYPES = {
797 _MIMETYPES = {
798 _FMT_PNG: 'image/png',
798 _FMT_PNG: 'image/png',
799 _FMT_JPEG: 'image/jpeg',
799 _FMT_JPEG: 'image/jpeg',
800 _FMT_GIF: 'image/gif',
800 _FMT_GIF: 'image/gif',
801 }
801 }
802
802
803 def __init__(self, data=None, url=None, filename=None, format=None,
803 def __init__(self, data=None, url=None, filename=None, format=None,
804 embed=None, width=None, height=None, retina=False,
804 embed=None, width=None, height=None, retina=False,
805 unconfined=False, metadata=None):
805 unconfined=False, metadata=None):
806 """Create a PNG/JPEG/GIF image object given raw data.
806 """Create a PNG/JPEG/GIF image object given raw data.
807
807
808 When this object is returned by an input cell or passed to the
808 When this object is returned by an input cell or passed to the
809 display function, it will result in the image being displayed
809 display function, it will result in the image being displayed
810 in the frontend.
810 in the frontend.
811
811
812 Parameters
812 Parameters
813 ----------
813 ----------
814 data : unicode, str or bytes
814 data : unicode, str or bytes
815 The raw image data or a URL or filename to load the data from.
815 The raw image data or a URL or filename to load the data from.
816 This always results in embedded image data.
816 This always results in embedded image data.
817 url : unicode
817 url : unicode
818 A URL to download the data from. If you specify `url=`,
818 A URL to download the data from. If you specify `url=`,
819 the image data will not be embedded unless you also specify `embed=True`.
819 the image data will not be embedded unless you also specify `embed=True`.
820 filename : unicode
820 filename : unicode
821 Path to a local file to load the data from.
821 Path to a local file to load the data from.
822 Images from a file are always embedded.
822 Images from a file are always embedded.
823 format : unicode
823 format : unicode
824 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
824 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
825 for format will be inferred from the filename extension.
825 for format will be inferred from the filename extension.
826 embed : bool
826 embed : bool
827 Should the image data be embedded using a data URI (True) or be
827 Should the image data be embedded using a data URI (True) or be
828 loaded using an <img> tag. Set this to True if you want the image
828 loaded using an <img> tag. Set this to True if you want the image
829 to be viewable later with no internet connection in the notebook.
829 to be viewable later with no internet connection in the notebook.
830
830
831 Default is `True`, unless the keyword argument `url` is set, then
831 Default is `True`, unless the keyword argument `url` is set, then
832 default value is `False`.
832 default value is `False`.
833
833
834 Note that QtConsole is not able to display images if `embed` is set to `False`
834 Note that QtConsole is not able to display images if `embed` is set to `False`
835 width : int
835 width : int
836 Width in pixels to which to constrain the image in html
836 Width in pixels to which to constrain the image in html
837 height : int
837 height : int
838 Height in pixels to which to constrain the image in html
838 Height in pixels to which to constrain the image in html
839 retina : bool
839 retina : bool
840 Automatically set the width and height to half of the measured
840 Automatically set the width and height to half of the measured
841 width and height.
841 width and height.
842 This only works for embedded images because it reads the width/height
842 This only works for embedded images because it reads the width/height
843 from image data.
843 from image data.
844 For non-embedded images, you can just set the desired display width
844 For non-embedded images, you can just set the desired display width
845 and height directly.
845 and height directly.
846 unconfined : bool
846 unconfined : bool
847 Set unconfined=True to disable max-width confinement of the image.
847 Set unconfined=True to disable max-width confinement of the image.
848 metadata : dict
848 metadata : dict
849 Specify extra metadata to attach to the image.
849 Specify extra metadata to attach to the image.
850
850
851 Examples
851 Examples
852 --------
852 --------
853 embedded image data, works in qtconsole and notebook
853 embedded image data, works in qtconsole and notebook
854 when passed positionally, the first arg can be any of raw image data,
854 when passed positionally, the first arg can be any of raw image data,
855 a URL, or a filename from which to load image data.
855 a URL, or a filename from which to load image data.
856 The result is always embedding image data for inline images.
856 The result is always embedding image data for inline images.
857
857
858 >>> Image('http://www.google.fr/images/srpr/logo3w.png')
858 >>> Image('http://www.google.fr/images/srpr/logo3w.png')
859 <IPython.core.display.Image object>
859 <IPython.core.display.Image object>
860
860
861 >>> Image('/path/to/image.jpg')
861 >>> Image('/path/to/image.jpg')
862 <IPython.core.display.Image object>
862 <IPython.core.display.Image object>
863
863
864 >>> Image(b'RAW_PNG_DATA...')
864 >>> Image(b'RAW_PNG_DATA...')
865 <IPython.core.display.Image object>
865 <IPython.core.display.Image object>
866
866
867 Specifying Image(url=...) does not embed the image data,
867 Specifying Image(url=...) does not embed the image data,
868 it only generates ``<img>`` tag with a link to the source.
868 it only generates ``<img>`` tag with a link to the source.
869 This will not work in the qtconsole or offline.
869 This will not work in the qtconsole or offline.
870
870
871 >>> Image(url='http://www.google.fr/images/srpr/logo3w.png')
871 >>> Image(url='http://www.google.fr/images/srpr/logo3w.png')
872 <IPython.core.display.Image object>
872 <IPython.core.display.Image object>
873
873
874 """
874 """
875 if isinstance(data, (Path, PurePath)):
875 if isinstance(data, (Path, PurePath)):
876 data = str(data)
876 data = str(data)
877
877
878 if filename is not None:
878 if filename is not None:
879 ext = self._find_ext(filename)
879 ext = self._find_ext(filename)
880 elif url is not None:
880 elif url is not None:
881 ext = self._find_ext(url)
881 ext = self._find_ext(url)
882 elif data is None:
882 elif data is None:
883 raise ValueError("No image data found. Expecting filename, url, or data.")
883 raise ValueError("No image data found. Expecting filename, url, or data.")
884 elif isinstance(data, str) and (
884 elif isinstance(data, str) and (
885 data.startswith('http') or _safe_exists(data)
885 data.startswith('http') or _safe_exists(data)
886 ):
886 ):
887 ext = self._find_ext(data)
887 ext = self._find_ext(data)
888 else:
888 else:
889 ext = None
889 ext = None
890
890
891 if format is None:
891 if format is None:
892 if ext is not None:
892 if ext is not None:
893 if ext == u'jpg' or ext == u'jpeg':
893 if ext == u'jpg' or ext == u'jpeg':
894 format = self._FMT_JPEG
894 format = self._FMT_JPEG
895 elif ext == u'png':
895 elif ext == u'png':
896 format = self._FMT_PNG
896 format = self._FMT_PNG
897 elif ext == u'gif':
897 elif ext == u'gif':
898 format = self._FMT_GIF
898 format = self._FMT_GIF
899 else:
899 else:
900 format = ext.lower()
900 format = ext.lower()
901 elif isinstance(data, bytes):
901 elif isinstance(data, bytes):
902 # infer image type from image data header,
902 # infer image type from image data header,
903 # only if format has not been specified.
903 # only if format has not been specified.
904 if data[:2] == _JPEG:
904 if data[:2] == _JPEG:
905 format = self._FMT_JPEG
905 format = self._FMT_JPEG
906
906
907 # failed to detect format, default png
907 # failed to detect format, default png
908 if format is None:
908 if format is None:
909 format = self._FMT_PNG
909 format = self._FMT_PNG
910
910
911 if format.lower() == 'jpg':
911 if format.lower() == 'jpg':
912 # jpg->jpeg
912 # jpg->jpeg
913 format = self._FMT_JPEG
913 format = self._FMT_JPEG
914
914
915 self.format = format.lower()
915 self.format = format.lower()
916 self.embed = embed if embed is not None else (url is None)
916 self.embed = embed if embed is not None else (url is None)
917
917
918 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
918 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
919 raise ValueError("Cannot embed the '%s' image format" % (self.format))
919 raise ValueError("Cannot embed the '%s' image format" % (self.format))
920 if self.embed:
920 if self.embed:
921 self._mimetype = self._MIMETYPES.get(self.format)
921 self._mimetype = self._MIMETYPES.get(self.format)
922
922
923 self.width = width
923 self.width = width
924 self.height = height
924 self.height = height
925 self.retina = retina
925 self.retina = retina
926 self.unconfined = unconfined
926 self.unconfined = unconfined
927 super(Image, self).__init__(data=data, url=url, filename=filename,
927 super(Image, self).__init__(data=data, url=url, filename=filename,
928 metadata=metadata)
928 metadata=metadata)
929
929
930 if self.width is None and self.metadata.get('width', {}):
930 if self.width is None and self.metadata.get('width', {}):
931 self.width = metadata['width']
931 self.width = metadata['width']
932
932
933 if self.height is None and self.metadata.get('height', {}):
933 if self.height is None and self.metadata.get('height', {}):
934 self.height = metadata['height']
934 self.height = metadata['height']
935
935
936 if retina:
936 if retina:
937 self._retina_shape()
937 self._retina_shape()
938
938
939
939
940 def _retina_shape(self):
940 def _retina_shape(self):
941 """load pixel-doubled width and height from image data"""
941 """load pixel-doubled width and height from image data"""
942 if not self.embed:
942 if not self.embed:
943 return
943 return
944 if self.format == self._FMT_PNG:
944 if self.format == self._FMT_PNG:
945 w, h = _pngxy(self.data)
945 w, h = _pngxy(self.data)
946 elif self.format == self._FMT_JPEG:
946 elif self.format == self._FMT_JPEG:
947 w, h = _jpegxy(self.data)
947 w, h = _jpegxy(self.data)
948 elif self.format == self._FMT_GIF:
948 elif self.format == self._FMT_GIF:
949 w, h = _gifxy(self.data)
949 w, h = _gifxy(self.data)
950 else:
950 else:
951 # retina only supports png
951 # retina only supports png
952 return
952 return
953 self.width = w // 2
953 self.width = w // 2
954 self.height = h // 2
954 self.height = h // 2
955
955
956 def reload(self):
956 def reload(self):
957 """Reload the raw data from file or URL."""
957 """Reload the raw data from file or URL."""
958 if self.embed:
958 if self.embed:
959 super(Image,self).reload()
959 super(Image,self).reload()
960 if self.retina:
960 if self.retina:
961 self._retina_shape()
961 self._retina_shape()
962
962
963 def _repr_html_(self):
963 def _repr_html_(self):
964 if not self.embed:
964 if not self.embed:
965 width = height = klass = ''
965 width = height = klass = ''
966 if self.width:
966 if self.width:
967 width = ' width="%d"' % self.width
967 width = ' width="%d"' % self.width
968 if self.height:
968 if self.height:
969 height = ' height="%d"' % self.height
969 height = ' height="%d"' % self.height
970 if self.unconfined:
970 if self.unconfined:
971 klass = ' class="unconfined"'
971 klass = ' class="unconfined"'
972 return u'<img src="{url}"{width}{height}{klass}/>'.format(
972 return u'<img src="{url}"{width}{height}{klass}/>'.format(
973 url=self.url,
973 url=self.url,
974 width=width,
974 width=width,
975 height=height,
975 height=height,
976 klass=klass,
976 klass=klass,
977 )
977 )
978
978
979 def _repr_mimebundle_(self, include=None, exclude=None):
979 def _repr_mimebundle_(self, include=None, exclude=None):
980 """Return the image as a mimebundle
980 """Return the image as a mimebundle
981
981
982 Any new mimetype support should be implemented here.
982 Any new mimetype support should be implemented here.
983 """
983 """
984 if self.embed:
984 if self.embed:
985 mimetype = self._mimetype
985 mimetype = self._mimetype
986 data, metadata = self._data_and_metadata(always_both=True)
986 data, metadata = self._data_and_metadata(always_both=True)
987 if metadata:
987 if metadata:
988 metadata = {mimetype: metadata}
988 metadata = {mimetype: metadata}
989 return {mimetype: data}, metadata
989 return {mimetype: data}, metadata
990 else:
990 else:
991 return {'text/html': self._repr_html_()}
991 return {'text/html': self._repr_html_()}
992
992
993 def _data_and_metadata(self, always_both=False):
993 def _data_and_metadata(self, always_both=False):
994 """shortcut for returning metadata with shape information, if defined"""
994 """shortcut for returning metadata with shape information, if defined"""
995 try:
995 try:
996 b64_data = b2a_base64(self.data).decode('ascii')
996 b64_data = b2a_base64(self.data).decode('ascii')
997 except TypeError as e:
997 except TypeError as e:
998 raise FileNotFoundError(
998 raise FileNotFoundError(
999 "No such file or directory: '%s'" % (self.data)) from e
999 "No such file or directory: '%s'" % (self.data)) from e
1000 md = {}
1000 md = {}
1001 if self.metadata:
1001 if self.metadata:
1002 md.update(self.metadata)
1002 md.update(self.metadata)
1003 if self.width:
1003 if self.width:
1004 md['width'] = self.width
1004 md['width'] = self.width
1005 if self.height:
1005 if self.height:
1006 md['height'] = self.height
1006 md['height'] = self.height
1007 if self.unconfined:
1007 if self.unconfined:
1008 md['unconfined'] = self.unconfined
1008 md['unconfined'] = self.unconfined
1009 if md or always_both:
1009 if md or always_both:
1010 return b64_data, md
1010 return b64_data, md
1011 else:
1011 else:
1012 return b64_data
1012 return b64_data
1013
1013
1014 def _repr_png_(self):
1014 def _repr_png_(self):
1015 if self.embed and self.format == self._FMT_PNG:
1015 if self.embed and self.format == self._FMT_PNG:
1016 return self._data_and_metadata()
1016 return self._data_and_metadata()
1017
1017
1018 def _repr_jpeg_(self):
1018 def _repr_jpeg_(self):
1019 if self.embed and self.format == self._FMT_JPEG:
1019 if self.embed and self.format == self._FMT_JPEG:
1020 return self._data_and_metadata()
1020 return self._data_and_metadata()
1021
1021
1022 def _find_ext(self, s):
1022 def _find_ext(self, s):
1023 base, ext = splitext(s)
1023 base, ext = splitext(s)
1024
1024
1025 if not ext:
1025 if not ext:
1026 return base
1026 return base
1027
1027
1028 # `splitext` includes leading period, so we skip it
1028 # `splitext` includes leading period, so we skip it
1029 return ext[1:].lower()
1029 return ext[1:].lower()
1030
1030
1031
1031
1032 class Video(DisplayObject):
1032 class Video(DisplayObject):
1033
1033
1034 def __init__(self, data=None, url=None, filename=None, embed=False,
1034 def __init__(self, data=None, url=None, filename=None, embed=False,
1035 mimetype=None, width=None, height=None, html_attributes="controls"):
1035 mimetype=None, width=None, height=None, html_attributes="controls"):
1036 """Create a video object given raw data or an URL.
1036 """Create a video object given raw data or an URL.
1037
1037
1038 When this object is returned by an input cell or passed to the
1038 When this object is returned by an input cell or passed to the
1039 display function, it will result in the video being displayed
1039 display function, it will result in the video being displayed
1040 in the frontend.
1040 in the frontend.
1041
1041
1042 Parameters
1042 Parameters
1043 ----------
1043 ----------
1044 data : unicode, str or bytes
1044 data : unicode, str or bytes
1045 The raw video data or a URL or filename to load the data from.
1045 The raw video data or a URL or filename to load the data from.
1046 Raw data will require passing `embed=True`.
1046 Raw data will require passing ``embed=True``.
1047 url : unicode
1047 url : unicode
1048 A URL for the video. If you specify `url=`,
1048 A URL for the video. If you specify ``url=``,
1049 the image data will not be embedded.
1049 the image data will not be embedded.
1050 filename : unicode
1050 filename : unicode
1051 Path to a local file containing the video.
1051 Path to a local file containing the video.
1052 Will be interpreted as a local URL unless `embed=True`.
1052 Will be interpreted as a local URL unless ``embed=True``.
1053 embed : bool
1053 embed : bool
1054 Should the video be embedded using a data URI (True) or be
1054 Should the video be embedded using a data URI (True) or be
1055 loaded using a <video> tag (False).
1055 loaded using a <video> tag (False).
1056
1056
1057 Since videos are large, embedding them should be avoided, if possible.
1057 Since videos are large, embedding them should be avoided, if possible.
1058 You must confirm embedding as your intention by passing `embed=True`.
1058 You must confirm embedding as your intention by passing ``embed=True``.
1059
1059
1060 Local files can be displayed with URLs without embedding the content, via::
1060 Local files can be displayed with URLs without embedding the content, via::
1061
1061
1062 Video('./video.mp4')
1062 Video('./video.mp4')
1063 mimetype : unicode
1063 mimetype : unicode
1064 Specify the mimetype for embedded videos.
1064 Specify the mimetype for embedded videos.
1065 Default will be guessed from file extension, if available.
1065 Default will be guessed from file extension, if available.
1066 width : int
1066 width : int
1067 Width in pixels to which to constrain the video in HTML.
1067 Width in pixels to which to constrain the video in HTML.
1068 If not supplied, defaults to the width of the video.
1068 If not supplied, defaults to the width of the video.
1069 height : int
1069 height : int
1070 Height in pixels to which to constrain the video in html.
1070 Height in pixels to which to constrain the video in html.
1071 If not supplied, defaults to the height of the video.
1071 If not supplied, defaults to the height of the video.
1072 html_attributes : str
1072 html_attributes : str
1073 Attributes for the HTML `<video>` block.
1073 Attributes for the HTML ``<video>`` block.
1074 Default: `"controls"` to get video controls.
1074 Default: ``"controls"`` to get video controls.
1075 Other examples: `"controls muted"` for muted video with controls,
1075 Other examples: ``"controls muted"`` for muted video with controls,
1076 `"loop autoplay"` for looping autoplaying video without controls.
1076 ``"loop autoplay"`` for looping autoplaying video without controls.
1077
1077
1078 Examples
1078 Examples
1079 --------
1079 --------
1080 ::
1080 ::
1081
1081
1082 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1082 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1083 Video('path/to/video.mp4')
1083 Video('path/to/video.mp4')
1084 Video('path/to/video.mp4', embed=True)
1084 Video('path/to/video.mp4', embed=True)
1085 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1085 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1086 Video(b'raw-videodata', embed=True)
1086 Video(b'raw-videodata', embed=True)
1087 """
1087 """
1088 if isinstance(data, (Path, PurePath)):
1088 if isinstance(data, (Path, PurePath)):
1089 data = str(data)
1089 data = str(data)
1090
1090
1091 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1091 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1092 url = data
1092 url = data
1093 data = None
1093 data = None
1094 elif data is not None and os.path.exists(data):
1094 elif data is not None and os.path.exists(data):
1095 filename = data
1095 filename = data
1096 data = None
1096 data = None
1097
1097
1098 if data and not embed:
1098 if data and not embed:
1099 msg = ''.join([
1099 msg = ''.join([
1100 "To embed videos, you must pass embed=True ",
1100 "To embed videos, you must pass embed=True ",
1101 "(this may make your notebook files huge)\n",
1101 "(this may make your notebook files huge)\n",
1102 "Consider passing Video(url='...')",
1102 "Consider passing Video(url='...')",
1103 ])
1103 ])
1104 raise ValueError(msg)
1104 raise ValueError(msg)
1105
1105
1106 self.mimetype = mimetype
1106 self.mimetype = mimetype
1107 self.embed = embed
1107 self.embed = embed
1108 self.width = width
1108 self.width = width
1109 self.height = height
1109 self.height = height
1110 self.html_attributes = html_attributes
1110 self.html_attributes = html_attributes
1111 super(Video, self).__init__(data=data, url=url, filename=filename)
1111 super(Video, self).__init__(data=data, url=url, filename=filename)
1112
1112
1113 def _repr_html_(self):
1113 def _repr_html_(self):
1114 width = height = ''
1114 width = height = ''
1115 if self.width:
1115 if self.width:
1116 width = ' width="%d"' % self.width
1116 width = ' width="%d"' % self.width
1117 if self.height:
1117 if self.height:
1118 height = ' height="%d"' % self.height
1118 height = ' height="%d"' % self.height
1119
1119
1120 # External URLs and potentially local files are not embedded into the
1120 # External URLs and potentially local files are not embedded into the
1121 # notebook output.
1121 # notebook output.
1122 if not self.embed:
1122 if not self.embed:
1123 url = self.url if self.url is not None else self.filename
1123 url = self.url if self.url is not None else self.filename
1124 output = """<video src="{0}" {1} {2} {3}>
1124 output = """<video src="{0}" {1} {2} {3}>
1125 Your browser does not support the <code>video</code> element.
1125 Your browser does not support the <code>video</code> element.
1126 </video>""".format(url, self.html_attributes, width, height)
1126 </video>""".format(url, self.html_attributes, width, height)
1127 return output
1127 return output
1128
1128
1129 # Embedded videos are base64-encoded.
1129 # Embedded videos are base64-encoded.
1130 mimetype = self.mimetype
1130 mimetype = self.mimetype
1131 if self.filename is not None:
1131 if self.filename is not None:
1132 if not mimetype:
1132 if not mimetype:
1133 mimetype, _ = mimetypes.guess_type(self.filename)
1133 mimetype, _ = mimetypes.guess_type(self.filename)
1134
1134
1135 with open(self.filename, 'rb') as f:
1135 with open(self.filename, 'rb') as f:
1136 video = f.read()
1136 video = f.read()
1137 else:
1137 else:
1138 video = self.data
1138 video = self.data
1139 if isinstance(video, str):
1139 if isinstance(video, str):
1140 # unicode input is already b64-encoded
1140 # unicode input is already b64-encoded
1141 b64_video = video
1141 b64_video = video
1142 else:
1142 else:
1143 b64_video = b2a_base64(video).decode('ascii').rstrip()
1143 b64_video = b2a_base64(video).decode('ascii').rstrip()
1144
1144
1145 output = """<video {0} {1} {2}>
1145 output = """<video {0} {1} {2}>
1146 <source src="data:{3};base64,{4}" type="{3}">
1146 <source src="data:{3};base64,{4}" type="{3}">
1147 Your browser does not support the video tag.
1147 Your browser does not support the video tag.
1148 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1148 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1149 return output
1149 return output
1150
1150
1151 def reload(self):
1151 def reload(self):
1152 # TODO
1152 # TODO
1153 pass
1153 pass
1154
1154
1155
1155
1156 @skip_doctest
1156 @skip_doctest
1157 def set_matplotlib_formats(*formats, **kwargs):
1157 def set_matplotlib_formats(*formats, **kwargs):
1158 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1158 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1159
1159
1160 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1160 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1161
1161
1162 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1162 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1163
1163
1164 To set this in your config files use the following::
1164 To set this in your config files use the following::
1165
1165
1166 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1166 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1167 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1167 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1168
1168
1169 Parameters
1169 Parameters
1170 ----------
1170 ----------
1171 *formats : strs
1171 *formats : strs
1172 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1172 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1173 **kwargs
1173 **kwargs
1174 Keyword args will be relayed to ``figure.canvas.print_figure``.
1174 Keyword args will be relayed to ``figure.canvas.print_figure``.
1175 """
1175 """
1176 from IPython.core.interactiveshell import InteractiveShell
1176 from IPython.core.interactiveshell import InteractiveShell
1177 from IPython.core.pylabtools import select_figure_formats
1177 from IPython.core.pylabtools import select_figure_formats
1178 # build kwargs, starting with InlineBackend config
1178 # build kwargs, starting with InlineBackend config
1179 kw = {}
1179 kw = {}
1180 from ipykernel.pylab.config import InlineBackend
1180 from ipykernel.pylab.config import InlineBackend
1181 cfg = InlineBackend.instance()
1181 cfg = InlineBackend.instance()
1182 kw.update(cfg.print_figure_kwargs)
1182 kw.update(cfg.print_figure_kwargs)
1183 kw.update(**kwargs)
1183 kw.update(**kwargs)
1184 shell = InteractiveShell.instance()
1184 shell = InteractiveShell.instance()
1185 select_figure_formats(shell, formats, **kw)
1185 select_figure_formats(shell, formats, **kw)
1186
1186
1187 @skip_doctest
1187 @skip_doctest
1188 def set_matplotlib_close(close=True):
1188 def set_matplotlib_close(close=True):
1189 """Set whether the inline backend closes all figures automatically or not.
1189 """Set whether the inline backend closes all figures automatically or not.
1190
1190
1191 By default, the inline backend used in the IPython Notebook will close all
1191 By default, the inline backend used in the IPython Notebook will close all
1192 matplotlib figures automatically after each cell is run. This means that
1192 matplotlib figures automatically after each cell is run. This means that
1193 plots in different cells won't interfere. Sometimes, you may want to make
1193 plots in different cells won't interfere. Sometimes, you may want to make
1194 a plot in one cell and then refine it in later cells. This can be accomplished
1194 a plot in one cell and then refine it in later cells. This can be accomplished
1195 by::
1195 by::
1196
1196
1197 In [1]: set_matplotlib_close(False)
1197 In [1]: set_matplotlib_close(False)
1198
1198
1199 To set this in your config files use the following::
1199 To set this in your config files use the following::
1200
1200
1201 c.InlineBackend.close_figures = False
1201 c.InlineBackend.close_figures = False
1202
1202
1203 Parameters
1203 Parameters
1204 ----------
1204 ----------
1205 close : bool
1205 close : bool
1206 Should all matplotlib figures be automatically closed after each cell is
1206 Should all matplotlib figures be automatically closed after each cell is
1207 run?
1207 run?
1208 """
1208 """
1209 from ipykernel.pylab.config import InlineBackend
1209 from ipykernel.pylab.config import InlineBackend
1210 cfg = InlineBackend.instance()
1210 cfg = InlineBackend.instance()
1211 cfg.close_figures = close
1211 cfg.close_figures = close
General Comments 0
You need to be logged in to leave comments. Login now