Merge "fix fuzzy search for same-distance case"
This commit is contained in:
commit
fa418b23b4
26
cliff/app.py
26
cliff/app.py
|
@ -9,7 +9,6 @@ import logging
|
|||
import logging.handlers
|
||||
import os
|
||||
import sys
|
||||
import operator
|
||||
|
||||
from .complete import CompleteCommand
|
||||
from .help import HelpAction, HelpCommand
|
||||
|
@ -314,21 +313,22 @@ class App(object):
|
|||
prefix = candidate.split(sep)[0]
|
||||
# Give prefix match a very good score
|
||||
if candidate.startswith(cmd):
|
||||
dist.append((candidate, 0))
|
||||
dist.append((0, candidate))
|
||||
continue
|
||||
# Levenshtein distance
|
||||
dist.append((candidate, damerau_levenshtein(cmd, prefix, COST)+1))
|
||||
dist = sorted(dist, key=operator.itemgetter(1, 0))
|
||||
dist.append((damerau_levenshtein(cmd, prefix, COST)+1, candidate))
|
||||
|
||||
matches = []
|
||||
i = 0
|
||||
# Find the best similarity
|
||||
while (not dist[i][1]):
|
||||
matches.append(dist[i][0])
|
||||
i += 1
|
||||
best_similarity = dist[i][1]
|
||||
while (dist[i][1] == best_similarity):
|
||||
matches.append(dist[i][0])
|
||||
i += 1
|
||||
match_distance = 0
|
||||
for distance, candidate in sorted(dist):
|
||||
if distance > match_distance:
|
||||
if match_distance:
|
||||
# we copied all items with minimum distance, we are done
|
||||
break
|
||||
# we copied all items with distance=0,
|
||||
# now we match all candidates at the minimum distance
|
||||
match_distance = distance
|
||||
matches.append(candidate)
|
||||
|
||||
return matches
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ from cliff.app import App
|
|||
from cliff.command import Command
|
||||
from cliff.commandmanager import CommandManager
|
||||
from cliff.tests import utils
|
||||
from cliff.utils import damerau_levenshtein, COST
|
||||
|
||||
|
||||
def make_app(**kwargs):
|
||||
|
@ -448,3 +449,42 @@ def test_list_matching_commands():
|
|||
assert "test: 't' is not a test command. See 'test --help'." in output
|
||||
assert 'Did you mean one of these?' in output
|
||||
assert 'three word command\n two words\n' in output
|
||||
|
||||
|
||||
def test_fuzzy_no_commands():
|
||||
cmd_mgr = CommandManager('cliff.fuzzy')
|
||||
app = App('test', '1.0', cmd_mgr)
|
||||
cmd_mgr.commands = {}
|
||||
matches = app.get_fuzzy_matches('foo')
|
||||
assert matches == []
|
||||
|
||||
|
||||
def test_fuzzy_common_prefix():
|
||||
# searched string is a prefix of all commands
|
||||
cmd_mgr = CommandManager('cliff.fuzzy')
|
||||
app = App('test', '1.0', cmd_mgr)
|
||||
cmd_mgr.commands = {}
|
||||
cmd_mgr.add_command('user list', utils.TestCommand)
|
||||
cmd_mgr.add_command('user show', utils.TestCommand)
|
||||
matches = app.get_fuzzy_matches('user')
|
||||
assert matches == ['user list', 'user show']
|
||||
|
||||
|
||||
def test_fuzzy_same_distance():
|
||||
# searched string has the same distance to all commands
|
||||
cmd_mgr = CommandManager('cliff.fuzzy')
|
||||
app = App('test', '1.0', cmd_mgr)
|
||||
cmd_mgr.add_command('user', utils.TestCommand)
|
||||
for cmd in cmd_mgr.commands.keys():
|
||||
assert damerau_levenshtein('node', cmd, COST) == 8
|
||||
matches = app.get_fuzzy_matches('node')
|
||||
assert matches == ['complete', 'help', 'user']
|
||||
|
||||
|
||||
def test_fuzzy_no_prefix():
|
||||
# search by distance, no common prefix with any command
|
||||
cmd_mgr = CommandManager('cliff.fuzzy')
|
||||
app = App('test', '1.0', cmd_mgr)
|
||||
cmd_mgr.add_command('user', utils.TestCommand)
|
||||
matches = app.get_fuzzy_matches('uesr')
|
||||
assert matches == ['user']
|
||||
|
|
Loading…
Reference in New Issue