Commit 4e9c689f authored by tamarin's avatar tamarin Committed by Guillaume Binet

Adding a callback allow plugins to catch unhandled messages (#931)

* Adding a callback_command_not_found to allow plugins to "catch" any commands that were not processed.  The goal is to allow a plugin to receive any message not already processed so that it may implement additional pattern matching or other functionality to process the message.

* Adding tests for command_not_found callback

* Rough draft for command_not_found core plugin

* Moving command-not-found functionality to core plugin

* Code style fixup

* Removing old rough draft using command_not_found callback

* Removing duplicate .replace for prefix test in cnf_plugin

* Updating plugin interface to use self.bot_config instead of _bot.
Updating command prefix check to use string instead of only character.

* Updating to use decorator parameter

* Refactoring catch_unprocessed flag set to more graceful .get
parent 253b20f3
......@@ -484,6 +484,7 @@ def cmdfilter(*args, **kwargs):
def decorate(func):
if not hasattr(func, '_err_command_filter'): # don't override generated functions
func._err_command_filter = True
func.catch_unprocessed = kwargs.get('catch_unprocessed', False)
return func
if len(args):
......@@ -328,14 +328,12 @@ class ErrBot(Backend, StoreMixin):
self._process_command(mess, cmd, args, match=None)
elif not only_check_re_command:
log.debug("Command not found")
if suppress_cmd_not_found:
log.debug("Surpressing command not found feedback")
reply = self.unknown_command(mess, command, args)
if reply is None:
reply = self.MSG_UNKNOWN_COMMAND % {'command': command}
if reply:
self.send_simple_reply(mess, reply)
for cmd_filter in self.command_filters:
if getattr(cmd_filter, 'catch_unprocessed', False):
reply = cmd_filter(mess, cmd, args, False, emptycmd=True)
if reply:
self.send_simple_reply(mess, reply)
return True
return True
def _process_command_filters(self, msg, cmd, args, dry_run=False):
Name = CommandNotFoundFilter
Module = cnf_filter
Core = True
Description = Allow overridable actions when a command is not present.
Version = 2+
from errbot import BotPlugin, cmdfilter
class CommandNotFoundFilter(BotPlugin):
def cnf_filter(self, msg, cmd, args, dry_run, emptycmd=False):
Check if command exists. If not, signal plugins. This plugin
will be called twice: once as a command filter and then again
as a "command not found" filter. See the emptycmd parameter.
:param msg: Original chat message.
:param cmd: Parsed command.
:param args: Command arguments.
:param dry_run: True when this is a dry-run.
:param emptycmd: False when this command has been parsed and is valid.
True if the command was not found.
if not emptycmd:
return msg, cmd, args
if self.bot_config.SUPPRESS_CMD_NOT_FOUND:
log.debug("Surpressing command not found feedback")
if msg.body.find(' ') > 0:
command = msg.body[:msg.body.index(' ')]
command = msg.body
prefixes = self.bot_config.BOT_ALT_PREFIXES + (self.bot_config.BOT_PREFIX,)
for prefix in prefixes:
if command.startswith(prefix):
command = command.replace(prefix, '', 1)
reply = self._bot.unknown_command(msg, command, args)
if reply is None:
reply = self.MSG_UNKNOWN_COMMAND % {'command': cmd}
if reply:
return reply
Name = TestCommandNotFoundFilter
Module = commandnotfound
from errbot import BotPlugin, cmdfilter
class TestCommandNotFoundFilter(BotPlugin):
def command_not_found(self, msg, cmd, args, dry_run, emptycmd=False):
if not emptycmd:
return msg, cmd, args
return "Command fell through: {}".format(msg)
......@@ -320,3 +320,18 @@ def test_no_suggest_on_re_commands(testbot):
# Don't suggest a regexp command.
assert '!re bar' not in testbot.pop_message()
def test_callback_no_command(testbot):
extra_plugin_dir = os.path.join(
cmd = '!this_is_not_a_real_command_at_all'
expected_str = "Command fell through: {}".format(cmd)
testbot.exec_command('!plugin deactivate CommandNotFoundFilter')[], extra_plugin_dir)
testbot.exec_command('!plugin activate TestCommandNotFoundFilter')
assert expected_str == testbot.exec_command(cmd)
import os
extra_plugin_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'room_plugin')
extra_config = {'CORE_PLUGINS': ('Help', 'Utils'), 'BOT_ALT_PREFIXES': ('!',), 'BOT_PREFIX': '$'}
extra_config = {'CORE_PLUGINS': ('Help', 'Utils', 'CommandNotFoundFilter'),
'BOT_PREFIX': '$'}
def test_help_is_still_here(testbot):
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment