diff --git a/src/callbacks.py b/src/callbacks.py index d2d6ba4b9..7b97a64c8 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -705,7 +705,14 @@ class NestedCommandsIrcProxy(ReplyIrcProxy): cbs = [cb for (cb, L) in cbs if L == maxL] if len(maxL) == 1: # Special case: one arg determines the callback. In this case, we - # have to check defaultPlugins. + # have to check, in order: + # 1. Whether the arg is the same as the name of a callback. This + # callback would then win. + for cb in cbs: + if cb.canonicalName() == maxL[0]: + return (maxL, [cb]) + + # 2. Whether a defaultplugin is defined. defaultPlugins = conf.supybot.commands.defaultPlugins try: defaultPlugin = defaultPlugins.get(maxL[0])() @@ -719,7 +726,9 @@ class NestedCommandsIrcProxy(ReplyIrcProxy): # actually have that command. return (maxL, [cb]) except registry.NonExistentRegistryEntry: - pass # No default plugin defined. + pass + + # 3. Whether an importantPlugin is one of the responses. important = defaultPlugins.importantPlugins() important = map(canonicalName, important) importants = [] diff --git a/test/test_callbacks.py b/test/test_callbacks.py index cbb2caa55..5ccbf1134 100644 --- a/test/test_callbacks.py +++ b/test/test_callbacks.py @@ -261,6 +261,21 @@ class FunctionsTestCase(SupyTestCase): self.assertEqual(callbacks.tokenize('bar [baz]'), ['bar', ['baz']]) +class AmbiguityTestCase(PluginTestCase): + plugins = ('Misc',) # Something so it doesn't complain. + class Foo(callbacks.Plugin): + def bar(self, irc, msg, args): + irc.reply('foo.bar') + class Bar(callbacks.Plugin): + def bar(self, irc, msg, args): + irc.reply('bar.bar') + + def testAmbiguityWithCommandSameNameAsPlugin(self): + self.irc.addCallback(self.Foo(self.irc)) + self.assertResponse('bar', 'foo.bar') + self.irc.addCallback(self.Bar(self.irc)) + self.assertResponse('bar', 'bar.bar') + class PrivmsgTestCase(ChannelPluginTestCase): plugins = ('Utilities', 'Misc',) conf.allowEval = True