0001"""
0002General-(web-)purpose functions for use in your applications.
0003"""
0004import cgi
0005import urllib
0006import re
0007import datetime
0008
0009__all__ = ['html_quote', 'url_quote', 'html_quote_whitespace']
0010
0011def html_quote(v):
0012 """
0013 HTML quote the value. None becomes an empty string. If a value
0014 has an ``__html__`` method, that will be called to get the HTML.
0015 """
0016 if v is None:
0017 return ''
0018 if hasattr(v, '__html__'):
0019 return v.__html__()
0020 if isinstance(v, basestring):
0021 return cgi.escape(v, 1)
0022 return cgi.escape(str(v), 1)
0023
0024def url_quote(v):
0025 """
0026 URL quote the value. None becomes the empty string. Dictionaries
0027 are mapped to
0028 """
0029 if isinstance(v, dict):
0030 return urllib.urlencode(v)
0031 elif v is None:
0032 return ''
0033 else:
0034 return urllib.urlquote(str(v))
0035
0036_whitespace_re = re.compile(r'[ ][ ]+')
0037
0038def html_quote_whitespace(v, newlines=True, strip=True):
0039 """
0040 HTML quote a value, and then make sure its whitespace is
0041 preserved. If ``newlines`` is true, then also turn newlines into
0042 ``<br>`` -- otherwise just horizontal whitespace will be preserved
0043 (using `` ``).
0044 """
0045 v = html_quote(v)
0046 if strip:
0047 v = v.strip()
0048 v = v.replace('\t', ' '*4)
0049 if newlines:
0050 lines = v.splitlines()
0051 for i in range(len(lines)):
0052 if lines[i].startswith(' '):
0053 lines[i] = ' '+lines[i][1:]
0054 v = '<br />\n'.join(lines)
0055 v = _whitespace_re.sub(_sub_white, v)
0056 return v
0057
0058def _sub_white(m):
0059 if len(m.group(0)) % 2:
0060 return m.group(0).replace(' ', ' ')
0061 else:
0062 return ' '+' '*(len(m.group(0))/2)
0063
0064def format_date_relative(date):
0065 """
0066 Formats a date relative to the current time. The result
0067 will be dates like 'Yesterday', 'Wednesday 10:00am',
0068 '12 May 2003', etc.
0069
0070 Specifically:
0071
0072 * If in the last 24 hours, just give the time.
0073 * If yesterday, give 'yesterday TIME'
0074 * If in the last 7 days, give 'DAY_OF_WEEK TIME'
0075 * If in the same calendar year, give 'DAY_OF_MONTH MONTH'
0076 * Otherwise gives 'DAY_OF_MONTH MONTH YEAR'
0077
0078 It uses english names when appropriate (e.g., Apr or Thu).
0079 """
0080 if date is None:
0081 return ''
0082 if isinstance(date, datetime.datetime):
0083 now = datetime.datetime.now()
0084 elif isinstance(date, datetime.date):
0085 now = datetime.date.today()
0086 else:
0087 raise ValueError(
0088 "Unknown type of date: %r" % date)
0089 year = date.year
0090 month = date.month
0091 day = date.day
0092 if now.year == year:
0093 if now.month == month:
0094 if (now - date) < datetime.timedelta(days=7):
0095 if now.day == day:
0096 return format_time(date)
0097 elif now.day - 1 == day:
0098 return 'Yest %s' % format_time(date)
0099 else:
0100 return date.strftime('%a ') + format_time(date)
0101 elif (now - date) < datetime.timedelta(days=7):
0102 return date.strftime('%a %d %b')
0103 else:
0104 return date.strftime('%d %b')
0105 else:
0106 return date.strftime('%d %b')
0107 else:
0108 return date.strftime('%d %b \'%y')
0109
0110def format_time(t):
0111 """
0112 Formats the time, like 4:20pm; unlike strftime, it lower-cases
0113 the am/pm, and doesn't create hours with leading zeros.
0114 """
0115 text = t.strftime('%I:%M%p')
0116 text = text[:-2] + text[-2:].lower()
0117 if text.startswith('0'):
0118 text = text[1:]
0119 return text