Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/prompt_toolkit/completion/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ def __eq__(self, other: object) -> bool:
)

def __hash__(self) -> int:
return hash((self.text, self.start_position, self.display, self._display_meta))
# Display and metadata may contain unhashable formatted text. These
# two fields alone still guarantee equal completions have equal hashes.
return hash((self.text, self.start_position))

@property
def display_text(self) -> str:
Expand Down
37 changes: 37 additions & 0 deletions tests/test_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from prompt_toolkit.completion import (
CompleteEvent,
Completion,
FuzzyWordCompleter,
NestedCompleter,
PathCompleter,
Expand Down Expand Up @@ -467,3 +468,39 @@ def create_completer(deduplicate: bool):
)
)
assert len(completions) == 5


def test_completion_hash_default_display():
first = Completion("example", start_position=-2)
equal = Completion("example", start_position=-2)
different = Completion("other", start_position=-2)
assert first == equal
assert hash(first) == hash(equal)
assert {first, equal, different} == {first, different}
assert {first: "cached"}[equal] == "cached"


def test_completion_hash_formatted_display_and_metadata():
first = Completion(
"example", display=[("class:name", "Example")], display_meta=[("", "meta")]
)
equal = Completion(
"example", display=[("class:name", "Example")], display_meta=[("", "meta")]
)
different = Completion(
"example", display=[("class:name", "Other")], display_meta=[("", "meta")]
)
assert first == equal
assert hash(first) == hash(equal)
assert len({first, equal, different}) == 2


def test_completion_hash_does_not_evaluate_lazy_metadata():
def metadata():
raise AssertionError("Metadata should remain lazy")

first = Completion("example", display_meta=metadata)
equal = Completion("example", display_meta=metadata)
assert first == equal
assert hash(first) == hash(equal)
assert len({first, equal}) == 1