Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/IPython/core/completer.py: 19%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1465 statements  

1"""Completion for IPython. 

2 

3This module started as fork of the rlcompleter module in the Python standard 

4library. The original enhancements made to rlcompleter have been sent 

5upstream and were accepted as of Python 2.3, 

6 

7This module now support a wide variety of completion mechanism both available 

8for normal classic Python code, as well as completer for IPython specific 

9Syntax like magics. 

10 

11Latex and Unicode completion 

12============================ 

13 

14IPython and compatible frontends not only can complete your code, but can help 

15you to input a wide range of characters. In particular we allow you to insert 

16a unicode character using the tab completion mechanism. 

17 

18Forward latex/unicode completion 

19-------------------------------- 

20 

21Forward completion allows you to easily type a unicode character using its latex 

22name, or unicode long description. To do so type a backslash follow by the 

23relevant name and press tab: 

24 

25 

26Using latex completion: 

27 

28.. code:: 

29 

30 \\alpha<tab> 

31 α 

32 

33or using unicode completion: 

34 

35 

36.. code:: 

37 

38 \\GREEK SMALL LETTER ALPHA<tab> 

39 α 

40 

41 

42Only valid Python identifiers will complete. Combining characters (like arrow or 

43dots) are also available, unlike latex they need to be put after the their 

44counterpart that is to say, ``F\\\\vec<tab>`` is correct, not ``\\\\vec<tab>F``. 

45 

46Some browsers are known to display combining characters incorrectly. 

47 

48Backward latex completion 

49------------------------- 

50 

51It is sometime challenging to know how to type a character, if you are using 

52IPython, or any compatible frontend you can prepend backslash to the character 

53and press :kbd:`Tab` to expand it to its latex form. 

54 

55.. code:: 

56 

57 \\α<tab> 

58 \\alpha 

59 

60 

61Both forward and backward completions can be deactivated by setting the 

62:std:configtrait:`Completer.backslash_combining_completions` option to 

63``False``. 

64 

65 

66Experimental 

67============ 

68 

69Starting with IPython 6.0, this module can make use of the Jedi library to 

70generate completions both using static analysis of the code, and dynamically 

71inspecting multiple namespaces. Jedi is an autocompletion and static analysis 

72for Python. The APIs attached to this new mechanism is unstable and will 

73raise unless use in an :any:`provisionalcompleter` context manager. 

74 

75You will find that the following are experimental: 

76 

77 - :any:`provisionalcompleter` 

78 - :any:`IPCompleter.completions` 

79 - :any:`Completion` 

80 - :any:`rectify_completions` 

81 

82.. note:: 

83 

84 better name for :any:`rectify_completions` ? 

85 

86We welcome any feedback on these new API, and we also encourage you to try this 

87module in debug mode (start IPython with ``--Completer.debug=True``) in order 

88to have extra logging information if :mod:`jedi` is crashing, or if current 

89IPython completer pending deprecations are returning results not yet handled 

90by :mod:`jedi` 

91 

92Using Jedi for tab completion allow snippets like the following to work without 

93having to execute any code: 

94 

95 >>> myvar = ['hello', 42] 

96 ... myvar[1].bi<tab> 

97 

98Tab completion will be able to infer that ``myvar[1]`` is a real number without 

99executing almost any code unlike the deprecated :any:`IPCompleter.greedy` 

100option. 

101 

102Be sure to update :mod:`jedi` to the latest stable version or to try the 

103current development version to get better completions. 

104 

105Matchers 

106======== 

107 

108All completions routines are implemented using unified *Matchers* API. 

109The matchers API is provisional and subject to change without notice. 

110 

111The built-in matchers include: 

112 

113- :any:`IPCompleter.dict_key_matcher`: dictionary key completions, 

114- :any:`IPCompleter.magic_matcher`: completions for magics, 

115- :any:`IPCompleter.unicode_name_matcher`, 

116 :any:`IPCompleter.fwd_unicode_matcher` 

117 and :any:`IPCompleter.latex_name_matcher`: see `Forward latex/unicode completion`_, 

118- :any:`back_unicode_name_matcher` and :any:`back_latex_name_matcher`: see `Backward latex completion`_, 

119- :any:`IPCompleter.file_matcher`: paths to files and directories, 

120- :any:`IPCompleter.python_func_kw_matcher` - function keywords, 

121- :any:`IPCompleter.python_matcher` - globals and attributes, 

122- ``IPCompleter.jedi_matcher`` - static analysis with Jedi, 

123- :any:`IPCompleter.custom_completer_matcher` - pluggable completer with a default 

124 implementation in :any:`InteractiveShell` which uses IPython hooks system 

125 (`complete_command`) with string dispatch (including regular expressions). 

126 Differently to other matchers, ``custom_completer_matcher`` will not suppress 

127 Jedi results to match behaviour in earlier IPython versions. 

128 

129Custom matchers can be added by appending to ``IPCompleter.custom_matchers`` list. 

130 

131Matcher API 

132----------- 

133 

134Simplifying some details, the ``Matcher`` interface can described as 

135 

136.. code-block:: 

137 

138 MatcherAPIv1 = Callable[[str], list[str]] 

139 MatcherAPIv2 = Callable[[CompletionContext], SimpleMatcherResult] 

140 

141 Matcher = MatcherAPIv1 | MatcherAPIv2 

142 

143The ``MatcherAPIv1`` reflects the matcher API as available prior to IPython 8.6.0 

144and remains supported as a simplest way for generating completions. This is also 

145currently the only API supported by the IPython hooks system `complete_command`. 

146 

147To distinguish between matcher versions ``matcher_api_version`` attribute is used. 

148More precisely, the API allows to omit ``matcher_api_version`` for v1 Matchers, 

149and requires a literal ``2`` for v2 Matchers. 

150 

151Once the API stabilises future versions may relax the requirement for specifying 

152``matcher_api_version`` by switching to :func:`functools.singledispatch`, therefore 

153please do not rely on the presence of ``matcher_api_version`` for any purposes. 

154 

155Suppression of competing matchers 

156--------------------------------- 

157 

158By default results from all matchers are combined, in the order determined by 

159their priority. Matchers can request to suppress results from subsequent 

160matchers by setting ``suppress`` to ``True`` in the ``MatcherResult``. 

161 

162When multiple matchers simultaneously request suppression, the results from of 

163the matcher with higher priority will be returned. 

164 

165Sometimes it is desirable to suppress most but not all other matchers; 

166this can be achieved by adding a set of identifiers of matchers which 

167should not be suppressed to ``MatcherResult`` under ``do_not_suppress`` key. 

168 

169The suppression behaviour can is user-configurable via 

170:std:configtrait:`IPCompleter.suppress_competing_matchers`. 

171""" 

172 

173 

174# Copyright (c) IPython Development Team. 

175# Distributed under the terms of the Modified BSD License. 

176# 

177# Some of this code originated from rlcompleter in the Python standard library 

178# Copyright (C) 2001 Python Software Foundation, www.python.org 

179 

180from __future__ import annotations 

181import builtins as builtin_mod 

182import enum 

183import glob 

184import importlib.util 

185import inspect 

186import itertools 

187import keyword 

188import ast 

189import os 

190import re 

191import string 

192import sys 

193import tokenize 

194import time 

195import unicodedata 

196import uuid 

197import warnings 

198from ast import literal_eval 

199from collections import defaultdict 

200from contextlib import contextmanager 

201from dataclasses import dataclass 

202from functools import cached_property, lru_cache, partial 

203from types import ModuleType, SimpleNamespace 

204from typing import ( 

205 Union, 

206 Any, 

207 TYPE_CHECKING, 

208 TypeVar, 

209 Literal, 

210) 

211from collections.abc import Iterable, Iterator, Sequence, Sized 

212 

213from IPython.core.guarded_eval import ( 

214 guarded_eval, 

215 EvaluationContext, 

216 _validate_policy_overrides, 

217) 

218from IPython.core.error import TryNext, UsageError 

219from IPython.core.inputtransformer2 import ( 

220 ESC_MAGIC, 

221 SystemAssign, 

222 make_tokens_by_line, 

223) 

224from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol 

225from IPython.testing.skipdoctest import skip_doctest 

226from IPython.utils import generics 

227from IPython.utils.PyColorize import theme_table 

228from IPython.utils.decorators import sphinx_options 

229from IPython.utils.dir2 import dir2, get_real_method 

230from IPython.utils.path import ensure_dir_exists 

231from IPython.utils.process import arg_split 

232from traitlets import ( 

233 Bool, 

234 Enum, 

235 Int, 

236 List as ListTrait, 

237 Unicode, 

238 Dict as DictTrait, 

239 DottedObjectName, 

240 Union as UnionTrait, 

241 observe, 

242) 

243from traitlets.config.configurable import Configurable 

244from traitlets.utils.importstring import import_item 

245 

246import __main__ 

247 

248from typing import cast, TypedDict, NotRequired, Protocol, TypeAlias, TypeGuard 

249 

250 

251# skip module docstests 

252__skip_doctest__ = True 

253 

254 

255# jedi is expensive to import (it pulls in parso, which compiles grammars), so 

256# only check for its presence here and import it lazily via `_get_jedi()` the 

257# first time a completion actually needs it. This keeps `import IPython` fast. 

258if TYPE_CHECKING: 

259 import jedi 

260 

261JEDI_INSTALLED = importlib.util.find_spec("jedi") is not None 

262 

263 

264@lru_cache(maxsize=1) 

265def _get_jedi() -> ModuleType: 

266 """Import, configure, and return the ``jedi`` module (cached).""" 

267 import jedi 

268 import jedi.api.classes 

269 import jedi.api.helpers 

270 

271 jedi.settings.case_insensitive_completion = False 

272 return jedi 

273 

274 

275# ----------------------------------------------------------------------------- 

276# Globals 

277#----------------------------------------------------------------------------- 

278 

279# ranges where we have most of the valid unicode names. We could be more finer 

280# grained but is it worth it for performance While unicode have character in the 

281# range 0, 0x110000, we seem to have name for about 10% of those. (131808 as I 

282# write this). With below range we cover them all, with a density of ~67% 

283# biggest next gap we consider only adds up about 1% density and there are 600 

284# gaps that would need hard coding. 

285_UNICODE_RANGES = [(32, 0x3347A), (0xE0001, 0xE01F0)] 

286 

287# Public API 

288__all__ = ["Completer", "IPCompleter"] 

289 

290if sys.platform == 'win32': 

291 PROTECTABLES = ' ' 

292else: 

293 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&' 

294 

295# Protect against returning an enormous number of completions which the frontend 

296# may have trouble processing. 

297MATCHES_LIMIT = 500 

298 

299# Completion type reported when no type can be inferred. 

300_UNKNOWN_TYPE = "<unknown>" 

301 

302# sentinel value to signal lack of a match 

303not_found = object() 

304 

305# Regexes compiled once at import time; some of these are used on every 

306# completion request, so recompiling them per call would be wasteful. 

307_SNAKE_CASE_RE = re.compile(r"[^_]+(_[^_]+)+?\Z") 

308_LEADING_DASHES_RE = re.compile(r"^--", re.MULTILINE) 

309_IDENTIFIER_END_RE = re.compile(r"\w+$") 

310 

311class ProvisionalCompleterWarning(FutureWarning): 

312 """ 

313 Exception raise by an experimental feature in this module. 

314 

315 Wrap code in :any:`provisionalcompleter` context manager if you 

316 are certain you want to use an unstable feature. 

317 """ 

318 pass 

319 

320warnings.filterwarnings('error', category=ProvisionalCompleterWarning) 

321 

322 

323@skip_doctest 

324@contextmanager 

325def provisionalcompleter(action='ignore'): 

326 """ 

327 This context manager has to be used in any place where unstable completer 

328 behavior and API may be called. 

329 

330 >>> with provisionalcompleter(): 

331 ... completer.do_experimental_things() # works 

332 

333 >>> completer.do_experimental_things() # raises. 

334 

335 .. note:: 

336 

337 Unstable 

338 

339 By using this context manager you agree that the API in use may change 

340 without warning, and that you won't complain if they do so. 

341 

342 You also understand that, if the API is not to your liking, you should report 

343 a bug to explain your use case upstream. 

344 

345 We'll be happy to get your feedback, feature requests, and improvements on 

346 any of the unstable APIs! 

347 """ 

348 with warnings.catch_warnings(): 

349 warnings.filterwarnings(action, category=ProvisionalCompleterWarning) 

350 yield 

351 

352 

353def has_open_quotes(s: str) -> str | bool: 

354 """Return whether a string has open quotes. 

355 

356 This simply counts whether the number of quote characters of either type in 

357 the string is odd. 

358 

359 Returns 

360 ------- 

361 If there is an open quote, the quote character is returned. Else, return 

362 False. 

363 """ 

364 # We check " first, then ', so complex cases with nested quotes will get 

365 # the " to take precedence. 

366 if s.count('"') % 2: 

367 return '"' 

368 elif s.count("'") % 2: 

369 return "'" 

370 else: 

371 return False 

372 

373 

374def protect_filename(s: str, protectables: str = PROTECTABLES) -> str: 

375 """Escape a string to protect certain characters.""" 

376 if set(s) & set(protectables): 

377 if sys.platform == "win32": 

378 return '"' + s + '"' 

379 else: 

380 return "".join(("\\" + c if c in protectables else c) for c in s) 

381 else: 

382 return s 

383 

384 

385def expand_user(path: str) -> tuple[str, bool, str]: 

386 """Expand ``~``-style usernames in strings. 

387 

388 This is similar to :func:`os.path.expanduser`, but it computes and returns 

389 extra information that will be useful if the input was being used in 

390 computing completions, and you wish to return the completions with the 

391 original '~' instead of its expanded value. 

392 

393 Parameters 

394 ---------- 

395 path : str 

396 String to be expanded. If no ~ is present, the output is the same as the 

397 input. 

398 

399 Returns 

400 ------- 

401 newpath : str 

402 Result of ~ expansion in the input path. 

403 tilde_expand : bool 

404 Whether any expansion was performed or not. 

405 tilde_val : str 

406 The value that ~ was replaced with. 

407 """ 

408 # Default values 

409 tilde_expand = False 

410 tilde_val = '' 

411 newpath = path 

412 

413 if path.startswith('~'): 

414 tilde_expand = True 

415 rest = len(path)-1 

416 newpath = os.path.expanduser(path) 

417 if rest: 

418 tilde_val = newpath[:-rest] 

419 else: 

420 tilde_val = newpath 

421 

422 return newpath, tilde_expand, tilde_val 

423 

424 

425def compress_user(path:str, tilde_expand:bool, tilde_val:str) -> str: 

426 """Does the opposite of expand_user, with its outputs. 

427 """ 

428 if tilde_expand: 

429 return path.replace(tilde_val, '~') 

430 else: 

431 return path 

432 

433 

434def completions_sorting_key(word): 

435 """key for sorting completions 

436 

437 This does several things: 

438 

439 - Demote any completions starting with underscores to the end 

440 - Insert any %magic and %%cellmagic completions in the alphabetical order 

441 by their name 

442 """ 

443 prio1, prio2 = 0, 0 

444 

445 if word.startswith('__'): 

446 prio1 = 2 

447 elif word.startswith('_'): 

448 prio1 = 1 

449 

450 if word.endswith('='): 

451 prio1 = -1 

452 

453 if word.startswith('%%'): 

454 # If there's another % in there, this is something else, so leave it alone 

455 if "%" not in word[2:]: 

456 word = word[2:] 

457 prio2 = 2 

458 elif word.startswith('%'): 

459 if "%" not in word[1:]: 

460 word = word[1:] 

461 prio2 = 1 

462 

463 return prio1, word, prio2 

464 

465 

466class _FakeJediCompletion: 

467 """ 

468 This is a workaround to communicate to the UI that Jedi has crashed and to 

469 report a bug. Will be used only id :any:`IPCompleter.debug` is set to true. 

470 

471 Added in IPython 6.0 so should likely be removed for 7.0 

472 

473 """ 

474 

475 def __init__(self, name): 

476 

477 self.name = name 

478 self.complete = name 

479 self.type = 'crashed' 

480 self.name_with_symbols = name 

481 self.signature = "" 

482 self._origin = "fake" 

483 self.text = "crashed" 

484 

485 def __repr__(self): 

486 return '<Fake completion object jedi has crashed>' 

487 

488 

489_JediCompletionLike = Union["jedi.api.Completion", _FakeJediCompletion] 

490 

491 

492class Completion: 

493 """ 

494 Completion object used and returned by IPython completers. 

495 

496 .. warning:: 

497 

498 Unstable 

499 

500 This function is unstable, API may change without warning. 

501 It will also raise unless use in proper context manager. 

502 

503 This act as a middle ground :any:`Completion` object between the 

504 :class:`jedi.api.classes.Completion` object and the Prompt Toolkit completion 

505 object. While Jedi need a lot of information about evaluator and how the 

506 code should be ran/inspected, PromptToolkit (and other frontend) mostly 

507 need user facing information. 

508 

509 - Which range should be replaced replaced by what. 

510 - Some metadata (like completion type), or meta information to displayed to 

511 the use user. 

512 

513 For debugging purpose we can also store the origin of the completion (``jedi``, 

514 ``IPython.python_matches``, ``IPython.magics_matches``...). 

515 """ 

516 

517 __slots__ = ["_origin", "end", "signature", "start", "text", "type"] 

518 

