Index: django/template/defaultfilters.py
===================================================================
--- django/template/defaultfilters.py	(revision 4985)
+++ django/template/defaultfilters.py	(working copy)
@@ -3,6 +3,7 @@
 from django.template import resolve_variable, Library
 from django.conf import settings
 from django.utils.translation import gettext
+from django.utils.encoding import smart_unicode, smart_str
 import re
 import random as random_module
 
@@ -12,27 +13,15 @@
 # STRING DECORATOR    #
 #######################
 
-def smart_string(obj):
-    # FUTURE: Unicode strings should probably be normalized to a specific
-    # encoding and non-unicode strings should be converted to unicode too.
-#    if isinstance(obj, unicode):
-#        obj = obj.encode(settings.DEFAULT_CHARSET)
-#    else:
-#        obj = unicode(obj, settings.DEFAULT_CHARSET)
-    # FUTURE: Replace dumb string logic below with cool unicode logic above.
-    if not isinstance(obj, basestring):
-        obj = str(obj)
-    return obj
-
 def stringfilter(func):
     """
-    Decorator for filters which should only receive strings. The object passed
-    as the first positional argument will be converted to a string.
+    Decorator for filters which should only receive unicode objects. The object passed
+    as the first positional argument will be converted to a unicode object.
     """
     def _dec(*args, **kwargs):
         if args:
             args = list(args)
-            args[0] = smart_string(args[0])
+            args[0] = smart_unicode(args[0])
         return func(*args, **kwargs)
         
     # Include a reference to the real function (used to check original
@@ -83,27 +72,27 @@
     try:
         f = float(text)
     except ValueError:
-        return ''
+        return u''
     try:
         d = int(arg)
     except ValueError:
-        return smart_string(f)
+        return smart_unicode(f)
     m = f - int(f)
     if not m and d < 0:
-        return '%d' % int(f)
+        return u'%d' % int(f)
     else:
-        formatstr = '%%.%df' % abs(d)
+        formatstr = u'%%.%df' % abs(d)
         return formatstr % f
 
 def linenumbers(value):
     "Displays text with line numbers"
     from django.utils.html import escape
-    lines = value.split('\n')
+    lines = value.split(u'\n')
     # Find the maximum width of the line count, for use with zero padding string format command
-    width = str(len(str(len(lines))))
+    width = unicode(len(unicode(len(lines))))
     for i, line in enumerate(lines):
-        lines[i] = ("%0" + width  + "d. %s") % (i + 1, escape(line))
-    return '\n'.join(lines)
+        lines[i] = (u"%0" + width  + u"d. %s") % (i + 1, escape(line))
+    return u'\n'.join(lines)
 linenumbers = stringfilter(linenumbers)
 
 def lower(value):
@@ -121,6 +110,7 @@
 
 def slugify(value):
     "Converts to lowercase, removes non-alpha chars and converts spaces to hyphens"
+    # Don't compile patterns as unicode because \w then would mean any letter. Slugify is effectively an asciiization.
     value = re.sub('[^\w\s-]', '', value).strip().lower()
     return re.sub('[-\s]+', '-', value)
 slugify = stringfilter(slugify)
