jaraco / irc

Full-featured Python IRC library for Python.
MIT License
390 stars 84 forks source link

Error when attempting to join multiple channels #218

Closed SomethingGeneric closed 6 months ago

SomethingGeneric commented 8 months ago
File "/home/matt/Documents/goobot/venv/lib/python3.11/site-packages/irc/bot.py", line 208, in _on_join
    self.channels[ch] = Channel()
    ~~~~~~~~~~~~~^^^^
TypeError: list indices must be integers or slices, not str

My code:

import irc.bot

class MultiChannelBot(irc.bot.SingleServerIRCBot):
    def __init__(self, channels, nickname, server, port=6667):
        print("Initializing bot...")
        server_list = [(server, port)]
        super().__init__(server_list, nickname, nickname)
        self.channels = channels
        print("Bot initialized!")

    def on_welcome(self, connection, event):
        print("Joining channels...")
        for channel in self.channels:
            connection.join(channel)

    def on_pubmsg(self, connection, event):
        print("Found public message!")
        message = event.arguments[0]
        user = event.source.nick
        channel = event.target

        if message.startswith("!hello"):
            connection.privmsg(channel, f"Hello, {user}!")

    def on_privmsg(self, connection, event):
        print("Received private message!")
        message = event.arguments[0]
        user = event.source.nick

        if message.startswith("!private"):
            connection.privmsg(user, f"Hello, {user}! This is a private message response.")

if __name__ == "__main__":
    print("Defining bot...")
    channels = ["#general", "#znc", "#bots", "#roadmap"]  # Add more channels as needed
    bot = MultiChannelBot(channels, "goobot", "goober.cloud")
    print("Starting bot...")
    bot.start()
SomethingGeneric commented 8 months ago

Not sure if this is a user error or library error?

henry40408 commented 8 months ago

@SomethingGeneric I encountered the same error and figure our a quick solution.

The issue arises because MultiChannelBot extends SingleServerIRCBot. When you define self.channels in the __init__ function of MultiChannelBot, it overrides self.channels in SingleServerIRCBot. As a result, SingleServerIRCBot fails to add channels to self.channels as a IRCDict, which is now a list overridden by MultiChannelBot.

import irc.bot

class MultiChannelBot(irc.bot.SingleServerIRCBot):
    def __init__(self, channels, nickname, server, port=6667):
        print("Initializing bot...")
        server_list = [(server, port)]
        super().__init__(server_list, nickname, nickname)
        # 👇  MultiChannelBot overrides self.channels, which is also used by SingleServerIRCBot
        # self.channels = channels
        self.my_channels = channels # rename to my_channels
        print("Bot initialized!")

    def on_welcome(self, connection, event):
        print("Joining channels...")
        for channel in self.my_channels: # rename to my_channels
            connection.join(channel)

    def on_pubmsg(self, connection, event):
        print("Found public message!")
        message = event.arguments[0]
        user = event.source.nick
        channel = event.target

        if message.startswith("!hello"):
            connection.privmsg(channel, f"Hello, {user}!")

    def on_privmsg(self, connection, event):
        print("Received private message!")
        message = event.arguments[0]
        user = event.source.nick

        if message.startswith("!private"):
            connection.privmsg(user, f"Hello, {user}! This is a private message response.")

if __name__ == "__main__":
    print("Defining bot...")
    channels = ["#general", "#znc", "#bots", "#roadmap"]  # Add more channels as needed
    bot = MultiChannelBot(channels, "goobot", "goober.cloud")
    print("Starting bot...")
    bot.start()

SingleServerIRCBot also uses self.channels to manage joined channels:

https://github.com/jaraco/irc/blob/5aa529d2052a569f9ecee6a65cc41c650e26bc44/irc/bot.py#L162

https://github.com/jaraco/irc/blob/5aa529d2052a569f9ecee6a65cc41c650e26bc44/irc/bot.py#L208

The quick solution is give self.channels another name e.g. self.my_channels.