519 def __init__( 

520 self, 

521 start: int, 

522 end: int, 

523 text: str, 

524 *, 

525 type: str | None = None, 

526 _origin="", 

527 signature="", 

528 ) -> None: 

529 warnings.warn( 

530 "``Completion`` is a provisional API (as of IPython 6.0). " 

531 "It may change without warnings. " 

532 "Use in corresponding context manager.", 

533 category=ProvisionalCompleterWarning, 

534 stacklevel=2, 

535 ) 

536 

537 self.start = start 

538 self.end = end 

539 self.text = text 

540 self.type = type 

541 self.signature = signature 

542 self._origin = _origin 

543 

544 def __repr__(self): 

545 return '<Completion start=%s end=%s text=%r type=%r, signature=%r,>' % \ 

546 (self.start, self.end, self.text, self.type or '?', self.signature or '?') 

547 

548 def __eq__(self, other) -> bool: 

549 """ 

550 Equality and hash do not hash the type (as some completer may not be 

551 able to infer the type), but are use to (partially) de-duplicate 

552 completion. 

553 

554 Completely de-duplicating completion is a bit tricker that just 

555 comparing as it depends on surrounding text, which Completions are not 

556 aware of. 

557 """ 

558 return self.start == other.start and \ 

559 self.end == other.end and \ 

560 self.text == other.text 

561 

562 def __hash__(self): 

563 return hash((self.start, self.end, self.text)) 

564 

565 

566class SimpleCompletion: 

567 """Completion item to be included in the dictionary returned by new-style Matcher (API v2). 

568 

569 .. warning:: 

570 

571 Provisional 

572 

573 This class is used to describe the currently supported attributes of 

574 simple completion items, and any additional implementation details 

575 should not be relied on. Additional attributes may be included in 

576 future versions, and meaning of text disambiguated from the current 

577 dual meaning of "text to insert" and "text to used as a label". 

578 """ 

579 

580 __slots__ = ["text", "type"] 

581 

582 def __init__(self, text: str, *, type: str | None = None): 

583 self.text = text 

584 self.type = type 

585 

586 def __repr__(self): 

587 return f"<SimpleCompletion text={self.text!r} type={self.type!r}>" 

588 

589 

590class _MatcherResultBase(TypedDict): 

591 """Definition of dictionary to be returned by new-style Matcher (API v2).""" 

592 

593 #: Suffix of the provided ``CompletionContext.token``, if not given defaults to full token. 

594 matched_fragment: NotRequired[str] 

595 

596 #: Whether to suppress results from all other matchers (True), some 

597 #: matchers (set of identifiers) or none (False); default is False. 

598 suppress: NotRequired[bool | set[str]] 

599 

600 #: Identifiers of matchers which should NOT be suppressed when this matcher 

601 #: requests to suppress all other matchers; defaults to an empty set. 

602 do_not_suppress: NotRequired[set[str]] 

603 

604 #: Are completions already ordered and should be left as-is? default is False. 

605 ordered: NotRequired[bool] 

606 

607 

608@sphinx_options(show_inherited_members=True, exclude_inherited_from=["dict"]) 

609class SimpleMatcherResult(_MatcherResultBase, TypedDict): 

610 """Result of new-style completion matcher.""" 

611 

612 # note: TypedDict is added again to the inheritance chain 

613 # in order to get __orig_bases__ for documentation 

614 

615 #: List of candidate completions 

616 completions: Sequence[SimpleCompletion] | Iterator[SimpleCompletion] 

617 

618 

619class _JediMatcherResult(_MatcherResultBase): 

620 """Matching result returned by Jedi (will be processed differently)""" 

621 

622 #: list of candidate completions 

623 completions: Iterator[_JediCompletionLike] 

624 

625 

626AnyMatcherCompletion = _JediCompletionLike | SimpleCompletion 

627AnyCompletion = TypeVar("AnyCompletion", AnyMatcherCompletion, Completion) 

628 

629 

630@dataclass 

631class CompletionContext: 

632 """Completion context provided as an argument to matchers in the Matcher API v2.""" 

633 

634 # rationale: many legacy matchers relied on completer state (`self.text_until_cursor`) 

635 # which was not explicitly visible as an argument of the matcher, making any refactor 

636 # prone to errors; by explicitly passing `cursor_position` we can decouple the matchers 

637 # from the completer, and make substituting them in sub-classes easier. 

638 

639 #: Relevant fragment of code directly preceding the cursor. 

640 #: The extraction of token is implemented via splitter heuristic 

641 #: (following readline behaviour for legacy reasons), which is user configurable 

642 #: (by switching the greedy mode). 

643 token: str 

644 

645 #: The full available content of the editor or buffer 

646 full_text: str 

647 

648 #: Cursor position in the line (the same for ``full_text`` and ``text``). 

649 cursor_position: int 

650 

651 #: Cursor line in ``full_text``. 

652 cursor_line: int 

653 

654 #: The maximum number of completions that will be used downstream. 

655 #: Matchers can use this information to abort early. 

656 #: The built-in Jedi matcher is currently excepted from this limit. 

657 # If not given, return all possible completions. 

658 limit: int | None 

659 

660 @cached_property 

661 def text_until_cursor(self) -> str: 

662 return self.line_with_cursor[: self.cursor_position] 

663 

664 @cached_property 

665 def line_with_cursor(self) -> str: 

666 return self.full_text.split("\n")[self.cursor_line] 

667 

668 

669#: Matcher results for API v2. 

670MatcherResult = SimpleMatcherResult | _JediMatcherResult 

671 

672 

673class _MatcherAPIv1Base(Protocol): 

674 def __call__(self, text: str) -> list[str]: 

675 """Call signature.""" 

676 ... 

677 

678 #: Used to construct the default matcher identifier 

679 __qualname__: str 

680 

681 

682class _MatcherAPIv1Total(_MatcherAPIv1Base, Protocol): 

683 #: API version 

684 matcher_api_version: Literal[1] | None 

685 

686 def __call__(self, text: str) -> list[str]: 

687 """Call signature.""" 

688 ... 

689 

690 

691#: Protocol describing Matcher API v1. 

692MatcherAPIv1: TypeAlias = _MatcherAPIv1Base | _MatcherAPIv1Total 

693 

694 

695class MatcherAPIv2(Protocol): 

696 """Protocol describing Matcher API v2.""" 

697 

698 #: API version 

699 matcher_api_version: Literal[2] = 2 

700 

701 def __call__(self, context: CompletionContext) -> MatcherResult: 

702 """Call signature.""" 

703 ... 

704 

705 #: Used to construct the default matcher identifier 

706 __qualname__: str 

707 

708 

709Matcher: TypeAlias = MatcherAPIv1 | MatcherAPIv2 

710 

711 

712def _is_matcher_v1(matcher: Matcher) -> TypeGuard[MatcherAPIv1]: 

713 api_version = _get_matcher_api_version(matcher) 

714 return api_version == 1 

715 

716 

717def _is_matcher_v2(matcher: Matcher) -> TypeGuard[MatcherAPIv2]: 

718 api_version = _get_matcher_api_version(matcher) 

719 return api_version == 2 

720 

721 

722def _is_sizable(value: Any) -> TypeGuard[Sized]: 

723 """Determines whether objects is sizable""" 

724 return hasattr(value, "__len__") 

725 

726 

727def _is_iterator(value: Any) -> TypeGuard[Iterator]: 

728 """Determines whether objects is sizable""" 

729 return hasattr(value, "__next__") 

730 

731 

732def has_any_completions(result: MatcherResult) -> bool: 

733 """Check if any result includes any completions.""" 

734 completions = result["completions"] 

735 if _is_sizable(completions): 

736 return len(completions) != 0 

737 if _is_iterator(completions): 

738 try: 

739 old_iterator = completions 

740 first = next(old_iterator) 

741 result["completions"] = cast( 

742 Iterator[SimpleCompletion], 

743 itertools.chain([first], old_iterator), 

744 ) 

745 return True 

746 except StopIteration: 

747 return False 

748 raise ValueError( 

749 "Completions returned by matcher need to be an Iterator or a Sizable" 

750 ) 

751 

752 

753def completion_matcher( 

754 *, 

755 priority: float | None = None, 

756 identifier: str | None = None, 

757 api_version: int = 1, 

758) -> Callable[[Matcher], Matcher]: 

759 """Adds attributes describing the matcher. 

760 

761 Parameters 

762 ---------- 

763 priority : Optional[float] 

764 The priority of the matcher, determines the order of execution of matchers. 

765 Higher priority means that the matcher will be executed first. Defaults to 0. 

766 identifier : Optional[str] 

767 identifier of the matcher allowing users to modify the behaviour via traitlets, 

768 and also used to for debugging (will be passed as ``origin`` with the completions). 

769 

770 Defaults to matcher function's ``__qualname__`` (for example, 

771 ``IPCompleter.file_matcher`` for the built-in matched defined 

772 as a ``file_matcher`` method of the ``IPCompleter`` class). 

773 api_version: Optional[int] 

774 version of the Matcher API used by this matcher. 

775 Currently supported values are 1 and 2. 

776 Defaults to 1. 

777 """ 

778 

779 def wrapper(func: Matcher): 

780 func.matcher_priority = priority or 0 # type: ignore 

781 func.matcher_identifier = identifier or func.__qualname__ # type: ignore 

782 func.matcher_api_version = api_version # type: ignore 

783 if TYPE_CHECKING: 

784 if api_version == 1: 

785 func = cast(MatcherAPIv1, func) 

786 elif api_version == 2: 

787 func = cast(MatcherAPIv2, func) 

788 return func 

789 

790 return wrapper 

791 

792 

793def _get_matcher_priority(matcher: Matcher): 

794 return getattr(matcher, "matcher_priority", 0) 

795 

796 

797def _get_matcher_id(matcher: Matcher): 

798 return getattr(matcher, "matcher_identifier", matcher.__qualname__) 

799 

800 

801def _get_matcher_api_version(matcher): 

802 return getattr(matcher, "matcher_api_version", 1) 

803 

804 

805context_matcher = partial(completion_matcher, api_version=2) 

806 

807 

808_IC = Iterable[Completion] 

809 

810 

811def _deduplicate_completions(text: str, completions: _IC)-> _IC: 

812 """ 

813 Deduplicate a set of completions. 

814 

815 .. warning:: 

816 

817 Unstable 

818 

819 This function is unstable, API may change without warning. 

820 

821 Parameters 

822 ---------- 

823 text : str 

824 text that should be completed. 

825 completions : Iterator[Completion] 

826 iterator over the completions to deduplicate 

827 

828 Yields 

829 ------ 

830 `Completions` objects 

831 Completions coming from multiple sources, may be different but end up having 

832 the same effect when applied to ``text``. If this is the case, this will 

833 consider completions as equal and only emit the first encountered. 

834 Not folded in `completions()` yet for debugging purpose, and to detect when 

835 the IPython completer does return things that Jedi does not, but should be 

836 at some point. 

837 """ 

838 completions = list(completions) 

839 if not completions: 

840 return 

841 

842 new_start = min(c.start for c in completions) 

843 new_end = max(c.end for c in completions) 

844 

845 seen = set() 

846 for c in completions: 

847 new_text = text[new_start:c.start] + c.text + text[c.end:new_end] 

848 if new_text not in seen: 

849 yield c 

850 seen.add(new_text) 

851 

852 

853def rectify_completions(text: str, completions: _IC, *, _debug: bool = False) -> _IC: 

854 """ 

855 Rectify a set of completions to all have the same ``start`` and ``end`` 

856 

857 .. warning:: 

858 

859 Unstable 

860 

861 This function is unstable, API may change without warning. 

862 It will also raise unless use in proper context manager. 

863 

864 Parameters 

865 ---------- 

866 text : str 

867 text that should be completed. 

868 completions : Iterator[Completion] 

869 iterator over the completions to rectify 

870 _debug : bool 

871 Log failed completion 

872 

873 Notes 

874 ----- 

875 :class:`jedi.api.classes.Completion` s returned by Jedi may not have the same start and end, though 

876 the Jupyter Protocol requires them to behave like so. This will readjust 

877 the completion to have the same ``start`` and ``end`` by padding both 

878 extremities with surrounding text. 

879 

880 During stabilisation should support a ``_debug`` option to log which 

881 completion are return by the IPython completer and not found in Jedi in 

882 order to make upstream bug report. 

883 """ 

884 warnings.warn("`rectify_completions` is a provisional API (as of IPython 6.0). " 

885 "It may change without warnings. " 

886 "Use in corresponding context manager.", 

887 category=ProvisionalCompleterWarning, stacklevel=2) 

888 

889 completions = list(completions) 

890 if not completions: 

891 return 

892 starts = (c.start for c in completions) 

893 ends = (c.end for c in completions) 

894 

895 new_start = min(starts) 

896 new_end = max(ends) 

897 

898 seen_jedi = set() 

899 seen_python_matches = set() 

900 for c in completions: 

901 new_text = text[new_start:c.start] + c.text + text[c.end:new_end] 

902 if c._origin == 'jedi': 

903 seen_jedi.add(new_text) 

904 elif c._origin == "IPCompleter.python_matcher": 

905 seen_python_matches.add(new_text) 

906 yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin, signature=c.signature) 

907 diff = seen_python_matches.difference(seen_jedi) 

908 if diff and _debug: 

909 print('IPython.python matches have extras:', diff) 

910 

911 

912if sys.platform == 'win32': 

913 DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?' 

914else: 

915 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?' 

916 

917GREEDY_DELIMS = ' =\r\n' 

918 

919 

920class CompletionSplitter: 

921 """An object to split an input line in a manner similar to readline. 

922 

923 By having our own implementation, we can expose readline-like completion in 

924 a uniform manner to all frontends. This object only needs to be given the 

925 line of text to be split and the cursor position on said line, and it 

926 returns the 'word' to be completed on at the cursor after splitting the 

927 entire line. 

928 

929 What characters are used as splitting delimiters can be controlled by 

930 setting the ``delims`` attribute (this is a property that internally 

931 automatically builds the necessary regular expression)""" 

932 

933 # Private interface 

934 

935 # A string of delimiter characters. The default value makes sense for 

936 # IPython's most typical usage patterns. 

937 _delims = DELIMS 

938 

939 # The expression (a normal string) to be compiled into a regular expression 

940 # for actual splitting. We store it as an attribute mostly for ease of 

941 # debugging, since this type of code can be so tricky to debug. 

942 _delim_expr = None 

943 

944 # The regular expression that does the actual splitting 

945 _delim_re = None 

946 

947 def __init__(self, delims=None): 

948 delims = CompletionSplitter._delims if delims is None else delims 

949 self.delims = delims 

950 

951 @property 

952 def delims(self): 

953 """Return the string of delimiter characters.""" 

954 return self._delims 

955 

956 @delims.setter 

957 def delims(self, delims): 

958 """Set the delimiters for line splitting.""" 

959 expr = '[' + ''.join('\\'+ c for c in delims) + ']' 

960 self._delim_re = re.compile(expr) 

961 self._delims = delims 

962 self._delim_expr = expr 

963 

964 def split_line(self, line, cursor_pos=None): 

965 """Split a line of text with a cursor at the given position. 

966 """ 

967 cut_line = line if cursor_pos is None else line[:cursor_pos] 

968 return self._delim_re.split(cut_line)[-1] 

969 

970 

971class Completer(Configurable): 

972 

973 greedy = Bool( 

974 False, 

975 help="""Activate greedy completion. 

976 

977 .. deprecated:: 8.8 

978 Use :std:configtrait:`Completer.evaluation` and :std:configtrait:`Completer.auto_close_dict_keys` instead. 

979 

980 When enabled in IPython 8.8 or newer, changes configuration as follows: 

981 

982 - ``Completer.evaluation = 'unsafe'`` 

983 - ``Completer.auto_close_dict_keys = True`` 

984 

985 Kept (deprecated, not yet removed) because downstream projects' 

986 test suites still set it via ``%config``. 

987 """, 

988 ).tag(config=True) 

989 

990 evaluation = Enum( 

991 ("forbidden", "minimal", "limited", "unsafe", "dangerous"), 

992 default_value="limited", 

993 help="""Policy for code evaluation under completion. 

994 

995 Successive options allow to enable more eager evaluation for better 

996 completion suggestions, including for nested dictionaries, nested lists, 

997 or even results of function calls. 

998 Setting ``unsafe`` or higher can lead to evaluation of arbitrary user 

999 code on :kbd:`Tab` with potentially unwanted or dangerous side effects. 

1000 

1001 Allowed values are: 

1002 

1003 - ``forbidden``: no evaluation of code is permitted, 

1004 - ``minimal``: evaluation of literals and access to built-in namespace; 

1005 no item/attribute evaluation, no access to locals/globals, 

1006 no evaluation of any operations or comparisons. 

1007 - ``limited``: access to all namespaces, evaluation of hard-coded methods 

1008 (for example: :py:meth:`dict.keys`, :py:meth:`object.__getattr__`, 

1009 :py:meth:`object.__getitem__`) on allow-listed objects (for example: 

1010 :py:class:`dict`, :py:class:`list`, :py:class:`tuple`, ``pandas.Series``), 

1011 - ``unsafe``: evaluation of all methods and function calls but not of 

1012 syntax with side-effects like `del x`, 

1013 - ``dangerous``: completely arbitrary evaluation; does not support auto-import. 

1014 

1015 To override specific elements of the policy, you can use ``policy_overrides`` trait. 

1016 """, 

1017 ).tag(config=True) 

1018 