@@ -135,9 +125,9 @@
     of Python string formatting
     """
     try:
-        return ("%" + str(arg)) % value
+        return (u"%" + unicode(arg)) % value
     except (ValueError, TypeError):
-        return ""
+        return u""
 
 def title(value):
     "Converts a string into titlecase"
@@ -155,8 +145,6 @@
         length = int(arg)
     except ValueError: # invalid literal for int()
         return value # Fail silently.
-    if not isinstance(value, basestring):
-        value = str(value)
     return truncate_words(value, length)
 truncatewords = stringfilter(truncatewords)
 
@@ -171,9 +159,11 @@
         length = int(arg)
     except ValueError: # invalid literal for int()
         return value # Fail silently.
-    if not isinstance(value, basestring):
-        value = str(value)
-    return truncate_html_words(value, length)
+    result = truncate_html_words(value, length)
+    # isagalaev: Actually the better solution would be converting text utils to output unicode
+    if isinstance(result, str):
+      result = result.decode('utf-8')
+    return result
 truncatewords_html = stringfilter(truncatewords_html)
 
 def upper(value):
@@ -184,9 +174,7 @@
 def urlencode(value):
     "Escapes a value for use in a URL"
     import urllib
-    if not isinstance(value, basestring):
-        value = str(value)
-    return urllib.quote(value)
+    return urllib.quote(value).decode('utf-8')
 urlencode = stringfilter(urlencode)
 
 def urlize(value):
@@ -246,7 +234,7 @@
 
 def cut(value, arg):
     "Removes all values of arg from the given string"
-    return value.replace(arg, '')
+    return value.replace(arg, u'')
 cut = stringfilter(cut)
 
 ###################
@@ -273,11 +261,11 @@
 def removetags(value, tags):
     "Removes a space separated list of [X]HTML tags from the output"
     tags = [re.escape(tag) for tag in tags.split()]
-    tags_re = '(%s)' % '|'.join(tags)
-    starttag_re = re.compile(r'<%s(/?>|(\s+[^>]*>))' % tags_re)
-    endtag_re = re.compile('</%s>' % tags_re)
-    value = starttag_re.sub('', value)
-    value = endtag_re.sub('', value)
+    tags_re = u'(%s)' % u'|'.join(tags)
+    starttag_re = re.compile(ur'<%s(/?>|(\s+[^>]*>))' % tags_re, re.U)
+    endtag_re = re.compile(u'</%s>' % tags_re, re.U)
+    value = starttag_re.sub(u'', value)
+    value = endtag_re.sub(u'', value)
     return value
 removetags = stringfilter(removetags)
 
@@ -296,7 +284,7 @@
     Takes a list of dicts, returns that list sorted by the property given in
     the argument.
     """
-    decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
+    decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value]
     decorated.sort()
     return [item[1] for item in decorated]
 
@@ -305,7 +293,7 @@
     Takes a list of dicts, returns that list sorted in reverse order by the
     property given in the argument.
     """
-    decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
+    decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value]
     decorated.sort()
     decorated.reverse()
     return [item[1] for item in decorated]
@@ -315,12 +303,12 @@
     try:
         return value[0]
     except IndexError:
-        return ''
+        return u''
 
 def join(value, arg):
     "Joins a list with a string, like Python's ``str.join(list)``"
     try:
-        return arg.join(map(smart_string, value))
+        return arg.join(map(smart_unicode, value))
     except AttributeError: # fail silently but nicely
         return value
 
@@ -346,7 +334,7 @@
     """
     try:
         bits = []
-        for x in arg.split(':'):
+        for x in arg.split(u':'):
             if len(x) == 0:
                 bits.append(None)
             else:
