diff --git a/src/callbacks.py b/src/callbacks.py index da3a998b2..90cbbe5d4 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -519,7 +519,59 @@ class RichReplyMethods(object): _repr = repr -class IrcObjectProxy(RichReplyMethods): +class IrcReplyProxy(RichReplyMethods): + """This class is a thin wrapper around an irclib.Irc object that gives it + the reply() and error() methods (as well as everything in RichReplyMethods, + based on those two).""" + def __init__(self, irc, msg): + self.irc = irc + self.msg = msg + + def getRealIrc(self): + if isinstance(self.irc, irclib.Irc): + return self.irc + else: + return self.irc.getRealIrc() + + # This should make us be considered equal to our irclib.Irc object for + # hashing; an important thing (no more "too many open files" exceptions :)) + def __hash__(self): + return hash(self.getRealIrc()) + def __eq__(self, other): + return self.getRealIrc() == other + __req__ = __eq__ + def __ne__(self, other): + return not (self == other) + __rne__ = __ne__ + + def error(self, s, msg=None, **kwargs): + if 'Raise' in kwargs and kwargs['Raise']: + if s: + raise Error, s + else: + raise ArgumentError + if msg is None: + msg = self.msg + m = error(msg, s, **kwargs) + self.irc.queueMsg(m) + return m + + def reply(self, s, msg=None, **kwargs): + if msg is None: + msg = self.msg + assert not isinstance(s, ircmsgs.IrcMsg), \ + 'Old code alert: there is no longer a "msg" argument to reply.' + kwargs.pop('noLengthCheck', None) + m = reply(msg, s, **kwargs) + self.irc.queueMsg(m) + return m + + def __getattr__(self, attr): + return getattr(self.irc, attr) + +SimpleProxy = IrcReplyProxy # Backwards-compatibility + +class IrcObjectProxy(IrcReplyProxy): "A proxy object to allow proper nested of commands (even threaded ones)." _mores = ircutils.IrcDict() def __init__(self, irc, msg, args, nested=0): @@ -1204,45 +1256,6 @@ class Plugin(PluginMixin, Commands): Privmsg = Plugin # Backwards compatibility. -class SimpleProxy(RichReplyMethods): - """This class is a thin wrapper around an irclib.Irc object that gives it - the reply() and error() methods (as well as everything in RichReplyMethods, - based on those two).""" - def __init__(self, irc, msg): - self.irc = irc - self.msg = msg - - def getRealIrc(self): - if isinstance(self.irc, irclib.Irc): - return self.irc - else: - return self.irc.getRealIrc() - - def error(self, s, msg=None, **kwargs): - if 'Raise' in kwargs and kwargs['Raise']: - if s: - raise Error, s - else: - raise ArgumentError - if msg is None: - msg = self.msg - m = error(msg, s, **kwargs) - self.irc.queueMsg(m) - return m - - def reply(self, s, msg=None, **kwargs): - if msg is None: - msg = self.msg - assert not isinstance(s, ircmsgs.IrcMsg), \ - 'Old code alert: there is no longer a "msg" argument to reply.' - kwargs.pop('noLengthCheck', None) - m = reply(msg, s, **kwargs) - self.irc.queueMsg(m) - return m - - def __getattr__(self, attr): - return getattr(self.irc, attr) - class PluginRegexp(Plugin): """Same as Plugin, except allows the user to also include regexp-based callbacks. All regexp-based callbacks must be specified in a set (or diff --git a/src/irclib.py b/src/irclib.py index 19cea46ae..42dd924b0 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -975,7 +975,12 @@ class Irc(IrcCommandDispatcher): return id(self) def __eq__(self, other): - return id(self) == id(other) + # We check isinstance here, so that if some proxy object (like those + # defined in callbacks.py) has overridden __eq__, it takes precedence. + if isinstance(other, self.__class__): + return id(self) == id(other) + else: + return other == self def __ne__(self, other): return not (self == other) diff --git a/test/test_callbacks.py b/test/test_callbacks.py index 6a0c22c66..fbc34fa2d 100644 --- a/test/test_callbacks.py +++ b/test/test_callbacks.py @@ -613,6 +613,36 @@ class WithPrivateNoticeTestCase(ChannelPluginTestCase): finally: conf.supybot.reply.withNoticeWhenPrivate.setValue(original) +class ProxyTestCase(SupyTestCase): + def testHashing(self): + msg = ircmsgs.ping('0') + irc = irclib.Irc('test') + proxy = callbacks.SimpleProxy(irc, msg) + # First one way... + self.failIf(proxy != irc) + self.failUnless(proxy == irc) + self.assertEqual(hash(proxy), hash(irc)) + # Then the other! + self.failIf(irc != proxy) + self.failUnless(irc == proxy) + self.assertEqual(hash(irc), hash(proxy)) + + # And now dictionaries... + d = {} + d[irc] = 'foo' + self.failUnless(len(d) == 1) + self.failUnless(d[irc] == 'foo') + self.failUnless(d[proxy] == 'foo') + d[proxy] = 'bar' + self.failUnless(len(d) == 1) + self.failUnless(d[irc] == 'bar') + self.failUnless(d[proxy] == 'bar') + d[irc] = 'foo' + self.failUnless(len(d) == 1) + self.failUnless(d[irc] == 'foo') + self.failUnless(d[proxy] == 'foo') + + # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: