Skip to content

gh-130472: Use fancycompleter in import completions#148188

Open
tomasr8 wants to merge 7 commits intopython:mainfrom
tomasr8:colorize-imports
Open

gh-130472: Use fancycompleter in import completions#148188
tomasr8 wants to merge 7 commits intopython:mainfrom
tomasr8:colorize-imports

Conversation

@tomasr8
Copy link
Copy Markdown
Member

@tomasr8 tomasr8 commented Apr 6, 2026

image

Now that #130473 has been merged, let's use it for import completions as well.
This is my first stab at this. First, I did a bit of refactoring and extracted the getattr and colorize logic from FancyCompleter into reusable functions since I needed those for module completions. I also modified ModuleCompleter to return attribute values in addition to names (for modules, it just returns the sys module as a dummy value, this is just to get the color right). Then I just needed to extend get_module_completions to do the colorization.

@loic-simon would love if you have some spare time to have a look :)

tomasr8 added 7 commits April 6, 2026 22:30
- Make module completer return both names and values (dummy `sys` module
in case of module completions)
- Colorize completions using `colorize_matches` from FancyCompleter
Copy link
Copy Markdown
Contributor

@loic-simon loic-simon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!! Here's a quick first pass, I'll play around with it in local later 😄

Comment on lines -74 to +75
def get_completions(self, line: str) -> tuple[list[str], CompletionAction | None] | None:
def get_completions(self, line: str) -> tuple[list[str], list[Any], CompletionAction | None] | None:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would've find it more natural to return a dict[str, Any] instead of two parallel lists, but I see that's what fancycompleter does, so let be it!

But I wonder if we haven't passed the point where a namedtuple would be more readeable / maintainable? I hesitated when adding completion action, something like

class _GetCompletionsReturn(NamedTuple):
    names: list[str]
    values: list[Any]
    action: CompletionAction | None

the docstring could use an update either way 😄

Comment on lines +121 to +122
all_values = [attr_map.get(n) if n not in submodule_set else sys
for n in all_names]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a name is both a submodule and an attribute, the attribute takes precedence at runtime, so I believe this should be

Suggested change
all_values = [attr_map.get(n) if n not in submodule_set else sys
for n in all_names]
all_values = [attr_map[n] if n in attr_map else sys for n in all_names]

readline_completer: Completer | None = None
completer_delims: frozenset[str] = frozenset(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?")
module_completer: ModuleCompleter = field(default_factory=make_default_module_completer)
colorize_completions: Callable[[list[str], list[object]], list[str]] | None = None
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a rationale for using list[object] here but list[Any] in _module_completer? I think it should be object anywhere (cf. mypy doc)

f"{module_color}importlib.metadata{R}",
])
self.assertIsNone(action)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe a test with a name both an attribute + a submodule with the same name would be great, to be sure everything combines well?

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.

2 participants