1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

Changed default template filters to always return unicode (and to handle unicode input better). Also changed all django.utils.* functions that are used (or likely to be used) by filters to return unicode strings.

Most of the filter porting was done by Ivan Sagalaev. Fixed #3977.


git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@5056 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-04-21 14:34:43 +00:00
parent dadbe3c737
commit b30e5b5434
11 changed files with 356 additions and 370 deletions

View File

@ -2,7 +2,8 @@
from django.template import resolve_variable, Library from django.template import resolve_variable, Library
from django.conf import settings from django.conf import settings
from django.utils.translation import gettext from django.utils.translation import ugettext
from django.utils.encoding import smart_unicode, smart_str
import re import re
import random as random_module import random as random_module
@ -12,27 +13,15 @@ register = Library()
# STRING DECORATOR # # 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): def stringfilter(func):
""" """
Decorator for filters which should only receive strings. The object passed Decorator for filters which should only receive unicode objects. The object passed
as the first positional argument will be converted to a string. as the first positional argument will be converted to a unicode object.
""" """
def _dec(*args, **kwargs): def _dec(*args, **kwargs):
if args: if args:
args = list(args) args = list(args)
args[0] = smart_string(args[0]) args[0] = smart_unicode(args[0])
return func(*args, **kwargs) return func(*args, **kwargs)
# Include a reference to the real function (used to check original # Include a reference to the real function (used to check original
@ -83,27 +72,27 @@ def floatformat(text, arg=-1):
try: try:
f = float(text) f = float(text)
except ValueError: except ValueError:
return '' return u''
try: try:
d = int(arg) d = int(arg)
except ValueError: except ValueError:
return smart_string(f) return smart_unicode(f)
m = f - int(f) m = f - int(f)
if not m and d < 0: if not m and d < 0:
return '%d' % int(f) return u'%d' % int(f)
else: else:
formatstr = '%%.%df' % abs(d) formatstr = u'%%.%df' % abs(d)
return formatstr % f return formatstr % f
def linenumbers(value): def linenumbers(value):
"Displays text with line numbers" "Displays text with line numbers"
from django.utils.html import escape 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 # 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): for i, line in enumerate(lines):
lines[i] = ("%0" + width + "d. %s") % (i + 1, escape(line)) lines[i] = (u"%0" + width + u"d. %s") % (i + 1, escape(line))
return '\n'.join(lines) return u'\n'.join(lines)
linenumbers = stringfilter(linenumbers) linenumbers = stringfilter(linenumbers)
def lower(value): def lower(value):
@ -121,6 +110,7 @@ make_list = stringfilter(make_list)
def slugify(value): def slugify(value):
"Converts to lowercase, removes non-alpha chars and converts spaces to hyphens" "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() value = re.sub('[^\w\s-]', '', value).strip().lower()
return re.sub('[-\s]+', '-', value) return re.sub('[-\s]+', '-', value)
slugify = stringfilter(slugify) slugify = stringfilter(slugify)
@ -135,9 +125,9 @@ def stringformat(value, arg):
of Python string formatting of Python string formatting
""" """
try: try:
return ("%" + str(arg)) % value return (u"%" + unicode(arg)) % value
except (ValueError, TypeError): except (ValueError, TypeError):
return "" return u""
def title(value): def title(value):
"Converts a string into titlecase" "Converts a string into titlecase"
@ -155,8 +145,6 @@ def truncatewords(value, arg):
length = int(arg) length = int(arg)
except ValueError: # invalid literal for int() except ValueError: # invalid literal for int()
return value # Fail silently. return value # Fail silently.
if not isinstance(value, basestring):
value = str(value)
return truncate_words(value, length) return truncate_words(value, length)
truncatewords = stringfilter(truncatewords) truncatewords = stringfilter(truncatewords)
@ -171,8 +159,6 @@ def truncatewords_html(value, arg):
length = int(arg) length = int(arg)
except ValueError: # invalid literal for int() except ValueError: # invalid literal for int()
return value # Fail silently. return value # Fail silently.
if not isinstance(value, basestring):
value = str(value)
return truncate_html_words(value, length) return truncate_html_words(value, length)
truncatewords_html = stringfilter(truncatewords_html) truncatewords_html = stringfilter(truncatewords_html)
@ -184,9 +170,7 @@ upper = stringfilter(upper)
def urlencode(value): def urlencode(value):
"Escapes a value for use in a URL" "Escapes a value for use in a URL"
import urllib import urllib
if not isinstance(value, basestring): return urllib.quote(value).decode('utf-8')
value = str(value)
return urllib.quote(value)
urlencode = stringfilter(urlencode) urlencode = stringfilter(urlencode)
def urlize(value): def urlize(value):
@ -246,7 +230,7 @@ center = stringfilter(center)
def cut(value, arg): def cut(value, arg):
"Removes all values of arg from the given string" "Removes all values of arg from the given string"
return value.replace(arg, '') return value.replace(arg, u'')
cut = stringfilter(cut) cut = stringfilter(cut)
################### ###################
@ -273,11 +257,11 @@ linebreaksbr = stringfilter(linebreaksbr)
def removetags(value, tags): def removetags(value, tags):
"Removes a space separated list of [X]HTML tags from the output" "Removes a space separated list of [X]HTML tags from the output"
tags = [re.escape(tag) for tag in tags.split()] tags = [re.escape(tag) for tag in tags.split()]
tags_re = '(%s)' % '|'.join(tags) tags_re = u'(%s)' % u'|'.join(tags)
starttag_re = re.compile(r'<%s(/?>|(\s+[^>]*>))' % tags_re) starttag_re = re.compile(ur'<%s(/?>|(\s+[^>]*>))' % tags_re, re.U)
endtag_re = re.compile('</%s>' % tags_re) endtag_re = re.compile(u'</%s>' % tags_re)
value = starttag_re.sub('', value) value = starttag_re.sub(u'', value)
value = endtag_re.sub('', value) value = endtag_re.sub(u'', value)
return value return value
removetags = stringfilter(removetags) removetags = stringfilter(removetags)
@ -296,7 +280,7 @@ def dictsort(value, arg):
Takes a list of dicts, returns that list sorted by the property given in Takes a list of dicts, returns that list sorted by the property given in
the argument. 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.sort()
return [item[1] for item in decorated] return [item[1] for item in decorated]
@ -305,7 +289,7 @@ def dictsortreversed(value, arg):
Takes a list of dicts, returns that list sorted in reverse order by the Takes a list of dicts, returns that list sorted in reverse order by the
property given in the argument. 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.sort()
decorated.reverse() decorated.reverse()
return [item[1] for item in decorated] return [item[1] for item in decorated]
@ -315,12 +299,12 @@ def first(value):
try: try:
return value[0] return value[0]
except IndexError: except IndexError:
return '' return u''
def join(value, arg): def join(value, arg):
"Joins a list with a string, like Python's ``str.join(list)``" "Joins a list with a string, like Python's ``str.join(list)``"
try: try:
return arg.join(map(smart_string, value)) return arg.join(map(smart_unicode, value))
except AttributeError: # fail silently but nicely except AttributeError: # fail silently but nicely
return value return value
@ -346,7 +330,7 @@ def slice_(value, arg):
""" """
try: try:
bits = [] bits = []
for x in arg.split(':'): for x in arg.split(u':'):
if len(x) == 0: if len(x) == 0:
bits.append(None) bits.append(None)
else: else:
@ -378,12 +362,12 @@ def unordered_list(value):
</li> </li>
""" """
def _helper(value, tabs): def _helper(value, tabs):
indent = '\t' * tabs indent = u'\t' * tabs
if value[1]: if value[1]:
return '%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, value[0], indent, return u'%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) u'\n'.join([_helper(v, tabs+1) for v in value[1]]), indent, indent)
else: else:
return '%s<li>%s</li>' % (indent, value[0]) return u'%s<li>%s</li>' % (indent, value[0])
return _helper(value, 1) return _helper(value, 1)
################### ###################
@ -421,7 +405,7 @@ def date(value, arg=None):
"Formats a date according to the given format" "Formats a date according to the given format"
from django.utils.dateformat import format from django.utils.dateformat import format
if not value: if not value:
return '' return u''
if arg is None: if arg is None:
arg = settings.DATE_FORMAT arg = settings.DATE_FORMAT
return format(value, arg) return format(value, arg)
@ -429,8 +413,8 @@ def date(value, arg=None):
def time(value, arg=None): def time(value, arg=None):
"Formats a time according to the given format" "Formats a time according to the given format"
from django.utils.dateformat import time_format from django.utils.dateformat import time_format
if value in (None, ''): if value in (None, u''):
return '' return u''
if arg is None: if arg is None:
arg = settings.TIME_FORMAT arg = settings.TIME_FORMAT
return time_format(value, arg) return time_format(value, arg)
@ -439,7 +423,7 @@ def timesince(value, arg=None):
'Formats a date as the time since that date (i.e. "4 days, 6 hours")' 'Formats a date as the time since that date (i.e. "4 days, 6 hours")'
from django.utils.timesince import timesince from django.utils.timesince import timesince
if not value: if not value:
return '' return u''
if arg: if arg:
return timesince(arg, value) return timesince(arg, value)
return timesince(value) return timesince(value)
@ -449,7 +433,7 @@ def timeuntil(value, arg=None):
from django.utils.timesince import timesince from django.utils.timesince import timesince
from datetime import datetime from datetime import datetime
if not value: if not value:
return '' return u''
if arg: if arg:
return timesince(arg, value) return timesince(arg, value)
return timesince(datetime.now(), value) return timesince(datetime.now(), value)
@ -488,8 +472,8 @@ def yesno(value, arg=None):
========== ====================== ================================== ========== ====================== ==================================
""" """
if arg is None: if arg is None:
arg = gettext('yes,no,maybe') arg = ugettext('yes,no,maybe')
bits = arg.split(',') bits = arg.split(u',')
if len(bits) < 2: if len(bits) < 2:
return value # Invalid arg. return value # Invalid arg.
try: try:
@ -514,28 +498,28 @@ def filesizeformat(bytes):
try: try:
bytes = float(bytes) bytes = float(bytes)
except TypeError: except TypeError:
return "0 bytes" return u"0 bytes"
if bytes < 1024: 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: if bytes < 1024 * 1024:
return "%.1f KB" % (bytes / 1024) return u"%.1f KB" % (bytes / 1024)
if bytes < 1024 * 1024 * 1024: if bytes < 1024 * 1024 * 1024:
return "%.1f MB" % (bytes / (1024 * 1024)) return u"%.1f MB" % (bytes / (1024 * 1024))
return "%.1f GB" % (bytes / (1024 * 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' 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 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 is used instead. If the provided argument contains a comma, the text before
the comma is used for the singular case. the comma is used for the singular case.
""" """
if not ',' in arg: if not u',' in arg:
arg = ',' + arg arg = u',' + arg
bits = arg.split(',') bits = arg.split(u',')
if len(bits) > 2: if len(bits) > 2:
return '' return u''
singular_suffix, plural_suffix = bits[:2] singular_suffix, plural_suffix = bits[:2]
try: try:
@ -562,7 +546,7 @@ def pprint(value):
try: try:
return pformat(value) return pformat(value)
except Exception, e: except Exception, e:
return "Error in formatting:%s" % e return u"Error in formatting:%s" % e
# Syntax: register.filter(name of filter, callback) # Syntax: register.filter(name of filter, callback)
register.filter(add) register.filter(add)

View File

@ -13,7 +13,7 @@ Usage:
from django.utils.dates import MONTHS, MONTHS_3, MONTHS_AP, WEEKDAYS from django.utils.dates import MONTHS, MONTHS_3, MONTHS_AP, WEEKDAYS
from django.utils.tzinfo import LocalTimezone from django.utils.tzinfo import LocalTimezone
from django.utils.translation import gettext as _ from django.utils.translation import ugettext as _
from calendar import isleap, monthrange from calendar import isleap, monthrange
import re, time import re, time
@ -28,7 +28,7 @@ class Formatter(object):
pieces.append(str(getattr(self, piece)())) pieces.append(str(getattr(self, piece)()))
elif piece: elif piece:
pieces.append(re_escaped.sub(r'\1', piece)) pieces.append(re_escaped.sub(r'\1', piece))
return ''.join(pieces) return u''.join(pieces)
class TimeFormat(Formatter): class TimeFormat(Formatter):
def __init__(self, t): def __init__(self, t):
@ -52,13 +52,14 @@ class TimeFormat(Formatter):
def f(self): def f(self):
""" """
Time, in 12-hour hours and minutes, with minutes left off if they're zero. Time, in 12-hour hours and minutes, with minutes left off if they're
zero.
Examples: '1', '1:30', '2:05', '2' Examples: '1', '1:30', '2:05', '2'
Proprietary extension. Proprietary extension.
""" """
if self.data.minute == 0: if self.data.minute == 0:
return self.g() return self.g()
return '%s:%s' % (self.g(), self.i()) return u'%s:%s' % (self.g(), self.i())
def g(self): def g(self):
"Hour, 12-hour format without leading zeros; i.e. '1' to '12'" "Hour, 12-hour format without leading zeros; i.e. '1' to '12'"
@ -74,15 +75,15 @@ class TimeFormat(Formatter):
def h(self): def h(self):
"Hour, 12-hour format; i.e. '01' to '12'" "Hour, 12-hour format; i.e. '01' to '12'"
return '%02d' % self.g() return u'%02d' % self.g()
def H(self): def H(self):
"Hour, 24-hour format; i.e. '00' to '23'" "Hour, 24-hour format; i.e. '00' to '23'"
return '%02d' % self.G() return u'%02d' % self.G()
def i(self): def i(self):
"Minutes; i.e. '00' to '59'" "Minutes; i.e. '00' to '59'"
return '%02d' % self.data.minute return u'%02d' % self.data.minute
def P(self): def P(self):
""" """
@ -95,11 +96,11 @@ class TimeFormat(Formatter):
return _('midnight') return _('midnight')
if self.data.minute == 0 and self.data.hour == 12: if self.data.minute == 0 and self.data.hour == 12:
return _('noon') return _('noon')
return '%s %s' % (self.f(), self.a()) return u'%s %s' % (self.f(), self.a())
def s(self): def s(self):
"Seconds; i.e. '00' to '59'" "Seconds; i.e. '00' to '59'"
return '%02d' % self.data.second return u'%02d' % self.data.second
class DateFormat(TimeFormat): class DateFormat(TimeFormat):
year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
@ -117,7 +118,7 @@ class DateFormat(TimeFormat):
def d(self): def d(self):
"Day of the month, 2 digits with leading zeros; i.e. '01' to '31'" "Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
return '%02d' % self.data.day return u'%02d' % self.data.day
def D(self): def D(self):
"Day of the week, textual, 3 letters; e.g. 'Fri'" "Day of the week, textual, 3 letters; e.g. 'Fri'"
@ -130,9 +131,9 @@ class DateFormat(TimeFormat):
def I(self): def I(self):
"'1' if Daylight Savings Time, '0' otherwise." "'1' if Daylight Savings Time, '0' otherwise."
if self.timezone.dst(self.data): if self.timezone.dst(self.data):
return '1' return u'1'
else: else:
return '0' return u'0'
def j(self): def j(self):
"Day of the month without leading zeros; i.e. '1' to '31'" "Day of the month without leading zeros; i.e. '1' to '31'"
@ -148,7 +149,7 @@ class DateFormat(TimeFormat):
def m(self): def m(self):
"Month; i.e. '01' to '12'" "Month; i.e. '01' to '12'"
return '%02d' % self.data.month return u'%02d' % self.data.month
def M(self): def M(self):
"Month, textual, 3 letters; e.g. 'Jan'" "Month, textual, 3 letters; e.g. 'Jan'"
@ -165,7 +166,7 @@ class DateFormat(TimeFormat):
def O(self): def O(self):
"Difference to Greenwich time in hours; e.g. '+0200'" "Difference to Greenwich time in hours; e.g. '+0200'"
tz = self.timezone.utcoffset(self.data) tz = self.timezone.utcoffset(self.data)
return "%+03d%02d" % (tz.seconds // 3600, (tz.seconds // 60) % 60) return u"%+03d%02d" % (tz.seconds // 3600, (tz.seconds // 60) % 60)
def r(self): def r(self):
"RFC 822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'" "RFC 822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
@ -174,26 +175,26 @@ class DateFormat(TimeFormat):
def S(self): def S(self):
"English ordinal suffix for the day of the month, 2 characters; i.e. 'st', 'nd', 'rd' or 'th'" "English ordinal suffix for the day of the month, 2 characters; i.e. 'st', 'nd', 'rd' or 'th'"
if self.data.day in (11, 12, 13): # Special case if self.data.day in (11, 12, 13): # Special case
return 'th' return u'th'
last = self.data.day % 10 last = self.data.day % 10
if last == 1: if last == 1:
return 'st' return u'st'
if last == 2: if last == 2:
return 'nd' return u'nd'
if last == 3: if last == 3:
return 'rd' return u'rd'
return 'th' return u'th'
def t(self): def t(self):
"Number of days in the given month; i.e. '28' to '31'" "Number of days in the given month; i.e. '28' to '31'"
return '%02d' % monthrange(self.data.year, self.data.month)[1] return u'%02d' % monthrange(self.data.year, self.data.month)[1]
def T(self): def T(self):
"Time zone of this machine; e.g. 'EST' or 'MDT'" "Time zone of this machine; e.g. 'EST' or 'MDT'"
name = self.timezone.tzname(self.data) name = self.timezone.tzname(self.data)
if name is None: if name is None:
name = self.format('O') name = self.format('O')
return name return unicode(name)
def U(self): def U(self):
"Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)" "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
@ -232,7 +233,7 @@ class DateFormat(TimeFormat):
def y(self): def y(self):
"Year, 2 digits; e.g. '99'" "Year, 2 digits; e.g. '99'"
return str(self.data.year)[2:] return unicode(self.data.year)[2:]
def Y(self): def Y(self):
"Year, 4 digits; e.g. '1999'" "Year, 4 digits; e.g. '1999'"

View File

@ -1,6 +1,6 @@
"Commonly-used date structures" "Commonly-used date structures"
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
WEEKDAYS = { WEEKDAYS = {
0:_('Monday'), 1:_('Tuesday'), 2:_('Wednesday'), 3:_('Thursday'), 4:_('Friday'), 0:_('Monday'), 1:_('Tuesday'), 2:_('Wednesday'), 3:_('Thursday'), 4:_('Friday'),

View File

@ -25,7 +25,7 @@ del x # Temporary variable
def escape(html): def escape(html):
"Returns the given HTML with ampersands, quotes and carets encoded" "Returns the given HTML with ampersands, quotes and carets encoded"
if not isinstance(html, basestring): if not isinstance(html, basestring):
html = str(html) html = smart_unicode(html)
return html.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;') return html.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;')
def linebreaks(value): def linebreaks(value):
@ -33,7 +33,7 @@ def linebreaks(value):
value = re.sub(r'\r\n|\r|\n', '\n', value) # normalize newlines value = re.sub(r'\r\n|\r|\n', '\n', value) # normalize newlines
paras = re.split('\n{2,}', value) paras = re.split('\n{2,}', value)
paras = ['<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras] paras = ['<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras]
return '\n\n'.join(paras) return u'\n\n'.join(paras)
def strip_tags(value): def strip_tags(value):
"Returns the given HTML with all tags stripped" "Returns the given HTML with all tags stripped"
@ -80,7 +80,7 @@ def urlize(text, trim_url_limit=None, nofollow=False):
middle = '<a href="mailto:%s">%s</a>' % (middle, middle) middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
if lead + middle + trail != word: if lead + middle + trail != word:
words[i] = lead + middle + trail words[i] = lead + middle + trail
return ''.join(words) return u''.join(words)
def clean_html(text): def clean_html(text):
""" """
@ -108,7 +108,7 @@ def clean_html(text):
s = match.group().replace('</p>', '</li>') s = match.group().replace('</p>', '</li>')
for d in DOTS: for d in DOTS:
s = s.replace('<p>%s' % d, '<li>') s = s.replace('<p>%s' % d, '<li>')
return '<ul>\n%s\n</ul>' % s return u'<ul>\n%s\n</ul>' % s
text = hard_coded_bullets_re.sub(replace_p_tags, text) text = hard_coded_bullets_re.sub(replace_p_tags, text)
# Remove stuff like "<p>&nbsp;&nbsp;</p>", but only if it's at the bottom of the text. # Remove stuff like "<p>&nbsp;&nbsp;</p>", but only if it's at the bottom of the text.
text = trailing_empty_content_re.sub('', text) text = trailing_empty_content_re.sub('', text)

View File

@ -38,5 +38,5 @@ def strip_stopwords(sentence):
for word in words: for word in words:
if word.lower() not in stopwords: if word.lower() not in stopwords:
sentence.append(word) sentence.append(word)
return ' '.join(sentence) return u' '.join(sentence)

View File

@ -1,6 +1,6 @@
import re import re
from django.conf import settings from django.conf import settings
from django.utils.encoding import smart_unicode
# Capitalizes the first letter of a string. # Capitalizes the first letter of a string.
capfirst = lambda x: x and x[0].upper() + x[1:] capfirst = lambda x: x and x[0].upper() + x[1:]
@ -10,6 +10,7 @@ def wrap(text, width):
A word-wrap function that preserves existing line breaks and most spaces in A word-wrap function that preserves existing line breaks and most spaces in
the text. Expects that existing line breaks are posix newlines. the text. Expects that existing line breaks are posix newlines.
""" """
text = smart_unicode(text)
def _generator(): def _generator():
it = iter(text.split(' ')) it = iter(text.split(' '))
word = it.next() word = it.next()
@ -29,26 +30,29 @@ def wrap(text, width):
if len(lines) > 1: if len(lines) > 1:
pos = len(lines[-1]) pos = len(lines[-1])
yield word yield word
return "".join(_generator()) return u''.join(_generator())
def truncate_words(s, num): def truncate_words(s, num):
"Truncates a string after a certain number of words." "Truncates a string after a certain number of words."
s = smart_unicode(s)
length = int(num) length = int(num)
words = s.split() words = s.split()
if len(words) > length: if len(words) > length:
words = words[:length] words = words[:length]
if not words[-1].endswith('...'): if not words[-1].endswith('...'):
words.append('...') words.append('...')
return ' '.join(words) return u' '.join(words)
def truncate_html_words(s, num): def truncate_html_words(s, num):
""" """
Truncates html to a certain number of words (not counting tags and comments). Truncates html to a certain number of words (not counting tags and
Closes opened tags if they were correctly closed in the given html. comments). Closes opened tags if they were correctly closed in the given
html.
""" """
s = smart_unicode(s)
length = int(num) length = int(num)
if length <= 0: if length <= 0:
return '' return u''
html4_singlets = ('br', 'col', 'link', 'base', 'img', 'param', 'area', 'hr', 'input') html4_singlets = ('br', 'col', 'link', 'base', 'img', 'param', 'area', 'hr', 'input')
# Set up regular expressions # Set up regular expressions
re_words = re.compile(r'&.*?;|<.*?>|([A-Za-z0-9][\w-]*)') re_words = re.compile(r'&.*?;|<.*?>|([A-Za-z0-9][\w-]*)')
@ -110,10 +114,10 @@ def get_valid_filename(s):
>>> get_valid_filename("john's portrait in 2004.jpg") >>> get_valid_filename("john's portrait in 2004.jpg")
'johns_portrait_in_2004.jpg' 'johns_portrait_in_2004.jpg'
""" """
s = s.strip().replace(' ', '_') s = smart_unicode(s).strip().replace(' ', '_')
return re.sub(r'[^-A-Za-z0-9_.]', '', s) return re.sub(r'[^-A-Za-z0-9_.]', '', s)
def get_text_list(list_, last_word='or'): def get_text_list(list_, last_word=u'or'):
""" """
>>> get_text_list(['a', 'b', 'c', 'd']) >>> get_text_list(['a', 'b', 'c', 'd'])
'a, b, c or d' 'a, b, c or d'
@ -126,22 +130,18 @@ def get_text_list(list_, last_word='or'):
>>> get_text_list([]) >>> get_text_list([])
'' ''
""" """
if len(list_) == 0: return '' if len(list_) == 0: return u''
if len(list_) == 1: return list_[0] if len(list_) == 1: return smart_unicode(list_[0])
return '%s %s %s' % (', '.join([str(i) for i in list_][:-1]), last_word, list_[-1]) return u'%s %s %s' % (', '.join([smart_unicode(i) for i in list_][:-1]), smart_unicode(last_word), smart_unicode(list_[-1]))
def normalize_newlines(text): def normalize_newlines(text):
return re.sub(r'\r\n|\r|\n', '\n', text) return smart_unicode(re.sub(r'\r\n|\r|\n', '\n', text))
def recapitalize(text): def recapitalize(text):
"Recapitalizes text, placing caps after end-of-sentence punctuation." "Recapitalizes text, placing caps after end-of-sentence punctuation."
# capwords = () text = smart_unicode(text).lower()
text = text.lower()
capsRE = re.compile(r'(?:^|(?<=[\.\?\!] ))([a-z])') capsRE = re.compile(r'(?:^|(?<=[\.\?\!] ))([a-z])')
text = capsRE.sub(lambda x: x.group(1).upper(), text) text = capsRE.sub(lambda x: x.group(1).upper(), text)
# for capword in capwords:
# capwordRE = re.compile(r'\b%s\b' % capword, re.I)
# text = capwordRE.sub(capword, text)
return text return text
def phone2numeric(phone): def phone2numeric(phone):
@ -172,7 +172,7 @@ def javascript_quote(s, quote_double_quotes=False):
return r"\u%04x" % ord(match.group(1)) return r"\u%04x" % ord(match.group(1))
if type(s) == str: if type(s) == str:
s = s.decode(settings.DEFAULT_CHARSET) s = s.decode('utf-8')
elif type(s) != unicode: elif type(s) != unicode:
raise TypeError, s raise TypeError, s
s = s.replace('\\', '\\\\') s = s.replace('\\', '\\\\')
@ -195,6 +195,7 @@ def smart_split(text):
>>> list(smart_split('This is "a person\'s" test.')) >>> list(smart_split('This is "a person\'s" test.'))
['This', 'is', '"a person\'s"', 'test.'] ['This', 'is', '"a person\'s"', 'test.']
""" """
text = smart_unicode(text)
for bit in smart_split_re.finditer(text): for bit in smart_split_re.finditer(text):
bit = bit.group(0) bit = bit.group(0)
if bit[0] == '"' and bit[-1] == '"': if bit[0] == '"' and bit[-1] == '"':

View File

@ -1,6 +1,6 @@
import datetime, math, time import datetime, math, time
from django.utils.tzinfo import LocalTimezone from django.utils.tzinfo import LocalTimezone
from django.utils.translation import ngettext from django.utils.translation import ungettext
def timesince(d, now=None): def timesince(d, now=None):
""" """
@ -9,12 +9,12 @@ def timesince(d, now=None):
Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
""" """
chunks = ( chunks = (
(60 * 60 * 24 * 365, lambda n: ngettext('year', 'years', n)), (60 * 60 * 24 * 365, lambda n: ungettext('year', 'years', n)),
(60 * 60 * 24 * 30, lambda n: ngettext('month', 'months', n)), (60 * 60 * 24 * 30, lambda n: ungettext('month', 'months', n)),
(60 * 60 * 24 * 7, lambda n : ngettext('week', 'weeks', n)), (60 * 60 * 24 * 7, lambda n : ungettext('week', 'weeks', n)),
(60 * 60 * 24, lambda n : ngettext('day', 'days', n)), (60 * 60 * 24, lambda n : ungettext('day', 'days', n)),
(60 * 60, lambda n: ngettext('hour', 'hours', n)), (60 * 60, lambda n: ungettext('hour', 'hours', n)),
(60, lambda n: ngettext('minute', 'minutes', n)) (60, lambda n: ungettext('minute', 'minutes', n))
) )
# Convert datetime.date to datetime.datetime for comparison # Convert datetime.date to datetime.datetime for comparison
if d.__class__ is not datetime.datetime: if d.__class__ is not datetime.datetime:
@ -37,8 +37,8 @@ def timesince(d, now=None):
if count != 0: if count != 0:
break break
if count < 0: if count < 0:
return '%d milliseconds' % math.floor((now - d).microseconds / 1000) return u'%d milliseconds' % math.floor((now - d).microseconds / 1000)
s = '%d %s' % (count, name(count)) s = u'%d %s' % (count, name(count))
if i + 1 < len(chunks): if i + 1 < len(chunks):
# Now get the second item # Now get the second item
seconds2, name2 = chunks[i + 1] seconds2, name2 = chunks[i + 1]

View File

@ -7,7 +7,7 @@ class FixedOffset(tzinfo):
"Fixed offset in minutes east from UTC." "Fixed offset in minutes east from UTC."
def __init__(self, offset): def __init__(self, offset):
self.__offset = timedelta(minutes=offset) self.__offset = timedelta(minutes=offset)
self.__name = "%+03d%02d" % (offset // 60, offset % 60) self.__name = u"%+03d%02d" % (offset // 60, offset % 60)
def __repr__(self): def __repr__(self):
return self.__name return self.__name
@ -25,7 +25,7 @@ class LocalTimezone(tzinfo):
"Proxy timezone information from time module." "Proxy timezone information from time module."
def __init__(self, dt): def __init__(self, dt):
tzinfo.__init__(self, dt) tzinfo.__init__(self, dt)
self._tzname = time.tzname[self._isdst(dt)] self._tzname = unicode(time.tzname[self._isdst(dt)])
def __repr__(self): def __repr__(self):
return self._tzname return self._tzname
@ -43,7 +43,7 @@ class LocalTimezone(tzinfo):
return timedelta(0) return timedelta(0)
def tzname(self, dt): def tzname(self, dt):
return time.tzname[self._isdst(dt)] return unicode(time.tzname[self._isdst(dt)])
def _isdst(self, dt): def _isdst(self, dt):
tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1) tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)

View File

@ -1,54 +1,54 @@
r""" r"""
>>> format(my_birthday, '') >>> format(my_birthday, '')
'' u''
>>> format(my_birthday, 'a') >>> format(my_birthday, 'a')
'p.m.' u'p.m.'
>>> format(my_birthday, 'A') >>> format(my_birthday, 'A')
'PM' u'PM'
>>> format(my_birthday, 'd') >>> format(my_birthday, 'd')
'08' u'08'
>>> format(my_birthday, 'j') >>> format(my_birthday, 'j')
'8' u'8'
>>> format(my_birthday, 'l') >>> format(my_birthday, 'l')
'Sunday' u'Sunday'
>>> format(my_birthday, 'L') >>> format(my_birthday, 'L')
'False' u'False'
>>> format(my_birthday, 'm') >>> format(my_birthday, 'm')
'07' u'07'
>>> format(my_birthday, 'M') >>> format(my_birthday, 'M')
'Jul' u'Jul'
>>> format(my_birthday, 'b') >>> format(my_birthday, 'b')
'jul' u'jul'
>>> format(my_birthday, 'n') >>> format(my_birthday, 'n')
'7' u'7'
>>> format(my_birthday, 'N') >>> format(my_birthday, 'N')
'July' u'July'
>>> no_tz or format(my_birthday, 'O') == '+0100' >>> no_tz or format(my_birthday, 'O') == '+0100'
True True
>>> format(my_birthday, 'P') >>> format(my_birthday, 'P')
'10 p.m.' u'10 p.m.'
>>> no_tz or format(my_birthday, 'r') == 'Sun, 8 Jul 1979 22:00:00 +0100' >>> no_tz or format(my_birthday, 'r') == 'Sun, 8 Jul 1979 22:00:00 +0100'
True True
>>> format(my_birthday, 's') >>> format(my_birthday, 's')
'00' u'00'
>>> format(my_birthday, 'S') >>> format(my_birthday, 'S')
'th' u'th'
>>> format(my_birthday, 't') >>> format(my_birthday, 't')
'31' u'31'
>>> no_tz or format(my_birthday, 'T') == 'CET' >>> no_tz or format(my_birthday, 'T') == 'CET'
True True
>>> no_tz or format(my_birthday, 'U') == '300531600' >>> no_tz or format(my_birthday, 'U') == '300531600'
True True
>>> format(my_birthday, 'w') >>> format(my_birthday, 'w')
'0' u'0'
>>> format(my_birthday, 'W') >>> format(my_birthday, 'W')
'27' u'27'
>>> format(my_birthday, 'y') >>> format(my_birthday, 'y')
'79' u'79'
>>> format(my_birthday, 'Y') >>> format(my_birthday, 'Y')
'1979' u'1979'
>>> format(my_birthday, 'z') >>> format(my_birthday, 'z')
'189' u'189'
>>> no_tz or format(my_birthday, 'Z') == '3600' >>> no_tz or format(my_birthday, 'Z') == '3600'
True True
@ -62,10 +62,10 @@ True
True True
>>> format(my_birthday, r'Y z \C\E\T') >>> format(my_birthday, r'Y z \C\E\T')
'1979 189 CET' u'1979 189 CET'
>>> format(my_birthday, r'jS o\f F') >>> format(my_birthday, r'jS o\f F')
'8th of July' u'8th of July'
""" """
from django.utils import dateformat, translation from django.utils import dateformat, translation

View File

@ -2,186 +2,186 @@
r""" r"""
>>> floatformat(7.7) >>> floatformat(7.7)
'7.7' u'7.7'
>>> floatformat(7.0) >>> floatformat(7.0)
'7' u'7'
>>> floatformat(0.7) >>> floatformat(0.7)
'0.7' u'0.7'
>>> floatformat(0.07) >>> floatformat(0.07)
'0.1' u'0.1'
>>> floatformat(0.007) >>> floatformat(0.007)
'0.0' u'0.0'
>>> floatformat(0.0) >>> floatformat(0.0)
'0' u'0'
>>> floatformat(7.7,3) >>> floatformat(7.7,3)
'7.700' u'7.700'
>>> floatformat(6.000000,3) >>> floatformat(6.000000,3)
'6.000' u'6.000'
>>> floatformat(13.1031,-3) >>> floatformat(13.1031,-3)
'13.103' u'13.103'
>>> floatformat(11.1197, -2) >>> floatformat(11.1197, -2)
'11.12' u'11.12'
>>> floatformat(11.0000, -2) >>> floatformat(11.0000, -2)
'11' u'11'
>>> floatformat(11.000001, -2) >>> floatformat(11.000001, -2)
'11.00' u'11.00'
>>> floatformat(8.2798, 3) >>> floatformat(8.2798, 3)
'8.280' u'8.280'
>>> floatformat('foo') >>> floatformat(u'foo')
'' u''
>>> floatformat(13.1031, 'bar') >>> floatformat(13.1031, u'bar')
'13.1031' u'13.1031'
>>> floatformat('foo', 'bar') >>> floatformat(u'foo', u'bar')
'' u''
>>> addslashes('"double quotes" and \'single quotes\'') >>> addslashes(u'"double quotes" and \'single quotes\'')
'\\"double quotes\\" and \\\'single quotes\\\'' u'\\"double quotes\\" and \\\'single quotes\\\''
>>> addslashes(r'\ : backslashes, too') >>> addslashes(ur'\ : backslashes, too')
'\\\\ : backslashes, too' u'\\\\ : backslashes, too'
>>> capfirst('hello world') >>> capfirst(u'hello world')
'Hello world' u'Hello world'
>>> fix_ampersands('Jack & Jill & Jeroboam') >>> fix_ampersands(u'Jack & Jill & Jeroboam')
'Jack &amp; Jill &amp; Jeroboam' u'Jack &amp; Jill &amp; Jeroboam'
>>> linenumbers('line 1\nline 2') >>> linenumbers(u'line 1\nline 2')
'1. line 1\n2. line 2' u'1. line 1\n2. line 2'
>>> linenumbers('\n'.join(['x'] * 10)) >>> linenumbers(u'\n'.join([u'x'] * 10))
'01. x\n02. x\n03. x\n04. x\n05. x\n06. x\n07. x\n08. x\n09. x\n10. x' u'01. x\n02. x\n03. x\n04. x\n05. x\n06. x\n07. x\n08. x\n09. x\n10. x'
>>> lower('TEST') >>> lower('TEST')
'test' u'test'
>>> lower(u'\xcb') # uppercase E umlaut >>> lower(u'\xcb') # uppercase E umlaut
u'\xeb' u'\xeb'
>>> make_list('abc') >>> make_list('abc')
['a', 'b', 'c'] [u'a', u'b', u'c']
>>> make_list(1234) >>> 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 ?%.$!/') >>> 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') >>> stringformat(1, u'03d')
'001' u'001'
>>> stringformat(1, 'z') >>> stringformat(1, u'z')
'' u''
>>> title('a nice title, isn\'t it?') >>> 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) >>> truncatewords(u'A sentence with a few words in it', 1)
'A ...' u'A ...'
>>> truncatewords('A sentence with a few words in it', 5) >>> truncatewords(u'A sentence with a few words in it', 5)
'A sentence with a few ...' u'A sentence with a few ...'
>>> truncatewords('A sentence with a few words in it', 100) >>> truncatewords(u'A sentence with a few words in it', 100)
'A sentence with a few words in it' u'A sentence with a few words in it'
>>> truncatewords('A sentence with a few words in it', 'not a number') >>> truncatewords(u'A sentence with a few words in it', 'not a number')
'A sentence with a few words in it' 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) >>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 2)
'<p>one <a href="#">two ...</a></p>' u'<p>one <a href="#">two ...</a></p>'
>>> truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 4) >>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 4)
'<p>one <a href="#">two - three <br>four ...</a></p>' 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) >>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 5)
'<p>one <a href="#">two - three <br>four</a> five</p>' 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) >>> truncatewords_html(u'<p>one <a href="#">two - three <br>four</a> five</p>', 100)
'<p>one <a href="#">two - three <br>four</a> five</p>' u'<p>one <a href="#">two - three <br>four</a> five</p>'
>>> upper('Mixed case input') >>> upper(u'Mixed case input')
'MIXED CASE INPUT' u'MIXED CASE INPUT'
>>> upper(u'\xeb') # lowercase e umlaut >>> upper(u'\xeb') # lowercase e umlaut
u'\xcb' u'\xcb'
>>> urlencode('jack & jill') >>> urlencode(u'jack & jill')
'jack%20%26%20jill' u'jack%20%26%20jill'
>>> urlencode(1) >>> urlencode(1)
'1' u'1'
>>> urlizetrunc('http://short.com/', 20) >>> urlizetrunc(u'http://short.com/', 20)
'<a href="http://short.com/" rel="nofollow">http://short.com/</a>' 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) >>> urlizetrunc(u'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>' 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 0
>>> wordcount('oneword') >>> wordcount(u'oneword')
1 1
>>> wordcount('lots of words') >>> wordcount(u'lots of words')
3 3
>>> wordwrap('this is a long paragraph of text that really needs to be wrapped I\'m afraid', 14) >>> wordwrap(u'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" 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) >>> wordwrap(u'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' 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) >>> wordwrap(u'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' u'this is a short\nparagraph of\ntext.\n But this line\nshould be\nindented'
>>> ljust('test', 10) >>> ljust(u'test', 10)
'test ' u'test '
>>> ljust('test', 3) >>> ljust(u'test', 3)
'test' u'test'
>>> rjust('test', 10) >>> rjust(u'test', 10)
' test' u' test'
>>> rjust('test', 3) >>> rjust(u'test', 3)
'test' u'test'
>>> center('test', 6) >>> center(u'test', 6)
' test ' u' test '
>>> cut('a string to be mangled', 'a') >>> cut(u'a string to be mangled', 'a')
' string to be mngled' u' string to be mngled'
>>> cut('a string to be mangled', 'ng') >>> cut(u'a string to be mangled', 'ng')
'a stri to be maled' u'a stri to be maled'
>>> cut('a string to be mangled', 'strings') >>> cut(u'a string to be mangled', 'strings')
'a string to be mangled' u'a string to be mangled'
>>> escape('<some html & special characters > here') >>> escape(u'<some html & special characters > here')
'&lt;some html &amp; special characters &gt; here' u'&lt;some html &amp; special characters &gt; here'
>>> escape(u'<some html & special characters > 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' u'&lt;some html &amp; special characters &gt; here \xc4\x90\xc3\x85\xe2\x82\xac\xc2\xa3'
>>> linebreaks('line 1') >>> linebreaks(u'line 1')
'<p>line 1</p>' u'<p>line 1</p>'
>>> linebreaks('line 1\nline 2') >>> linebreaks(u'line 1\nline 2')
'<p>line 1<br />line 2</p>' u'<p>line 1<br />line 2</p>'
>>> removetags('some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags', 'script img') >>> removetags(u'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' 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') >>> striptags(u'some <b>html</b> with <script>alert("You smell")</script> disallowed <img /> tags')
'some html with alert("You smell") disallowed tags' u'some html with alert("You smell") disallowed tags'
>>> dictsort([{'age': 23, 'name': 'Barbara-Ann'}, >>> dictsort([{'age': 23, 'name': 'Barbara-Ann'},
... {'age': 63, 'name': 'Ra Ra Rasputin'}, ... {'age': 63, 'name': 'Ra Ra Rasputin'},
@ -196,16 +196,16 @@ u'&lt;some html &amp; special characters &gt; here \xc4\x90\xc3\x85\xe2\x82\xac\
>>> first([0,1,2]) >>> first([0,1,2])
0 0
>>> first('') >>> first(u'')
'' u''
>>> first('test') >>> first(u'test')
't' u't'
>>> join([0,1,2], 'glue') >>> join([0,1,2], u'glue')
'0glue1glue2' u'0glue1glue2'
>>> length('1234') >>> length(u'1234')
4 4
>>> length([1,2,3,4]) >>> length([1,2,3,4])
@ -220,37 +220,37 @@ False
>>> length_is('a', 1) >>> length_is('a', 1)
True True
>>> length_is('a', 10) >>> length_is(u'a', 10)
False False
>>> slice_('abcdefg', '0') >>> slice_(u'abcdefg', u'0')
'' u''
>>> slice_('abcdefg', '1') >>> slice_(u'abcdefg', u'1')
'a' u'a'
>>> slice_('abcdefg', '-1') >>> slice_(u'abcdefg', u'-1')
'abcdef' u'abcdef'
>>> slice_('abcdefg', '1:2') >>> slice_(u'abcdefg', u'1:2')
'b' u'b'
>>> slice_('abcdefg', '1:3') >>> slice_(u'abcdefg', u'1:3')
'bc' u'bc'
>>> slice_('abcdefg', '0::2') >>> slice_(u'abcdefg', u'0::2')
'aceg' u'aceg'
>>> unordered_list(['item 1', []]) >>> unordered_list([u'item 1', []])
'\t<li>item 1</li>' u'\t<li>item 1</li>'
>>> unordered_list(['item 1', [['item 1.1', []]]]) >>> unordered_list([u'item 1', [[u'item 1.1', []]]])
'\t<li>item 1\n\t<ul>\n\t\t<li>item 1.1</li>\n\t</ul>\n\t</li>' 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', []]]]) >>> unordered_list([u'item 1', [[u'item 1.1', []], [u'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>' 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 3
>>> get_digit(123, 1) >>> get_digit(123, 1)
@ -268,43 +268,43 @@ False
>>> get_digit(123, 0) >>> get_digit(123, 0)
123 123
>>> get_digit('xyz', 0) >>> get_digit(u'xyz', 0)
'xyz' u'xyz'
# real testing of date() is in dateformat.py # real testing of date() is in dateformat.py
>>> date(datetime.datetime(2005, 12, 29), "d F Y") >>> date(datetime.datetime(2005, 12, 29), u"d F Y")
'29 December 2005' u'29 December 2005'
>>> date(datetime.datetime(2005, 12, 29), r'jS o\f F') >>> date(datetime.datetime(2005, 12, 29), ur'jS o\f F')
'29th of December' u'29th of December'
# real testing of time() is done in dateformat.py # real testing of time() is done in dateformat.py
>>> time(datetime.time(13), "h") >>> time(datetime.time(13), u"h")
'01' u'01'
>>> time(datetime.time(0), "h") >>> time(datetime.time(0), u"h")
'12' u'12'
# real testing is done in timesince.py, where we can provide our own 'now' # real testing is done in timesince.py, where we can provide our own 'now'
>>> timesince(datetime.datetime.now() - datetime.timedelta(1)) >>> timesince(datetime.datetime.now() - datetime.timedelta(1))
'1 day' u'1 day'
>>> default("val", "default") >>> default(u"val", u"default")
'val' u'val'
>>> default(None, "default") >>> default(None, u"default")
'default' u'default'
>>> default('', "default") >>> default(u'', u"default")
'default' u'default'
>>> default_if_none("val", "default") >>> default_if_none(u"val", u"default")
'val' u'val'
>>> default_if_none(None, "default") >>> default_if_none(None, u"default")
'default' u'default'
>>> default_if_none('', "default") >>> default_if_none(u'', u"default")
'' u''
>>> divisibleby(4, 2) >>> divisibleby(4, 2)
True True
@ -313,139 +313,139 @@ True
False False
>>> yesno(True) >>> yesno(True)
'yes' u'yes'
>>> yesno(False) >>> yesno(False)
'no' u'no'
>>> yesno(None) >>> yesno(None)
'maybe' u'maybe'
>>> yesno(True, 'certainly,get out of town,perhaps') >>> yesno(True, u'certainly,get out of town,perhaps')
'certainly' u'certainly'
>>> yesno(False, 'certainly,get out of town,perhaps') >>> yesno(False, u'certainly,get out of town,perhaps')
'get out of town' u'get out of town'
>>> yesno(None, 'certainly,get out of town,perhaps') >>> yesno(None, u'certainly,get out of town,perhaps')
'perhaps' u'perhaps'
>>> yesno(None, 'certainly,get out of town') >>> yesno(None, u'certainly,get out of town')
'get out of town' u'get out of town'
>>> filesizeformat(1023) >>> filesizeformat(1023)
'1023 bytes' u'1023 bytes'
>>> filesizeformat(1024) >>> filesizeformat(1024)
'1.0 KB' u'1.0 KB'
>>> filesizeformat(10*1024) >>> filesizeformat(10*1024)
'10.0 KB' u'10.0 KB'
>>> filesizeformat(1024*1024-1) >>> filesizeformat(1024*1024-1)
'1024.0 KB' u'1024.0 KB'
>>> filesizeformat(1024*1024) >>> filesizeformat(1024*1024)
'1.0 MB' u'1.0 MB'
>>> filesizeformat(1024*1024*50) >>> filesizeformat(1024*1024*50)
'50.0 MB' u'50.0 MB'
>>> filesizeformat(1024*1024*1024-1) >>> filesizeformat(1024*1024*1024-1)
'1024.0 MB' u'1024.0 MB'
>>> filesizeformat(1024*1024*1024) >>> filesizeformat(1024*1024*1024)
'1.0 GB' u'1.0 GB'
>>> pluralize(1) >>> pluralize(1)
'' u''
>>> pluralize(0) >>> pluralize(0)
's' u's'
>>> pluralize(2) >>> pluralize(2)
's' u's'
>>> pluralize([1]) >>> pluralize([1])
'' u''
>>> pluralize([]) >>> pluralize([])
's' u's'
>>> pluralize([1,2,3]) >>> pluralize([1,2,3])
's' u's'
>>> pluralize(1,'es') >>> pluralize(1,u'es')
'' u''
>>> pluralize(0,'es') >>> pluralize(0,u'es')
'es' u'es'
>>> pluralize(2,'es') >>> pluralize(2,u'es')
'es' u'es'
>>> pluralize(1,'y,ies') >>> pluralize(1,u'y,ies')
'y' u'y'
>>> pluralize(0,'y,ies') >>> pluralize(0,u'y,ies')
'ies' u'ies'
>>> pluralize(2,'y,ies') >>> pluralize(2,u'y,ies')
'ies' u'ies'
>>> pluralize(0,'y,ies,error') >>> pluralize(0,u'y,ies,error')
'' u''
>>> phone2numeric('0800 flowers') >>> phone2numeric(u'0800 flowers')
'0800 3569377' u'0800 3569377'
# Filters shouldn't break if passed non-strings # Filters shouldn't break if passed non-strings
>>> addslashes(123) >>> addslashes(123)
'123' u'123'
>>> linenumbers(123) >>> linenumbers(123)
'1. 123' u'1. 123'
>>> lower(123) >>> lower(123)
'123' u'123'
>>> make_list(123) >>> make_list(123)
['1', '2', '3'] [u'1', u'2', u'3']
>>> slugify(123) >>> slugify(123)
'123' u'123'
>>> title(123) >>> title(123)
'123' u'123'
>>> truncatewords(123, 2) >>> truncatewords(123, 2)
'123' u'123'
>>> upper(123) >>> upper(123)
'123' u'123'
>>> urlencode(123) >>> urlencode(123)
'123' u'123'
>>> urlize(123) >>> urlize(123)
'123' u'123'
>>> urlizetrunc(123, 1) >>> urlizetrunc(123, 1)
'123' u'123'
>>> wordcount(123) >>> wordcount(123)
1 1
>>> wordwrap(123, 2) >>> wordwrap(123, 2)
'123' u'123'
>>> ljust('123', 4) >>> ljust('123', 4)
'123 ' u'123 '
>>> rjust('123', 4) >>> rjust('123', 4)
' 123' u' 123'
>>> center('123', 5) >>> center('123', 5)
' 123 ' u' 123 '
>>> center('123', 6) >>> center('123', 6)
' 123 ' u' 123 '
>>> cut(123, '2') >>> cut(123, '2')
'13' u'13'
>>> escape(123) >>> escape(123)
'123' u'123'
>>> linebreaks(123) >>> linebreaks(123)
'<p>123</p>' u'<p>123</p>'
>>> linebreaksbr(123) >>> linebreaksbr(123)
'123' u'123'
>>> removetags(123, 'a') >>> removetags(123, 'a')
'123' u'123'
>>> striptags(123) >>> striptags(123)
'123' u'123'
""" """

View File

@ -5,13 +5,13 @@
### smart_split ########################################################### ### smart_split ###########################################################
>>> list(smart_split(r'''This is "a person" test.''')) >>> list(smart_split(r'''This is "a person" test.'''))
['This', 'is', '"a person"', 'test.'] [u'This', u'is', u'"a person"', u'test.']
>>> print list(smart_split(r'''This is "a person's" test.'''))[2] >>> print list(smart_split(r'''This is "a person's" test.'''))[2]
"a person's" "a person's"
>>> print list(smart_split(r'''This is "a person\\"s" test.'''))[2] >>> print list(smart_split(r'''This is "a person\\"s" test.'''))[2]
"a person"s" "a person"s"
>>> list(smart_split('''"a 'one''')) >>> list(smart_split('''"a 'one'''))
['"a', "'one"] [u'"a', u"'one"]
>>> print list(smart_split(r'''all friends' tests'''))[1] >>> print list(smart_split(r'''all friends' tests'''))[1]
friends' friends'
""" """