1019 use_jedi = Bool(default_value=JEDI_INSTALLED, 

1020 help="Experimental: Use Jedi to generate autocompletions. " 

1021 "Default to True if jedi is installed.").tag(config=True) 

1022 

1023 jedi_compute_type_timeout = Int(default_value=400, 

1024 help="""Experimental: restrict time (in milliseconds) during which Jedi can compute types. 

1025 Set to 0 to stop computing types. Non-zero value lower than 100ms may hurt 

1026 performance by preventing jedi to build its cache. 

1027 """).tag(config=True) 

1028 

1029 debug = Bool(default_value=False, 

1030 help='Enable debug for the Completer. Mostly print extra ' 

1031 'information for experimental jedi integration.')\ 

1032 .tag(config=True) 

1033 

1034 backslash_combining_completions = Bool(True, 

1035 help="Enable unicode completions, e.g. \\alpha<tab> . " 

1036 "Includes completion of latex commands, unicode names, and expanding " 

1037 "unicode characters back to latex commands.").tag(config=True) 

1038 

1039 auto_close_dict_keys = Bool( 

1040 False, 

1041 help=""" 

1042 Enable auto-closing dictionary keys. 

1043 

1044 When enabled string keys will be suffixed with a final quote 

1045 (matching the opening quote), tuple keys will also receive a 

1046 separating comma if needed, and keys which are final will 

1047 receive a closing bracket (``]``). 

1048 """, 

1049 ).tag(config=True) 

1050 

1051 policy_overrides = DictTrait( 

1052 default_value={}, 

1053 key_trait=Unicode(), 

1054 help="""Overrides for policy evaluation. 

1055 

1056 For example, to enable auto-import on completion specify: 

1057 

1058 .. code-block:: 

1059 

1060 ipython --Completer.policy_overrides='{"allow_auto_import": True}' --Completer.use_jedi=False 

1061 

1062 """, 

1063 ).tag(config=True) 

1064 

1065 @observe("evaluation") 

1066 def _evaluation_changed(self, _change): 

1067 _validate_policy_overrides( 

1068 policy_name=self.evaluation, policy_overrides=self.policy_overrides 

1069 ) 

1070 

1071 @observe("policy_overrides") 

1072 def _policy_overrides_changed(self, _change): 

1073 _validate_policy_overrides( 

1074 policy_name=self.evaluation, policy_overrides=self.policy_overrides 

1075 ) 

1076 

1077 auto_import_method = DottedObjectName( 

1078 default_value="importlib.import_module", 

1079 allow_none=True, 

1080 help="""\ 

1081 Provisional: 

1082 This is a provisional API in IPython 9.3, it may change without warnings. 

1083 

1084 A fully qualified path to an auto-import method for use by completer. 

1085 The function should take a single string and return `ModuleType` and 

1086 can raise `ImportError` exception if module is not found. 

1087 

1088 The default auto-import implementation does not populate the user namespace with the imported module. 

1089 """, 

1090 ).tag(config=True) 

1091 

1092 def __init__(self, namespace=None, global_namespace=None, **kwargs): 

1093 """Create a new completer for the command line. 

1094 

1095 Completer(namespace=ns, global_namespace=ns2) -> completer instance. 

1096 

1097 If unspecified, the default namespace where completions are performed 

1098 is __main__ (technically, __main__.__dict__). Namespaces should be 

1099 given as dictionaries. 

1100 

1101 An optional second namespace can be given. This allows the completer 

1102 to handle cases where both the local and global scopes need to be 

1103 distinguished. 

1104 """ 

1105 

1106 # Don't bind to namespace quite yet, but flag whether the user wants a 

1107 # specific namespace or to use __main__.__dict__. This will allow us 

1108 # to bind to __main__.__dict__ at completion time, not now. 

1109 if namespace is None: 

1110 self.use_main_ns = True 

1111 else: 

1112 self.use_main_ns = False 

1113 self.namespace = namespace 

1114 

1115 # The global namespace, if given, can be bound directly 

1116 if global_namespace is None: 

1117 self.global_namespace = {} 

1118 else: 

1119 self.global_namespace = global_namespace 

1120 

1121 self.custom_matchers = [] 

1122 

1123 super().__init__(**kwargs) 

1124 

1125 def complete(self, text, state): 

1126 """Return the next possible completion for 'text'. 

1127 

1128 This is called successively with state == 0, 1, 2, ... until it 

1129 returns None. The completion should begin with 'text'. 

1130 

1131 """ 

1132 if self.use_main_ns: 

1133 self.namespace = __main__.__dict__ 

1134 

1135 if state == 0: 

1136 if "." in text: 

1137 self.matches = self.attr_matches(text) 

1138 else: 

1139 self.matches = self.global_matches(text) 

1140 try: 

1141 return self.matches[state] 

1142 except IndexError: 

1143 return None 

1144 

1145 def global_matches(self, text: str, context: CompletionContext | None = None): 

1146 """Compute matches when text is a simple name. 

1147 

1148 Return a list of all keywords, built-in functions and names currently 

1149 defined in self.namespace or self.global_namespace that match. 

1150 

1151 """ 

1152 matches = [] 

1153 match_append = matches.append 

1154 n = len(text) 

1155 

1156 search_lists = [ 

1157 keyword.kwlist, 

1158 builtin_mod.__dict__.keys(), 

1159 list(self.namespace.keys()), 

1160 list(self.global_namespace.keys()), 

1161 ] 

1162 if context and context.full_text.count("\n") > 1: 

1163 # try to evaluate on full buffer 

1164 previous_lines = "\n".join( 

1165 context.full_text.split("\n")[: context.cursor_line] 

1166 ) 

1167 if previous_lines: 

1168 all_code_lines_before_cursor = ( 

1169 self._extract_code(previous_lines) + "\n" + text 

1170 ) 

1171 context = EvaluationContext( 

1172 globals=self.global_namespace, 

1173 locals=self.namespace, 

1174 evaluation=self.evaluation, 

1175 auto_import=self._auto_import, 

1176 policy_overrides=self.policy_overrides, 

1177 ) 

1178 try: 

1179 obj = guarded_eval( 

1180 all_code_lines_before_cursor, 

1181 context, 

1182 ) 

1183 except Exception as e: 

1184 if self.debug: 

1185 warnings.warn(f"Evaluation exception {e}") 

1186 

1187 search_lists.append(list(context.transient_locals.keys())) 

1188 

1189 for lst in search_lists: 

1190 for word in lst: 

1191 if word[:n] == text and word != "__builtins__": 

1192 match_append(word) 

1193 

1194 for lst in [list(self.namespace.keys()), list(self.global_namespace.keys())]: 

1195 shortened = { 

1196 "_".join([sub[0] for sub in word.split("_")]): word 

1197 for word in lst 

1198 if _SNAKE_CASE_RE.match(word) 

1199 } 

1200 for word in shortened.keys(): 

1201 if word[:n] == text and word != "__builtins__": 

1202 match_append(shortened[word]) 

1203 

1204 return matches 

1205 

1206 def attr_matches(self, text): 

1207 """Compute matches when text contains a dot. 

1208 

1209 Assuming the text is of the form NAME.NAME....[NAME], and is 

1210 evaluatable in self.namespace or self.global_namespace, it will be 

1211 evaluated and its attributes (as revealed by dir()) are used as 

1212 possible completions. (For class instances, class members are 

1213 also considered.) 

1214 

1215 WARNING: this can still invoke arbitrary C code, if an object 

1216 with a __getattr__ hook is evaluated. 

1217 

1218 """ 

1219 return self._attr_matches(text)[0] 

1220 

1221 # we simple attribute matching with normal identifiers. 

1222 _ATTR_MATCH_RE = re.compile(r"(.+)\.(\w*)$") 

1223 

1224 def _strip_code_before_operator(self, code: str) -> str: 

1225 o_parens = {"(", "[", "{"} 

1226 c_parens = {")", "]", "}"} 

1227 

1228 # Dry-run tokenize to catch errors 

1229 try: 

1230 _ = list(tokenize.generate_tokens(iter(code.splitlines()).__next__)) 

1231 except tokenize.TokenError: 

1232 # Try trimming the expression and retrying 

1233 trimmed_code = self._trim_expr(code) 

1234 try: 

1235 _ = list( 

1236 tokenize.generate_tokens(iter(trimmed_code.splitlines()).__next__) 

1237 ) 

1238 code = trimmed_code 

1239 except tokenize.TokenError: 

1240 return code 

1241 

1242 tokens = _parse_tokens(code) 

1243 encountered_operator = False 

1244 after_operator = [] 

1245 nesting_level = 0 

1246 

1247 for t in tokens: 

1248 if t.type == tokenize.OP: 

1249 if t.string in o_parens: 

1250 nesting_level += 1 

1251 elif t.string in c_parens: 

1252 nesting_level -= 1 

1253 elif t.string != "." and nesting_level == 0: 

1254 encountered_operator = True 

1255 after_operator = [] 

1256 continue 

1257 

1258 if encountered_operator: 

1259 after_operator.append(t.string) 

1260 

1261 if encountered_operator: 

1262 return "".join(after_operator) 

1263 else: 

1264 return code 

1265 

1266 def _extract_code(self, line: str): 

1267 """No-op in Completer, but can be used in subclasses to customise behaviour""" 

1268 return line 

1269 

1270 def _attr_matches( 

1271 self, 

1272 text: str, 

1273 include_prefix: bool = True, 

1274 context: CompletionContext | None = None, 

1275 ) -> tuple[Sequence[str], str]: 

1276 m2 = self._ATTR_MATCH_RE.match(text) 

1277 if not m2: 

1278 return [], "" 

1279 expr, attr = m2.group(1, 2) 

1280 try: 

1281 expr = self._strip_code_before_operator(expr) 

1282 except tokenize.TokenError: 

1283 pass 

1284 

1285 obj = self._evaluate_expr(expr) 

1286 if obj is not_found: 

1287 if context: 

1288 # try to evaluate on full buffer 

1289 previous_lines = "\n".join( 

1290 context.full_text.split("\n")[: context.cursor_line] 

1291 ) 

1292 if previous_lines: 

1293 all_code_lines_before_cursor = ( 

1294 self._extract_code(previous_lines) + "\n" + expr 

1295 ) 

1296 obj = self._evaluate_expr(all_code_lines_before_cursor) 

1297 

1298 if obj is not_found: 

1299 return [], "" 

1300 

1301 words = dir2(obj) 

1302 

1303 try: 

1304 words = generics.complete_object(obj, words) 

1305 except TryNext: 

1306 pass 

1307 except AssertionError: 

1308 raise 

1309 except Exception: 

1310 # Silence errors from completion function 

1311 pass 

1312 # Build match list to return 

1313 n = len(attr) 

1314 

1315 # Note: ideally we would just return words here and the prefix 

1316 # reconciliator would know that we intend to append to rather than 

1317 # replace the input text; this requires refactoring to return range 

1318 # which ought to be replaced (as does jedi). 

1319 if include_prefix: 

1320 tokens = _parse_tokens(expr) 

1321 rev_tokens = reversed(tokens) 

1322 skip_over = {tokenize.ENDMARKER, tokenize.NEWLINE} 

1323 name_turn = True 

1324 

1325 parts = [] 

1326 for token in rev_tokens: 

1327 if token.type in skip_over: 

1328 continue 

1329 if token.type == tokenize.NAME and name_turn: 

1330 parts.append(token.string) 

1331 name_turn = False 

1332 elif ( 

1333 token.type == tokenize.OP and token.string == "." and not name_turn 

1334 ): 

1335 parts.append(token.string) 

1336 name_turn = True 

1337 else: 

1338 # short-circuit if not empty nor name token 

1339 break 

1340 

1341 prefix_after_space = "".join(reversed(parts)) 

1342 else: 

1343 prefix_after_space = "" 

1344 

1345 return ( 

1346 ["{}.{}".format(prefix_after_space, w) for w in words if w[:n] == attr], 

1347 "." + attr, 

1348 ) 

1349 

1350 def _trim_expr(self, code: str) -> str: 

1351 """ 

1352 Trim the code until it is a valid expression and not a tuple; 

1353 

1354 return the trimmed expression for guarded_eval. 

1355 """ 

1356 while code: 

1357 code = code[1:] 

1358 try: 

1359 res = ast.parse(code) 

1360 except SyntaxError: 

1361 continue 

1362 

1363 assert res is not None 

1364 if len(res.body) != 1: 

1365 continue 

1366 if not isinstance(res.body[0], ast.Expr): 

1367 continue 

1368 expr = res.body[0].value 

1369 if isinstance(expr, ast.Tuple) and not code[-1] == ")": 

1370 # we skip implicit tuple, like when trimming `fun(a,b`<completion> 

1371 # as `a,b` would be a tuple, and we actually expect to get only `b` 

1372 continue 

1373 return code 

1374 return "" 

1375 

1376 def _evaluate_expr(self, expr): 

1377 obj = not_found 

1378 done = False 

1379 while not done and expr: 

1380 try: 

1381 obj = guarded_eval( 

1382 expr, 

1383 EvaluationContext( 

1384 globals=self.global_namespace, 

1385 locals=self.namespace, 

1386 evaluation=self.evaluation, 

1387 auto_import=self._auto_import, 

1388 policy_overrides=self.policy_overrides, 

1389 ), 

1390 ) 

1391 done = True 

1392 except (SyntaxError, TypeError) as e: 

1393 if self.debug: 

1394 warnings.warn(f"Trimming because of {e}") 

1395 # TypeError can show up with something like `+ d` 

1396 # where `d` is a dictionary. 

1397 

1398 # trim the expression to remove any invalid prefix 

1399 # e.g. user starts `(d[`, so we get `expr = '(d'`, 

1400 # where parenthesis is not closed. 

1401 # TODO: make this faster by reusing parts of the computation? 

1402 expr = self._trim_expr(expr) 

1403 except Exception as e: 

1404 if self.debug: 

1405 warnings.warn(f"Evaluation exception {e}") 

1406 done = True 

1407 if self.debug: 

1408 warnings.warn(f"Resolved to {obj}") 

1409 return obj 

1410 

1411 @property 

1412 def _auto_import(self): 

1413 if self.auto_import_method is None: 

1414 return None 

1415 if not hasattr(self, "_auto_import_func"): 

1416 self._auto_import_func = import_item(self.auto_import_method) 

1417 return self._auto_import_func 

1418 

1419 

1420def get__all__entries(obj: Any) -> list[str]: 

1421 """returns the strings in the __all__ attribute""" 

1422 try: 

1423 words = getattr(obj, '__all__') 

1424 except Exception: 

1425 return [] 

1426 

1427 return [w for w in words if isinstance(w, str)] 

1428 

1429 

1430class _DictKeyState(enum.Flag): 

1431 """Represent state of the key match in context of other possible matches. 

1432 

1433 - given `d1 = {'a': 1}` completion on `d1['<tab>` will yield `{'a': END_OF_ITEM}` as there is no tuple. 

1434 - given `d2 = {('a', 'b'): 1}`: `d2['a', '<tab>` will yield `{'b': END_OF_TUPLE}` as there is no tuple members to add beyond `'b'`. 

1435 - given `d3 = {('a', 'b'): 1}`: `d3['<tab>` will yield `{'a': IN_TUPLE}` as `'a'` can be added. 

1436 - given `d4 = {'a': 1, ('a', 'b'): 2}`: `d4['<tab>` will yield `{'a': END_OF_ITEM & END_OF_TUPLE}` 

1437 """ 

1438 

1439 BASELINE = 0 

1440 END_OF_ITEM = enum.auto() 

1441 END_OF_TUPLE = enum.auto() 

1442 IN_TUPLE = enum.auto() 

1443 

1444 

1445def _parse_tokens(c: str) -> list[tokenize.TokenInfo]: 

1446 """Parse tokens even if there is an error.""" 

1447 tokens = [] 

1448 token_generator = tokenize.generate_tokens(iter(c.splitlines()).__next__) 

1449 while True: 

1450 try: 

1451 tokens.append(next(token_generator)) 

1452 except tokenize.TokenError: 

1453 return tokens 

1454 except StopIteration: 

1455 return tokens 

1456 

1457 

1458def _match_number_in_dict_key_prefix(prefix: str) -> str | None: 

1459 """Match any valid Python numeric literal in a prefix of dictionary keys. 

1460 

1461 References: 

1462 - https://docs.python.org/3/reference/lexical_analysis.html#numeric-literals 

1463 - https://docs.python.org/3/library/tokenize.html 

1464 """ 

1465 if prefix[-1].isspace(): 

1466 # if user typed a space we do not have anything to complete 

1467 # even if there was a valid number token before 

1468 return None 

1469 tokens = _parse_tokens(prefix) 

1470 rev_tokens = reversed(tokens) 

1471 skip_over = {tokenize.ENDMARKER, tokenize.NEWLINE} 

1472 number = None 

1473 for token in rev_tokens: 

1474 if token.type in skip_over: 

1475 continue 

1476 if number is None: 

1477 if token.type == tokenize.NUMBER: 

1478 number = token.string 

1479 continue 

1480 else: 

1481 # we did not match a number 

1482 return None 

1483 if token.type == tokenize.OP: 

1484 if token.string == ",": 

1485 break 

1486 if token.string in {"+", "-"}: 

1487 number = token.string + number 

1488 else: 

1489 return None 

1490 return number 

1491 

1492 

1493_INT_FORMATS = { 

1494 "0b": bin, 

1495 "0o": oct, 

1496 "0x": hex, 

1497} 

1498 

1499 

