aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/ipython/py3/IPython/core/completer.py
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2025-01-04 15:53:08 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2025-01-04 16:07:11 +0300
commit0aaf156b641766ba2f26c5c54f2aa02016bb51f4 (patch)
tree4aefc952c87e1dc424ec9002f05412ce4b2b2598 /contrib/python/ipython/py3/IPython/core/completer.py
parenta719ba289f03a96a2ad4e96605e57870e50a992b (diff)
downloadydb-0aaf156b641766ba2f26c5c54f2aa02016bb51f4.tar.gz
Intermediate changes
commit_hash:52e193336c733675186ea9e84a61825375cdab04
Diffstat (limited to 'contrib/python/ipython/py3/IPython/core/completer.py')
-rw-r--r--contrib/python/ipython/py3/IPython/core/completer.py66
1 files changed, 49 insertions, 17 deletions
diff --git a/contrib/python/ipython/py3/IPython/core/completer.py b/contrib/python/ipython/py3/IPython/core/completer.py
index 8260975765..db5de81019 100644
--- a/contrib/python/ipython/py3/IPython/core/completer.py
+++ b/contrib/python/ipython/py3/IPython/core/completer.py
@@ -184,6 +184,7 @@ import glob
import inspect
import itertools
import keyword
+import ast
import os
import re
import string
@@ -347,7 +348,7 @@ def provisionalcompleter(action='ignore'):
yield
-def has_open_quotes(s):
+def has_open_quotes(s: str) -> Union[str, bool]:
"""Return whether a string has open quotes.
This simply counts whether the number of quote characters of either type in
@@ -368,7 +369,7 @@ def has_open_quotes(s):
return False
-def protect_filename(s, protectables=PROTECTABLES):
+def protect_filename(s: str, protectables: str = PROTECTABLES) -> str:
"""Escape a string to protect certain characters."""
if set(s) & set(protectables):
if sys.platform == "win32":
@@ -449,11 +450,11 @@ def completions_sorting_key(word):
if word.startswith('%%'):
# If there's another % in there, this is something else, so leave it alone
- if not "%" in word[2:]:
+ if "%" not in word[2:]:
word = word[2:]
prio2 = 2
elif word.startswith('%'):
- if not "%" in word[1:]:
+ if "%" not in word[1:]:
word = word[1:]
prio2 = 1
@@ -752,7 +753,7 @@ def completion_matcher(
priority: Optional[float] = None,
identifier: Optional[str] = None,
api_version: int = 1,
-):
+) -> Callable[[Matcher], Matcher]:
"""Adds attributes describing the matcher.
Parameters
@@ -961,8 +962,8 @@ class CompletionSplitter(object):
def split_line(self, line, cursor_pos=None):
"""Split a line of text with a cursor at the given position.
"""
- l = line if cursor_pos is None else line[:cursor_pos]
- return self._delim_re.split(l)[-1]
+ cut_line = line if cursor_pos is None else line[:cursor_pos]
+ return self._delim_re.split(cut_line)[-1]
@@ -1141,8 +1142,13 @@ class Completer(Configurable):
"""
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)
+ # we simple attribute matching with normal identifiers.
+ _ATTR_MATCH_RE = re.compile(r"(.+)\.(\w*)$")
+
+ def _attr_matches(
+ self, text: str, include_prefix: bool = True
+ ) -> Tuple[Sequence[str], str]:
+ m2 = self._ATTR_MATCH_RE.match(self.line_buffer)
if not m2:
return [], ""
expr, attr = m2.group(1, 2)
@@ -1204,6 +1210,30 @@ class Completer(Configurable):
"." + attr,
)
+ def _trim_expr(self, code: str) -> str:
+ """
+ Trim the code until it is a valid expression and not a tuple;
+
+ return the trimmed expression for guarded_eval.
+ """
+ while code:
+ code = code[1:]
+ try:
+ res = ast.parse(code)
+ except SyntaxError:
+ continue
+
+ assert res is not None
+ if len(res.body) != 1:
+ continue
+ expr = res.body[0].value
+ if isinstance(expr, ast.Tuple) and not code[-1] == ")":
+ # we skip implicit tuple, like when trimming `fun(a,b`<completion>
+ # as `a,b` would be a tuple, and we actually expect to get only `b`
+ continue
+ return code
+ return ""
+
def _evaluate_expr(self, expr):
obj = not_found
done = False
@@ -1225,14 +1255,14 @@ class Completer(Configurable):
# e.g. user starts `(d[`, so we get `expr = '(d'`,
# where parenthesis is not closed.
# TODO: make this faster by reusing parts of the computation?
- expr = expr[1:]
+ expr = self._trim_expr(expr)
return obj
def get__all__entries(obj):
"""returns the strings in the __all__ attribute"""
try:
words = getattr(obj, '__all__')
- except:
+ except Exception:
return []
return [w for w in words if isinstance(w, str)]
@@ -1447,7 +1477,7 @@ def match_dict_keys(
try:
if not str_key.startswith(prefix_str):
continue
- except (AttributeError, TypeError, UnicodeError) as e:
+ except (AttributeError, TypeError, UnicodeError):
# Python 3+ TypeError on b'a'.startswith('a') or vice-versa
continue
@@ -1495,7 +1525,7 @@ def cursor_to_position(text:str, line:int, column:int)->int:
lines = text.split('\n')
assert line <= len(lines), '{} <= {}'.format(str(line), str(len(lines)))
- return sum(len(l) + 1 for l in lines[:line]) + column
+ return sum(len(line) + 1 for line in lines[:line]) + column
def position_to_cursor(text:str, offset:int)->Tuple[int, int]:
"""
@@ -2113,7 +2143,7 @@ class IPCompleter(Completer):
result["suppress"] = is_magic_prefix and bool(result["completions"])
return result
- def magic_matches(self, text: str):
+ def magic_matches(self, text: str) -> List[str]:
"""Match magics.
.. deprecated:: 8.6
@@ -2470,7 +2500,8 @@ class IPCompleter(Completer):
# parenthesis before the cursor
# e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
tokens = regexp.findall(self.text_until_cursor)
- iterTokens = reversed(tokens); openPar = 0
+ iterTokens = reversed(tokens)
+ openPar = 0
for token in iterTokens:
if token == ')':
@@ -2490,7 +2521,8 @@ class IPCompleter(Completer):
try:
ids.append(next(iterTokens))
if not isId(ids[-1]):
- ids.pop(); break
+ ids.pop()
+ break
if not next(iterTokens) == '.':
break
except StopIteration:
@@ -3216,7 +3248,7 @@ class IPCompleter(Completer):
else:
api_version = _get_matcher_api_version(matcher)
raise ValueError(f"Unsupported API version {api_version}")
- except:
+ except BaseException:
# Show the ugly traceback if the matcher causes an
# exception, but do NOT crash the kernel!
sys.excepthook(*sys.exc_info())