Skip to content

Fix completer regressions - #15395

Open
krassowski wants to merge 2 commits into
ipython:mainfrom
krassowski:fix-completer-regressions
Open

krassowski wants to merge 2 commits into
ipython:mainfrom
krassowski:fix-completer-regressions

Conversation

@krassowski

Copy link
Copy Markdown
Member

References

Code changes

  • Cuts at a keyword as well as at an operator in _strip_code_before_operator, so for k in d gives d, the way a + d already did. Leaves out True, False and None, which are values rather than boundaries.
  • Calls _strip_code_before_operator from dict_key_matches, so x = d["<Tab> evaluates d and not x = d.
  • Adds parametrized tests for the eight lines in the issue, four DataFrame lines, and six further lines that use a keyword or an operator.

User-facing changes

Dict key completion gave nothing whenever the subscript was not the first thing on the line. x = d["<Tab> broke in 9.6, for k in d["<Tab> and lambda: d["<Tab> broke in 9.5, and d["bar"] * d["<Tab> never worked. The form people hit most is df["k"] = df["Year<Tab> in pandas. With this PR all of them offer the keys again.

Attribute completion shares that function, so it changes too when jedi is disabled. for x in v.<Tab>, x = v if cond else v.<Tab>, del v.<Tab>, return v.<Tab>, yield v.<Tab> and x = q in v.<Tab> gave nothing before and now offer the attributes of v.

Before - no suggestions

image

After - suggestions

image

Performance

The text on the left of the subscript no longer reaches _trim_expr, which drops it one character at a time. Microseconds per completion call, jedi disabled:

line before after
d["comp 93 107
x = d["comp 292 110
for k in d["comp 355 111
d["k"] = d["comp 349 114

The saving grows with the length of the text before the subscript. Milliseconds for x = [0, 1, ...] + d["comp:

line length before after
204 3.7 0.3
904 44.3 0.7
2404 301.1 1.7

A line with an unclosed bracket still goes through the trim, because the tokenizer raises and the existing fallback runs. print(0, 1, ..., d["comp stays at 438 ms for 2403 characters.

Alternatives considered

  • Trimming the captured text when it is not a single expression, leaving DICT_MATCHER_REGEX alone.
    • Pro: reuses _trim_expr, and the regular expression stays as it is.
    • Con: leaves for, lambda, the ternary, the comprehension and yield broken, because each is a valid expression or evaluates without raising.
    • Con: covering those needs more AST node classes in the check or more exception types in the retry loop, and widening that retry is what Invalid completions shown when evaluation policy forbids access #14916 closed.
    • Con: slower than today on a long assignment, because the fix works by trimming.
  • Narrowing DICT_MATCHER_REGEX to capture only the subscripted expression.
    • Pro: smallest patch, and depends on nothing but re.
    • Pro: fastest of the three on every expression it matches.
    • Con: stops completing d[idx[0]][", nest["a"] ["b"] [", ((d))[" and any key holding a bracket, because a regular expression cannot match nested brackets.
    • Con: completes inside comments.
    • Con: quadratic on a long run of word characters, at 92 ms per keystroke on a 2000-character line against 0.14 ms here.

AI usage

Opus 5 ultra

@AylmerTH

Copy link
Copy Markdown

This fixes the issues I was having, cheers.

@krassowski krassowski added this to the 9.18 milestone Sep 19, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dict key completion gives nothing when the subscript is on the right of an assignment (regression in 9.6)

2 participants