1500def match_dict_keys( 

1501 keys: list[str | bytes | tuple[str | bytes, ...]], 

1502 prefix: str, 

1503 delims: str, 

1504 extra_prefix: tuple[str | bytes, ...] | None = None, 

1505) -> tuple[str, int, dict[str, _DictKeyState]]: 

1506 """Used by dict_key_matches, matching the prefix to a list of keys 

1507 

1508 Parameters 

1509 ---------- 

1510 keys 

1511 list of keys in dictionary currently being completed. 

1512 prefix 

1513 Part of the text already typed by the user. E.g. `mydict[b'fo` 

1514 delims 

1515 String of delimiters to consider when finding the current key. 

1516 extra_prefix : optional 

1517 Part of the text already typed in multi-key index cases. E.g. for 

1518 `mydict['foo', "bar", 'b`, this would be `('foo', 'bar')`. 

1519 

1520 Returns 

1521 ------- 

1522 A tuple of three elements: ``quote``, ``token_start``, ``matched``, with 

1523 ``quote`` being the quote that need to be used to close current string. 

1524 ``token_start`` the position where the replacement should start occurring, 

1525 ``matches`` a dictionary of replacement/completion keys on keys and values 

1526 indicating whether the state. 

1527 """ 

1528 prefix_tuple = extra_prefix if extra_prefix else () 

1529 

1530 prefix_tuple_size = sum( 

1531 [ 

1532 # for pandas, do not count slices as taking space 

1533 not isinstance(k, slice) 

1534 for k in prefix_tuple 

1535 ] 

1536 ) 

1537 text_serializable_types = (str, bytes, int, float, slice) 

1538 

1539 def filter_prefix_tuple(key): 

1540 # Reject too short keys 

1541 if len(key) <= prefix_tuple_size: 

1542 return False 

1543 # Reject keys which cannot be serialised to text 

1544 for k in key: 

1545 if not isinstance(k, text_serializable_types): 

1546 return False 

1547 # Reject keys that do not match the prefix 

1548 for k, pt in zip(key, prefix_tuple): 

1549 if k != pt and not isinstance(pt, slice): 

1550 return False 

1551 # All checks passed! 

1552 return True 

1553 

1554 filtered_key_is_final: dict[ 

1555 str | bytes | int | float, _DictKeyState 

1556 ] = defaultdict(lambda: _DictKeyState.BASELINE) 

1557 

1558 for k in keys: 

1559 # If at least one of the matches is not final, mark as undetermined. 

1560 # This can happen with `d = {111: 'b', (111, 222): 'a'}` where 

1561 # `111` appears final on first match but is not final on the second. 

1562 

1563 if isinstance(k, tuple): 

1564 if filter_prefix_tuple(k): 

1565 key_fragment = k[prefix_tuple_size] 

1566 filtered_key_is_final[key_fragment] |= ( 

1567 _DictKeyState.END_OF_TUPLE 

1568 if len(k) == prefix_tuple_size + 1 

1569 else _DictKeyState.IN_TUPLE 

1570 ) 

1571 elif prefix_tuple_size > 0: 

1572 # we are completing a tuple but this key is not a tuple, 

1573 # so we should ignore it 

1574 pass 

1575 else: 

1576 if isinstance(k, text_serializable_types): 

1577 filtered_key_is_final[k] |= _DictKeyState.END_OF_ITEM 

1578 

1579 filtered_keys = filtered_key_is_final.keys() 

1580 

1581 if not prefix: 

1582 return "", 0, {repr(k): v for k, v in filtered_key_is_final.items()} 

1583 

1584 quote_match = re.search("(?:\"|')", prefix) 

1585 is_user_prefix_numeric = False 

1586 

1587 if quote_match: 

1588 quote = quote_match.group() 

1589 valid_prefix = prefix + quote 

1590 try: 

1591 prefix_str = literal_eval(valid_prefix) 

1592 except Exception: 

1593 return "", 0, {} 

1594 else: 

1595 # If it does not look like a string, let's assume 

1596 # we are dealing with a number or variable. 

1597 number_match = _match_number_in_dict_key_prefix(prefix) 

1598 

1599 # We do not want the key matcher to suggest variable names so we yield: 

1600 if number_match is None: 

1601 # The alternative would be to assume that user forgort the quote 

1602 # and if the substring matches, suggest adding it at the start. 

1603 return "", 0, {} 

1604 

1605 prefix_str = number_match 

1606 is_user_prefix_numeric = True 

1607 quote = "" 

1608 

1609 pattern = '[^' + ''.join('\\' + c for c in delims) + ']*$' 

1610 token_match = re.search(pattern, prefix, re.UNICODE) 

1611 assert token_match is not None # silence mypy 

1612 token_start = token_match.start() 

1613 token_prefix = token_match.group() 

1614 

1615 matched: dict[str, _DictKeyState] = {} 

1616 

1617 str_key: str | bytes 

1618 

1619 for key in filtered_keys: 

1620 if isinstance(key, (int, float)): 

1621 # User typed a number but this key is not a number. 

1622 if not is_user_prefix_numeric: 

1623 continue 

1624 str_key = str(key) 

1625 if isinstance(key, int): 

1626 int_base = prefix_str[:2].lower() 

1627 # if user typed integer using binary/oct/hex notation: 

1628 if int_base in _INT_FORMATS: 

1629 int_format = _INT_FORMATS[int_base] 

1630 str_key = int_format(key) 

1631 else: 

1632 # User typed a string but this key is a number. 

1633 if is_user_prefix_numeric: 

1634 continue 

1635 str_key = key 

1636 try: 

1637 if not str_key.startswith(prefix_str): 

1638 continue 

1639 except (AttributeError, TypeError, UnicodeError): 

1640 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa 

1641 continue 

1642 

1643 # reformat remainder of key to begin with prefix 

1644 rem = str_key[len(prefix_str) :] 

1645 # force repr wrapped in ' 

1646 rem_repr = repr(rem + '"') if isinstance(rem, str) else repr(rem + b'"') 

1647 rem_repr = rem_repr[1 + rem_repr.index("'"):-2] 

1648 if quote == '"': 

1649 # The entered prefix is quoted with ", 

1650 # but the match is quoted with '. 

1651 # A contained " hence needs escaping for comparison: 

1652 rem_repr = rem_repr.replace('"', '\\"') 

1653 

1654 # then reinsert prefix from start of token 

1655 match = "{}{}".format(token_prefix, rem_repr) 

1656 

1657 matched[match] = filtered_key_is_final[key] 

1658 return quote, token_start, matched 

1659 

1660 

1661def cursor_to_position(text:str, line:int, column:int)->int: 

1662 """ 

1663 Convert the (line,column) position of the cursor in text to an offset in a 

1664 string. 

1665 

1666 Parameters 

1667 ---------- 

1668 text : str 

1669 The text in which to calculate the cursor offset 

1670 line : int 

1671 Line of the cursor; 0-indexed 

1672 column : int 

1673 Column of the cursor 0-indexed 

1674 

1675 Returns 

1676 ------- 

1677 Position of the cursor in ``text``, 0-indexed. 

1678 

1679 See Also 

1680 -------- 

1681 position_to_cursor : reciprocal of this function 

1682 

1683 """ 

1684 lines = text.split('\n') 

1685 assert line <= len(lines), f'{str(line)} <= {str(len(lines))}' 

1686 

1687 return sum(len(line) + 1 for line in lines[:line]) + column 

1688 

1689 

1690def position_to_cursor(text: str, offset: int) -> tuple[int, int]: 

1691 """ 

1692 Convert the position of the cursor in text (0 indexed) to a line 

1693 number(0-indexed) and a column number (0-indexed) pair 

1694 

1695 Position should be a valid position in ``text``. 

1696 

1697 Parameters 

1698 ---------- 

1699 text : str 

1700 The text in which to calculate the cursor offset 

1701 offset : int 

1702 Position of the cursor in ``text``, 0-indexed. 

1703 

1704 Returns 

1705 ------- 

1706 (line, column) : (int, int) 

1707 Line of the cursor; 0-indexed, column of the cursor 0-indexed 

1708 

1709 See Also 

1710 -------- 

1711 cursor_to_position : reciprocal of this function 

1712 

1713 """ 

1714 

1715 assert 0 <= offset <= len(text) , "0 <= {} <= {}".format(offset , len(text)) 

1716 

1717 before = text[:offset] 

1718 blines = before.split('\n') # ! splitnes trim trailing \n 

1719 line = before.count('\n') 

1720 col = len(blines[-1]) 

1721 return line, col 

1722 

1723 

1724def _safe_isinstance(obj, module, class_name, *attrs): 

1725 """Checks if obj is an instance of module.class_name if loaded 

1726 """ 

1727 if module in sys.modules: 

1728 m = sys.modules[module] 

1729 for attr in [class_name, *attrs]: 

1730 m = getattr(m, attr) 

1731 return isinstance(obj, m) 

1732 

1733 

1734@context_matcher() 

1735def back_unicode_name_matcher(context: CompletionContext): 

1736 """Match Unicode characters back to Unicode name 

1737 

1738 Same as :any:`back_unicode_name_matches`, but adopted to new Matcher API. 

1739 """ 

1740 fragment, matches = back_unicode_name_matches(context.text_until_cursor) 

1741 return _convert_matcher_v1_result_to_v2( 

1742 matches, type="unicode", fragment=fragment, suppress_if_matches=True 

1743 ) 

1744 

1745 

1746def back_unicode_name_matches(text: str) -> tuple[str, Sequence[str]]: 

1747 """Match Unicode characters back to Unicode name 

1748 

1749 This does ``☃`` -> ``\\snowman`` 

1750 

1751 Note that snowman is not a valid python3 combining character but will be expanded. 

1752 Though it will not recombine back to the snowman character by the completion machinery. 

1753 

1754 This will not either back-complete standard sequences like \\n, \\b ... 

1755 

1756 .. deprecated:: 8.6 

1757 You can use :meth:`back_unicode_name_matcher` instead. 

1758 

1759 Returns 

1760 ======= 

1761 

1762 Return a tuple with two elements: 

1763 

1764 - The Unicode character that was matched (preceded with a backslash), or 

1765 empty string, 

1766 - a sequence (of 1), name for the match Unicode character, preceded by 

1767 backslash, or empty if no match. 

1768 """ 

1769 if len(text)<2: 

1770 return '', () 

1771 maybe_slash = text[-2] 

1772 if maybe_slash != '\\': 

1773 return '', () 

1774 

1775 char = text[-1] 

1776 # no expand on quote for completion in strings. 

1777 # nor backcomplete standard ascii keys 

1778 if char in string.ascii_letters or char in ('"',"'"): 

1779 return '', () 

1780 try : 

1781 unic = unicodedata.name(char) 

1782 return '\\'+char,('\\'+unic,) 

1783 except KeyError: 

1784 pass 

1785 return '', () 

1786 

1787 

1788@context_matcher() 

1789def back_latex_name_matcher(context: CompletionContext) -> SimpleMatcherResult: 

1790 """Match latex characters back to unicode name 

1791 

1792 This does ``\\ℵ`` -> ``\\aleph`` 

1793 """ 

1794 

1795 text = context.text_until_cursor 

1796 no_match = { 

1797 "completions": [], 

1798 "suppress": False, 

1799 } 

1800 

1801 if len(text)<2: 

1802 return no_match 

1803 maybe_slash = text[-2] 

1804 if maybe_slash != '\\': 

1805 return no_match 

1806 

1807 char = text[-1] 

1808 # no expand on quote for completion in strings. 

1809 # nor backcomplete standard ascii keys 

1810 if char in string.ascii_letters or char in ('"',"'"): 

1811 return no_match 

1812 try : 

1813 latex = reverse_latex_symbol[char] 

1814 # '\\' replace the \ as well 

1815 return { 

1816 "completions": [SimpleCompletion(text=latex, type="latex")], 

1817 "suppress": True, 

1818 "matched_fragment": "\\" + char, 

1819 } 

1820 except KeyError: 

1821 pass 

1822 

1823 return no_match 

1824 

1825def _formatparamchildren(parameter) -> str: 

1826 """ 

1827 Get parameter name and value from Jedi Private API 

1828 

1829 Jedi does not expose a simple way to get `param=value` from its API. 

1830 

1831 Parameters 

1832 ---------- 

1833 parameter 

1834 Jedi's function `Param` 

1835 

1836 Returns 

1837 ------- 

1838 A string like 'a', 'b=1', '*args', '**kwargs' 

1839 

1840 """ 

1841 description = parameter.description 

1842 if not description.startswith('param '): 

1843 raise ValueError('Jedi function parameter description have change format.' 

1844 'Expected "param ...", found %r".' % description) 

1845 return description[6:] 

1846 

1847def _make_signature(completion)-> str: 

1848 """ 

1849 Make the signature from a jedi completion 

1850 

1851 Parameters 

1852 ---------- 

1853 completion : jedi.Completion 

1854 object does not complete a function type 

1855 

1856 Returns 

1857 ------- 

1858 a string consisting of the function signature, with the parenthesis but 

1859 without the function name. example: 

1860 `(a, *args, b=1, **kwargs)` 

1861 

1862 """ 

1863 

1864 # it looks like this might work on jedi 0.17 

1865 if hasattr(completion, 'get_signatures'): 

1866 signatures = completion.get_signatures() 

1867 if not signatures: 

1868 return '(?)' 

1869 

1870 c0 = completion.get_signatures()[0] 

1871 return '('+c0.to_string().split('(', maxsplit=1)[1] 

1872 

1873 return '(%s)'% ', '.join([f for f in (_formatparamchildren(p) for signature in completion.get_signatures() 

1874 for p in signature.defined_names()) if f]) 

1875 

1876 

1877_CompleteResult = dict[str, MatcherResult] 

1878 

1879 

1880DICT_MATCHER_REGEX = re.compile( 

1881 r"""(?x) 

1882( # match dict-referring - or any get item object - expression 

1883 .+ 

1884) 

1885\[ # open bracket 

1886\s* # and optional whitespace 

1887# Capture any number of serializable objects (e.g. "a", "b", 'c') 

1888# and slices 

1889((?:(?: 

1890 (?: # closed string 

1891 [uUbB]? # string prefix (r not handled) 

1892 (?: 

1893 '(?:[^']|(?<!\\)\\')*' 

1894 | 

1895 "(?:[^"]|(?<!\\)\\")*" 

1896 ) 

1897 ) 

1898 | 

1899 # capture integers and slices 

1900 (?:[-+]?\d+)?(?::(?:[-+]?\d+)?){0,2} 

1901 | 

1902 # integer in bin/hex/oct notation 

1903 0[bBxXoO]_?(?:\w|\d)+ 

1904 ) 

1905 \s*,\s* 

1906)*) 

1907((?: 

1908 (?: # unclosed string 

1909 [uUbB]? # string prefix (r not handled) 

1910 (?: 

1911 '(?:[^']|(?<!\\)\\')* 

1912 | 

1913 "(?:[^"]|(?<!\\)\\")* 

1914 ) 

1915 ) 

1916 | 

1917 # unfinished integer 

1918 (?:[-+]?\d+) 

1919 | 

1920 # integer in bin/hex/oct notation 

1921 0[bBxXoO]_?(?:\w|\d)+ 

1922 ) 

1923)? 

1924$ 

1925""" 

1926) 

1927 

1928 

1929def _convert_matcher_v1_result_to_v2_no_no( 

1930 matches: Sequence[str], 

1931 type: str, 

1932) -> SimpleMatcherResult: 

1933 """same as _convert_matcher_v1_result_to_v2 but fragment=None, and suppress_if_matches is False by construction""" 

1934 return SimpleMatcherResult( 

1935 completions=[SimpleCompletion(text=match, type=type) for match in matches], 

1936 suppress=False, 

1937 ) 

1938 

1939 

1940def _convert_matcher_v1_result_to_v2( 

1941 matches: Sequence[str], 

1942 type: str, 

1943 fragment: str | None = None, 

1944 suppress_if_matches: bool = False, 

1945) -> SimpleMatcherResult: 

1946 """Utility to help with transition""" 

1947 result = { 

1948 "completions": [SimpleCompletion(text=match, type=type) for match in matches], 

1949 "suppress": (True if matches else False) if suppress_if_matches else False, 

1950 } 

1951 if fragment is not None: 

1952 result["matched_fragment"] = fragment 

1953 return cast(SimpleMatcherResult, result) 

1954 

1955 

1956class IPCompleter(Completer): 

1957 """Extension of the completer class with IPython-specific features""" 

1958 

1959 @observe("greedy") 

1960 def _greedy_changed(self, change): 

1961 """update the splitter and readline delims when greedy is changed""" 

1962 if change["new"]: 

1963 self.evaluation = "unsafe" 

1964 self.auto_close_dict_keys = True 

1965 self.splitter.delims = GREEDY_DELIMS 

1966 else: 

1967 self.evaluation = "limited" 

1968 self.auto_close_dict_keys = False 

1969 self.splitter.delims = DELIMS 

1970 

1971 dict_keys_only = Bool( 

1972 False, 

1973 help=""" 

1974 Whether to show dict key matches only. 

1975 

1976 (disables all matchers except for `IPCompleter.dict_key_matcher`). 

1977 """, 

1978 ) 

1979 

