config: Steal did you mean code from settings.
This commit is contained in:
parent
c9115aa480
commit
bd3d8f6932
@ -33,6 +33,39 @@ def validate_maximum(value, maximum):
|
|||||||
raise ValueError('%r must be smaller than %r.' % (value, maximum))
|
raise ValueError('%r must be smaller than %r.' % (value, maximum))
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: move this and levenshtein to a more appropriate class.
|
||||||
|
def did_you_mean(name, choices):
|
||||||
|
"""Suggest most likely setting based on levenshtein."""
|
||||||
|
if not choices:
|
||||||
|
return None
|
||||||
|
|
||||||
|
name = name.lower()
|
||||||
|
candidates = [(levenshtein(name, c), c) for c in choices]
|
||||||
|
candidates.sort()
|
||||||
|
|
||||||
|
if candidates[0][0] <= 3:
|
||||||
|
return candidates[0][1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def levenshtein(a, b):
|
||||||
|
"""Calculates the Levenshtein distance between a and b."""
|
||||||
|
n, m = len(a), len(b)
|
||||||
|
if n > m:
|
||||||
|
return levenshtein(b, a)
|
||||||
|
|
||||||
|
current = xrange(n + 1)
|
||||||
|
for i in xrange(1, m + 1):
|
||||||
|
previous, current = current, [i] + [0] * n
|
||||||
|
for j in xrange(1, n + 1):
|
||||||
|
add, delete = previous[j] + 1, current[j - 1] + 1
|
||||||
|
change = previous[j - 1]
|
||||||
|
if a[j - 1] != b[i - 1]:
|
||||||
|
change += 1
|
||||||
|
current[j] = min(add, delete, change)
|
||||||
|
return current[n]
|
||||||
|
|
||||||
|
|
||||||
class ConfigValue(object):
|
class ConfigValue(object):
|
||||||
"""Represents a config key's value and how to handle it.
|
"""Represents a config key's value and how to handle it.
|
||||||
|
|
||||||
@ -248,6 +281,9 @@ class ConfigSchema(object):
|
|||||||
values[key] = self._schema[key].deserialize(value)
|
values[key] = self._schema[key].deserialize(value)
|
||||||
except KeyError: # not in our schema
|
except KeyError: # not in our schema
|
||||||
errors[key] = 'unknown config key.'
|
errors[key] = 'unknown config key.'
|
||||||
|
suggestion = did_you_mean(key, self._schema.keys())
|
||||||
|
if suggestion:
|
||||||
|
errors[key] += ' Did you mean %s?' % suggestion
|
||||||
except ValueError as e: # deserialization failed
|
except ValueError as e: # deserialization failed
|
||||||
errors[key] = str(e)
|
errors[key] = str(e)
|
||||||
|
|
||||||
|
|||||||
@ -395,3 +395,22 @@ class LogLevelConfigSchemaTest(unittest.TestCase):
|
|||||||
result = schema.format('levels', {'foo.bar': logging.DEBUG, 'baz': logging.INFO})
|
result = schema.format('levels', {'foo.bar': logging.DEBUG, 'baz': logging.INFO})
|
||||||
self.assertEqual('\n'.join(expected), result)
|
self.assertEqual('\n'.join(expected), result)
|
||||||
|
|
||||||
|
|
||||||
|
class DidYouMeanTest(unittest.TestCase):
|
||||||
|
def testSuggestoins(self):
|
||||||
|
choices = ('enabled', 'username', 'password', 'bitrate', 'timeout')
|
||||||
|
|
||||||
|
suggestion = config.did_you_mean('bitrate', choices)
|
||||||
|
self.assertEqual(suggestion, 'bitrate')
|
||||||
|
|
||||||
|
suggestion = config.did_you_mean('bitrote', choices)
|
||||||
|
self.assertEqual(suggestion, 'bitrate')
|
||||||
|
|
||||||
|
suggestion = config.did_you_mean('Bitrot', choices)
|
||||||
|
self.assertEqual(suggestion, 'bitrate')
|
||||||
|
|
||||||
|
suggestion = config.did_you_mean('BTROT', choices)
|
||||||
|
self.assertEqual(suggestion, 'bitrate')
|
||||||
|
|
||||||
|
suggestion = config.did_you_mean('btro', choices)
|
||||||
|
self.assertEqual(suggestion, None)
|
||||||
|
|||||||
@ -149,27 +149,3 @@ class SettingsProxyTest(unittest.TestCase):
|
|||||||
def test_value_ending_in_path_can_be_none(self):
|
def test_value_ending_in_path_can_be_none(self):
|
||||||
self.settings.TEST_PATH = None
|
self.settings.TEST_PATH = None
|
||||||
self.assertEqual(self.settings.TEST_PATH, None)
|
self.assertEqual(self.settings.TEST_PATH, None)
|
||||||
|
|
||||||
|
|
||||||
class DidYouMeanTest(unittest.TestCase):
|
|
||||||
def testSuggestoins(self):
|
|
||||||
defaults = {
|
|
||||||
'MPD_SERVER_HOSTNAME': '::',
|
|
||||||
'MPD_SERVER_PORT': 6600,
|
|
||||||
'SPOTIFY_BITRATE': 160,
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestion = setting_utils.did_you_mean('spotify_bitrate', defaults)
|
|
||||||
self.assertEqual(suggestion, 'SPOTIFY_BITRATE')
|
|
||||||
|
|
||||||
suggestion = setting_utils.did_you_mean('SPOTIFY_BITROTE', defaults)
|
|
||||||
self.assertEqual(suggestion, 'SPOTIFY_BITRATE')
|
|
||||||
|
|
||||||
suggestion = setting_utils.did_you_mean('SPITIFY_BITROT', defaults)
|
|
||||||
self.assertEqual(suggestion, 'SPOTIFY_BITRATE')
|
|
||||||
|
|
||||||
suggestion = setting_utils.did_you_mean('SPTIFY_BITROT', defaults)
|
|
||||||
self.assertEqual(suggestion, 'SPOTIFY_BITRATE')
|
|
||||||
|
|
||||||
suggestion = setting_utils.did_you_mean('SPTIFY_BITRO', defaults)
|
|
||||||
self.assertEqual(suggestion, None)
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user