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