1980 suppress_competing_matchers = UnionTrait( 

1981 [Bool(allow_none=True), DictTrait(Bool(None, allow_none=True))], 

1982 default_value=None, 

1983 help=""" 

1984 Whether to suppress completions from other *Matchers*. 

1985 

1986 When set to ``None`` (default) the matchers will attempt to auto-detect 

1987 whether suppression of other matchers is desirable. For example, at 

1988 the beginning of a line followed by `%` we expect a magic completion 

1989 to be the only applicable option, and after ``my_dict['`` we usually 

1990 expect a completion with an existing dictionary key. 

1991 

1992 If you want to disable this heuristic and see completions from all matchers, 

1993 set ``IPCompleter.suppress_competing_matchers = False``. 

1994 To disable the heuristic for specific matchers provide a dictionary mapping: 

1995 ``IPCompleter.suppress_competing_matchers = {'IPCompleter.dict_key_matcher': False}``. 

1996 

1997 Set ``IPCompleter.suppress_competing_matchers = True`` to limit 

1998 completions to the set of matchers with the highest priority; 

1999 this is equivalent to ``IPCompleter.merge_completions`` and 

2000 can be beneficial for performance, but will sometimes omit relevant 

2001 candidates from matchers further down the priority list. 

2002 """, 

2003 ).tag(config=True) 

2004 

2005 merge_completions = Bool( 

2006 True, 

2007 help="""Whether to merge completion results into a single list 

2008 

2009 If False, only the completion results from the first non-empty 

2010 completer will be returned. 

2011 

2012 As of version 8.6.0, setting the value to ``False`` is an alias for: 

2013 ``IPCompleter.suppress_competing_matchers = True.``. 

2014 """, 

2015 ).tag(config=True) 

2016 

2017 disable_matchers = ListTrait( 

2018 Unicode(), 

2019 help="""List of matchers to disable. 

2020 

2021 The list should contain matcher identifiers (see :any:`completion_matcher`). 

2022 """, 

2023 ).tag(config=True) 

2024 

2025 omit__names = Enum( 

2026 (0, 1, 2), 

2027 default_value=2, 

2028 help="""Instruct the completer to omit private method names 

2029 

2030 Specifically, when completing on ``object.<tab>``. 

2031 

2032 When 2 [default]: all names that start with '_' will be excluded. 

2033 

2034 When 1: all 'magic' names (``__foo__``) will be excluded. 

2035 

2036 When 0: nothing will be excluded. 

2037 """ 

2038 ).tag(config=True) 

2039 profile_completions = Bool( 

2040 default_value=False, 

2041 help="If True, emit profiling data for completion subsystem using cProfile." 

2042 ).tag(config=True) 

2043 

2044 profiler_output_dir = Unicode( 

2045 default_value=".completion_profiles", 

2046 help="Template for path at which to output profile data for completions." 

2047 ).tag(config=True) 

2048 

2049 def __init__( 

2050 self, shell=None, namespace=None, global_namespace=None, config=None, **kwargs 

2051 ): 

2052 """IPCompleter() -> completer 

2053 

2054 Return a completer object. 

2055 

2056 Parameters 

2057 ---------- 

2058 shell 

2059 a pointer to the ipython shell itself. This is needed 

2060 because this completer knows about magic functions, and those can 

2061 only be accessed via the ipython instance. 

2062 namespace : dict, optional 

2063 an optional dict where completions are performed. 

2064 global_namespace : dict, optional 

2065 secondary optional dict for completions, to 

2066 handle cases (such as IPython embedded inside functions) where 

2067 both Python scopes are visible. 

2068 config : Config 

2069 traitlet's config object 

2070 **kwargs 

2071 passed to super class unmodified. 

2072 """ 

2073 

2074 self.magic_escape = ESC_MAGIC 

2075 self.splitter = CompletionSplitter() 

2076 

2077 # _greedy_changed() depends on splitter and readline being defined: 

2078 super().__init__( 

2079 namespace=namespace, 

2080 global_namespace=global_namespace, 

2081 config=config, 

2082 **kwargs, 

2083 ) 

2084 

2085 # List where completion matches will be stored 

2086 self.matches = [] 

2087 self.shell = shell 

2088 # Regexp to split filenames with spaces in them 

2089 self.space_name_re = re.compile(r'([^\\] )') 

2090 # Hold a local ref. to glob.glob for speed 

2091 self.glob = glob.glob 

2092 

2093 # Determine if we are running on 'dumb' terminals, like (X)Emacs 

2094 # buffers, to avoid completion problems. 

2095 term = os.environ.get('TERM','xterm') 

2096 self.dumb_terminal = term in ['dumb','emacs'] 

2097 

2098 # Special handling of backslashes needed in win32 platforms 

2099 if sys.platform == "win32": 

2100 self.clean_glob = self._clean_glob_win32 

2101 else: 

2102 self.clean_glob = self._clean_glob 

2103 

2104 #regexp to parse docstring for function signature 

2105 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*') 

2106 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)') 

2107 #use this if positional argument name is also needed 

2108 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)') 

2109 

2110 self.magic_arg_matchers = [ 

2111 self.magic_config_matcher, 

2112 self.magic_color_matcher, 

2113 ] 

2114 

2115 # This is set externally by InteractiveShell 

2116 self.custom_completers = None 

2117 

2118 # This is a list of names of unicode characters that can be completed 

2119 # into their corresponding unicode value. The list is large, so we 

2120 # lazily initialize it on first use. Consuming code should access this 

2121 # attribute through the `@unicode_names` property. 

2122 self._unicode_names = None 

2123 

2124 self._backslash_combining_matchers = [ 

2125 self.latex_name_matcher, 

2126 self.unicode_name_matcher, 

2127 back_latex_name_matcher, 

2128 back_unicode_name_matcher, 

2129 self.fwd_unicode_matcher, 

2130 ] 

2131 

2132 if not self.backslash_combining_completions: 

2133 for matcher in self._backslash_combining_matchers: 

2134 self.disable_matchers.append(_get_matcher_id(matcher)) 

2135 

2136 if not self.merge_completions: 

2137 self.suppress_competing_matchers = True 

2138 

2139 @property 

2140 def matchers(self) -> list[Matcher]: 

2141 """All active matcher routines for completion""" 

2142 if self.dict_keys_only: 

2143 return [self.dict_key_matcher] 

2144 

2145 if self.use_jedi: 

2146 return [ 

2147 *self.custom_matchers, 

2148 *self._backslash_combining_matchers, 

2149 *self.magic_arg_matchers, 

2150 self.custom_completer_matcher, 

2151 self.magic_matcher, 

2152 self._jedi_matcher, 

2153 self.dict_key_matcher, 

2154 self.file_matcher, 

2155 ] 

2156 else: 

2157 return [ 

2158 *self.custom_matchers, 

2159 *self._backslash_combining_matchers, 

2160 *self.magic_arg_matchers, 

2161 self.custom_completer_matcher, 

2162 self.dict_key_matcher, 

2163 self.magic_matcher, 

2164 self.python_matcher, 

2165 self.file_matcher, 

2166 self.python_func_kw_matcher, 

2167 ] 

2168 

2169 def all_completions(self, text: str) -> list[str]: 

2170 """ 

2171 Wrapper around the completion methods for the benefit of emacs. 

2172 """ 

2173 prefix = text.rpartition('.')[0] 

2174 with provisionalcompleter(): 

2175 return ['.'.join([prefix, c.text]) if prefix and self.use_jedi else c.text 

2176 for c in self.completions(text, len(text))] 

2177 

2178 return self.complete(text)[1] 

2179 

2180 def _clean_glob(self, text:str): 

2181 return self.glob("%s*" % text) 

2182 

2183 def _clean_glob_win32(self, text:str): 

2184 return [f.replace("\\","/") 

2185 for f in self.glob("%s*" % text)] 

2186 

2187 @context_matcher() 

2188 def file_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

2189 """Match filenames, expanding ~USER type strings. 

2190 

2191 Most of the seemingly convoluted logic in this completer is an 

2192 attempt to handle filenames with spaces in them. And yet it's not 

2193 quite perfect, because Python's readline doesn't expose all of the 

2194 GNU readline details needed for this to be done correctly. 

2195 

2196 For a filename with a space in it, the printed completions will be 

2197 only the parts after what's already been typed (instead of the 

2198 full completions, as is normally done). I don't think with the 

2199 current (as of Python 2.3) Python readline it's possible to do 

2200 better. 

2201 """ 

2202 # TODO: add a heuristic for suppressing (e.g. if it has OS-specific delimiter, 

2203 # starts with `/home/`, `C:\`, etc) 

2204 

2205 text = context.token 

2206 raw_text_until_cursor = context.text_until_cursor 

2207 code_until_cursor = self._extract_code(raw_text_until_cursor) 

2208 in_cli_context = self._is_completing_in_cli_context( 

2209 raw_text_until_cursor 

2210 ) or self._is_completing_in_cli_context(code_until_cursor) 

2211 if ( 

2212 not in_cli_context 

2213 and not self._is_completing_in_string(code_until_cursor) 

2214 and not self._looks_like_path(text) 

2215 ): 

2216 return { 

2217 "completions": [], 

2218 "suppress": False, 

2219 } 

2220 

2221 completion_type = self._determine_completion_context(code_until_cursor) 

2222 if ( 

2223 completion_type == self._CompletionContextType.ATTRIBUTE 

2224 and not in_cli_context 

2225 ): 

2226 return { 

2227 "completions": [], 

2228 "suppress": False, 

2229 } 

2230 

2231 # chars that require escaping with backslash - i.e. chars 

2232 # that readline treats incorrectly as delimiters, but we 

2233 # don't want to treat as delimiters in filename matching 

2234 # when escaped with backslash 

2235 if text.startswith('!'): 

2236 text = text[1:] 

2237 text_prefix = '!' 

2238 else: 

2239 text_prefix = '' 

2240 

2241 text_until_cursor = self.text_until_cursor 

2242 # track strings with open quotes 

2243 open_quotes = has_open_quotes(text_until_cursor) 

2244 

2245 if '(' in text_until_cursor or '[' in text_until_cursor: 

2246 lsplit = text 

2247 else: 

2248 try: 

2249 # arg_split ~ shlex.split, but with unicode bugs fixed by us 

2250 lsplit = arg_split(text_until_cursor)[-1] 

2251 except ValueError: 

2252 # typically an unmatched ", or backslash without escaped char. 

2253 if open_quotes: 

2254 lsplit = text_until_cursor.split(open_quotes)[-1] 

2255 else: 

2256 return { 

2257 "completions": [], 

2258 "suppress": False, 

2259 } 

2260 except IndexError: 

2261 # tab pressed on empty line 

2262 lsplit = "" 

2263 

2264 if not open_quotes and lsplit != protect_filename(lsplit): 

2265 # if protectables are found, do matching on the whole escaped name 

2266 has_protectables = True 

2267 text0,text = text,lsplit 

2268 else: 

2269 has_protectables = False 

2270 text = os.path.expanduser(text) 

2271 

2272 if text == "": 

2273 return { 

2274 "completions": [ 

2275 SimpleCompletion( 

2276 text=text_prefix + protect_filename(f), type="path" 

2277 ) 

2278 for f in self.glob("*") 

2279 ], 

2280 "suppress": False, 

2281 } 

2282 

2283 # Compute the matches from the filesystem 

2284 if sys.platform == 'win32': 

2285 m0 = self.clean_glob(text) 

2286 else: 

2287 m0 = self.clean_glob(text.replace('\\', '')) 

2288 

2289 if has_protectables: 

2290 # If we had protectables, we need to revert our changes to the 

2291 # beginning of filename so that we don't double-write the part 

2292 # of the filename we have so far 

2293 len_lsplit = len(lsplit) 

2294 matches = [text_prefix + text0 + 

2295 protect_filename(f[len_lsplit:]) for f in m0] 

2296 else: 

2297 if open_quotes: 

2298 # if we have a string with an open quote, we don't need to 

2299 # protect the names beyond the quote (and we _shouldn't_, as 

2300 # it would cause bugs when the filesystem call is made). 

2301 matches = m0 if sys.platform == "win32" else\ 

2302 [protect_filename(f, open_quotes) for f in m0] 

2303 else: 

2304 matches = [text_prefix + 

2305 protect_filename(f) for f in m0] 

2306 

2307 # Mark directories in input list by appending '/' to their names. 

2308 return { 

2309 "completions": [ 

2310 SimpleCompletion(text=x + "/" if os.path.isdir(x) else x, type="path") 

2311 for x in matches 

2312 ], 

2313 "suppress": False, 

2314 } 

2315 

2316 def _extract_code(self, line: str) -> str: 

2317 """Extract code from magics if any.""" 

2318 

2319 if not line: 

2320 return line 

2321 maybe_magic, *rest = line.split(maxsplit=1) 

2322 if not rest: 

2323 return line 

2324 args = rest[0] 

2325 known_magics = self.shell.magics_manager.lsmagic() 

2326 line_magics = known_magics["line"] 

2327 magic_name = maybe_magic.lstrip(self.magic_escape) 

2328 if magic_name not in line_magics: 

2329 return line 

2330 

2331 if not maybe_magic.startswith(self.magic_escape): 

2332 all_variables = [*self.namespace.keys(), *self.global_namespace.keys()] 

2333 if magic_name in all_variables: 

2334 # short circuit if we see a line starting with say `time` 

2335 # but time is defined as a variable (in addition to being 

2336 # a magic). In these cases users need to use explicit `%time`. 

2337 return line 

2338 

2339 magic_method = line_magics[magic_name] 

2340 

2341 try: 

2342 if magic_name == "timeit": 

2343 opts, stmt = magic_method.__self__.parse_options( 

2344 args, 

2345 "n:r:tcp:qov:", 

2346 posix=False, 

2347 strict=False, 

2348 preserve_non_opts=True, 

2349 ) 

2350 return stmt 

2351 elif magic_name == "prun": 

2352 opts, stmt = magic_method.__self__.parse_options( 

2353 args, "D:l:rs:T:q", list_all=True, posix=False 

2354 ) 

2355 return stmt 

2356 elif hasattr(magic_method, "parser") and getattr( 

2357 magic_method, "has_arguments", False 

2358 ): 

2359 # e.g. %debug, %time 

2360 args, extra = magic_method.parser.parse_argstring(args, partial=True) 

2361 return " ".join(extra) 

2362 except UsageError: 

2363 return line 

2364 

2365 return line 

2366 

2367 @context_matcher() 

2368 def magic_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

2369 """Match magics.""" 

2370 

2371 # Get all shell magics now rather than statically, so magics loaded at 

2372 # runtime show up too. 

2373 text = context.token 

2374 lsm = self.shell.magics_manager.lsmagic() 

2375 line_magics = lsm['line'] 

2376 cell_magics = lsm['cell'] 

2377 pre = self.magic_escape 

2378 pre2 = pre + pre 

2379 

2380 explicit_magic = text.startswith(pre) 

2381 

2382 # Completion logic: 

2383 # - user gives %%: only do cell magics 

2384 # - user gives %: do both line and cell magics 

2385 # - no prefix: do both 

2386 # In other words, line magics are skipped if the user gives %% explicitly 

2387 # 

2388 # We also exclude magics that match any currently visible names: 

2389 # https://github.com/ipython/ipython/issues/4877, unless the user has 

2390 # typed a %: 

2391 # https://github.com/ipython/ipython/issues/10754 

2392 bare_text = text.lstrip(pre) 

2393 global_matches = self.global_matches(bare_text) 

2394 if not explicit_magic: 

2395 def matches(magic): 

2396 """ 

2397 Filter magics, in particular remove magics that match 

2398 a name present in global namespace. 

2399 """ 

2400 return ( magic.startswith(bare_text) and 

2401 magic not in global_matches ) 

2402 else: 

2403 def matches(magic): 

2404 return magic.startswith(bare_text) 

2405 

2406 completions = [pre2 + m for m in cell_magics if matches(m)] 

2407 if not text.startswith(pre2): 

2408 completions += [pre + m for m in line_magics if matches(m)] 

2409 

2410 is_magic_prefix = len(text) > 0 and text[0] == "%" 

2411 

2412 return { 

2413 "completions": [ 

2414 SimpleCompletion(text=comp, type="magic") for comp in completions 

2415 ], 

2416 "suppress": is_magic_prefix and len(completions) > 0, 

2417 } 

2418 

2419 @context_matcher() 

2420 def magic_config_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

2421 """Match class names and attributes for %config magic.""" 

2422 # NOTE: uses `line_buffer` equivalent for compatibility 

2423 matches = self.magic_config_matches(context.line_with_cursor) 

2424 return _convert_matcher_v1_result_to_v2_no_no(matches, type="param") 

2425 

2426 def magic_config_matches(self, text: str) -> list[str]: 

2427 """Match class names and attributes for %config magic. 

2428 

2429 .. deprecated:: 8.6 

2430 You can use :meth:`magic_config_matcher` instead. 

2431 """ 

2432 texts = text.strip().split() 

2433 

2434 if len(texts) > 0 and (texts[0] == 'config' or texts[0] == '%config'): 

2435 # get all configuration classes 

2436 classes = sorted({ c for c in self.shell.configurables 

2437 if c.__class__.class_traits(config=True) 

2438 }, key=lambda x: x.__class__.__name__) 

2439 classnames = [ c.__class__.__name__ for c in classes ] 

2440 

2441 # return all classnames if config or %config is given 

2442 if len(texts) == 1: 

2443 return classnames 

2444 

2445 # match classname 

2446 classname_texts = texts[1].split('.') 

2447 classname = classname_texts[0] 

2448 classname_matches = [ c for c in classnames 

2449 if c.startswith(classname) ] 

2450 

2451 # return matched classes or the matched class with attributes 

2452 if texts[1].find('.') < 0: 

