Merge "fix fuzzy search for same-distance case"

This commit is contained in:
Jenkins 2015-11-13 10:42:17 +00:00 committed by Gerrit Code Review
commit fa418b23b4
2 changed files with 53 additions and 13 deletions

View File

@ -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

View File

@ -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']