Commits

Jason R. Coombs committed 911941b

Fix broken LineBuffer implementation

Comments (0)

Files changed (2)

+3.4.1
+=====
+
+3.4 never worked - the decoding customization feature was improperly
+implemented and never tested.
+
+* The ServerConnection now allows custom classes to be supplied to customize
+  the decoding of incoming lines. For example, to disable the decoding of incoming lines,
+  replace the `buffer_class` on the ServerConnection with a version that
+  passes through the lines directly::
+
+    irc.client.ServerConnection.buffer_class = irc.client.LineBuffer
+
+  This fixes #5.
+
 3.4
 ===
 
-* LineBuffer now allows customization of the decoding (including disabling
-  decoding altogether). To disable decoding of incoming lines, invoke the
-  following at some point before the connection is established::
-
-    irc.client.LineBuffer.decoder = lambda line: line
-
-  This fixes #5.
+*Broken Release*
 
 3.3
 ===
     >>> len(b)
     7
     >>> list(b.lines())
-    [u'foo']
+    ['foo']
     >>> len(b)
     3
 
     >>> b.feed(b'bar\r\nbaz\n')
     >>> list(b.lines())
-    [u'barbar', u'baz']
+    ['barbar', 'baz']
     >>> len(b)
     0
 
-    Some clients will feed latin-1 or other encodings. This client assumes
-    UTF-8 and any other encodings will produce the "replacement character",
-    �.
+    The buffer will not perform any decoding.
     >>> b.feed(b'Ol\xe9\n')
     >>> list(b.lines())
-    [u'Ol\ufffd']
+    ['Ol\xe9']
     """
     line_sep_exp = re.compile(b'\r?\n')
-    decoder = lambda line: line.decode('utf-8', 'replace')
 
     def __init__(self):
         self.buffer = b''
         lines = self.line_sep_exp.split(self.buffer)
         # save the last, unfinished, possibly empty line
         self.buffer = lines.pop()
-        return (self.decoder(line) for line in lines)
+        return lines
 
     def __iter__(self):
         return self.lines()
     def __len__(self):
         return len(self.buffer)
 
+class DecodingLineBuffer(LineBuffer):
+    r"""
+    Like LineBuffer, but decode the output (default assumes UTF-8).
+
+    >>> b = DecodingLineBuffer()
+    >>> b.feed(b'bar\r\nbaz\nOl\xc3\xa9\n')
+    >>> list(b.lines())
+    [u'bar', u'baz', u'Ol\xe9']
+    >>> len(b)
+    0
+
+    Some clients will feed latin-1 or other encodings. If your client should
+    support docoding from these clients (and not raise a UnicodeDecodeError),
+    set errors='replace':
+
+    >>> rb = DecodingLineBuffer()
+    >>> b.errors = 'replace'
+    >>> b.feed(b'Ol\xe9\n')
+    >>> list(b.lines())
+    [u'Ol\ufffd']
+    """
+    encoding = 'utf-8'
+    errors = 'strict'
+
+    def lines(self):
+        return (line.decode(self.encoding, self.errors)
+            for line in super(DecodingLineBuffer, self).lines())
+
 
 class ServerConnection(Connection):
-    """This class represents an IRC server connection.
+    """
+    An IRC server connection.
 
     ServerConnection objects are instantiated by calling the server
     method on an IRC object.
     """
 
+    buffer_class = DecodingLineBuffer
+
     def __init__(self, irclibobj):
         super(ServerConnection, self).__init__(irclibobj)
         self.connected = False
         if self.connected:
             self.disconnect("Changing servers")
 
-        self.buffer = LineBuffer()
+        self.buffer = self.buffer_class()
         self.handlers = {}
         self.real_server_name = ""
         self.real_nickname = nickname