2453 return classname_matches 

2454 elif len(classname_matches) == 1 and \ 

2455 classname_matches[0] == classname: 

2456 cls = classes[classnames.index(classname)].__class__ 

2457 help = cls.class_get_help() 

2458 # strip leading '--' from cl-args: 

2459 help = _LEADING_DASHES_RE.sub("", help) 

2460 return [ attr.split('=')[0] 

2461 for attr in help.strip().splitlines() 

2462 if attr.startswith(texts[1]) ] 

2463 return [] 

2464 

2465 @context_matcher() 

2466 def magic_color_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

2467 """Match color schemes for %colors magic.""" 

2468 text = context.line_with_cursor 

2469 texts = text.split() 

2470 if text.endswith(' '): 

2471 # .split() strips off the trailing whitespace. Add '' back 

2472 # so that: '%colors ' -> ['%colors', ''] 

2473 texts.append('') 

2474 

2475 if len(texts) == 2 and (texts[0] == 'colors' or texts[0] == '%colors'): 

2476 prefix = texts[1] 

2477 return SimpleMatcherResult( 

2478 completions=[ 

2479 SimpleCompletion(color, type="param") 

2480 for color in theme_table.keys() 

2481 if color.startswith(prefix) 

2482 ], 

2483 suppress=False, 

2484 ) 

2485 return SimpleMatcherResult( 

2486 completions=[], 

2487 suppress=False, 

2488 ) 

2489 

2490 @context_matcher(identifier="IPCompleter.jedi_matcher") 

2491 def _jedi_matcher(self, context: CompletionContext) -> _JediMatcherResult: 

2492 matches = self._jedi_matches( 

2493 cursor_column=context.cursor_position, 

2494 cursor_line=context.cursor_line, 

2495 text=context.full_text, 

2496 ) 

2497 return { 

2498 "completions": matches, 

2499 # static analysis should not suppress other matcher 

2500 # NOTE: file_matcher is automatically suppressed on attribute completions 

2501 "suppress": False, 

2502 } 

2503 

2504 def _jedi_matches( 

2505 self, cursor_column: int, cursor_line: int, text: str 

2506 ) -> Iterator[_JediCompletionLike]: 

2507 """ 

2508 Return a list of :any:`jedi.api.Completion`\\s object from a ``text`` and 

2509 cursor position. 

2510 

2511 Parameters 

2512 ---------- 

2513 cursor_column : int 

2514 column position of the cursor in ``text``, 0-indexed. 

2515 cursor_line : int 

2516 line position of the cursor in ``text``, 0-indexed 

2517 text : str 

2518 text to complete 

2519 

2520 Notes 

2521 ----- 

2522 If ``IPCompleter.debug`` is ``True`` may return a :any:`_FakeJediCompletion` 

2523 object containing a string with the Jedi debug information attached. 

2524 

2525 .. deprecated:: 8.6 

2526 You can use :meth:`_jedi_matcher` instead. 

2527 """ 

2528 namespaces = [self.namespace] 

2529 if self.global_namespace is not None: 

2530 namespaces.append(self.global_namespace) 

2531 

2532 completion_filter = lambda x:x 

2533 offset = cursor_to_position(text, cursor_line, cursor_column) 

2534 # filter output if we are completing for object members 

2535 if offset: 

2536 pre = text[offset-1] 

2537 if pre == '.': 

2538 if self.omit__names == 2: 

2539 completion_filter = lambda c:not c.name.startswith('_') 

2540 elif self.omit__names == 1: 

2541 completion_filter = lambda c:not (c.name.startswith('__') and c.name.endswith('__')) 

2542 elif self.omit__names == 0: 

2543 completion_filter = lambda x:x 

2544 else: 

2545 raise ValueError(f"Don't understand self.omit__names == {self.omit__names}") 

2546 

2547 interpreter = _get_jedi().Interpreter(text[:offset], namespaces) 

2548 try_jedi = True 

2549 

2550 try: 

2551 # find the first token in the current tree -- if it is a ' or " then we are in a string 

2552 completing_string = False 

2553 try: 

2554 first_child = next(c for c in interpreter._get_module().tree_node.children if hasattr(c, 'value')) 

2555 except StopIteration: 

2556 pass 

2557 else: 

2558 # note the value may be ', ", or it may also be ''' or """, or 

2559 # in some cases, """what/you/typed..., but all of these are 

2560 # strings. 

2561 completing_string = len(first_child.value) > 0 and first_child.value[0] in {"'", '"'} 

2562 

2563 # if we are in a string jedi is likely not the right candidate for 

2564 # now. Skip it. 

2565 try_jedi = not completing_string 

2566 except Exception as e: 

2567 # many of things can go wrong, we are using private API just don't crash. 

2568 if self.debug: 

2569 print("Error detecting if completing a non-finished string :", e, '|') 

2570 

2571 if not try_jedi: 

2572 return iter([]) 

2573 try: 

2574 return filter(completion_filter, interpreter.complete(column=cursor_column, line=cursor_line + 1)) 

2575 except Exception as e: 

2576 if self.debug: 

2577 return iter( 

2578 [ 

2579 _FakeJediCompletion( 

2580 'Oops Jedi has crashed, please report a bug with the following:\n"""\n%s\ns"""' 

2581 % (e) 

2582 ) 

2583 ] 

2584 ) 

2585 else: 

2586 return iter([]) 

2587 

2588 class _CompletionContextType(enum.Enum): 

2589 ATTRIBUTE = "attribute" # For attribute completion 

2590 GLOBAL = "global" # For global completion 

2591 

2592 def _determine_completion_context(self, line): 

2593 """ 

2594 Determine whether the cursor is in an attribute or global completion context. 

2595 """ 

2596 # Cursor in string/comment → GLOBAL. 

2597 is_string, is_in_expression = self._is_in_string_or_comment(line) 

2598 if is_string and not is_in_expression: 

2599 return self._CompletionContextType.GLOBAL 

2600 

2601 # If we're in a template string expression, handle specially 

2602 if is_string and is_in_expression: 

2603 # Extract the expression part - look for the last { that isn't closed 

2604 expr_start = line.rfind("{") 

2605 if expr_start >= 0: 

2606 # We're looking at the expression inside a template string 

2607 expr = line[expr_start + 1 :] 

2608 # Recursively determine the context of the expression 

2609 return self._determine_completion_context(expr) 

2610 

2611 # Handle plain number literals - should be global context 

2612 # Ex: 3. -42.14 but not 3.1. 

2613 if re.search(r"(?<!\w)(?<!\d\.)([-+]?\d+\.(\d+)?)(?!\w)$", line): 

2614 return self._CompletionContextType.GLOBAL 

2615 

2616 # Handle all other attribute matches np.ran, d[0].k, (a,b).count, obj._private 

2617 chain_match = re.search(r".*(.+(?<!\s)\.(?:[a-zA-Z_]\w*)?)$", line) 

2618 if chain_match: 

2619 return self._CompletionContextType.ATTRIBUTE 

2620 

2621 return self._CompletionContextType.GLOBAL 

2622 

2623 def _is_completing_in_cli_context(self, text: str) -> bool: 

2624 """ 

2625 Determine if we are completing in a CLI alias, line magic, or bang expression context. 

2626 """ 

2627 stripped = text.lstrip() 

2628 if stripped.startswith("!") or stripped.startswith("%"): 

2629 return True 

2630 if self._is_completing_in_system_assignment(text): 

2631 return True 

2632 # Check for CLI aliases 

2633 try: 

2634 tokens = stripped.split(None, 1) 

2635 if not tokens: 

2636 return False 

2637 first_token = tokens[0] 

2638 

2639 # Must have arguments after the command for this to apply 

2640 if len(tokens) < 2: 

2641 return False 

2642 

2643 # Check if first token is a known alias 

2644 if not any( 

2645 alias[0] == first_token for alias in self.shell.alias_manager.aliases 

2646 ): 

2647 return False 

2648 

2649 try: 

2650 if first_token in self.shell.user_ns: 

2651 # There's a variable defined, so the alias is overshadowed 

2652 return False 

2653 except (AttributeError, KeyError): 

2654 pass 

2655 

2656 return True 

2657 except Exception: 

2658 return False 

2659 

2660 def _is_completing_in_system_assignment(self, text: str) -> bool: 

2661 """Return True for IPython ``name = !command`` syntax.""" 

2662 try: 

2663 transform = SystemAssign.find(make_tokens_by_line([text + "\n"])) 

2664 except Exception: 

2665 return False 

2666 return transform is not None and transform.start_col < len(text) 

2667 

2668 def _is_completing_in_string(self, text: str) -> bool: 

2669 """Return True if the cursor is in a string literal, not a comment.""" 

2670 is_string, is_in_expression = self._is_in_string_or_comment(text) 

2671 if not is_string or is_in_expression: 

2672 return False 

2673 return not any(token.type == tokenize.COMMENT for token in _parse_tokens(text)) 

2674 

2675 def _looks_like_path(self, text: str) -> bool: 

2676 if text.startswith(("~", "/", "./", "../", ".\\", "..\\")): 

2677 return True 

2678 return bool(sys.platform == "win32" and re.match(r"^[a-zA-Z]:[\\/]", text)) 

2679 

2680 def _is_in_string_or_comment(self, text): 

2681 """ 

2682 Determine if the cursor is inside a string or comment. 

2683 Returns (is_string, is_in_expression) tuple: 

2684 - is_string: True if in any kind of string 

2685 - is_in_expression: True if inside an f-string/t-string expression 

2686 """ 

2687 in_single_quote = False 

2688 in_double_quote = False 

2689 in_triple_single = False 

2690 in_triple_double = False 

2691 in_template_string = False # Covers both f-strings and t-strings 

2692 in_expression = False # For expressions in f/t-strings 

2693 expression_depth = 0 # Track nested braces in expressions 

2694 i = 0 

2695 

2696 while i < len(text): 

2697 # Check for f-string or t-string start 

2698 if ( 

2699 i + 1 < len(text) 

2700 and text[i] in ("f", "t") 

2701 and (text[i + 1] == '"' or text[i + 1] == "'") 

2702 and not ( 

2703 in_single_quote 

2704 or in_double_quote 

2705 or in_triple_single 

2706 or in_triple_double 

2707 ) 

2708 ): 

2709 in_template_string = True 

2710 i += 1 # Skip the 'f' or 't' 

2711 

2712 # Handle triple quotes 

2713 if i + 2 < len(text): 

2714 if ( 

2715 text[i : i + 3] == '"""' 

2716 and not in_single_quote 

2717 and not in_triple_single 

2718 ): 

2719 in_triple_double = not in_triple_double 

2720 if not in_triple_double: 

2721 in_template_string = False 

2722 i += 3 

2723 continue 

2724 if ( 

2725 text[i : i + 3] == "'''" 

2726 and not in_double_quote 

2727 and not in_triple_double 

2728 ): 

2729 in_triple_single = not in_triple_single 

2730 if not in_triple_single: 

2731 in_template_string = False 

2732 i += 3 

2733 continue 

2734 

2735 # Handle escapes 

2736 if text[i] == "\\" and i + 1 < len(text): 

2737 i += 2 

2738 continue 

2739 

2740 # Handle nested braces within f-strings 

2741 if in_template_string: 

2742 # Special handling for consecutive opening braces 

2743 if i + 1 < len(text) and text[i : i + 2] == "{{": 

2744 i += 2 

2745 continue 

2746 

2747 # Detect start of an expression 

2748 if text[i] == "{": 

2749 # Only increment depth and mark as expression if not already in an expression 

2750 # or if we're at a top-level nested brace 

2751 if not in_expression or (in_expression and expression_depth == 0): 

2752 in_expression = True 

2753 expression_depth += 1 

2754 i += 1 

2755 continue 

2756 

2757 # Detect end of an expression 

2758 if text[i] == "}": 

2759 expression_depth -= 1 

2760 if expression_depth <= 0: 

2761 in_expression = False 

2762 expression_depth = 0 

2763 i += 1 

2764 continue 

2765 

2766 in_triple_quote = in_triple_single or in_triple_double 

2767 

2768 # Handle quotes - also reset template string when closing quotes are encountered 

2769 if text[i] == '"' and not in_single_quote and not in_triple_quote: 

2770 in_double_quote = not in_double_quote 

2771 if not in_double_quote and not in_triple_quote: 

2772 in_template_string = False 

2773 elif text[i] == "'" and not in_double_quote and not in_triple_quote: 

2774 in_single_quote = not in_single_quote 

2775 if not in_single_quote and not in_triple_quote: 

2776 in_template_string = False 

2777 

2778 # Check for comment 

2779 if text[i] == "#" and not ( 

2780 in_single_quote or in_double_quote or in_triple_quote 

2781 ): 

2782 return True, False 

2783 

2784 i += 1 

2785 

2786 is_string = ( 

2787 in_single_quote or in_double_quote or in_triple_single or in_triple_double 

2788 ) 

2789 

2790 # Return tuple (is_string, is_in_expression) 

2791 return ( 

2792 is_string or (in_template_string and not in_expression), 

2793 in_expression and expression_depth > 0, 

2794 ) 

2795 

2796 @context_matcher() 

2797 def python_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

2798 """Match attributes or global python names""" 

2799 text = context.text_until_cursor 

2800 text = self._extract_code(text) 

2801 in_cli_context = self._is_completing_in_cli_context(text) 

2802 if in_cli_context: 

2803 completion_type = self._CompletionContextType.GLOBAL 

2804 else: 

2805 completion_type = self._determine_completion_context(text) 

2806 if completion_type == self._CompletionContextType.ATTRIBUTE: 

2807 try: 

2808 matches, fragment = self._attr_matches( 

2809 text, include_prefix=False, context=context 

2810 ) 

2811 if text.endswith(".") and self.omit__names: 

2812 if self.omit__names == 1: 

2813 # true if txt is _not_ a __ name, false otherwise: 

2814 no__name = lambda txt: re.match(r".*\.__.*?__", txt) is None 

2815 else: 

2816 # true if txt is _not_ a _ name, false otherwise: 

2817 no__name = ( 

2818 lambda txt: re.match(r"\._.*?", txt[txt.rindex(".") :]) 

2819 is None 

2820 ) 

2821 matches = filter(no__name, matches) 

2822 matches = _convert_matcher_v1_result_to_v2( 

2823 matches, type="attribute", fragment=fragment 

2824 ) 

2825 return matches 

2826 except NameError: 

2827 # catches <undefined attributes>.<tab> 

2828 return SimpleMatcherResult(completions=[], suppress=False) 

2829 else: 

2830 try: 

2831 matches = self.global_matches(context.token, context=context) 

2832 except TypeError: 

2833 matches = self.global_matches(context.token) 

2834 # TODO: maybe distinguish between functions, modules and just "variables" 

2835 return SimpleMatcherResult( 

2836 completions=[ 

2837 SimpleCompletion(text=match, type="variable") for match in matches 

2838 ], 

2839 suppress=False, 

2840 ) 

2841 

2842 def _default_arguments_from_docstring(self, doc): 

2843 """Parse the first line of docstring for call signature. 

2844 

2845 Docstring should be of the form 'min(iterable[, key=func])\n'. 

2846 It can also parse cython docstring of the form 

2847 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'. 

2848 """ 

2849 if doc is None: 

2850 return [] 

2851 

2852 #care only the firstline 

2853 line = doc.lstrip().splitlines()[0] 

2854 

2855 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*') 

2856 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]' 

2857 sig = self.docstring_sig_re.search(line) 

2858 if sig is None: 

2859 return [] 

2860 # iterable[, key=func]' -> ['iterable[' ,' key=func]'] 

2861 sig = sig.groups()[0].split(',') 

2862 ret = [] 

2863 for s in sig: 

2864 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)') 

2865 ret += self.docstring_kwd_re.findall(s) 

2866 return ret 

2867 

2868 def _default_arguments(self, obj): 

2869 """Return the list of default arguments of obj if it is callable, 

2870 or empty list otherwise.""" 

2871 call_obj = obj 

2872 ret = [] 

2873 if inspect.isbuiltin(obj): 

2874 pass 

2875 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)): 

2876 if inspect.isclass(obj): 

2877 #for cython embedsignature=True the constructor docstring 

2878 #belongs to the object itself not __init__ 

2879 ret += self._default_arguments_from_docstring( 

2880 getattr(obj, '__doc__', '')) 

2881 # for classes, check for __init__,__new__ 

2882 call_obj = (getattr(obj, '__init__', None) or 

2883 getattr(obj, '__new__', None)) 

2884 # for all others, check if they are __call__able 

2885 elif hasattr(obj, '__call__'): 

2886 call_obj = obj.__call__ 

2887 ret += self._default_arguments_from_docstring( 

2888 getattr(call_obj, '__doc__', '')) 

2889 

2890 _keeps = (inspect.Parameter.KEYWORD_ONLY, 

2891 inspect.Parameter.POSITIONAL_OR_KEYWORD) 

2892 

2893 try: 

2894 sig = inspect.signature(obj) 

2895 ret.extend(k for k, v in sig.parameters.items() if 

2896 v.kind in _keeps) 

2897 except ValueError: 

2898 pass 

2899 

2900 return list(set(ret)) 

2901 

2902 @context_matcher() 

2903 def python_func_kw_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

2904 """Match named parameters (kwargs) of the last open function.""" 

2905 matches = self.python_func_kw_matches(context.token) 

2906 return _convert_matcher_v1_result_to_v2_no_no(matches, type="param") 

2907 

2908 def python_func_kw_matches(self, text: str) -> list[str]: 

