diff --git a/plugins/Scheduler/test.py b/plugins/Scheduler/test.py index f6cb22fd8..a01069173 100644 --- a/plugins/Scheduler/test.py +++ b/plugins/Scheduler/test.py @@ -89,7 +89,6 @@ class SchedulerTestCase(ChannelPluginTestCase): self.assertResponse( 'scheduler list', 'There are currently no scheduled commands.') - def testRepeat(self): self.assertRegexp('scheduler repeat repeater 5 echo testRepeat', 'testRepeat') @@ -132,6 +131,32 @@ class SchedulerTestCase(ChannelPluginTestCase): timeFastForward(5) self.assertNoResponse(' ', timeout=1) + def testRepeatWorksWithNestedCommandsWithNoReply(self): + # the 'trylater' command uses ircmsgs.privmsg + irc.noReply(), + # similar to how the Anonymous plugin implements sending messages + # to channels/users without .reply() (as it is technically not a + # reply to the origin message) + count = 0 + class TryLater(callbacks.Plugin): + def trylater(self, irc, msg, args): + nonlocal count + msg = ircmsgs.privmsg(msg.nick, "%d %s" % (count, args)) + irc.queueMsg(msg) + irc.noReply() + count += 1 + + cb = TryLater(self.irc) + self.irc.addCallback(cb) + try: + self.assertResponse('scheduler repeat foo 5 "trylater [echo foo]"', + "0 ['foo']") + timeFastForward(5) + self.assertResponse(' ', "1 ['foo']") + timeFastForward(5) + self.assertResponse(' ', "2 ['foo']") + finally: + self.irc.removeCallback('TryLater') + def testRepeatDisallowsIntegerNames(self): self.assertError('scheduler repeat 1234 1234 "echo NoIntegerNames"') @@ -187,7 +212,5 @@ class SchedulerTestCase(ChannelPluginTestCase): self.assertResponse(' ', 'testRepeat', timeout=1) # T+106 - - # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/src/callbacks.py b/src/callbacks.py index dcccab3c5..85f4d8020 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -990,10 +990,19 @@ class NestedCommandsIrcProxy(ReplyIrcProxy): self.error(_('You\'ve attempted more nesting than is ' 'currently allowed on this bot.')) return + # The deepcopy here is necessary for Scheduler; it re-runs already # tokenized commands. There's a possibility a simple copy[:] would # work, but we're being careful. self.args = copy.deepcopy(args) + + # Another trick needed for Scheduler: + # A previous run of the command may have set 'ignored' to True, + # causing this run to not include response from nested commands; + # as NestedCommandsIrcProxy.reply() would confuse it with the + # subcommand setting 'ignored' to True itself. + msg.tag('ignored', False) + self.counter = 0 self._resetReplyAttributes() if not args: