Commits

Matthew Frazier committed fa4356a

refactored UTF8 and UTF16 into a single TextConverter class

Comments (0)

Files changed (4)

docs/converters.rst

 
 Builtin Converters
 ==================
-.. autoclass:: UTF8
+.. autodata:: UTF8
 
-.. autoclass:: UTF16
+.. autodata:: UTF16
 
 .. autoclass:: Bytes
 
 .. autoclass:: Timestamp
 
 .. autoclass:: Date
+
+
+Converter Types
+===============
+These are classes that, rather than being converters themselves, are used to
+build converters.
+
+.. autoclass:: TextConverter

redismap/__init__.py

 """
 from .key import Key, to_key
 from .converters import (UTF8, UTF16, Bytes, Integer, Decimal, Float, Boolean,
-                         DateTime, Timestamp, Date)
+                         DateTime, Timestamp, Date, TextConverter)
 from .collections import (Set, SetView, List, ListView, SortedSet,
                           SortedSetView, Hash, HashView, Queue, Stack)
 from .exceptions import RedismapError, ValidationError

redismap/converters.py

         return True
 
 
-class UTF8(object):
+class TextConverter(object):
     """
-    This stores `unicode` by encoding it as UTF-8.
+    Instances of `TextConverter` can be used to store `unicode` text in an
+    encoding of your choice. (Though `UTF8` and `UTF16` will suffice for most
+    purposes.)
+    
+    :param encoding: The encoding to store the text in. This should be a valid
+                     Python encoding.
     """
-    @staticmethod
-    def to_redis(value):
+    def __init__(self, encoding):
+        self.encoding = encoding
+    
+    def __repr__(self):
+        return "TextConverter(%r)" % self.encoding
+    
+    def to_redis(self, value):
+        encoding = self.encoding
         if isinstance(value, unicode):
-            return value.encode('utf-8')
-        elif isinstance(value, str) and is_encoded(value, 'utf-8'):
+            return value.encode(encoding)
+        elif isinstance(value, str) and is_encoded(value, encoding):
             return value
-        raise TypeError("can only convert unicode (and UTF-8 str) instances")
+        raise TypeError("can only convert unicode (and %s str) instances" %
+                        encoding)
     
-    @staticmethod
-    def from_redis(value):
-        return value.decode('utf-8', 'replace')
+    def from_redis(self, value):
+        return value.decode(self.encoding, 'replace')
 
 
-class UTF16(object):
-    """
-    This stores `unicode` by encoding it as UTF-16, with a byte order mark.
-    Redis includes native support for UTF-8, so you should use `UTF8` instead
-    of this unless you have special requirements (i.e. your application
-    stores large amounts of CJK data).
-    """
-    @staticmethod
-    def to_redis(value):
-        if isinstance(value, unicode):
-            return value.encode('utf-16')
-        elif isinstance(value, str) and is_encoded(value, 'utf-16'):
-            return value
-        raise TypeError("can only convert unicode (and UTF-16 str) instances")
-    
-    @staticmethod
-    def from_redis(value):
-        return value.decode('utf-16', 'replace')
+#: This stores `unicode` by encoding it as UTF-8.
+UTF8 = TextConverter('utf-8')
+
+#: This stores `unicode` by encoding it as UTF-16, with a byte order mark.
+#: Redis includes native support for UTF-8, so you should use `UTF8` instead
+#: of this unless you have special requirements (i.e. your application
+#: stores large amounts of CJK data).
+UTF16 = TextConverter('utf-16')
 
 
 class Bytes(object):

tests/converters.py

 from datetime import datetime, date
 from decimal import Decimal as decimal
 from redismap import (UTF8, Bytes, Integer, Boolean, DateTime, Float, Decimal,
-                      Timestamp, Date, UTF16)
+                      Timestamp, Date, UTF16, TextConverter)
 
 convertertests = Tests()
 
 
 
 @convertertests.test
+def test_textconverter():
+    Latin1 = TextConverter("latin1")
+    como = u"¿Cómo estás?"
+    como_encoded = "\xbfC\xf3mo est\xe1s?"
+    neko = u"ねこ"
+    # encoding
+    assert Latin1.to_redis(u"Hello") == "Hello"
+    assert Latin1.to_redis(como) == como_encoded
+    assert Latin1.to_redis(como_encoded) == como_encoded
+    with raises(UnicodeEncodeError):
+        Latin1.to_redis(neko)
+    # decoding
+    assert Latin1.from_redis(como_encoded) == como
+    assert isinstance(Latin1.from_redis(como_encoded), unicode)
+    assert Latin1.from_redis(como_encoded) == como
+
+
+@convertertests.test
 def test_bytes():
     # encoding
     assert Bytes.to_redis("Hello") == "Hello"