Skip to content

Commit 1ca1904

Browse files
committed
Introduce more advanced method of commands comparison
1 parent 275d004 commit 1ca1904

File tree

1 file changed

+35
-5
lines changed

1 file changed

+35
-5
lines changed

invoke/program.py

+35-5
Original file line numberDiff line numberDiff line change
@@ -999,13 +999,11 @@ def print_columns(
999999
print("")
10001000

10011001
def _possible_commands_msg(self, unknown_cmd: str) -> str:
1002-
try:
1002+
all_tasks = {}
1003+
if hasattr(self, "scoped_collection"):
10031004
all_tasks = self.scoped_collection.task_names
1004-
except AttributeError:
1005-
all_tasks = {}
1006-
10071005
possible_cmds = list(all_tasks.keys())
1008-
suggestions = difflib.get_close_matches(
1006+
suggestions = _get_best_match(
10091007
unknown_cmd, possible_cmds, n=3, cutoff=0.7
10101008
)
10111009
output_message = f"'{unknown_cmd}' is not an invoke command. "
@@ -1017,3 +1015,35 @@ def _possible_commands_msg(self, unknown_cmd: str) -> str:
10171015
else:
10181016
output_message += "\nNo suggestions was found.\n"
10191017
return output_message
1018+
1019+
1020+
def _get_best_match(
1021+
word: str, possibilities: List[str], n: int = 3, cutoff: float = 0.7
1022+
) -> List[str]:
1023+
"""Return a list of the top `n` best-matching commands for a given word.
1024+
1025+
This function accounts for dot-separated commands by normalizing them—
1026+
splitting them into parts, sorting them alphabetically, and rejoining them.
1027+
This allows for matching commands that contain the same elements but in
1028+
different orders.
1029+
1030+
For example, 'task1.task2' and 'task2.task1' will have a similarity score
1031+
of 0.98.
1032+
"""
1033+
normalized_unknown_cmd = ".".join(sorted(word.split(".")))
1034+
matches = []
1035+
for cmd in possibilities:
1036+
normalized_cmd = ".".join(sorted(cmd.split(".")))
1037+
similarity_normalized = difflib.SequenceMatcher(
1038+
None, normalized_unknown_cmd, normalized_cmd
1039+
).ratio()
1040+
similarity_raw = difflib.SequenceMatcher(None, word, cmd).ratio()
1041+
# The idea here is to decrease the similarity score if we have
1042+
# reordered the given word
1043+
similarity = max(similarity_normalized * 0.98, similarity_raw)
1044+
if similarity >= cutoff:
1045+
matches.append((similarity, cmd))
1046+
1047+
matches.sort(reverse=True)
1048+
1049+
return [match[1] for match in matches[:n]]

0 commit comments

Comments
 (0)