@@ -378,12 +366,12 @@
         </li>
     """
     def _helper(value, tabs):
-        indent = '\t' * tabs
+        indent = u'\t' * tabs
         if value[1]:
-            return '%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, value[0], indent,
-                '\n'.join([_helper(v, tabs+1) for v in value[1]]), indent, indent)
+            return u'%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, value[0], indent,
+                u'\n'.join([_helper(v, tabs+1) for v in value[1]]), indent, indent)
         else:
-            return '%s<li>%s</li>' % (indent, value[0])
+            return u'%s<li>%s</li>' % (indent, value[0])
     return _helper(value, 1)
 
 ###################
@@ -409,7 +397,7 @@
     if arg < 1:
         return value
     try:
-        return int(str(value)[-arg])
+        return int(smart_unicode(value)[-arg])
     except IndexError:
         return 0
 
@@ -421,38 +409,45 @@
     "Formats a date according to the given format"
     from django.utils.dateformat import format
     if not value:
-        return ''
+        return u''
     if arg is None:
         arg = settings.DATE_FORMAT
-    return format(value, arg)
+    else:
+        arg = smart_str(arg)
+    # isagalaev: Actually the better solution would be converting dateformat utils to deal with unicode
+    return format(value, arg).decode('utf-8')
 
 def time(value, arg=None):
     "Formats a time according to the given format"
     from django.utils.dateformat import time_format
-    if value in (None, ''):
-        return ''
+    if value in (None, u''):
+        return u''
     if arg is None:
         arg = settings.TIME_FORMAT
-    return time_format(value, arg)
+    else:
+        arg = smart_str(arg)
+    # isagalaev: Actually the better solution would be converting dateformat utils to deal with unicode
+    return time_format(value, arg).decode('utf-8')
 
 def timesince(value, arg=None):
     'Formats a date as the time since that date (i.e. "4 days, 6 hours")'
     from django.utils.timesince import timesince
     if not value:
-        return ''
+        return u''
     if arg:
-        return timesince(arg, value)
-    return timesince(value)
+        return timesince(arg, value).decode('utf-8')
+    return timesince(value).decode('utf-8')
 
 def timeuntil(value, arg=None):
     'Formats a date as the time until that date (i.e. "4 days, 6 hours")'
     from django.utils.timesince import timesince
     from datetime import datetime
     if not value:
-        return ''
+        return u''
+    # isagalaev: Actually the better solution would be converting timesince utils to deal with unicode
     if arg:
-        return timesince(arg, value)
-    return timesince(datetime.now(), value)
+        return timesince(arg, value).decode('utf-8')
+    return timesince(datetime.now(), value).decode('utf-8')
 
 ###################
 # LOGIC           #
@@ -488,8 +483,8 @@
     ==========  ======================  ==================================
     """
     if arg is None:
-        arg = gettext('yes,no,maybe')
-    bits = arg.split(',')
+        arg = gettext('yes,no,maybe').decode('utf-8')
+    bits = arg.split(u',')
     if len(bits) < 2:
         return value # Invalid arg.
     try:
@@ -514,28 +509,28 @@
     try:
         bytes = float(bytes)
     except TypeError:
-        return "0 bytes"
+        return u"0 bytes"
         
     if bytes < 1024:
-        return "%d byte%s" % (bytes, bytes != 1 and 's' or '')
+        return u"%d byte%s" % (bytes, bytes != 1 and u's' or u'')
     if bytes < 1024 * 1024:
-        return "%.1f KB" % (bytes / 1024)
+        return u"%.1f KB" % (bytes / 1024)
     if bytes < 1024 * 1024 * 1024:
-        return "%.1f MB" % (bytes / (1024 * 1024))
-    return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
+        return u"%.1f MB" % (bytes / (1024 * 1024))
+    return u"%.1f GB" % (bytes / (1024 * 1024 * 1024))
 
-def pluralize(value, arg='s'):
+def pluralize(value, arg=u's'):
     """
     Returns a plural suffix if the value is not 1, for '1 vote' vs. '2 votes'
     By default, 's' is used as a suffix; if an argument is provided, that string
     is used instead. If the provided argument contains a comma, the text before
     the comma is used for the singular case.
     """
-    if not ',' in arg:
-        arg = ',' + arg
-    bits = arg.split(',')
+    if not u',' in arg:
+        arg = u',' + arg
+    bits = arg.split(u',')
     if len(bits) > 2:
-        return ''
+        return u''
     singular_suffix, plural_suffix = bits[:2]
 
     try:
@@ -554,7 +549,8 @@
 def phone2numeric(value):
     "Takes a phone number and converts it in to its numerical equivalent"
     from django.utils.text import phone2numeric
-    return phone2numeric(value)
+    # isagalaev: Actually the better solution would be converting text utils to return unicode
+    return phone2numeric(value).decode('utf-8')
 
 def pprint(value):
     "A wrapper around pprint.pprint -- for debugging, really"
