Commits

Jason R. Coombs  committed 2b58692

Restored use of IRCDict, which should follow the RFC spec for case insensitivity. Thanks to xrogaan for pointing out the regression.

  • Participants
  • Parent commits b213a3e

Comments (0)

Files changed (2)

 import re
 from UserDict import UserDict
 
-from irclib import SimpleIRCClient
-from irclib import nm_to_n, irc_lower, all_events
-from irclib import parse_channel_modes, is_channel
-from irclib import ServerConnectionError
+import irclib
+from irclib import (SimpleIRCClient, nm_to_n, irc_lower, all_events,
+    parse_channel_modes, is_channel, ServerConnectionError)
 
 class SingleServerIRCBot(SimpleIRCClient):
     """A single-server IRC bot class.
     """
 
     def __init__(self):
-        self.userdict = FoldedCaseKeyedDict()
-        self.operdict = FoldedCaseKeyedDict()
-        self.voiceddict = FoldedCaseKeyedDict()
+        self.userdict = IRCDict()
+        self.operdict = IRCDict()
+        self.voiceddict = IRCDict()
         self.modes = {}
 
     def users(self):
         else:
             return None
 
-# from jaraco.util.string
-class FoldedCase(str):
-    """
-    A case insensitive string class; behaves just like str
-    except compares equal when the only variation is case.
-    >>> s = FoldedCase('hello world')
-
-    >>> s == 'Hello World'
-    True
-
-    >>> 'Hello World' == s
-    True
-
-    >>> s.index('O')
-    4
-
-    >>> s.split('O')
-    ['hell', ' w', 'rld']
-
-    >>> names = map(FoldedCase, ['GAMMA', 'alpha', 'Beta'])
-    >>> names.sort()
-    >>> names
-    ['alpha', 'Beta', 'GAMMA']
-    """
-    def __lt__(self, other):
-        return self.lower() < other.lower()
-    def __gt__(self, other):
-        return self.lower() > other.lower()
-    def __eq__(self, other):
-        return self.lower() == other.lower()
-    def __hash__(self):
-        return hash(self.lower())
-    # cache lower since it's likely to be called frequently.
-    def lower(self):
-        self._lower = super(FoldedCase, self).lower()
-        self.lower = lambda: self._lower
-        return self._lower
-
-    def index(self, sub):
-        return self.lower().index(sub.lower())
-
-    def split(self, splitter=' ', maxsplit=0):
-        pattern = re.compile(re.escape(splitter), re.I)
-        return pattern.split(self, maxsplit)
-
-# from jaraco.util.dictlib
+# based on jaraco.util.dictlib
 class FoldedCaseKeyedDict(dict):
     """A case-insensitive dictionary (keys are compared as insensitive
     if they are strings).
     >>> d
     {'heLlo': 'world'}
     """
+
+    @staticmethod
+    def key_transform(key):
+        if isinstance(key, basestring):
+            key = irclib.FoldedCase(key)
+        return key
+
     def __init__(self, *args, **kargs):
         super(FoldedCaseKeyedDict, self).__init__()
         # build a dictionary using the default constructs
             self.__setitem__(*item)
 
     def __setitem__(self, key, val):
-        if isinstance(key, basestring):
-            key = FoldedCase(key)
+        key = self.key_transform(key)
         super(FoldedCaseKeyedDict, self).__setitem__(key, val)
 
     def __getitem__(self, key):
-        if isinstance(key, basestring):
-            key = FoldedCase(key)
+        key = self.key_transform(key)
         return super(FoldedCaseKeyedDict, self).__getitem__(key)
 
     def __contains__(self, key):
+        key = self.key_transform(key)
+        return super(FoldedCaseKeyedDict, self).__contains__(key)
+
+class IRCDict(FoldedCaseKeyedDict):
+    """
+    Like FoldedCaseKeyedDict except uses IRCFoldedCase for the keys.
+
+    >>> d = IRCDict({'[This]': 'that'}, A='foo')
+    >>> d['a']
+    'foo'
+    >>> d['{this}']
+    'that'
+    >>> d['{THIS}']
+    'that'
+    """
+    @staticmethod
+    def key_transform(key):
         if isinstance(key, basestring):
-            key = FoldedCase(key)
-        return super(FoldedCaseKeyedDict, self).__contains__(key)
+            key = irclib.IRCFoldedCase(key)
+        return key
 
 _special = "-[]\\`^{}"
 nick_characters = string.ascii_letters + string.digits + _special
-_ircstring_translation = string.maketrans(string.ascii_uppercase + "[]\\^",
-                                          string.ascii_lowercase + "{}|~")
-
-def irc_lower(s):
-    """Returns a lowercased string.
-
-    The definition of lowercased comes from the IRC specification (RFC
-    1459).
-    """
-    return s.translate(_ircstring_translation)
 
 def _ctcp_dequote(message):
     """[Internal] Dequote a message according to CTCP specifications.
     if isinstance(item, basestring) or not hasattr(item, '__iter__'):
         item = item,
     return item
+
+# from jaraco.util.string
+class FoldedCase(str):
+    """
+    A case insensitive string class; behaves just like str
+    except compares equal when the only variation is case.
+    >>> s = FoldedCase('hello world')
+
+    >>> s == 'Hello World'
+    True
+
+    >>> 'Hello World' == s
+    True
+
+    >>> s.index('O')
+    4
+
+    >>> s.split('O')
+    ['hell', ' w', 'rld']
+
+    >>> names = map(FoldedCase, ['GAMMA', 'alpha', 'Beta'])
+    >>> names.sort()
+    >>> names
+    ['alpha', 'Beta', 'GAMMA']
+    """
+    def __lt__(self, other):
+        return self.lower() < other.lower()
+    def __gt__(self, other):
+        return self.lower() > other.lower()
+    def __eq__(self, other):
+        return self.lower() == other.lower()
+    def __hash__(self):
+        return hash(self.lower())
+    # cache lower since it's likely to be called frequently.
+    def lower(self):
+        self._lower = super(FoldedCase, self).lower()
+        self.lower = lambda: self._lower
+        return self._lower
+
+    def index(self, sub):
+        return self.lower().index(sub.lower())
+
+    def split(self, splitter=' ', maxsplit=0):
+        pattern = re.compile(re.escape(splitter), re.I)
+        return pattern.split(self, maxsplit)
+
+class IRCFoldedCase(FoldedCase):
+    """
+    A version of FoldedCase that honors the IRC specification for lowercased
+    strings (RFC 1459).
+
+    >>> IRCFoldedCase('Foo^').lower()
+    'foo~'
+    >>> IRCFoldedCase('[this]') == IRCFoldedCase('{THIS}')
+    True
+    """
+    translation = string.maketrans(
+        string.ascii_uppercase + r"[]\^",
+        string.ascii_lowercase + r"{}|~",
+    )
+
+    def lower(self):
+        return self.translate(self.translation)
+
+# for compatibility
+def irc_lower(str):
+    return IRCFoldedCase(str).lower()