diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-09-14 16:34:07 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-09-14 16:42:44 +0300 |
commit | 65e983f916c022329f41054c72ca552faf372941 (patch) | |
tree | be2e2380b20ac115946c2e43e10bb900d6ee67a6 /contrib/python/ipython/py3/IPython | |
parent | abdb8cda9345851fdea911b3016fafc5780c12f3 (diff) | |
download | ydb-65e983f916c022329f41054c72ca552faf372941.tar.gz |
Intermediate changes
commit_hash:315a764ebe0b22f720e1d1f1147e3f2ab88f6ea4
Diffstat (limited to 'contrib/python/ipython/py3/IPython')
8 files changed, 134 insertions, 64 deletions
diff --git a/contrib/python/ipython/py3/IPython/core/completer.py b/contrib/python/ipython/py3/IPython/core/completer.py index 09a033a227..c639ce07a1 100644 --- a/contrib/python/ipython/py3/IPython/core/completer.py +++ b/contrib/python/ipython/py3/IPython/core/completer.py @@ -898,7 +898,7 @@ def rectify_completions(text: str, completions: _IC, *, _debug: bool = False) -> new_text = text[new_start:c.start] + c.text + text[c.end:new_end] if c._origin == 'jedi': seen_jedi.add(new_text) - elif c._origin == 'IPCompleter.python_matches': + elif c._origin == "IPCompleter.python_matcher": seen_python_matches.add(new_text) yield Completion(new_start, new_end, new_text, type=c.type, _origin=c._origin, signature=c.signature) diff = seen_python_matches.difference(seen_jedi) @@ -1139,15 +1139,18 @@ class Completer(Configurable): with a __getattr__ hook is evaluated. """ + return self._attr_matches(text)[0] + + def _attr_matches(self, text, include_prefix=True) -> Tuple[Sequence[str], str]: m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer) if not m2: - return [] + return [], "" expr, attr = m2.group(1, 2) obj = self._evaluate_expr(expr) if obj is not_found: - return [] + return [], "" if self.limit_to__all__ and hasattr(obj, '__all__'): words = get__all__entries(obj) @@ -1170,28 +1173,36 @@ class Completer(Configurable): # reconciliator would know that we intend to append to rather than # replace the input text; this requires refactoring to return range # which ought to be replaced (as does jedi). - tokens = _parse_tokens(expr) - rev_tokens = reversed(tokens) - skip_over = {tokenize.ENDMARKER, tokenize.NEWLINE} - name_turn = True - - parts = [] - for token in rev_tokens: - if token.type in skip_over: - continue - if token.type == tokenize.NAME and name_turn: - parts.append(token.string) - name_turn = False - elif token.type == tokenize.OP and token.string == "." and not name_turn: - parts.append(token.string) - name_turn = True - else: - # short-circuit if not empty nor name token - break + if include_prefix: + tokens = _parse_tokens(expr) + rev_tokens = reversed(tokens) + skip_over = {tokenize.ENDMARKER, tokenize.NEWLINE} + name_turn = True + + parts = [] + for token in rev_tokens: + if token.type in skip_over: + continue + if token.type == tokenize.NAME and name_turn: + parts.append(token.string) + name_turn = False + elif ( + token.type == tokenize.OP and token.string == "." and not name_turn + ): + parts.append(token.string) + name_turn = True + else: + # short-circuit if not empty nor name token + break - prefix_after_space = "".join(reversed(parts)) + prefix_after_space = "".join(reversed(parts)) + else: + prefix_after_space = "" - return ["%s.%s" % (prefix_after_space, w) for w in words if w[:n] == attr] + return ( + ["%s.%s" % (prefix_after_space, w) for w in words if w[:n] == attr], + "." + attr, + ) def _evaluate_expr(self, expr): obj = not_found @@ -1974,9 +1985,8 @@ class IPCompleter(Completer): *self.magic_arg_matchers, self.custom_completer_matcher, self.dict_key_matcher, - # TODO: convert python_matches to v2 API self.magic_matcher, - self.python_matches, + self.python_matcher, self.file_matcher, self.python_func_kw_matcher, ] @@ -2317,9 +2327,42 @@ class IPCompleter(Completer): else: return iter([]) + @context_matcher() + def python_matcher(self, context: CompletionContext) -> SimpleMatcherResult: + """Match attributes or global python names""" + text = context.line_with_cursor + if "." in text: + try: + matches, fragment = self._attr_matches(text, include_prefix=False) + if text.endswith(".") and self.omit__names: + if self.omit__names == 1: + # true if txt is _not_ a __ name, false otherwise: + no__name = lambda txt: re.match(r".*\.__.*?__", txt) is None + else: + # true if txt is _not_ a _ name, false otherwise: + no__name = ( + lambda txt: re.match(r"\._.*?", txt[txt.rindex(".") :]) + is None + ) + matches = filter(no__name, matches) + return _convert_matcher_v1_result_to_v2( + matches, type="attribute", fragment=fragment + ) + except NameError: + # catches <undefined attributes>.<tab> + matches = [] + return _convert_matcher_v1_result_to_v2(matches, type="attribute") + else: + matches = self.global_matches(context.token) + # TODO: maybe distinguish between functions, modules and just "variables" + return _convert_matcher_v1_result_to_v2(matches, type="variable") + @completion_matcher(api_version=1) def python_matches(self, text: str) -> Iterable[str]: - """Match attributes or global python names""" + """Match attributes or global python names. + + .. deprecated:: 8.27 + You can use :meth:`python_matcher` instead.""" if "." in text: try: matches = self.attr_matches(text) diff --git a/contrib/python/ipython/py3/IPython/core/magics/pylab.py b/contrib/python/ipython/py3/IPython/core/magics/pylab.py index 265f860063..423498d404 100644 --- a/contrib/python/ipython/py3/IPython/core/magics/pylab.py +++ b/contrib/python/ipython/py3/IPython/core/magics/pylab.py @@ -100,7 +100,7 @@ class PylabMagics(Magics): % _list_matplotlib_backends_and_gui_loops() ) else: - gui, backend = self.shell.enable_matplotlib(args.gui.lower() if isinstance(args.gui, str) else args.gui) + gui, backend = self.shell.enable_matplotlib(args.gui) self._show_matplotlib_backend(args.gui, backend) @skip_doctest diff --git a/contrib/python/ipython/py3/IPython/core/prefilter.py b/contrib/python/ipython/py3/IPython/core/prefilter.py index e611b4b834..a29df0c27a 100644 --- a/contrib/python/ipython/py3/IPython/core/prefilter.py +++ b/contrib/python/ipython/py3/IPython/core/prefilter.py @@ -476,8 +476,8 @@ class PythonOpsChecker(PrefilterChecker): any python operator, we should simply execute the line (regardless of whether or not there's a possible autocall expansion). This avoids spurious (and very confusing) geattr() accesses.""" - if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|': - return self.prefilter_manager.get_handler_by_name('normal') + if line_info.the_rest and line_info.the_rest[0] in "!=()<>,+*/%^&|": + return self.prefilter_manager.get_handler_by_name("normal") else: return None @@ -512,6 +512,8 @@ class AutocallChecker(PrefilterChecker): callable(oinfo.obj) and (not self.exclude_regexp.match(line_info.the_rest)) and self.function_name_regexp.match(line_info.ifun) + and line_info.raw_the_rest.startswith(" ") + or not line_info.raw_the_rest.strip() ): return self.prefilter_manager.get_handler_by_name("auto") else: diff --git a/contrib/python/ipython/py3/IPython/core/profiledir.py b/contrib/python/ipython/py3/IPython/core/profiledir.py index cb4d39339a..a38d771ef5 100644 --- a/contrib/python/ipython/py3/IPython/core/profiledir.py +++ b/contrib/python/ipython/py3/IPython/core/profiledir.py @@ -14,6 +14,8 @@ from ..paths import get_ipython_package_dir from ..utils.path import expand_path, ensure_dir_exists from traitlets import Unicode, Bool, observe +from typing import Optional + #----------------------------------------------------------------------------- # Module errors #----------------------------------------------------------------------------- @@ -68,18 +70,31 @@ class ProfileDir(LoggingConfigurable): self.pid_dir = os.path.join(new, self.pid_dir_name) self.static_dir = os.path.join(new, self.static_dir_name) self.check_dirs() - - def _mkdir(self, path, mode=None): + + def _mkdir(self, path: str, mode: Optional[int] = None) -> bool: """ensure a directory exists at a given path This is a version of os.mkdir, with the following differences: - - returns True if it created the directory, False otherwise + - returns whether the directory has been created or not. - ignores EEXIST, protecting against race conditions where the dir may have been created in between the check and the creation - sets permissions if requested and the dir already exists + + Parameters + ---------- + path: str + path of the dir to create + mode: int + see `mode` of `os.mkdir` + + Returns + ------- + bool: + returns True if it created the directory, False otherwise """ + if os.path.exists(path): if mode and os.stat(path).st_mode != mode: try: @@ -109,14 +124,14 @@ class ProfileDir(LoggingConfigurable): @observe('startup_dir') def check_startup_dir(self, change=None): - self._mkdir(self.startup_dir) - - readme = os.path.join(self.startup_dir, 'README') - - if not os.path.exists(readme): - import pkgutil - with open(readme, 'wb') as f: - f.write(pkgutil.get_data(__name__, 'profile/README_STARTUP')) + if self._mkdir(self.startup_dir): + readme = os.path.join(self.startup_dir, "README") + + if not os.path.exists(readme): + import pkgutil + with open(readme, "wb") as f: + f.write(pkgutil.get_data(__name__, "profile/README_STARTUP")) + return @observe('security_dir') def check_security_dir(self, change=None): diff --git a/contrib/python/ipython/py3/IPython/core/release.py b/contrib/python/ipython/py3/IPython/core/release.py index b72524d6ff..c77f561096 100644 --- a/contrib/python/ipython/py3/IPython/core/release.py +++ b/contrib/python/ipython/py3/IPython/core/release.py @@ -16,7 +16,7 @@ # release. 'dev' as a _version_extra string means this is a development # version _version_major = 8 -_version_minor = 26 +_version_minor = 27 _version_patch = 0 _version_extra = ".dev" # _version_extra = "rc1" diff --git a/contrib/python/ipython/py3/IPython/core/splitinput.py b/contrib/python/ipython/py3/IPython/core/splitinput.py index 0cd70ec910..33e462b3b8 100644 --- a/contrib/python/ipython/py3/IPython/core/splitinput.py +++ b/contrib/python/ipython/py3/IPython/core/splitinput.py @@ -76,7 +76,7 @@ def split_user_input(line, pattern=None): # print('line:<%s>' % line) # dbg # print('pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest)) # dbg - return pre, esc or '', ifun.strip(), the_rest.lstrip() + return pre, esc or "", ifun.strip(), the_rest class LineInfo(object): @@ -107,11 +107,15 @@ class LineInfo(object): the_rest Everything else on the line. + + raw_the_rest + the_rest without whitespace stripped. """ def __init__(self, line, continue_prompt=False): self.line = line self.continue_prompt = continue_prompt - self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line) + self.pre, self.esc, self.ifun, self.raw_the_rest = split_user_input(line) + self.the_rest = self.raw_the_rest.lstrip() self.pre_char = self.pre.strip() if self.pre_char: @@ -136,3 +140,6 @@ class LineInfo(object): def __str__(self): return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest) + + def __repr__(self): + return "<" + str(self) + ">" diff --git a/contrib/python/ipython/py3/IPython/core/ultratb.py b/contrib/python/ipython/py3/IPython/core/ultratb.py index 382ab1c029..15c835f4d2 100644 --- a/contrib/python/ipython/py3/IPython/core/ultratb.py +++ b/contrib/python/ipython/py3/IPython/core/ultratb.py @@ -552,28 +552,31 @@ class ListTB(TBTools): lines = ''.join(self._format_exception_only(etype, evalue)) out_list.append(lines) - exception = self.get_parts_of_chained_exception(evalue) + # Find chained exceptions if we have a traceback (not for exception-only mode) + if etb is not None: + exception = self.get_parts_of_chained_exception(evalue) - if exception and (id(exception[1]) not in chained_exc_ids): - chained_exception_message = ( - self.prepare_chained_exception_message(evalue.__cause__)[0] - if evalue is not None - else "" - ) - etype, evalue, etb = exception - # Trace exception to avoid infinite 'cause' loop - chained_exc_ids.add(id(exception[1])) - chained_exceptions_tb_offset = 0 - out_list = ( - self.structured_traceback( - etype, - evalue, - (etb, chained_exc_ids), # type: ignore - chained_exceptions_tb_offset, - context, + if exception and (id(exception[1]) not in chained_exc_ids): + chained_exception_message = ( + self.prepare_chained_exception_message(evalue.__cause__)[0] + if evalue is not None + else "" + ) + etype, evalue, etb = exception + # Trace exception to avoid infinite 'cause' loop + chained_exc_ids.add(id(exception[1])) + chained_exceptions_tb_offset = 0 + out_list = ( + self.structured_traceback( + etype, + evalue, + (etb, chained_exc_ids), # type: ignore + chained_exceptions_tb_offset, + context, + ) + + chained_exception_message + + out_list ) - + chained_exception_message - + out_list) return out_list diff --git a/contrib/python/ipython/py3/IPython/utils/_sysinfo.py b/contrib/python/ipython/py3/IPython/utils/_sysinfo.py index 14569760e1..58edebdad2 100644 --- a/contrib/python/ipython/py3/IPython/utils/_sysinfo.py +++ b/contrib/python/ipython/py3/IPython/utils/_sysinfo.py @@ -1,2 +1,2 @@ # GENERATED BY setup.py -commit = "e0c8289d9" +commit = "82690a067" |