2909 """Match named parameters (kwargs) of the last open function. 

2910 

2911 .. deprecated:: 8.6 

2912 You can use :meth:`python_func_kw_matcher` instead. 

2913 """ 

2914 

2915 if "." in text: # a parameter cannot be dotted 

2916 return [] 

2917 try: regexp = self.__funcParamsRegex 

2918 except AttributeError: 

2919 regexp = self.__funcParamsRegex = re.compile(r''' 

2920 '.*?(?<!\\)' | # single quoted strings or 

2921 ".*?(?<!\\)" | # double quoted strings or 

2922 \w+ | # identifier 

2923 \S # other characters 

2924 ''', re.VERBOSE | re.DOTALL) 

2925 # 1. find the nearest identifier that comes before an unclosed 

2926 # parenthesis before the cursor 

2927 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo" 

2928 tokens = regexp.findall(self.text_until_cursor) 

2929 iterTokens = reversed(tokens) 

2930 openPar = 0 

2931 

2932 for token in iterTokens: 

2933 if token == ')': 

2934 openPar -= 1 

2935 elif token == '(': 

2936 openPar += 1 

2937 if openPar > 0: 

2938 # found the last unclosed parenthesis 

2939 break 

2940 else: 

2941 return [] 

2942 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" ) 

2943 ids = [] 

2944 isId = _IDENTIFIER_END_RE.match 

2945 

2946 while True: 

2947 try: 

2948 ids.append(next(iterTokens)) 

2949 if not isId(ids[-1]): 

2950 ids.pop() 

2951 break 

2952 if not next(iterTokens) == '.': 

2953 break 

2954 except StopIteration: 

2955 break 

2956 

2957 # Find all named arguments already assigned to, as to avoid suggesting 

2958 # them again 

2959 usedNamedArgs = set() 

2960 par_level = -1 

2961 for token, next_token in itertools.pairwise(tokens): 

2962 if token == '(': 

2963 par_level += 1 

2964 elif token == ')': 

2965 par_level -= 1 

2966 

2967 if par_level != 0: 

2968 continue 

2969 

2970 if next_token != '=': 

2971 continue 

2972 

2973 usedNamedArgs.add(token) 

2974 

2975 argMatches = [] 

2976 try: 

2977 callableObj = '.'.join(ids[::-1]) 

2978 namedArgs = self._default_arguments(eval(callableObj, 

2979 self.namespace)) 

2980 

2981 # Remove used named arguments from the list, no need to show twice 

2982 for namedArg in set(namedArgs) - usedNamedArgs: 

2983 if namedArg.startswith(text): 

2984 argMatches.append("%s=" %namedArg) 

2985 except Exception: 

2986 pass 

2987 

2988 return argMatches 

2989 

2990 @staticmethod 

2991 def _get_keys(obj: Any) -> list[Any]: 

2992 # Objects can define their own completions by defining an 

2993 # _ipy_key_completions_() method. 

2994 method = get_real_method(obj, '_ipython_key_completions_') 

2995 if method is not None: 

2996 return method() 

2997 

2998 # Special case some common in-memory dict-like types 

2999 if isinstance(obj, dict) or _safe_isinstance(obj, "pandas", "DataFrame"): 

3000 try: 

3001 return list(obj.keys()) 

3002 except Exception: 

3003 return [] 

3004 elif _safe_isinstance(obj, "pandas", "core", "indexing", "_LocIndexer"): 

3005 try: 

3006 return list(obj.obj.keys()) 

3007 except Exception: 

3008 return [] 

3009 elif _safe_isinstance(obj, 'numpy', 'ndarray') or\ 

3010 _safe_isinstance(obj, 'numpy', 'void'): 

3011 return obj.dtype.names or [] 

3012 return [] 

3013 

3014 @context_matcher() 

3015 def dict_key_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

3016 """Match string keys in a dictionary, after e.g. ``foo[``.""" 

3017 matches = self.dict_key_matches(context.token) 

3018 return _convert_matcher_v1_result_to_v2( 

3019 matches, type="dict key", suppress_if_matches=True 

3020 ) 

3021 

3022 def dict_key_matches(self, text: str) -> list[str]: 

3023 """Match string keys in a dictionary, after e.g. ``foo[``. 

3024 

3025 .. deprecated:: 8.6 

3026 You can use :meth:`dict_key_matcher` instead. 

3027 """ 

3028 

3029 # Short-circuit on closed dictionary (regular expression would 

3030 # not match anyway, but would take quite a while). 

3031 if self.text_until_cursor.strip().endswith("]"): 

3032 return [] 

3033 

3034 match = DICT_MATCHER_REGEX.search(self.text_until_cursor) 

3035 

3036 if match is None: 

3037 return [] 

3038 

3039 expr, prior_tuple_keys, key_prefix = match.groups() 

3040 

3041 obj = self._evaluate_expr(expr) 

3042 

3043 if obj is not_found: 

3044 return [] 

3045 

3046 keys = self._get_keys(obj) 

3047 if not keys: 

3048 return keys 

3049 

3050 tuple_prefix = guarded_eval( 

3051 prior_tuple_keys, 

3052 EvaluationContext( 

3053 globals=self.global_namespace, 

3054 locals=self.namespace, 

3055 evaluation=self.evaluation, # type: ignore 

3056 in_subscript=True, 

3057 auto_import=self._auto_import, 

3058 policy_overrides=self.policy_overrides, 

3059 ), 

3060 ) 

3061 

3062 closing_quote, token_offset, matches = match_dict_keys( 

3063 keys, key_prefix, self.splitter.delims, extra_prefix=tuple_prefix 

3064 ) 

3065 if not matches: 

3066 return [] 

3067 

3068 # get the cursor position of 

3069 # - the text being completed 

3070 # - the start of the key text 

3071 # - the start of the completion 

3072 text_start = len(self.text_until_cursor) - len(text) 

3073 if key_prefix: 

3074 key_start = match.start(3) 

3075 completion_start = key_start + token_offset 

3076 else: 

3077 key_start = completion_start = match.end() 

3078 

3079 # grab the leading prefix, to make sure all completions start with `text` 

3080 if text_start > key_start: 

3081 leading = '' 

3082 else: 

3083 leading = text[text_start:completion_start] 

3084 

3085 # append closing quote and bracket as appropriate 

3086 # this is *not* appropriate if the opening quote or bracket is outside 

3087 # the text given to this method, e.g. `d["""a\nt 

3088 can_close_quote = False 

3089 can_close_bracket = False 

3090 

3091 continuation = self.line_buffer[len(self.text_until_cursor) :].strip() 

3092 

3093 if continuation.startswith(closing_quote): 

3094 # do not close if already closed, e.g. `d['a<tab>'` 

3095 continuation = continuation[len(closing_quote) :] 

3096 else: 

3097 can_close_quote = True 

3098 

3099 continuation = continuation.strip() 

3100 

3101 # e.g. `pandas.DataFrame` has different tuple indexer behaviour, 

3102 # handling it is out of scope, so let's avoid appending suffixes. 

3103 has_known_tuple_handling = isinstance(obj, dict) 

3104 

3105 can_close_bracket = ( 

3106 not continuation.startswith("]") and self.auto_close_dict_keys 

3107 ) 

3108 can_close_tuple_item = ( 

3109 not continuation.startswith(",") 

3110 and has_known_tuple_handling 

3111 and self.auto_close_dict_keys 

3112 ) 

3113 can_close_quote = can_close_quote and self.auto_close_dict_keys 

3114 

3115 # fast path if closing quote should be appended but not suffix is allowed 

3116 if not can_close_quote and not can_close_bracket and closing_quote: 

3117 return [leading + k for k in matches] 

3118 

3119 results = [] 

3120 

3121 end_of_tuple_or_item = _DictKeyState.END_OF_TUPLE | _DictKeyState.END_OF_ITEM 

3122 

3123 for k, state_flag in matches.items(): 

3124 result = leading + k 

3125 if can_close_quote and closing_quote: 

3126 result += closing_quote 

3127 

3128 if state_flag == end_of_tuple_or_item: 

3129 # We do not know which suffix to add, 

3130 # e.g. both tuple item and string 

3131 # match this item. 

3132 pass 

3133 

3134 if state_flag in end_of_tuple_or_item and can_close_bracket: 

3135 result += "]" 

3136 if state_flag == _DictKeyState.IN_TUPLE and can_close_tuple_item: 

3137 result += ", " 

3138 results.append(result) 

3139 return results 

3140 

3141 @context_matcher() 

3142 def unicode_name_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

3143 """Match Latex-like syntax for unicode characters base 

3144 on the name of the character. 

3145 

3146 This does ``\\GREEK SMALL LETTER ETA`` -> ``η`` 

3147 

3148 Works only on valid python 3 identifier, or on combining characters that 

3149 will combine to form a valid identifier. 

3150 """ 

3151 

3152 text = context.text_until_cursor 

3153 

3154 slashpos = text.rfind('\\') 

3155 if slashpos > -1: 

3156 s = text[slashpos+1:] 

3157 try : 

3158 unic = unicodedata.lookup(s) 

3159 # allow combining chars 

3160 if ('a'+unic).isidentifier(): 

3161 return { 

3162 "completions": [SimpleCompletion(text=unic, type="unicode")], 

3163 "suppress": True, 

3164 "matched_fragment": "\\" + s, 

3165 } 

3166 except KeyError: 

3167 pass 

3168 return { 

3169 "completions": [], 

3170 "suppress": False, 

3171 } 

3172 

3173 @context_matcher() 

3174 def latex_name_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

3175 """Match Latex syntax for unicode characters. 

3176 

3177 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α`` 

3178 """ 

3179 fragment, matches = self.latex_matches(context.text_until_cursor) 

3180 return _convert_matcher_v1_result_to_v2( 

3181 matches, type="latex", fragment=fragment, suppress_if_matches=True 

3182 ) 

3183 

3184 def latex_matches(self, text: str) -> tuple[str, Sequence[str]]: 

3185 """Match Latex syntax for unicode characters. 

3186 

3187 This does both ``\\alp`` -> ``\\alpha`` and ``\\alpha`` -> ``α`` 

3188 

3189 .. deprecated:: 8.6 

3190 You can use :meth:`latex_name_matcher` instead. 

3191 """ 

3192 slashpos = text.rfind('\\') 

3193 if slashpos > -1: 

3194 s = text[slashpos:] 

3195 if s in latex_symbols: 

3196 # Try to complete a full latex symbol to unicode 

3197 # \\alpha -> α 

3198 return s, [latex_symbols[s]] 

3199 else: 

3200 # If a user has partially typed a latex symbol, give them 

3201 # a full list of options \al -> [\aleph, \alpha] 

3202 matches = [k for k in latex_symbols if k.startswith(s)] 

3203 if matches: 

3204 return s, matches 

3205 return '', () 

3206 

3207 @context_matcher() 

3208 def custom_completer_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

3209 """Dispatch custom completer. 

3210 

3211 If a match is found, suppresses all other matchers except for Jedi. 

3212 """ 

3213 matches = self.dispatch_custom_completer(context.token) or [] 

3214 result = _convert_matcher_v1_result_to_v2( 

3215 matches, type=_UNKNOWN_TYPE, suppress_if_matches=True 

3216 ) 

3217 result["ordered"] = True 

3218 result["do_not_suppress"] = {_get_matcher_id(self._jedi_matcher)} 

3219 return result 

3220 

3221 def dispatch_custom_completer(self, text: str) -> list[str] | None: 

3222 """ 

3223 .. deprecated:: 8.6 

3224 You can use :meth:`custom_completer_matcher` instead. 

3225 """ 

3226 if not self.custom_completers: 

3227 return 

3228 

3229 line = self.line_buffer 

3230 if not line.strip(): 

3231 return None 

3232 

3233 # Create a little structure to pass all the relevant information about 

3234 # the current completion to any custom completer. 

3235 event = SimpleNamespace() 

3236 event.line = line 

3237 event.symbol = text 

3238 cmd = line.split(None,1)[0] 

3239 event.command = cmd 

3240 event.text_until_cursor = self.text_until_cursor 

3241 

3242 # for foo etc, try also to find completer for %foo 

3243 if not cmd.startswith(self.magic_escape): 

3244 try_magic = self.custom_completers.s_matches( 

3245 self.magic_escape + cmd) 

3246 else: 

3247 try_magic = [] 

3248 

3249 for c in itertools.chain(self.custom_completers.s_matches(cmd), 

3250 try_magic, 

3251 self.custom_completers.flat_matches(self.text_until_cursor)): 

3252 try: 

3253 res = c(event) 

3254 if res: 

3255 # first, try case sensitive match 

3256 withcase = [r for r in res if r.startswith(text)] 

3257 if withcase: 

3258 return withcase 

3259 # if none, then case insensitive ones are ok too 

3260 text_low = text.lower() 

3261 return [r for r in res if r.lower().startswith(text_low)] 

3262 except TryNext: 

3263 pass 

3264 except KeyboardInterrupt: 

3265 """ 

3266 If custom completer take too long, 

3267 let keyboard interrupt abort and return nothing. 

3268 """ 

3269 break 

3270 

3271 return None 

3272 

3273 def completions(self, text: str, offset: int)->Iterator[Completion]: 

3274 """ 

3275 Returns an iterator over the possible completions 

3276 

3277 .. warning:: 

3278 

3279 Unstable 

3280 

3281 This function is unstable, API may change without warning. 

3282 It will also raise unless use in proper context manager. 

3283 

3284 Parameters 

3285 ---------- 

3286 text : str 

3287 Full text of the current input, multi line string. 

3288 offset : int 

3289 Integer representing the position of the cursor in ``text``. Offset 

3290 is 0-based indexed. 

3291 

3292 Yields 

3293 ------ 

3294 Completion 

3295 

3296 Notes 

3297 ----- 

3298 The cursor on a text can either be seen as being "in between" 

3299 characters or "On" a character depending on the interface visible to 

3300 the user. For consistency the cursor being on "in between" characters X 

3301 and Y is equivalent to the cursor being "on" character Y, that is to say 

3302 the character the cursor is on is considered as being after the cursor. 

3303 

3304 Combining characters may span more that one position in the 

3305 text. 

3306 

3307 .. note:: 

3308 

3309 If ``IPCompleter.debug`` is :py:data:`True` will yield a ``--jedi/ipython--`` 

3310 fake Completion token to distinguish completion returned by Jedi 

3311 and usual IPython completion. 

3312 

3313 .. note:: 

3314 

3315 Completions are not completely deduplicated yet. If identical 

3316 completions are coming from different sources this function does not 

3317 ensure that each completion object will only be present once. 

3318 """ 

3319 warnings.warn("_complete is a provisional API (as of IPython 6.0). " 

3320 "It may change without warnings. " 

3321 "Use in corresponding context manager.", 

3322 category=ProvisionalCompleterWarning, stacklevel=2) 

3323 

3324 seen = set() 

3325 profiler:cProfile.Profile | None 

3326 try: 

3327 if self.profile_completions: 

3328 import cProfile 

3329 profiler = cProfile.Profile() 

3330 profiler.enable() 

3331 else: 

3332 profiler = None 

3333 

3334 for c in self._completions(text, offset, _timeout=self.jedi_compute_type_timeout/1000): 

3335 if c and (c in seen): 

3336 continue 

3337 yield c 

3338 seen.add(c) 

3339 except KeyboardInterrupt: 

3340 """if completions take too long and users send keyboard interrupt, 

3341 do not crash and return ASAP. """ 

3342 pass 

3343 finally: 

3344 if profiler is not None: 

3345 profiler.disable() 

3346 ensure_dir_exists(self.profiler_output_dir) 

3347 output_path = os.path.join(self.profiler_output_dir, str(uuid.uuid4())) 

3348 print("Writing profiler output to", output_path) 

3349 profiler.dump_stats(output_path) 

3350 

3351 def _completions(self, full_text: str, offset: int, *, _timeout) -> Iterator[Completion]: 

3352 """ 

3353 Core completion module.Same signature as :any:`completions`, with the 

3354 extra `timeout` parameter (in seconds). 

3355 

3356 Computing jedi's completion ``.type`` can be quite expensive (it is a 

3357 lazy property) and can require some warm-up, more warm up than just 

3358 computing the ``name`` of a completion. The warm-up can be : 

3359 

3360 - Long warm-up the first time a module is encountered after 

3361 install/update: actually build parse/inference tree. 

3362 

3363 - first time the module is encountered in a session: load tree from 

3364 disk. 

3365 

3366 We don't want to block completions for tens of seconds so we give the 

3367 completer a "budget" of ``_timeout`` seconds per invocation to compute 

3368 completions types, the completions that have not yet been computed will 

3369 be marked as "unknown" an will have a chance to be computed next round 

3370 are things get cached. 

3371 

3372 Keep in mind that Jedi is not the only thing treating the completion so 

3373 keep the timeout short-ish as if we take more than 0.3 second we still 

3374 have lots of processing to do. 

3375 

3376 """ 

3377 deadline = time.monotonic() + _timeout 

3378 

3379 before = full_text[:offset] 

3380 cursor_line, cursor_column = position_to_cursor(full_text, offset) 

3381 

3382 jedi_matcher_id = _get_matcher_id(self._jedi_matcher) 

3383 

3384 def is_non_jedi_result( 

3385 result: MatcherResult, identifier: str 

3386 ) -> TypeGuard[SimpleMatcherResult]: 

3387 return identifier != jedi_matcher_id 

3388 

