anlutro / botologist

Plugin-driven Python3 IRC
MIT License
5 stars 5 forks source link

KeyErrors when users quit/get kicked #66

Closed anlutro closed 8 years ago

anlutro commented 8 years ago

Sometimes when a user gets kicked, an exception occurs:

[2016-06-09 10:17:13,702] DEBUG - botologist.protocol.irc - RECEIVED: ':Bad!sid38082@BadFurDay.users.quakenet.org KICK #redditeu Naypam :jesus fuck remove your EH bind'
[2016-06-09 10:17:13,702] ERROR - botologist.error - Uncaught exception - KeyError: <botologist.protocol.irc.User object at 0x7fc7354026a0>
Traceback (most recent call last):
  File "/home/andreas/scripts/ircbot/botologist/protocol/irc.py", line 135, in loop
    self.handle_msg(msg)
  File "/home/andreas/scripts/ircbot/botologist/protocol/irc.py", line 225, in handle_msg
    channel.users.remove(kicked_user)
KeyError: <botologist.protocol.irc.User object at 0x7fc7354026a0>

Relevant code: https://github.com/anlutro/botologist/blob/6d4f286b6933f7c732783cd02501cb7b05f22f8a/botologist/protocol/irc.py#L224-L225

I don't see how this is possible since if find_user returns a user, the user pretty much has to be in the channel.

Threading issue? GIL bullshit? Who knows!

anlutro commented 8 years ago

This might be because find_user can return the wrong user object when, for example, two users share the same host. However, when the error has happened in the past, it's been for users with guaranteed unique hosts.

It might instead be channel.nicks becoming out of sync somehow, containing duplicate users or something like that.

anlutro commented 8 years ago

This makes 0 sense

_______________________________________________ IrcChannelTest.test_issue66 _______________________________________________

self = <tests.botologist.irc_test.IrcChannelTest testMethod=test_issue66>

    def test_issue66(self):
            chan = Channel('#foobar')
            user1 = User('nick', 'host.com', 'ident')
            chan.add_user(user1)
            user2 = User('nick_', 'host.com', 'ident')
            chan.add_user(user2)
            chan.remove_user(name=user1.nick, identifier=user1.host)
            user2.name = 'nick'
>           chan.remove_user(name=user2.nick, identifier=user2.host)

tests/botologist/irc_test.py:65: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
botologist/protocol/irc.py:436: in remove_user
    return super().remove_user(user=user, name=name, identifier=identifier)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <botologist.protocol.irc.Channel object at 0x7ff2df035390>
user = <botologist.protocol.irc.User "nick!ident@host.com" at 0x7ff2df035400>, name = 'nick', identifier = 'host.com'

    def remove_user(self, user=None, name=None, identifier=None):
            assert user or name or identifier

            users = self.find_users(user, name, identifier)
            user = None
            print('len(users):', len(users))
            print('len(self.users):', len(self.users))
            for user in users:
                    print('self.users:', self.users)
                    print('user:', user)
                    log.debug('removing user %r from %s', user, self.name)
                    print('self.users.remove(user)')
                    print()
>                   self.users.remove(user)
E                   KeyError: <botologist.protocol.irc.User "nick!ident@host.com" at 0x7ff2df035400>

botologist/protocol/__init__.py:119: KeyError
-------------------------------------------------- Captured stdout call ---------------------------------------------------
len(users): 1
len(self.users): 2
self.users: {<botologist.protocol.irc.User "nick_!ident@host.com" at 0x7ff2df035400>, <botologist.protocol.irc.User "nick!ident@host.com" at 0x7ff2df0353c8>}
user: <botologist.protocol.irc.User "nick!ident@host.com" at 0x7ff2df0353c8>
self.users.remove(user)

len(users): 1
len(self.users): 1
self.users: {<botologist.protocol.irc.User "nick!ident@host.com" at 0x7ff2df035400>}
user: <botologist.protocol.irc.User "nick!ident@host.com" at 0x7ff2df035400>
self.users.remove(user)

---------------------------------------------------- Captured log call ----------------------------------------------------
__init__.py                116 DEBUG    removing user <botologist.protocol.irc.User "nick!ident@host.com" at 0x7ff2df0353c8> from #foobar
__init__.py                116 DEBUG    removing user <botologist.protocol.irc.User "nick!ident@host.com" at 0x7ff2df035400> from #foobar
anlutro commented 8 years ago

http://stackoverflow.com/questions/38746185/removing-objects-that-have-changed-from-a-python-set

TLDR: stop using sets?