@@ -562,7 +558,7 @@
     try:
         return pformat(value)
     except Exception, e:
-        return "Error in formatting:%s" % e
+        return u"Error in formatting:%s" % e
 
 # Syntax: register.filter(name of filter, callback)
 register.filter(add)
Index: tests/regressiontests/defaultfilters/tests.py
===================================================================
--- tests/regressiontests/defaultfilters/tests.py	(revision 4985)
+++ tests/regressiontests/defaultfilters/tests.py	(working copy)
@@ -2,186 +2,186 @@
 
 r"""
 >>> floatformat(7.7)
-'7.7'
+u'7.7'
 >>> floatformat(7.0)
-'7'
+u'7'
 >>> floatformat(0.7)
-'0.7'
+u'0.7'
 >>> floatformat(0.07)
-'0.1'
+u'0.1'
 >>> floatformat(0.007)
-'0.0'
+u'0.0'
 >>> floatformat(0.0)
-'0'
+u'0'
 >>> floatformat(7.7,3)
-'7.700'
+u'7.700'
 >>> floatformat(6.000000,3)
-'6.000'
+u'6.000'
 >>> floatformat(13.1031,-3)
-'13.103'
+u'13.103'
 >>> floatformat(11.1197, -2)
-'11.12'
+u'11.12'
 >>> floatformat(11.0000, -2)
-'11'
+u'11'
 >>> floatformat(11.000001, -2)
-'11.00'
+u'11.00'
 >>> floatformat(8.2798, 3)
-'8.280'
->>> floatformat('foo')
-''
->>> floatformat(13.1031, 'bar')
-'13.1031'
->>> floatformat('foo', 'bar')
-''
+u'8.280'
+>>> floatformat(u'foo')
+u''
+>>> floatformat(13.1031, u'bar')
+u'13.1031'
+>>> floatformat(u'foo', u'bar')
+u''
 
->>> addslashes('"double quotes" and \'single quotes\'')
-'\\"double quotes\\" and \\\'single quotes\\\''
+>>> addslashes(u'"double quotes" and \'single quotes\'')
+u'\\"double quotes\\" and \\\'single quotes\\\''
 
->>> addslashes(r'\ : backslashes, too')
-'\\\\ : backslashes, too'
+>>> addslashes(ur'\ : backslashes, too')
+u'\\\\ : backslashes, too'
 
->>> capfirst('hello world')
-'Hello world'
+>>> capfirst(u'hello world')
+u'Hello world'
 
->>> fix_ampersands('Jack & Jill & Jeroboam')
-'Jack &amp; Jill &amp; Jeroboam'
+>>> fix_ampersands(u'Jack & Jill & Jeroboam')
+u'Jack &amp; Jill &amp; Jeroboam'
 
->>> linenumbers('line 1\nline 2')
-'1. line 1\n2. line 2'
+>>> linenumbers(u'line 1\nline 2')
+u'1. line 1\n2. line 2'
 
->>> linenumbers('\n'.join(['x'] * 10))
-'01. x\n02. x\n03. x\n04. x\n05. x\n06. x\n07. x\n08. x\n09. x\n10. x'
+>>> linenumbers(u'\n'.join([u'x'] * 10))
+u'01. x\n02. x\n03. x\n04. x\n05. x\n06. x\n07. x\n08. x\n09. x\n10. x'
 
 >>> lower('TEST')
-'test'
+u'test'
 
 >>> lower(u'\xcb') # uppercase E umlaut
 u'\xeb'
 
 >>> make_list('abc')
-['a', 'b', 'c']
+[u'a', u'b', u'c']
 
 >>> make_list(1234)
-['1', '2', '3', '4']
+[u'1', u'2', u'3', u'4']
 
 >>> slugify(' Jack & Jill like numbers 1,2,3 and 4 and silly characters ?%.$!/')
-'jack-jill-like-numbers-123-and-4-and-silly-characters'
+u'jack-jill-like-numbers-123-and-4-and-silly-characters'
 
->>> stringformat(1, '03d')
-'001'
+>>> stringformat(1, u'03d')
+u'001'
 
->>> stringformat(1, 'z')
-''
+>>> stringformat(1, u'z')
+u''
 
 >>> title('a nice title, isn\'t it?')
-"A Nice Title, Isn't It?"
+u"A Nice Title, Isn't It?"
 
 
->>> truncatewords('A sentence with a few words in it', 1)
-'A ...'
+>>> truncatewords(u'A sentence with a few words in it', 1)
+u'A ...'
 
->>> truncatewords('A sentence with a few words in it', 5)
-'A sentence with a few ...'
+>>> truncatewords(u'A sentence with a few words in it', 5)
+u'A sentence with a few ...'
 
->>> truncatewords('A sentence with a few words in it', 100)
-'A sentence with a few words in it'
+>>> truncatewords(u'A sentence with a few words in it', 100)
+u'A sentence with a few words in it'
 
->>> truncatewords('A sentence with a few words in it', 'not a number')
-'A sentence with a few words in it'
+>>> truncatewords(u'A sentence with a few words in it', 'not a number')
+u'A sentence with a few words in it'
 
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 0)
-''
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 0)
+u''
 
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 2)
-'<p>one <a href="#">two ...</a></p>'
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 2)
+u'<p>one <a href="#">two ...</a></p>'
 
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 4)
-'<p>one <a href="#">two - three <br>four ...</a></p>'
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 4)
+u'<p>one <a href="#">two - three <br>four ...</a></p>'
 
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 5)
-'<p>one <a href="#">two - three <br>four</a> five</p>'
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 5)
+u'<p>one <a href="#">two - three <br>four</a> five</p>'
 
->>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 100)
-'<p>one <a href="#">two - three <br>four</a> five</p>'
+>>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 100)
+u'<p>one <a href="#">two - three <br>four</a> five</p>'
 
->>> upper('Mixed case input')
-'MIXED CASE INPUT'
+>>> upper(u'Mixed case input')
+u'MIXED CASE INPUT'
 
 >>> upper(u'\xeb') # lowercase e umlaut
 u'\xcb'
 
 
->>> urlencode('jack & jill')
-'jack%20%26%20jill'
+>>> urlencode(u'jack & jill')
+u'jack%20%26%20jill'
 >>> urlencode(1)
-'1'
+u'1'
 
 
->>> urlizetrunc('http://short.com/', 20)
-'<a href="http://short.com/" rel="nofollow">http://short.com/</a>'
+>>> urlizetrunc(u'http://short.com/', 20)
+u'<a href="http://short.com/" rel="nofollow">http://short.com/</a>'
 
->>> urlizetrunc('http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=', 20)
-'<a href="http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=" rel="nofollow">http://www.google.co...</a>'
+>>> urlizetrunc(u'http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=', 20)
+u'<a href="http://www.google.co.uk/search?hl=en&q=some+long+url&btnG=Search&meta=" rel="nofollow">http://www.google.co...</a>'
 
->>> wordcount('')
+>>> wordcount(u'')
 0
 
->>> wordcount('oneword')
+>>> wordcount(u'oneword')
 1
 
->>> wordcount('lots of words')
+>>> wordcount(u'lots of words')
 3
 
->>> wordwrap('this is a long paragraph of text that really needs to be wrapped I\'m afraid', 14)
-"this is a long\nparagraph of\ntext that\nreally needs\nto be wrapped\nI'm afraid"
+>>> wordwrap(u'this is a long paragraph of text that really needs to be wrapped I\'m afraid', 14)
+u"this is a long\nparagraph of\ntext that\nreally needs\nto be wrapped\nI'm afraid"
 
->>> wordwrap('this is a short paragraph of text.\n  But this line should be indented',14)
-'this is a\nshort\nparagraph of\ntext.\n  But this\nline should be\nindented'
+>>> wordwrap(u'this is a short paragraph of text.\n  But this line should be indented',14)
+u'this is a\nshort\nparagraph of\ntext.\n  But this\nline should be\nindented'
 
->>> wordwrap('this is a short paragraph of text.\n  But this line should be indented',15)
-'this is a short\nparagraph of\ntext.\n  But this line\nshould be\nindented'
+>>> wordwrap(u'this is a short paragraph of text.\n  But this line should be indented',15)
+u'this is a short\nparagraph of\ntext.\n  But this line\nshould be\nindented'
 
->>> ljust('test', 10)
-'test      '
+>>> ljust(u'test', 10)
+u'test      '
 
->>> ljust('test', 3)
-'test'
+>>> ljust(u'test', 3)
+u'test'
 
->>> rjust('test', 10)
-'      test'
+>>> rjust(u'test', 10)
+u'      test'
 
->>> rjust('test', 3)
-'test'
+>>> rjust(u'test', 3)
+u'test'
 
->>> center('test', 6)
-' test '
+>>> center(u'test', 6)
+u' test '
 
->>> cut('a string to be mangled', 'a')
-' string to be mngled'
+>>> cut(u'a string to be mangled', 'a')
+u' string to be mngled'
 
->>> cut('a string to be mangled', 'ng')
-'a stri to be maled'
+>>> cut(u'a string to be mangled', 'ng')
+u'a stri to be maled'
 
->>> cut('a string to be mangled', 'strings')
-'a string to be mangled'
+>>> cut(u'a string to be mangled', 'strings')
+u'a string to be mangled'
 
->>> escape('<some html & special characters > here')
-'&lt;some html &amp; special characters &gt; here'
+>>> escape(u'<some html & special characters > here')
+u'&lt;some html &amp; special characters &gt; here'
 
 >>> escape(u'<some html & special characters > here ĐÅ€£')
 u'&lt;some html &amp; special characters &gt; here \xc4\x90\xc3\x85\xe2\x82\xac\xc2\xa3'
 
->>> linebreaks('line 1')
-'<p>line 1</p>'
+>>> linebreaks(u'line 1')
+u'<p>line 1</p>'
 
->>> linebreaks('line 1\nline 2')
-'<p>line 1<br />line 2</p>'
+>>> linebreaks(u'line 1\nline 2')
+u'<p>line 1<br />line 2</p>'
 
->>> removetags('some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags', 'script img')
-'some <b>html</b> with alert("You smell") disallowed  tags'
+>>> removetags(u'some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags', 'script img')
+u'some <b>html</b> with alert("You smell") disallowed  tags'
 
->>> striptags('some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags')
-'some html with alert("You smell") disallowed  tags'
+>>> striptags(u'some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags')
+u'some html with alert("You smell") disallowed  tags'
 
 >>> dictsort([{'age': 23, 'name': 'Barbara-Ann'},
 ...           {'age': 63, 'name': 'Ra Ra Rasputin'},
@@ -196,16 +196,16 @@
 >>> first([0,1,2])
 0
 
->>> first('')
-''
+>>> first(u'')
+u''
 
->>> first('test')
-'t'
+>>> first(u'test')
+u't'
 
->>> join([0,1,2], 'glue')
-'0glue1glue2'
+>>> join([0,1,2], u'glue')
+u'0glue1glue2'
 
->>> length('1234')
+>>> length(u'1234')
 4
 
 >>> length([1,2,3,4])
@@ -220,37 +220,37 @@
 >>> length_is('a', 1)
 True
 
->>> length_is('a', 10)
+>>> length_is(u'a', 10)
 False
 
->>> slice_('abcdefg', '0')
-''
+>>> slice_(u'abcdefg', u'0')
+u''
 
->>> slice_('abcdefg', '1')
-'a'
+>>> slice_(u'abcdefg', u'1')
+u'a'
 
->>> slice_('abcdefg', '-1')
-'abcdef'
+>>> slice_(u'abcdefg', u'-1')
+u'abcdef'
 
->>> slice_('abcdefg', '1:2')
-'b'
+>>> slice_(u'abcdefg', u'1:2')
+u'b'
 
->>> slice_('abcdefg', '1:3')
-'bc'
+>>> slice_(u'abcdefg', u'1:3')
+u'bc'
 
->>> slice_('abcdefg', '0::2')
-'aceg'
+>>> slice_(u'abcdefg', u'0::2')
+u'aceg'
 
->>> unordered_list(['item 1', []])
-'\t<li>item 1</li>'
+>>> unordered_list([u'item 1', []])
+u'\t<li>item 1</li>'
 
->>> unordered_list(['item 1', [['item 1.1', []]]])
-'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t</ul>\n\t</li>'
+>>> unordered_list([u'item 1', [[u'item 1.1', []]]])
+u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t</ul>\n\t</li>'
 
->>> unordered_list(['item 1', [['item 1.1', []], ['item 1.2', []]]])
-'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t\t<li>item 1.2</li>\n\t</ul>\n\t</li>'
+>>> unordered_list([u'item 1', [[u'item 1.1', []], [u'item 1.2', []]]])
+u'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t\t<li>item 1.2</li>\n\t</ul>\n\t</li>'
 
->>> add('1', '2')
+>>> add(u'1', u'2')
 3
 
 >>> get_digit(123, 1)
@@ -268,43 +268,43 @@
 >>> get_digit(123, 0)
 123
 
->>> get_digit('xyz', 0)
-'xyz'
+>>> get_digit(u'xyz', 0)
+u'xyz'
 
 # real testing of date() is in dateformat.py
->>> date(datetime.datetime(2005, 12, 29), "d F Y")
-'29 December 2005'
->>> date(datetime.datetime(2005, 12, 29), r'jS o\f F')
-'29th of December'
+>>> date(datetime.datetime(2005, 12, 29), u"d F Y")
+u'29 December 2005'
+>>> date(datetime.datetime(2005, 12, 29), ur'jS o\f F')
+u'29th of December'
 
 # real testing of time() is done in dateformat.py
->>> time(datetime.time(13), "h")
-'01'
+>>> time(datetime.time(13), u"h")
+u'01'
 
->>> time(datetime.time(0), "h")
-'12'
+>>> time(datetime.time(0), u"h")
+u'12'
 
 # real testing is done in timesince.py, where we can provide our own 'now'
 >>> timesince(datetime.datetime.now() - datetime.timedelta(1))
-'1 day'
+u'1 day'
 
->>> default("val", "default")
-'val'
+>>> default(u"val", u"default")
+u'val'
 
->>> default(None, "default")
-'default'
+>>> default(None, u"default")
+u'default'
 
->>> default('', "default")
-'default'
+>>> default(u'', u"default")
+u'default'
 
->>> default_if_none("val", "default")
-'val'
+>>> default_if_none(u"val", u"default")
+u'val'
 
->>> default_if_none(None, "default")
-'default'
+>>> default_if_none(None, u"default")
+u'default'
 
->>> default_if_none('', "default")
-''
+>>> default_if_none(u'', u"default")
+u''
 
 >>> divisibleby(4, 2)
 True
@@ -313,139 +313,139 @@
 False
 
 >>> yesno(True)
-'yes'
+u'yes'
 
 >>> yesno(False)
-'no'
+u'no'
 
 >>> yesno(None)
-'maybe'
+u'maybe'
 
->>> yesno(True, 'certainly,get out of town,perhaps')
-'certainly'
+>>> yesno(True, u'certainly,get out of town,perhaps')
+u'certainly'
 
->>> yesno(False, 'certainly,get out of town,perhaps')
-'get out of town'
+>>> yesno(False, u'certainly,get out of town,perhaps')
+u'get out of town'
 
->>> yesno(None, 'certainly,get out of town,perhaps')
-'perhaps'
+>>> yesno(None, u'certainly,get out of town,perhaps')
+u'perhaps'
 
->>> yesno(None, 'certainly,get out of town')
-'get out of town'
+>>> yesno(None, u'certainly,get out of town')
+u'get out of town'
 
 >>> filesizeformat(1023)
-'1023 bytes'
+u'1023 bytes'
 
 >>> filesizeformat(1024)
-'1.0 KB'
+u'1.0 KB'
 
 >>> filesizeformat(10*1024)
-'10.0 KB'
+u'10.0 KB'
 
 >>> filesizeformat(1024*1024-1)
-'1024.0 KB'
+u'1024.0 KB'
 
 >>> filesizeformat(1024*1024)
-'1.0 MB'
+u'1.0 MB'
 
 >>> filesizeformat(1024*1024*50)
-'50.0 MB'
+u'50.0 MB'
 
 >>> filesizeformat(1024*1024*1024-1)
-'1024.0 MB'
+u'1024.0 MB'
 
 >>> filesizeformat(1024*1024*1024)
-'1.0 GB'
+u'1.0 GB'
 
 >>> pluralize(1)
-''
+u''
 
 >>> pluralize(0)
-'s'
+u's'
 
 >>> pluralize(2)
-'s'
+u's'
 
 >>> pluralize([1])
-''
+u''
 
 >>> pluralize([])
-'s'
+u's'
 
 >>> pluralize([1,2,3])
-'s'
+u's'
 
->>> pluralize(1,'es')
-''
+>>> pluralize(1,u'es')
+u''
 
->>> pluralize(0,'es')
-'es'
+>>> pluralize(0,u'es')
+u'es'
 
->>> pluralize(2,'es')
-'es'
+>>> pluralize(2,u'es')
+u'es'
 
->>> pluralize(1,'y,ies')
-'y'
+>>> pluralize(1,u'y,ies')
+u'y'
 
->>> pluralize(0,'y,ies')
-'ies'
+>>> pluralize(0,u'y,ies')
+u'ies'
 
->>> pluralize(2,'y,ies')
-'ies'
+>>> pluralize(2,u'y,ies')
+u'ies'
 
->>> pluralize(0,'y,ies,error')
-''
+>>> pluralize(0,u'y,ies,error')
+u''
 
->>> phone2numeric('0800 flowers')
-'0800 3569377'
+>>> phone2numeric(u'0800 flowers')
+u'0800 3569377'
 
 # Filters shouldn't break if passed non-strings
 >>> addslashes(123)
-'123'
+u'123'
 >>> linenumbers(123)
-'1. 123'
+u'1. 123'
 >>> lower(123)
-'123'
+u'123'
 >>> make_list(123)
-['1', '2', '3']
+[u'1', u'2', u'3']
 >>> slugify(123)
-'123'
+u'123'
 >>> title(123)
-'123'
+u'123'
 >>> truncatewords(123, 2)
-'123'
+u'123'
 >>> upper(123)
-'123'
+u'123'
 >>> urlencode(123)
-'123'
+u'123'
 >>> urlize(123)
-'123'
+u'123'
 >>> urlizetrunc(123, 1)
-'123'
+u'123'
 >>> wordcount(123)
 1
 >>> wordwrap(123, 2)
-'123'
+u'123'
 >>> ljust('123', 4)
-'123 '
+u'123 '
 >>> rjust('123', 4)
-' 123'
+u' 123'
 >>> center('123', 5)
-' 123 '
+u' 123 '
 >>> center('123', 6)
-' 123  '
+u' 123  '
 >>> cut(123, '2')
-'13'
+u'13'
 >>> escape(123)
-'123'
+u'123'
 >>> linebreaks(123)
-'<p>123</p>'
+u'<p>123</p>'
 >>> linebreaksbr(123)
-'123'
+u'123'
 >>> removetags(123, 'a')
-'123'
+u'123'
 >>> striptags(123)
-'123'
+u'123'
 
 """
 