3389 results = self._complete( 

3390 full_text=full_text, cursor_line=cursor_line, cursor_pos=cursor_column 

3391 ) 

3392 

3393 non_jedi_results: dict[str, SimpleMatcherResult] = { 

3394 identifier: result 

3395 for identifier, result in results.items() 

3396 if is_non_jedi_result(result, identifier) 

3397 } 

3398 

3399 jedi_matches = ( 

3400 cast(_JediMatcherResult, results[jedi_matcher_id])["completions"] 

3401 if jedi_matcher_id in results 

3402 else () 

3403 ) 

3404 

3405 iter_jm = iter(jedi_matches) 

3406 if _timeout: 

3407 for jm in iter_jm: 

3408 try: 

3409 type_ = jm.type 

3410 except Exception: 

3411 if self.debug: 

3412 print("Error in Jedi getting type of ", jm) 

3413 type_ = None 

3414 delta = len(jm.name_with_symbols) - len(jm.complete) 

3415 if type_ == 'function': 

3416 signature = _make_signature(jm) 

3417 else: 

3418 signature = '' 

3419 yield Completion(start=offset - delta, 

3420 end=offset, 

3421 text=jm.name_with_symbols, 

3422 type=type_, 

3423 signature=signature, 

3424 _origin='jedi') 

3425 

3426 if time.monotonic() > deadline: 

3427 break 

3428 

3429 for jm in iter_jm: 

3430 delta = len(jm.name_with_symbols) - len(jm.complete) 

3431 yield Completion( 

3432 start=offset - delta, 

3433 end=offset, 

3434 text=jm.name_with_symbols, 

3435 type=_UNKNOWN_TYPE, # don't compute type for speed 

3436 _origin="jedi", 

3437 signature="", 

3438 ) 

3439 

3440 # TODO: 

3441 # Suppress this, right now just for debug. 

3442 if jedi_matches and non_jedi_results and self.debug: 

3443 some_start_offset = before.rfind( 

3444 next(iter(non_jedi_results.values()))["matched_fragment"] 

3445 ) 

3446 yield Completion( 

3447 start=some_start_offset, 

3448 end=offset, 

3449 text="--jedi/ipython--", 

3450 _origin="debug", 

3451 type="none", 

3452 signature="", 

3453 ) 

3454 

3455 ordered: list[Completion] = [] 

3456 sortable: list[Completion] = [] 

3457 

3458 for origin, result in non_jedi_results.items(): 

3459 matched_text = result["matched_fragment"] 

3460 start_offset = before.rfind(matched_text) 

3461 is_ordered = result.get("ordered", False) 

3462 container = ordered if is_ordered else sortable 

3463 

3464 # I'm unsure if this is always true, so let's assert and see if it 

3465 # crash 

3466 assert before.endswith(matched_text) 

3467 

3468 for simple_completion in result["completions"]: 

3469 completion = Completion( 

3470 start=start_offset, 

3471 end=offset, 

3472 text=simple_completion.text, 

3473 _origin=origin, 

3474 signature="", 

3475 type=simple_completion.type or _UNKNOWN_TYPE, 

3476 ) 

3477 container.append(completion) 

3478 

3479 yield from list(self._deduplicate(ordered + self._sort(sortable)))[ 

3480 :MATCHES_LIMIT 

3481 ] 

3482 

3483 def complete( 

3484 self, text=None, line_buffer=None, cursor_pos=None 

3485 ) -> tuple[str, Sequence[str]]: 

3486 """Find completions for the given text and line context. 

3487 

3488 Note that both the text and the line_buffer are optional, but at least 

3489 one of them must be given. 

3490 

3491 Parameters 

3492 ---------- 

3493 text : string, optional 

3494 Text to perform the completion on. If not given, the line buffer 

3495 is split using the instance's CompletionSplitter object. 

3496 line_buffer : string, optional 

3497 If not given, the completer attempts to obtain the current line 

3498 buffer via readline. This keyword allows clients which are 

3499 requesting for text completions in non-readline contexts to inform 

3500 the completer of the entire text. 

3501 cursor_pos : int, optional 

3502 Index of the cursor in the full line buffer. Should be provided by 

3503 remote frontends where kernel has no access to frontend state. 

3504 

3505 Returns 

3506 ------- 

3507 Tuple of two items: 

3508 text : str 

3509 Text that was actually used in the completion. 

3510 matches : list 

3511 A list of completion matches. 

3512 

3513 Notes 

3514 ----- 

3515 This API is likely to be deprecated and replaced by 

3516 :any:`IPCompleter.completions` in the future. 

3517 

3518 """ 

3519 warnings.warn('`Completer.complete` is pending deprecation since ' 

3520 'IPython 6.0 and will be replaced by `Completer.completions`.', 

3521 PendingDeprecationWarning) 

3522 # potential todo, FOLD the 3rd throw away argument of _complete 

3523 # into the first 2 one. 

3524 # TODO: Q: does the above refer to jedi completions (i.e. 0-indexed?) 

3525 # TODO: should we deprecate now, or does it stay? 

3526 

3527 results = self._complete( 

3528 line_buffer=line_buffer, cursor_pos=cursor_pos, text=text, cursor_line=0 

3529 ) 

3530 

3531 jedi_matcher_id = _get_matcher_id(self._jedi_matcher) 

3532 

3533 return self._arrange_and_extract( 

3534 results, 

3535 # TODO: can we confirm that excluding Jedi here was a deliberate choice in previous version? 

3536 skip_matchers={jedi_matcher_id}, 

3537 # this API does not support different start/end positions (fragments of token). 

3538 abort_if_offset_changes=True, 

3539 ) 

3540 

3541 def _arrange_and_extract( 

3542 self, 

3543 results: dict[str, MatcherResult], 

3544 skip_matchers: set[str], 

3545 abort_if_offset_changes: bool, 

3546 ): 

3547 sortable: list[AnyMatcherCompletion] = [] 

3548 ordered: list[AnyMatcherCompletion] = [] 

3549 most_recent_fragment = None 

3550 for identifier, result in results.items(): 

3551 if identifier in skip_matchers: 

3552 continue 

3553 if not result["completions"]: 

3554 continue 

3555 if not most_recent_fragment: 

3556 most_recent_fragment = result["matched_fragment"] 

3557 if ( 

3558 abort_if_offset_changes 

3559 and result["matched_fragment"] != most_recent_fragment 

3560 ): 

3561 break 

3562 if result.get("ordered", False): 

3563 ordered.extend(result["completions"]) 

3564 else: 

3565 sortable.extend(result["completions"]) 

3566 

3567 if not most_recent_fragment: 

3568 most_recent_fragment = "" # to satisfy typechecker (and just in case) 

3569 

3570 return most_recent_fragment, [ 

3571 m.text for m in self._deduplicate(ordered + self._sort(sortable)) 

3572 ] 

3573 

3574 def _complete(self, *, cursor_line, cursor_pos, line_buffer=None, text=None, 

3575 full_text=None) -> _CompleteResult: 

3576 """ 

3577 Like complete but can also returns raw jedi completions as well as the 

3578 origin of the completion text. This could (and should) be made much 

3579 cleaner but that will be simpler once we drop the old (and stateful) 

3580 :any:`complete` API. 

3581 

3582 With current provisional API, cursor_pos act both (depending on the 

3583 caller) as the offset in the ``text`` or ``line_buffer``, or as the 

3584 ``column`` when passing multiline strings this could/should be renamed 

3585 but would add extra noise. 

3586 

3587 Parameters 

3588 ---------- 

3589 cursor_line 

3590 Index of the line the cursor is on. 0 indexed. 

3591 cursor_pos 

3592 Position of the cursor in the current line/line_buffer/text. 0 

3593 indexed. 

3594 line_buffer : optional, str 

3595 The current line the cursor is in, this is mostly due to legacy 

3596 reason that readline could only give a us the single current line. 

3597 Prefer `full_text`. 

3598 text : str 

3599 The current "token" the cursor is in, mostly also for historical 

3600 reasons. as the completer would trigger only after the current line 

3601 was parsed. 

3602 full_text : str 

3603 Full text of the current cell. 

3604 

3605 Returns 

3606 ------- 

3607 An ordered dictionary where keys are identifiers of completion 

3608 matchers and values are ``MatcherResult``s. 

3609 """ 

3610 

3611 # if the cursor position isn't given, the only sane assumption we can 

3612 # make is that it's at the end of the line (the common case) 

3613 if cursor_pos is None: 

3614 cursor_pos = len(line_buffer) if text is None else len(text) 

3615 

3616 if self.use_main_ns: 

3617 self.namespace = __main__.__dict__ 

3618 

3619 # if text is either None or an empty string, rely on the line buffer 

3620 if (not line_buffer) and full_text: 

3621 line_buffer = full_text.split('\n')[cursor_line] 

3622 if not text: # issue #11508: check line_buffer before calling split_line 

3623 text = ( 

3624 self.splitter.split_line(line_buffer, cursor_pos) if line_buffer else "" 

3625 ) 

3626 

3627 # If no line buffer is given, assume the input text is all there was 

3628 if line_buffer is None: 

3629 line_buffer = text 

3630 

3631 # deprecated - do not use `line_buffer` in new code. 

3632 self.line_buffer = line_buffer 

3633 self.text_until_cursor = self.line_buffer[:cursor_pos] 

3634 

3635 if not full_text: 

3636 full_text = line_buffer 

3637 

3638 context = CompletionContext( 

3639 full_text=full_text, 

3640 cursor_position=cursor_pos, 

3641 cursor_line=cursor_line, 

3642 token=self._extract_code(text), 

3643 limit=MATCHES_LIMIT, 

3644 ) 

3645 

3646 # Start with a clean slate of completions 

3647 results: dict[str, MatcherResult] = {} 

3648 

3649 jedi_matcher_id = _get_matcher_id(self._jedi_matcher) 

3650 

3651 suppressed_matchers: set[str] = set() 

3652 

3653 matchers = { 

3654 _get_matcher_id(matcher): matcher 

3655 for matcher in sorted( 

3656 self.matchers, key=_get_matcher_priority, reverse=True 

3657 ) 

3658 } 

3659 

3660 for matcher_id, matcher in matchers.items(): 

3661 matcher_id = _get_matcher_id(matcher) 

3662 

3663 if matcher_id in self.disable_matchers: 

3664 continue 

3665 

3666 if matcher_id in results: 

3667 warnings.warn(f"Duplicate matcher ID: {matcher_id}.") 

3668 

3669 if matcher_id in suppressed_matchers: 

3670 continue 

3671 

3672 result: MatcherResult 

3673 try: 

3674 if _is_matcher_v1(matcher): 

3675 result = _convert_matcher_v1_result_to_v2_no_no( 

3676 matcher(text), type=_UNKNOWN_TYPE 

3677 ) 

3678 elif _is_matcher_v2(matcher): 

3679 result = matcher(context) 

3680 else: 

3681 api_version = _get_matcher_api_version(matcher) 

3682 raise ValueError(f"Unsupported API version {api_version}") 

3683 except BaseException: 

3684 # Show the ugly traceback if the matcher causes an 

3685 # exception, but do NOT crash the kernel! 

3686 sys.excepthook(*sys.exc_info()) 

3687 continue 

3688 

3689 # set default value for matched fragment if suffix was not selected. 

3690 result["matched_fragment"] = result.get("matched_fragment", context.token) 

3691 

3692 if not suppressed_matchers: 

3693 suppression_recommended: bool | set[str] = result.get( 

3694 "suppress", False 

3695 ) 

3696 

3697 suppression_config = ( 

3698 self.suppress_competing_matchers.get(matcher_id, None) 

3699 if isinstance(self.suppress_competing_matchers, dict) 

3700 else self.suppress_competing_matchers 

3701 ) 

3702 should_suppress = ( 

3703 (suppression_config is True) 

3704 or (suppression_recommended and (suppression_config is not False)) 

3705 ) and has_any_completions(result) 

3706 

3707 if should_suppress: 

3708 suppression_exceptions: set[str] = result.get( 

3709 "do_not_suppress", set() 

3710 ) 

3711 if isinstance(suppression_recommended, Iterable): 

3712 to_suppress = set(suppression_recommended) 

3713 else: 

3714 to_suppress = set(matchers) 

3715 suppressed_matchers = to_suppress - suppression_exceptions 

3716 

3717 new_results = {} 

3718 for previous_matcher_id, previous_result in results.items(): 

3719 if previous_matcher_id not in suppressed_matchers: 

3720 new_results[previous_matcher_id] = previous_result 

3721 results = new_results 

3722 

3723 results[matcher_id] = result 

3724 

3725 _, matches = self._arrange_and_extract( 

3726 results, 

3727 # TODO Jedi completions non included in legacy stateful API; was this deliberate or omission? 

3728 # if it was omission, we can remove the filtering step, otherwise remove this comment. 

3729 skip_matchers={jedi_matcher_id}, 

3730 abort_if_offset_changes=False, 

3731 ) 

3732 

3733 # populate legacy stateful API 

3734 self.matches = matches 

3735 

3736 return results 

3737 

3738 @staticmethod 

3739 def _deduplicate( 

3740 matches: Sequence[AnyCompletion], 

3741 ) -> Iterable[AnyCompletion]: 

3742 filtered_matches: dict[str, AnyCompletion] = {} 

3743 for match in matches: 

3744 text = match.text 

3745 if ( 

3746 text not in filtered_matches 

3747 or filtered_matches[text].type == _UNKNOWN_TYPE 

3748 ): 

3749 filtered_matches[text] = match 

3750 

3751 return filtered_matches.values() 

3752 

3753 @staticmethod 

3754 def _sort(matches: Sequence[AnyCompletion]): 

3755 return sorted(matches, key=lambda x: completions_sorting_key(x.text)) 

3756 

3757 @context_matcher() 

3758 def fwd_unicode_matcher(self, context: CompletionContext) -> SimpleMatcherResult: 

3759 """Same as :any:`fwd_unicode_match`, but adopted to new Matcher API.""" 

3760 # TODO: use `context.limit` to terminate early once we matched the maximum 

3761 # number that will be used downstream; can be added as an optional to 

3762 # `fwd_unicode_match(text: str, limit: int = None)` or we could re-implement here. 

3763 fragment, matches = self.fwd_unicode_match(context.text_until_cursor) 

3764 return _convert_matcher_v1_result_to_v2( 

3765 matches, type="unicode", fragment=fragment, suppress_if_matches=True 

3766 ) 

3767 

3768 def fwd_unicode_match(self, text: str) -> tuple[str, Sequence[str]]: 

3769 """ 

3770 Forward match a string starting with a backslash with a list of 

3771 potential Unicode completions. 

3772 

3773 Will compute list of Unicode character names on first call and cache it. 

3774 

3775 .. deprecated:: 8.6 

3776 You can use :meth:`fwd_unicode_matcher` instead. 

3777 

3778 Returns 

3779 ------- 

3780 At tuple with: 

3781 - matched text (empty if no matches) 

3782 - list of potential completions, empty tuple otherwise) 

3783 """ 

3784 # TODO: self.unicode_names is here a list we traverse each time with ~100k elements. 

3785 # We could do a faster match using a Trie. 

3786 

3787 # Using pygtrie the following seem to work: 

3788 

3789 # s = PrefixSet() 

3790 

3791 # for c in range(0,0x10FFFF + 1): 

3792 # try: 

3793 # s.add(unicodedata.name(chr(c))) 

3794 # except ValueError: 

3795 # pass 

3796 # [''.join(k) for k in s.iter(prefix)] 

3797 

3798 # But need to be timed and adds an extra dependency. 

3799 

3800 slashpos = text.rfind('\\') 

3801 # if text starts with slash 

3802 if slashpos > -1: 

3803 # PERF: It's important that we don't access self._unicode_names 

3804 # until we're inside this if-block. _unicode_names is lazily 

3805 # initialized, and it takes a user-noticeable amount of time to 

3806 # initialize it, so we don't want to initialize it unless we're 

3807 # actually going to use it. 

3808 s = text[slashpos + 1 :] 

3809 sup = s.upper() 

3810 candidates = [x for x in self.unicode_names if x.startswith(sup)] 

3811 if candidates: 

3812 return s, candidates 

3813 candidates = [x for x in self.unicode_names if sup in x] 

3814 if candidates: 

3815 return s, candidates 

3816 splitsup = sup.split(" ") 

3817 candidates = [ 

3818 x for x in self.unicode_names if all(u in x for u in splitsup) 

3819 ] 

3820 if candidates: 

3821 return s, candidates 

3822 

3823 return "", () 

3824 

3825 # if text does not start with slash 

3826 else: 

3827 return '', () 

3828 

3829 @property 

3830 def unicode_names(self) -> list[str]: 

3831 """List of names of unicode code points that can be completed. 

3832 

3833 The list is lazily initialized on first access. 

3834 """ 

3835 if self._unicode_names is None: 

3836 names = [] 

3837 for c in range(0,0x10FFFF + 1): 

3838 try: 

3839 names.append(unicodedata.name(chr(c))) 

3840 except ValueError: 

3841 pass 

3842 self._unicode_names = _unicode_name_compute(_UNICODE_RANGES) 

3843 

3844 return self._unicode_names 

3845 

3846 

3847def _unicode_name_compute(ranges: list[tuple[int, int]]) -> list[str]: 

3848 names = [] 

3849 for start,stop in ranges: 

3850 for c in range(start, stop) : 

3851 try: 

3852 names.append(unicodedata.name(chr(c))) 

3853 except ValueError: 

3854 pass 

3855 return names