callbacks: Fix interference between Scheduler.repeat, Anonymous, and nested commands

Specifically, the issue is with Anonymous using irc.noReply() in
the first call, preventing nested commands' result from being used.

Before this commit, the second and third responses in the test would be
only "1" and "2" instead of "1 ['foo']" and "2 ['foo']".
This commit is contained in:
Valentin Lorentz 2023-01-19 10:18:59 +01:00
parent b42596a021
commit f409111872
2 changed files with 35 additions and 3 deletions

View File

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

View File

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