コード例 #1
0
ファイル: 0047_utc_datetimes.py プロジェクト: 1nv4d3r5/test
def new_date(old_date, reverse=False):
    if old_date is None:
        return None
    tz = LocalTimezone(old_date)
    offset = tz.utcoffset(old_date)
    if reverse:
        offset = -offset
    return old_date - offset
コード例 #2
0
def new_date(old_date, reverse=False):
    if old_date is None:
        return None
    tz = LocalTimezone(old_date)
    offset = tz.utcoffset(old_date)
    if reverse:
        offset = -offset
    return old_date - offset
コード例 #3
0
ファイル: dateformat.py プロジェクト: LAMike310/ecommerce
 def __init__(self, dt):
     # Accepts either a datetime or date object.
     self.data = dt
     self.timezone = None
     if isinstance(dt, datetime.datetime):
         if is_naive(dt):
             self.timezone = LocalTimezone(dt)
         else:
             self.timezone = dt.tzinfo
コード例 #4
0
ファイル: dateformat.py プロジェクト: zhonggehan/django
    def __init__(self, obj):
        self.data = obj
        self.timezone = None

        # We only support timezone when formatting datetime objects,
        # not date objects (timezone information not appropriate),
        # or time objects (against established django policy).
        if isinstance(obj, datetime.datetime):
            if is_naive(obj):
                self.timezone = LocalTimezone(obj)
            else:
                self.timezone = obj.tzinfo
コード例 #5
0
ファイル: date.py プロジェクト: Lucas-ech/zds-site
def date_formatter(value, tooltip, small):
    """
    Format a date to an human readable string.

    :param value: Date to format.
    :param bool tooltip: if `True`, format date to a tooltip label.
    :param bool small: if `True`, create a shorter string.
    :return:
    """
    try:
        value = datetime(value.year, value.month, value.day,
                         value.hour, value.minute, value.second)
    except (AttributeError, ValueError):
        # todo : Check why not raise template.TemplateSyntaxError() ?
        return value

    if getattr(value, 'tzinfo', None):
        now = datetime.now(LocalTimezone(value))
    else:
        now = datetime.now()
    now = now - timedelta(microseconds=now.microsecond)

    if value > now:
        return __DATE_FMT_FUTUR
    else:
        delta = now - value
        # Natural time for today, absolute date after.
        # Reverse if in tooltip
        if (delta.days == 0) != tooltip:
            return naturaltime(value)
        else:
            return date(value, __ABS_DATE_FMT_SMALL if small else __ABS_DATE_FMT_NORMAL)
コード例 #6
0
def format_datetime(date):
    """
    A utility method that converts the datetime to UTC serialized
    for Google Calendar.
    """
    local = date.replace(tzinfo=LocalTimezone(date))
    return local.astimezone(FixedOffset(0)).strftime(DATE_FORMAT)
コード例 #7
0
ファイル: misc.py プロジェクト: alexissmirnov/donomo
def days_since(d, now=None):
    """
    Takes two datetime objects and returns the number of days between them.
    If d occurs after now, then 0 is returned.

    Adapted from django.utils.timesince
    """
    import time
    import datetime
    from django.utils.tzinfo import LocalTimezone

    # Convert datetime.date to datetime.datetime for comparison
    if d.__class__ is not datetime.datetime:
        d = datetime.datetime(d.year, d.month, d.day)
    if now:
        t = now.timetuple()
    else:
        t = time.localtime()
    if d.tzinfo:
        tz = LocalTimezone(d)
    else:
        tz = None
    now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz)

    # ignore microsecond part of 'd' since we removed it from 'now'
    delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
    if delta.days <= 0:
        return 0
コード例 #8
0
ファイル: utils.py プロジェクト: mrenoch/occupywallst
def timesince(d, now=None):
    """Shortened version of django.utils.timesince.timesince"""
    chunks = (
        (60 * 60 * 24 * 365, lambda n: ungettext('year', 'years', n)),
        (60 * 60 * 24 * 30, lambda n: ungettext('month', 'months', n)),
        (60 * 60 * 24 * 7, lambda n: ungettext('week', 'weeks', n)),
        (60 * 60 * 24, lambda n: ungettext('day', 'days', n)),
        (60 * 60, lambda n: ungettext('hour', 'hours', n)),
        (60, lambda n: ungettext('minute', 'minutes', n))
    )
    # Convert datetime.date to datetime.datetime for comparison.
    if not isinstance(d, datetime):
        d = datetime(d.year, d.month, d.day)
    if now and not isinstance(now, datetime):
        now = datetime(now.year, now.month, now.day)
    if not now:
        if d.tzinfo:
            now = datetime.now(LocalTimezone(d))
        else:
            now = datetime.now()
    # ignore microsecond part of 'd' since we removed it from 'now'
    delta = now - (d - timedelta(0, 0, d.microsecond))
    since = delta.days * 24 * 60 * 60 + delta.seconds
    if since <= 0:
        # d is in the future compared to now, stop processing.
        return u'0 ' + ugettext('minutes')
    for i, (seconds, name) in enumerate(chunks):
        count = since // seconds
        if count != 0:
            break
    return ugettext('%(number)d %(type)s') % {
        'number': count, 'type': name(count)}
コード例 #9
0
def date_formatter(value, tooltip, small):
    try:
        value = datetime(value.year, value.month, value.day, value.hour,
                         value.minute, value.second)
    except AttributeError:
        return value
    except ValueError:
        return value

    if getattr(value, 'tzinfo', None):
        now = datetime.now(LocalTimezone(value))
    else:
        now = datetime.now()
    now = now - timedelta(0, 0, now.microsecond)
    if value > now:
        return "Dans le futur"
    else:
        delta = now - value
        # Natural time for today, absolute date after.
        # Reverse if in tooltip
        if (delta.days == 0) != tooltip:
            return naturaltime(value)
        elif small:
            return date(value, 'd/m/y à H\hi')
        else:
            return date(value, 'l d F Y à H\hi')
コード例 #10
0
 def test_datetime_with_local_tzinfo(self):
     ltz = LocalTimezone(datetime.now())
     dt = datetime(2009, 5, 16, 5, 30, 30, tzinfo=ltz)
     self.assertEquals(datetime.fromtimestamp(int(format(dt, 'U')), ltz),
                       dt)
     self.assertEquals(datetime.fromtimestamp(int(format(dt, 'U'))),
                       dt.replace(tzinfo=None))
コード例 #11
0
    def test_different_timezones(self):
        """ When using two different timezones. """
        now = datetime.datetime.now()
        now_tz = datetime.datetime.now(LocalTimezone(now))
        now_tz_i = datetime.datetime.now(FixedOffset((3 * 60) + 15))

        self.assertEqual(timesince(now), '0 minutes')
        self.assertEqual(timesince(now_tz), '0 minutes')
        self.assertEqual(timeuntil(now_tz, now_tz_i), '0 minutes')
コード例 #12
0
ファイル: dateformat.py プロジェクト: AlfredFu/django
 def __init__(self, dt):
     # Accepts either a datetime or date object.
     self.data = dt
     self.timezone = None
     if isinstance(dt, datetime.datetime):
         if is_naive(dt):
             self.timezone = LocalTimezone(dt)
         else:
             self.timezone = dt.tzinfo
コード例 #13
0
 def test_datetime_with_tzinfo(self):
     tz = FixedOffset(-510)
     ltz = LocalTimezone(datetime.now())
     dt = datetime(2009, 5, 16, 5, 30, 30, tzinfo=tz)
     self.assertEquals(datetime.fromtimestamp(int(format(dt, 'U')), tz), dt)
     self.assertEquals(datetime.fromtimestamp(int(format(dt, 'U')), ltz), dt)
     self.assertEquals(datetime.fromtimestamp(int(format(dt, 'U'))), dt.astimezone(ltz).replace(tzinfo=None))
     self.assertEquals(datetime.fromtimestamp(int(format(dt, 'U')), tz).utctimetuple(), dt.utctimetuple())
     self.assertEquals(datetime.fromtimestamp(int(format(dt, 'U')), ltz).utctimetuple(), dt.utctimetuple())
コード例 #14
0
def timesince(d, now=None):
    """
    Takes two datetime objects and returns the time between d and now
    as a nicely formatted string, e.g. "10 minutes".  If d occurs after now,
    then "0 minutes" is returned.

    Units used are years, months, weeks, days, hours, and minutes.
    Seconds and microseconds are ignored.  Up to two adjacent units will be
    displayed.  For example, "2 weeks, 3 days" and "1 year, 3 months" are
    possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.

    Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
    """
    chunks = ((60 * 60 * 24 * 365, lambda n: ungettext('year', 'years', n)),
              (60 * 60 * 24 * 30, lambda n: ungettext('month', 'months', n)),
              (60 * 60 * 24 * 7, lambda n: ungettext('week', 'weeks', n)),
              (60 * 60 * 24, lambda n: ungettext('day', 'days', n)),
              (60 * 60, lambda n: ungettext('hour', 'hours', n)),
              (60, lambda n: ungettext('minute', 'minutes', n)))
    # Convert datetime.date to datetime.datetime for comparison
    if d.__class__ is not datetime.datetime:
        d = datetime.datetime(d.year, d.month, d.day)
    if now:
        t = now.timetuple()
    else:
        t = time.localtime()
    if d.tzinfo:
        tz = LocalTimezone(d)
    else:
        tz = None
    now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz)

    # ignore microsecond part of 'd' since we removed it from 'now'
    delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
    since = delta.days * 24 * 60 * 60 + delta.seconds
    if since <= 0:
        # d is in the future compared to now, stop processing.
        return u'0 ' + ugettext('minutes')
    for i, (seconds, name) in enumerate(chunks):
        count = since // seconds
        if count != 0:
            break
    s = ugettext('%(number)d %(type)s') % {
        'number': count,
        'type': name(count)
    }
    if i + 1 < len(chunks):
        # Now get the second item
        seconds2, name2 = chunks[i + 1]
        count2 = (since - (seconds * count)) // seconds2
        if count2 != 0:
            s += ugettext(', %(number)d %(type)s') % {
                'number': count2,
                'type': name2(count2)
            }
    return s
コード例 #15
0
def timeuntil(d, now=None):
    """
    Like timesince, but returns a string measuring the time until
    the given time.
    """
    if not now:
        if getattr(d, 'tzinfo', None):
            now = datetime.datetime.now(LocalTimezone(d))
        else:
            now = datetime.datetime.now()
    return timesince(now, d)
コード例 #16
0
ファイル: dateformat.py プロジェクト: streeter/django
    def __init__(self, obj):
        self.data = obj
        self.timezone = None

        # We only support timezone when formatting datetime objects,
        # not date objects (timezone information not appropriate),
        # or time objects (against established django policy).
        if isinstance(obj, datetime.datetime):
            if is_naive(obj):
                self.timezone = LocalTimezone(obj)
            else:
                self.timezone = obj.tzinfo
コード例 #17
0
def timesince(d, now=None):
    """Take two datetime objects and return the time between d and now as a
    nicely formatted string, e.g. "10 minutes".  If d is None or occurs after
    now, return ''.

    Units used are years, months, weeks, days, hours, and minutes. Seconds and
    microseconds are ignored.  Just one unit is displayed.  For example,
    "2 weeks" and "1 year" are possible outputs, but "2 weeks, 3 days" and "1
    year, 5 months" are not.

    Adapted from django.utils.timesince to have better i18n (not assuming
    commas as list separators and including "ago" so order of words isn't
    assumed), show only one time unit, and include seconds.

    """
    if d is None:
        return u''
    chunks = [
        (60 * 60 * 24 * 365,
         lambda n: ungettext('%(number)d year ago', '%(number)d years ago', n)
         ),
        (60 * 60 * 24 * 30, lambda n: ungettext('%(number)d month ago',
                                                '%(number)d months ago', n)),
        (60 * 60 * 24 * 7,
         lambda n: ungettext('%(number)d week ago', '%(number)d weeks ago', n)
         ),
        (60 * 60 * 24,
         lambda n: ungettext('%(number)d day ago', '%(number)d days ago', n)),
        (60 * 60,
         lambda n: ungettext('%(number)d hour ago', '%(number)d hours ago', n)
         ),
        (60, lambda n: ungettext('%(number)d minute ago',
                                 '%(number)d minutes ago', n)),
        (1, lambda n: ungettext('%(number)d second ago',
                                '%(number)d seconds ago', n))
    ]
    if not now:
        if d.tzinfo:
            now = datetime.datetime.now(LocalTimezone(d))
        else:
            now = datetime.datetime.now()

    # Ignore microsecond part of 'd' since we removed it from 'now'
    delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
    since = delta.days * 24 * 60 * 60 + delta.seconds
    if since <= 0:
        # d is in the future compared to now, stop processing.
        return u''
    for i, (seconds, name) in enumerate(chunks):
        count = since // seconds
        if count != 0:
            break
    return name(count) % {'number': count}
コード例 #18
0
 def test_16899(self):
     if not self.tz_tests:
         return
     ts = 1289106000
     # Midnight at the end of DST in US/Eastern: 2010-11-07T05:00:00Z
     dt = datetime.datetime.utcfromtimestamp(ts)
     # US/Eastern -- we force its representation to "EST"
     tz = LocalTimezone(dt + datetime.timedelta(days=1))
     self.assertEqual(repr(datetime.datetime.fromtimestamp(ts - 3600, tz)),
                      'datetime.datetime(2010, 11, 7, 0, 0, tzinfo=EST)')
     self.assertEqual(repr(datetime.datetime.fromtimestamp(ts, tz)),
                      'datetime.datetime(2010, 11, 7, 1, 0, tzinfo=EST)')
     self.assertEqual(repr(datetime.datetime.fromtimestamp(ts + 3600, tz)),
                      'datetime.datetime(2010, 11, 7, 1, 0, tzinfo=EST)')
コード例 #19
0
ファイル: timesince.py プロジェクト: Normatica/django-11599
def timeuntil(d, now=None):
    """
    Like timesince, but returns a string measuring the time until
    the given time.
    """
    if not now:
        if getattr(d, 'tzinfo', None):
            now = datetime.datetime.now(LocalTimezone(d))
        else:
            now = datetime.datetime.now()

    # Convert datetime.date to datetime.datetime for comparison
    if d.__class__ is not datetime.datetime:
        d = datetime.datetime(d.year, d.month, d.day)

    return timesince(now, d)
コード例 #20
0
ファイル: timesince.py プロジェクト: peterbe/tornado_gists
def smartertimesince(d, now=None):
    if not isinstance(d, datetime.datetime):
        d = datetime.datetime(d.year, d.month, d.day)
    if now and not isinstance(now, datetime.datetime):
        now = datetime.datetime(now.year, now.month, now.day)

    if not now:
        if d.tzinfo:
            from django.utils.tzinfo import LocalTimezone
            now = datetime.datetime.now(LocalTimezone(d))
        else:
            now = datetime.datetime.now()

    r = timeSince(d, now, max_no_sections=1, minute_granularity=True)
    if not r:
        return "seconds"
    return r
コード例 #21
0
def iso8601(dt):
    try:
        offset = LocalTimezone(dt).utcoffset(dt).seconds
        if offset == 0:
            return u'Z'
        hours = offset / 3600
        minutes = offset % 3600
        difference = u'+'
        if offset < 0:
            difference = u'-'
        return '%s%02d:%02d' % (
            difference,
            hours,
            minutes,
        )
    except:
        return u'Z'
コード例 #22
0
def calculate_shorttimesince(d, now=None):
    """
    like django's built in timesince but abbreviates units
    """
    chunks = ((60 * 60 * 24 * 365, lambda n: ungettext('yr', 'yr', n)),
              (60 * 60 * 24 * 30, lambda n: ungettext('mn', 'mn', n)),
              (60 * 60 * 24 * 7, lambda n: ungettext('wk', 'wk', n)),
              (60 * 60 * 24, lambda n: ungettext('d', 'd', n)),
              (60 * 60, lambda n: ungettext('hr', 'hr', n)),
              (60, lambda n: ungettext('min', 'min', n)))
    # Convert datetime.date to datetime.datetime for comparison
    if d.__class__ is not datetime.datetime:
        d = datetime.datetime(d.year, d.month, d.day)
    if now:
        t = now.timetuple()
    else:
        t = time.localtime()
    if d.tzinfo:
        tz = LocalTimezone(d)
    else:
        tz = None
    now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz)

    # ignore microsecond part of 'd' since we removed it from 'now'
    delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
    since = delta.days * 24 * 60 * 60 + delta.seconds
    if since <= 0:
        # d is in the future compared to now, stop processing.
        return u'0' + ugettext('min')
    for i, (seconds, name) in enumerate(chunks):
        count = since // seconds
        if count != 0:
            break
    s = ugettext('%(number)d%(type)s') % {'number': count, 'type': name(count)}
    if i + 1 < len(chunks):
        # Now get the second item
        seconds2, name2 = chunks[i + 1]
        count2 = (since - (seconds * count)) // seconds2
        if count2 != 0:
            s += ugettext(', %(number)d%(type)s') % {
                'number': count2,
                'type': name2(count2)
            }
    return s
コード例 #23
0
ファイル: timesince.py プロジェクト: jonaustin/advisoryscan
def timesince(d, now=None):
    """
    Takes two datetime objects and returns the time between then and now
    as a nicely formatted string, e.g "10 minutes"
    Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
    """
    chunks = (
      (60 * 60 * 24 * 365, lambda n: ngettext('year', 'years', n)),
      (60 * 60 * 24 * 30, lambda n: ngettext('month', 'months', n)),
      (60 * 60 * 24 * 7, lambda n : ngettext('week', 'weeks', n)),
      (60 * 60 * 24, lambda n : ngettext('day', 'days', n)),
      (60 * 60, lambda n: ngettext('hour', 'hours', n)),
      (60, lambda n: ngettext('minute', 'minutes', n))
    )
    # Convert datetime.date to datetime.datetime for comparison
    if d.__class__ is not datetime.datetime:
        d = datetime.datetime(d.year, d.month, d.day)
    if now:
        t = now.timetuple()
    else:
        t = time.localtime()
    if d.tzinfo:
        tz = LocalTimezone(d)
    else:
        tz = None
    now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz)

    # ignore microsecond part of 'd' since we removed it from 'now'
    delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
    since = delta.days * 24 * 60 * 60 + delta.seconds
    for i, (seconds, name) in enumerate(chunks):
        count = since / seconds
        if count != 0:
            break
    if count < 0:
        return gettext('%d milliseconds') % math.floor((now - d).microseconds / 1000)
    s = gettext('%(number)d %(type)s') % {'number': count, 'type': name(count)}
    if i + 1 < len(chunks):
        # Now get the second item
        seconds2, name2 = chunks[i + 1]
        count2 = (since - (seconds * count)) / seconds2
        if count2 != 0:
            s += gettext(', %(number)d %(type)s') % {'number': count2, 'type': name2(count2)}
    return s
コード例 #24
0
def lbtimesince(d, now=None):
    # Convert datetime.date to datetime.datetime for comparison.
    if not d:
        return ''
    if not isinstance(d, datetime.datetime):
        d = datetime.datetime(d.year, d.month, d.day)
    if now and not isinstance(now, datetime.datetime):
        now = datetime.datetime(now.year, now.month, now.day)
    if not now:
        if d.tzinfo:
            now = datetime.datetime.now(LocalTimezone(d))
        else:
            now = datetime.datetime.now()
    # ignore microsecond part of 'd' since we removed it from 'now'
    delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
    since = delta.days * 24 * 60 * 60 + delta.seconds
    if since // (60 * 60 * 24) < 3:
        return _("%s ago") % _timesince(d)
    return _date(d, "Y-m-d H:i")
コード例 #25
0
 def test_deepcopy(self):
     now = datetime.datetime.now()
     self.assertIsInstance(copy.deepcopy(FixedOffset(90)), FixedOffset)
     self.assertIsInstance(copy.deepcopy(LocalTimezone(now)), LocalTimezone)
コード例 #26
0
def get_filter_tests():
    now = datetime.now()
    now_tz = datetime.now(LocalTimezone(now))
    now_tz_i = datetime.now(FixedOffset((3 * 60) + 15))  # imaginary time zone
    today = date.today()

    return {
        # Default compare with datetime.now()
        'filter-timesince01': ('{{ a|timesince }}', {
            'a':
            datetime.now() + timedelta(minutes=-1, seconds=-10)
        }, '1 minute'),
        'filter-timesince02': ('{{ a|timesince }}', {
            'a':
            datetime.now() - timedelta(days=1, minutes=1)
        }, '1 day'),
        'filter-timesince03': ('{{ a|timesince }}', {
            'a':
            datetime.now() - timedelta(hours=1, minutes=25, seconds=10)
        }, '1 hour, 25 minutes'),

        # Compare to a given parameter
        'filter-timesince04': ('{{ a|timesince:b }}', {
            'a': now - timedelta(days=2),
            'b': now - timedelta(days=1)
        }, '1 day'),
        'filter-timesince05': ('{{ a|timesince:b }}', {
            'a': now - timedelta(days=2, minutes=1),
            'b': now - timedelta(days=2)
        }, '1 minute'),

        # Check that timezone is respected
        'filter-timesince06': ('{{ a|timesince:b }}', {
            'a': now_tz - timedelta(hours=8),
            'b': now_tz
        }, '8 hours'),

        # Regression for #7443
        'filter-timesince07': ('{{ earlier|timesince }}', {
            'earlier': now - timedelta(days=7)
        }, '1 week'),
        'filter-timesince08': ('{{ earlier|timesince:now }}', {
            'now': now,
            'earlier': now - timedelta(days=7)
        }, '1 week'),
        'filter-timesince09': ('{{ later|timesince }}', {
            'later': now + timedelta(days=7)
        }, '0 minutes'),
        'filter-timesince10': ('{{ later|timesince:now }}', {
            'now': now,
            'later': now + timedelta(days=7)
        }, '0 minutes'),

        # Ensures that differing timezones are calculated correctly
        'filter-timesince11': ('{{ a|timesince }}', {
            'a': now
        }, '0 minutes'),
        'filter-timesince12': ('{{ a|timesince }}', {
            'a': now_tz
        }, '0 minutes'),
        'filter-timesince13': ('{{ a|timesince }}', {
            'a': now_tz_i
        }, '0 minutes'),
        'filter-timesince14': ('{{ a|timesince:b }}', {
            'a': now_tz,
            'b': now_tz_i
        }, '0 minutes'),
        'filter-timesince15': ('{{ a|timesince:b }}', {
            'a': now,
            'b': now_tz_i
        }, ''),
        'filter-timesince16': ('{{ a|timesince:b }}', {
            'a': now_tz_i,
            'b': now
        }, ''),

        # Regression for #9065 (two date objects).
        'filter-timesince17': ('{{ a|timesince:b }}', {
            'a': today,
            'b': today
        }, '0 minutes'),
        'filter-timesince18': ('{{ a|timesince:b }}', {
            'a': today,
            'b': today + timedelta(hours=24)
        }, '1 day'),

        # Default compare with datetime.now()
        'filter-timeuntil01': ('{{ a|timeuntil }}', {
            'a':
            datetime.now() + timedelta(minutes=2, seconds=10)
        }, '2 minutes'),
        'filter-timeuntil02': ('{{ a|timeuntil }}', {
            'a': (datetime.now() + timedelta(days=1, seconds=10))
        }, '1 day'),
        'filter-timeuntil03': ('{{ a|timeuntil }}', {
            'a': (datetime.now() + timedelta(hours=8, minutes=10, seconds=10))
        }, '8 hours, 10 minutes'),

        # Compare to a given parameter
        'filter-timeuntil04': ('{{ a|timeuntil:b }}', {
            'a': now - timedelta(days=1),
            'b': now - timedelta(days=2)
        }, '1 day'),
        'filter-timeuntil05': ('{{ a|timeuntil:b }}', {
            'a': now - timedelta(days=2),
            'b': now - timedelta(days=2, minutes=1)
        }, '1 minute'),

        # Regression for #7443
        'filter-timeuntil06': ('{{ earlier|timeuntil }}', {
            'earlier': now - timedelta(days=7)
        }, '0 minutes'),
        'filter-timeuntil07': ('{{ earlier|timeuntil:now }}', {
            'now': now,
            'earlier': now - timedelta(days=7)
        }, '0 minutes'),
        'filter-timeuntil08': ('{{ later|timeuntil }}', {
            'later': now + timedelta(days=7, hours=1)
        }, '1 week'),
        'filter-timeuntil09': ('{{ later|timeuntil:now }}', {
            'now': now,
            'later': now + timedelta(days=7)
        }, '1 week'),

        # Ensures that differing timezones are calculated correctly
        'filter-timeuntil10': ('{{ a|timeuntil }}', {
            'a': now_tz_i
        }, '0 minutes'),
        'filter-timeuntil11': ('{{ a|timeuntil:b }}', {
            'a': now_tz_i,
            'b': now_tz
        }, '0 minutes'),

        # Regression for #9065 (two date objects).
        'filter-timeuntil12': ('{{ a|timeuntil:b }}', {
            'a': today,
            'b': today
        }, '0 minutes'),
        'filter-timeuntil13': ('{{ a|timeuntil:b }}', {
            'a': today,
            'b': today - timedelta(hours=24)
        }, '1 day'),
        'filter-addslash01':
        ("{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}",
         {
             "a": "<a>'",
             "b": mark_safe("<a>'")
         }, ur"<a>\' <a>\'"),
        'filter-addslash02': ("{{ a|addslashes }} {{ b|addslashes }}", {
            "a": "<a>'",
            "b": mark_safe("<a>'")
        }, ur"&lt;a&gt;\&#39; <a>\'"),
        'filter-capfirst01':
        ("{% autoescape off %}{{ a|capfirst }} {{ b|capfirst }}{% endautoescape %}",
         {
             "a": "fred>",
             "b": mark_safe("fred&gt;")
         }, u"Fred> Fred&gt;"),
        'filter-capfirst02': ("{{ a|capfirst }} {{ b|capfirst }}", {
            "a": "fred>",
            "b": mark_safe("fred&gt;")
        }, u"Fred&gt; Fred&gt;"),

        # Note that applying fix_ampsersands in autoescape mode leads to
        # double escaping.
        'filter-fix_ampersands01':
        ("{% autoescape off %}{{ a|fix_ampersands }} {{ b|fix_ampersands }}{% endautoescape %}",
         {
             "a": "a&b",
             "b": mark_safe("a&b")
         }, u"a&amp;b a&amp;b"),
        'filter-fix_ampersands02':
        ("{{ a|fix_ampersands }} {{ b|fix_ampersands }}", {
            "a": "a&b",
            "b": mark_safe("a&b")
        }, u"a&amp;amp;b a&amp;b"),
        'filter-floatformat01':
        ("{% autoescape off %}{{ a|floatformat }} {{ b|floatformat }}{% endautoescape %}",
         {
             "a": "1.42",
             "b": mark_safe("1.42")
         }, u"1.4 1.4"),
        'filter-floatformat02': ("{{ a|floatformat }} {{ b|floatformat }}", {
            "a": "1.42",
            "b": mark_safe("1.42")
        }, u"1.4 1.4"),

        # The contents of "linenumbers" is escaped according to the current
        # autoescape setting.
        'filter-linenumbers01':
        ("{{ a|linenumbers }} {{ b|linenumbers }}",
         {
             "a": "one\n<two>\nthree",
             "b": mark_safe("one\n&lt;two&gt;\nthree")
         },
         u"1. one\n2. &lt;two&gt;\n3. three 1. one\n2. &lt;two&gt;\n3. three"),
        'filter-linenumbers02':
        ("{% autoescape off %}{{ a|linenumbers }} {{ b|linenumbers }}{% endautoescape %}",
         {
             "a": "one\n<two>\nthree",
             "b": mark_safe("one\n&lt;two&gt;\nthree")
         }, u"1. one\n2. <two>\n3. three 1. one\n2. &lt;two&gt;\n3. three"),
        'filter-lower01':
        ("{% autoescape off %}{{ a|lower }} {{ b|lower }}{% endautoescape %}",
         {
             "a": "Apple & banana",
             "b": mark_safe("Apple &amp; banana")
         }, u"apple & banana apple &amp; banana"),
        'filter-lower02': ("{{ a|lower }} {{ b|lower }}", {
            "a": "Apple & banana",
            "b": mark_safe("Apple &amp; banana")
        }, u"apple &amp; banana apple &amp; banana"),

        # The make_list filter can destroy existing escaping, so the results are
        # escaped.
        'filter-make_list01':
        ("{% autoescape off %}{{ a|make_list }}{% endautoescape %}", {
            "a": mark_safe("&")
        }, u"[u'&']"),
        'filter-make_list02': ("{{ a|make_list }}", {
            "a": mark_safe("&")
        }, u"[u&#39;&amp;&#39;]"),
        'filter-make_list03':
        ('{% autoescape off %}{{ a|make_list|stringformat:"s"|safe }}{% endautoescape %}',
         {
             "a": mark_safe("&")
         }, u"[u'&']"),
        'filter-make_list04': ('{{ a|make_list|stringformat:"s"|safe }}', {
            "a": mark_safe("&")
        }, u"[u'&']"),

        # Running slugify on a pre-escaped string leads to odd behavior,
        # but the result is still safe.
        'filter-slugify01':
        ("{% autoescape off %}{{ a|slugify }} {{ b|slugify }}{% endautoescape %}",
         {
             "a": "a & b",
             "b": mark_safe("a &amp; b")
         }, u"a-b a-amp-b"),
        'filter-slugify02': ("{{ a|slugify }} {{ b|slugify }}", {
            "a": "a & b",
            "b": mark_safe("a &amp; b")
        }, u"a-b a-amp-b"),

        # Notice that escaping is applied *after* any filters, so the string
        # formatting here only needs to deal with pre-escaped characters.
        'filter-stringformat01':
        ('{% autoescape off %}.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.{% endautoescape %}',
         {
             "a": "a<b",
             "b": mark_safe("a<b")
         }, u".  a<b. .  a<b."),
        'filter-stringformat02':
        ('.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.', {
            "a": "a<b",
            "b": mark_safe("a<b")
        }, u".  a&lt;b. .  a<b."),

        # Test the title filter
        'filter-title1': ('{{ a|title }}', {
            'a': 'JOE\'S CRAB SHACK'
        }, u'Joe&#39;s Crab Shack'),
        'filter-title2': ('{{ a|title }}', {
            'a': '555 WEST 53RD STREET'
        }, u'555 West 53rd Street'),
        'filter-truncatewords01':
        ('{% autoescape off %}{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}{% endautoescape %}',
         {
             "a": "alpha & bravo",
             "b": mark_safe("alpha &amp; bravo")
         }, u"alpha & ... alpha &amp; ..."),
        'filter-truncatewords02':
        ('{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}', {
            "a": "alpha & bravo",
            "b": mark_safe("alpha &amp; bravo")
        }, u"alpha &amp; ... alpha &amp; ..."),
        'filter-truncatechars01': ('{{ a|truncatechars:5 }}', {
            'a': "Testing, testing"
        }, u"Te..."),
        'filter-truncatechars02': ('{{ a|truncatechars:7 }}', {
            'a': "Testing"
        }, u"Testing"),

        # The "upper" filter messes up entities (which are case-sensitive),
        # so it's not safe for non-escaping purposes.
        'filter-upper01':
        ('{% autoescape off %}{{ a|upper }} {{ b|upper }}{% endautoescape %}',
         {
             "a": "a & b",
             "b": mark_safe("a &amp; b")
         }, u"A & B A &AMP; B"),
        'filter-upper02': ('{{ a|upper }} {{ b|upper }}', {
            "a": "a & b",
            "b": mark_safe("a &amp; b")
        }, u"A &amp; B A &amp;AMP; B"),
        'filter-urlize01':
        ('{% autoescape off %}{{ a|urlize }} {{ b|urlize }}{% endautoescape %}',
         {
             "a": "http://example.com/?x=&y=",
             "b": mark_safe("http://example.com?x=&amp;y=")
         },
         u'<a href="http://example.com/?x=&y=" rel="nofollow">http://example.com/?x=&y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>'
         ),
        'filter-urlize02':
        ('{{ a|urlize }} {{ b|urlize }}',
         {
             "a": "http://example.com/?x=&y=",
             "b": mark_safe("http://example.com?x=&amp;y=")
         },
         u'<a href="http://example.com/?x=&amp;y=" rel="nofollow">http://example.com/?x=&amp;y=</a> <a href="http://example.com?x=&amp;y=" rel="nofollow">http://example.com?x=&amp;y=</a>'
         ),
        'filter-urlize03':
        ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {
            "a": mark_safe("a &amp; b")
        }, 'a &amp; b'),
        'filter-urlize04': ('{{ a|urlize }}', {
            "a": mark_safe("a &amp; b")
        }, 'a &amp; b'),

        # This will lead to a nonsense result, but at least it won't be
        # exploitable for XSS purposes when auto-escaping is on.
        'filter-urlize05':
        ('{% autoescape off %}{{ a|urlize }}{% endautoescape %}', {
            "a": "<script>alert('foo')</script>"
        }, "<script>alert('foo')</script>"),
        'filter-urlize06': ('{{ a|urlize }}', {
            "a": "<script>alert('foo')</script>"
        }, '&lt;script&gt;alert(&#39;foo&#39;)&lt;/script&gt;'),

        # mailto: testing for urlize
        'filter-urlize07': ('{{ a|urlize }}', {
            "a": "Email me at [email protected]"
        }, 'Email me at <a href="mailto:[email protected]">[email protected]</a>'),
        'filter-urlize08':
        ('{{ a|urlize }}',
         {
             "a": "Email me at <*****@*****.**>"
         },
         'Email me at &lt;<a href="mailto:[email protected]">[email protected]</a>&gt;'
         ),
        'filter-urlizetrunc01':
        ('{% autoescape off %}{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}{% endautoescape %}',
         {
             "a": '"Unsafe" http://example.com/x=&y=',
             "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')
         },
         u'"Unsafe" <a href="http://example.com/x=&y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>'
         ),
        'filter-urlizetrunc02':
        ('{{ a|urlizetrunc:"8" }} {{ b|urlizetrunc:"8" }}', {
            "a": '"Unsafe" http://example.com/x=&y=',
            "b": mark_safe('&quot;Safe&quot; http://example.com?x=&amp;y=')
        },
         u'&quot;Unsafe&quot; <a href="http://example.com/x=&amp;y=" rel="nofollow">http:...</a> &quot;Safe&quot; <a href="http://example.com?x=&amp;y=" rel="nofollow">http:...</a>'
         ),
        'filter-wordcount01':
        ('{% autoescape off %}{{ a|wordcount }} {{ b|wordcount }}{% endautoescape %}',
         {
             "a": "a & b",
             "b": mark_safe("a &amp; b")
         }, "3 3"),
        'filter-wordcount02': ('{{ a|wordcount }} {{ b|wordcount }}', {
            "a": "a & b",
            "b": mark_safe("a &amp; b")
        }, "3 3"),
        'filter-wordwrap01':
        ('{% autoescape off %}{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}{% endautoescape %}',
         {
             "a": "a & b",
             "b": mark_safe("a & b")
         }, u"a &\nb a &\nb"),
        'filter-wordwrap02': ('{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}', {
            "a": "a & b",
            "b": mark_safe("a & b")
        }, u"a &amp;\nb a &\nb"),
        'filter-ljust01':
        ('{% autoescape off %}.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.{% endautoescape %}',
         {
             "a": "a&b",
             "b": mark_safe("a&b")
         }, u".a&b  . .a&b  ."),
        'filter-ljust02': ('.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.', {
            "a": "a&b",
            "b": mark_safe("a&b")
        }, u".a&amp;b  . .a&b  ."),
        'filter-rjust01':
        ('{% autoescape off %}.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.{% endautoescape %}',
         {
             "a": "a&b",
             "b": mark_safe("a&b")
         }, u".  a&b. .  a&b."),
        'filter-rjust02': ('.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.', {
            "a": "a&b",
            "b": mark_safe("a&b")
        }, u".  a&amp;b. .  a&b."),
        'filter-center01':
        ('{% autoescape off %}.{{ a|center:"5" }}. .{{ b|center:"5" }}.{% endautoescape %}',
         {
             "a": "a&b",
             "b": mark_safe("a&b")
         }, u". a&b . . a&b ."),
        'filter-center02': ('.{{ a|center:"5" }}. .{{ b|center:"5" }}.', {
            "a": "a&b",
            "b": mark_safe("a&b")
        }, u". a&amp;b . . a&b ."),
        'filter-cut01':
        ('{% autoescape off %}{{ a|cut:"x" }} {{ b|cut:"x" }}{% endautoescape %}',
         {
             "a": "x&y",
             "b": mark_safe("x&amp;y")
         }, u"&y &amp;y"),
        'filter-cut02': ('{{ a|cut:"x" }} {{ b|cut:"x" }}', {
            "a": "x&y",
            "b": mark_safe("x&amp;y")
        }, u"&amp;y &amp;y"),
        'filter-cut03':
        ('{% autoescape off %}{{ a|cut:"&" }} {{ b|cut:"&" }}{% endautoescape %}',
         {
             "a": "x&y",
             "b": mark_safe("x&amp;y")
         }, u"xy xamp;y"),
        'filter-cut04': ('{{ a|cut:"&" }} {{ b|cut:"&" }}', {
            "a": "x&y",
            "b": mark_safe("x&amp;y")
        }, u"xy xamp;y"),
        # Passing ';' to cut can break existing HTML entities, so those strings
        # are auto-escaped.
        'filter-cut05':
        ('{% autoescape off %}{{ a|cut:";" }} {{ b|cut:";" }}{% endautoescape %}',
         {
             "a": "x&y",
             "b": mark_safe("x&amp;y")
         }, u"x&y x&ampy"),
        'filter-cut06': ('{{ a|cut:";" }} {{ b|cut:";" }}', {
            "a": "x&y",
            "b": mark_safe("x&amp;y")
        }, u"x&amp;y x&amp;ampy"),

        # The "escape" filter works the same whether autoescape is on or off,
        # but it has no effect on strings already marked as safe.
        'filter-escape01': ('{{ a|escape }} {{ b|escape }}', {
            "a": "x&y",
            "b": mark_safe("x&y")
        }, u"x&amp;y x&y"),
        'filter-escape02':
        ('{% autoescape off %}{{ a|escape }} {{ b|escape }}{% endautoescape %}',
         {
             "a": "x&y",
             "b": mark_safe("x&y")
         }, "x&amp;y x&y"),

        # It is only applied once, regardless of the number of times it
        # appears in a chain.
        'filter-escape03':
        ('{% autoescape off %}{{ a|escape|escape }}{% endautoescape %}', {
            "a": "x&y"
        }, u"x&amp;y"),
        'filter-escape04': ('{{ a|escape|escape }}', {
            "a": "x&y"
        }, u"x&amp;y"),

        # Force_escape is applied immediately. It can be used to provide
        # double-escaping, for example.
        'filter-force-escape01':
        ('{% autoescape off %}{{ a|force_escape }}{% endautoescape %}', {
            "a": "x&y"
        }, u"x&amp;y"),
        'filter-force-escape02': ('{{ a|force_escape }}', {
            "a": "x&y"
        }, u"x&amp;y"),
        'filter-force-escape03':
        ('{% autoescape off %}{{ a|force_escape|force_escape }}{% endautoescape %}',
         {
             "a": "x&y"
         }, u"x&amp;amp;y"),
        'filter-force-escape04': ('{{ a|force_escape|force_escape }}', {
            "a": "x&y"
        }, u"x&amp;amp;y"),

        # Because the result of force_escape is "safe", an additional
        # escape filter has no effect.
        'filter-force-escape05':
        ('{% autoescape off %}{{ a|force_escape|escape }}{% endautoescape %}',
         {
             "a": "x&y"
         }, u"x&amp;y"),
        'filter-force-escape06': ('{{ a|force_escape|escape }}', {
            "a": "x&y"
        }, u"x&amp;y"),
        'filter-force-escape07':
        ('{% autoescape off %}{{ a|escape|force_escape }}{% endautoescape %}',
         {
             "a": "x&y"
         }, u"x&amp;y"),
        'filter-force-escape08': ('{{ a|escape|force_escape }}', {
            "a": "x&y"
        }, u"x&amp;y"),

        # The contents in "linebreaks" and "linebreaksbr" are escaped
        # according to the current autoescape setting.
        'filter-linebreaks01': ('{{ a|linebreaks }} {{ b|linebreaks }}', {
            "a": "x&\ny",
            "b": mark_safe("x&\ny")
        }, u"<p>x&amp;<br />y</p> <p>x&<br />y</p>"),
        'filter-linebreaks02':
        ('{% autoescape off %}{{ a|linebreaks }} {{ b|linebreaks }}{% endautoescape %}',
         {
             "a": "x&\ny",
             "b": mark_safe("x&\ny")
         }, u"<p>x&<br />y</p> <p>x&<br />y</p>"),
        'filter-linebreaksbr01': ('{{ a|linebreaksbr }} {{ b|linebreaksbr }}',
                                  {
                                      "a": "x&\ny",
                                      "b": mark_safe("x&\ny")
                                  }, u"x&amp;<br />y x&<br />y"),
        'filter-linebreaksbr02':
        ('{% autoescape off %}{{ a|linebreaksbr }} {{ b|linebreaksbr }}{% endautoescape %}',
         {
             "a": "x&\ny",
             "b": mark_safe("x&\ny")
         }, u"x&<br />y x&<br />y"),
        'filter-safe01': ("{{ a }} -- {{ a|safe }}", {
            "a": u"<b>hello</b>"
        }, "&lt;b&gt;hello&lt;/b&gt; -- <b>hello</b>"),
        'filter-safe02':
        ("{% autoescape off %}{{ a }} -- {{ a|safe }}{% endautoescape %}", {
            "a": "<b>hello</b>"
        }, u"<b>hello</b> -- <b>hello</b>"),
        'filter-safeseq01': ('{{ a|join:", " }} -- {{ a|safeseq|join:", " }}',
                             {
                                 "a": ["&", "<"]
                             }, "&amp;, &lt; -- &, <"),
        'filter-safeseq02':
        ('{% autoescape off %}{{ a|join:", " }} -- {{ a|safeseq|join:", " }}{% endautoescape %}',
         {
             "a": ["&", "<"]
         }, "&, < -- &, <"),
        'filter-removetags01':
        ('{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}', {
            "a": "<a>x</a> <p><b>y</b></p>",
            "b": mark_safe("<a>x</a> <p><b>y</b></p>")
        }, u"x &lt;p&gt;y&lt;/p&gt; x <p>y</p>"),
        'filter-removetags02':
        ('{% autoescape off %}{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}{% endautoescape %}',
         {
             "a": "<a>x</a> <p><b>y</b></p>",
             "b": mark_safe("<a>x</a> <p><b>y</b></p>")
         }, u"x <p>y</p> x <p>y</p>"),
        'filter-striptags01': ('{{ a|striptags }} {{ b|striptags }}', {
            "a": "<a>x</a> <p><b>y</b></p>",
            "b": mark_safe("<a>x</a> <p><b>y</b></p>")
        }, "x y x y"),
        'filter-striptags02':
        ('{% autoescape off %}{{ a|striptags }} {{ b|striptags }}{% endautoescape %}',
         {
             "a": "<a>x</a> <p><b>y</b></p>",
             "b": mark_safe("<a>x</a> <p><b>y</b></p>")
         }, "x y x y"),
        'filter-first01': ('{{ a|first }} {{ b|first }}', {
            "a": ["a&b", "x"],
            "b": [mark_safe("a&b"), "x"]
        }, "a&amp;b a&b"),
        'filter-first02':
        ('{% autoescape off %}{{ a|first }} {{ b|first }}{% endautoescape %}',
         {
             "a": ["a&b", "x"],
             "b": [mark_safe("a&b"), "x"]
         }, "a&b a&b"),
        'filter-last01': ('{{ a|last }} {{ b|last }}', {
            "a": ["x", "a&b"],
            "b": ["x", mark_safe("a&b")]
        }, "a&amp;b a&b"),
        'filter-last02':
        ('{% autoescape off %}{{ a|last }} {{ b|last }}{% endautoescape %}', {
            "a": ["x", "a&b"],
            "b": ["x", mark_safe("a&b")]
        }, "a&b a&b"),
        'filter-random01': ('{{ a|random }} {{ b|random }}', {
            "a": ["a&b", "a&b"],
            "b": [mark_safe("a&b"), mark_safe("a&b")]
        }, "a&amp;b a&b"),
        'filter-random02':
        ('{% autoescape off %}{{ a|random }} {{ b|random }}{% endautoescape %}',
         {
             "a": ["a&b", "a&b"],
             "b": [mark_safe("a&b"), mark_safe("a&b")]
         }, "a&b a&b"),
        'filter-slice01': ('{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}', {
            "a": "a&b",
            "b": mark_safe("a&b")
        }, "&amp;b &b"),
        'filter-slice02':
        ('{% autoescape off %}{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}{% endautoescape %}',
         {
             "a": "a&b",
             "b": mark_safe("a&b")
         }, "&b &b"),
        'filter-unordered_list01': ('{{ a|unordered_list }}', {
            "a": ["x>", [["<y", []]]]
        }, "\t<li>x&gt;\n\t<ul>\n\t\t<li>&lt;y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list02': (
            '{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {
                "a": ["x>", [["<y", []]]]
            }, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list03': ('{{ a|unordered_list }}', {
            "a": ["x>", [[mark_safe("<y"), []]]]
        }, "\t<li>x&gt;\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list04': (
            '{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {
                "a": ["x>", [[mark_safe("<y"), []]]]
            }, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
        'filter-unordered_list05': (
            '{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {
                "a": ["x>", [["<y", []]]]
            }, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),

        # Literal string arguments to the default filter are always treated as
        # safe strings, regardless of the auto-escaping state.
        #
        # Note: we have to use {"a": ""} here, otherwise the invalid template
        # variable string interferes with the test result.
        'filter-default01': ('{{ a|default:"x<" }}', {
            "a": ""
        }, "x<"),
        'filter-default02': (
            '{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {
                "a": ""
            }, "x<"),
        'filter-default03': ('{{ a|default:"x<" }}', {
            "a": mark_safe("x>")
        }, "x>"),
        'filter-default04': (
            '{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {
                "a": mark_safe("x>")
            }, "x>"),
        'filter-default_if_none01': ('{{ a|default:"x<" }}', {
            "a": None
        }, "x<"),
        'filter-default_if_none02': (
            '{% autoescape off %}{{ a|default:"x<" }}{% endautoescape %}', {
                "a": None
            }, "x<"),
        'filter-phone2numeric01': (
            '{{ a|phone2numeric }} {{ b|phone2numeric }}', {
                "a": "<1-800-call-me>",
                "b": mark_safe("<1-800-call-me>")
            }, "&lt;1-800-2255-63&gt; <1-800-2255-63>"),
        'filter-phone2numeric02':
        ('{% autoescape off %}{{ a|phone2numeric }} {{ b|phone2numeric }}{% endautoescape %}',
         {
             "a": "<1-800-call-me>",
             "b": mark_safe("<1-800-call-me>")
         }, "<1-800-2255-63> <1-800-2255-63>"),
        'filter-phone2numeric03': ('{{ a|phone2numeric }}', {
            "a":
            "How razorback-jumping frogs can level six piqued gymnasts!"
        }, "469 729672225-5867464 37647 226 53835 749 747833 49662787!"),

        # Ensure iriencode keeps safe strings:
        'filter-iriencode01': ('{{ url|iriencode }}', {
            'url': '?test=1&me=2'
        }, '?test=1&amp;me=2'),
        'filter-iriencode02': (
            '{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {
                'url': '?test=1&me=2'
            }, '?test=1&me=2'),
        'filter-iriencode03': ('{{ url|iriencode }}', {
            'url': mark_safe('?test=1&me=2')
        }, '?test=1&me=2'),
        'filter-iriencode04': (
            '{% autoescape off %}{{ url|iriencode }}{% endautoescape %}', {
                'url': mark_safe('?test=1&me=2')
            }, '?test=1&me=2'),

        # urlencode
        'filter-urlencode01': ('{{ url|urlencode }}', {
            'url': '/test&"/me?/'
        }, '/test%26%22/me%3F/'),
        'filter-urlencode02': ('/test/{{ urlbit|urlencode:"" }}/', {
            'urlbit': 'escape/slash'
        }, '/test/escape%2Fslash/'),

        # Chaining a bunch of safeness-preserving filters should not alter
        # the safe status either way.
        'chaining01': (
            '{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}', {
                "a": "a < b",
                "b": mark_safe("a < b")
            }, " A &lt; b . A < b "),
        'chaining02':
        ('{% autoescape off %}{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}{% endautoescape %}',
         {
             "a": "a < b",
             "b": mark_safe("a < b")
         }, " A < b . A < b "),

        # Using a filter that forces a string back to unsafe:
        'chaining03': ('{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}', {
            "a": "a < b",
            "b": mark_safe("a < b")
        }, "A &lt; .A < "),
        'chaining04':
        ('{% autoescape off %}{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}{% endautoescape %}',
         {
             "a": "a < b",
             "b": mark_safe("a < b")
         }, "A < .A < "),

        # Using a filter that forces safeness does not lead to double-escaping
        'chaining05': ('{{ a|escape|capfirst }}', {
            "a": "a < b"
        }, "A &lt; b"),
        'chaining06': (
            '{% autoescape off %}{{ a|escape|capfirst }}{% endautoescape %}', {
                "a": "a < b"
            }, "A &lt; b"),

        # Force to safe, then back (also showing why using force_escape too
        # early in a chain can lead to unexpected results).
        'chaining07': ('{{ a|force_escape|cut:";" }}', {
            "a": "a < b"
        }, "a &amp;lt b"),
        'chaining08':
        ('{% autoescape off %}{{ a|force_escape|cut:";" }}{% endautoescape %}',
         {
             "a": "a < b"
         }, "a &lt b"),
        'chaining09': ('{{ a|cut:";"|force_escape }}', {
            "a": "a < b"
        }, "a &lt; b"),
        'chaining10':
        ('{% autoescape off %}{{ a|cut:";"|force_escape }}{% endautoescape %}',
         {
             "a": "a < b"
         }, "a &lt; b"),
        'chaining11': ('{{ a|cut:"b"|safe }}', {
            "a": "a < b"
        }, "a < "),
        'chaining12': (
            '{% autoescape off %}{{ a|cut:"b"|safe }}{% endautoescape %}', {
                "a": "a < b"
            }, "a < "),
        'chaining13': ('{{ a|safe|force_escape }}', {
            "a": "a < b"
        }, "a &lt; b"),
        'chaining14': (
            '{% autoescape off %}{{ a|safe|force_escape }}{% endautoescape %}',
            {
                "a": "a < b"
            }, "a &lt; b"),

        # Filters decorated with stringfilter still respect is_safe.
        'autoescape-stringfilter01': (r'{{ unsafe|capfirst }}', {
            'unsafe': UnsafeClass()
        }, 'You &amp; me'),
        'autoescape-stringfilter02': (
            r'{% autoescape off %}{{ unsafe|capfirst }}{% endautoescape %}', {
                'unsafe': UnsafeClass()
            }, 'You & me'),
        'autoescape-stringfilter03': (r'{{ safe|capfirst }}', {
            'safe': SafeClass()
        }, 'You &gt; me'),
        'autoescape-stringfilter04': (
            r'{% autoescape off %}{{ safe|capfirst }}{% endautoescape %}', {
                'safe': SafeClass()
            }, 'You &gt; me'),
        'escapejs01':
        (r'{{ a|escapejs }}',
         {
             'a': 'testing\r\njavascript \'string" <b>escaping</b>'
         },
         'testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E'
         ),
        'escapejs02':
        (r'{% autoescape off %}{{ a|escapejs }}{% endautoescape %}', {
            'a': 'testing\r\njavascript \'string" <b>escaping</b>'
        },
         'testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E'
         ),

        # length filter.
        'length01': ('{{ list|length }}', {
            'list': ['4', None, True, {}]
        }, '4'),
        'length02': ('{{ list|length }}', {
            'list': []
        }, '0'),
        'length03': ('{{ string|length }}', {
            'string': ''
        }, '0'),
        'length04': ('{{ string|length }}', {
            'string': 'django'
        }, '6'),
        # Invalid uses that should fail silently.
        'length05': ('{{ int|length }}', {
            'int': 7
        }, ''),
        'length06': ('{{ None|length }}', {
            'None': None
        }, ''),

        # length_is filter.
        'length_is01': ('{% if some_list|length_is:"4" %}Four{% endif %}', {
            'some_list': ['4', None, True, {}]
        }, 'Four'),
        'length_is02':
        ('{% if some_list|length_is:"4" %}Four{% else %}Not Four{% endif %}', {
            'some_list': ['4', None, True, {}, 17]
        }, 'Not Four'),
        'length_is03': ('{% if mystring|length_is:"4" %}Four{% endif %}', {
            'mystring': 'word'
        }, 'Four'),
        'length_is04': (
            '{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}',
            {
                'mystring': 'Python'
            }, 'Not Four'),
        'length_is05': (
            '{% if mystring|length_is:"4" %}Four{% else %}Not Four{% endif %}',
            {
                'mystring': ''
            }, 'Not Four'),
        'length_is06': (
            '{% with var|length as my_length %}{{ my_length }}{% endwith %}', {
                'var': 'django'
            }, '6'),
        # Boolean return value from length_is should not be coerced to a string
        'length_is07':
        (r'{% if "X"|length_is:0 %}Length is 0{% else %}Length not 0{% endif %}',
         {}, 'Length not 0'),
        'length_is08':
        (r'{% if "X"|length_is:1 %}Length is 1{% else %}Length not 1{% endif %}',
         {}, 'Length is 1'),
        # Invalid uses that should fail silently.
        'length_is09': ('{{ var|length_is:"fish" }}', {
            'var': 'django'
        }, ''),
        'length_is10': ('{{ int|length_is:"1" }}', {
            'int': 7
        }, ''),
        'length_is11': ('{{ none|length_is:"1" }}', {
            'none': None
        }, ''),
        'join01': (r'{{ a|join:", " }}', {
            'a': ['alpha', 'beta & me']
        }, 'alpha, beta &amp; me'),
        'join02': (r'{% autoescape off %}{{ a|join:", " }}{% endautoescape %}',
                   {
                       'a': ['alpha', 'beta & me']
                   }, 'alpha, beta & me'),
        'join03': (r'{{ a|join:" &amp; " }}', {
            'a': ['alpha', 'beta & me']
        }, 'alpha &amp; beta &amp; me'),
        'join04': (
            r'{% autoescape off %}{{ a|join:" &amp; " }}{% endautoescape %}', {
                'a': ['alpha', 'beta & me']
            }, 'alpha &amp; beta & me'),

        # Test that joining with unsafe joiners don't result in unsafe strings (#11377)
        'join05': (r'{{ a|join:var }}', {
            'a': ['alpha', 'beta & me'],
            'var': ' & '
        }, 'alpha &amp; beta &amp; me'),
        'join06': (r'{{ a|join:var }}', {
            'a': ['alpha', 'beta & me'],
            'var': mark_safe(' & ')
        }, 'alpha & beta &amp; me'),
        'join07': (r'{{ a|join:var|lower }}', {
            'a': ['Alpha', 'Beta & me'],
            'var': ' & '
        }, 'alpha &amp; beta &amp; me'),
        'join08': (r'{{ a|join:var|lower }}', {
            'a': ['Alpha', 'Beta & me'],
            'var': mark_safe(' & ')
        }, 'alpha & beta &amp; me'),
        'date01': (r'{{ d|date:"m" }}', {
            'd': datetime(2008, 1, 1)
        }, '01'),
        'date02': (r'{{ d|date }}', {
            'd': datetime(2008, 1, 1)
        }, 'Jan. 1, 2008'),
        #Ticket 9520: Make sure |date doesn't blow up on non-dates
        'date03': (r'{{ d|date:"m" }}', {
            'd': 'fail_string'
        }, ''),
        # ISO date formats
        'date04': (r'{{ d|date:"o" }}', {
            'd': datetime(2008, 12, 29)
        }, '2009'),
        'date05': (r'{{ d|date:"o" }}', {
            'd': datetime(2010, 1, 3)
        }, '2009'),
        # Timezone name
        'date06': (r'{{ d|date:"e" }}', {
            'd': datetime(2009, 3, 12, tzinfo=FixedOffset(30))
        }, '+0030'),
        'date07': (r'{{ d|date:"e" }}', {
            'd': datetime(2009, 3, 12)
        }, ''),

        # Tests for #11687 and #16676
        'add01': (r'{{ i|add:"5" }}', {
            'i': 2000
        }, '2005'),
        'add02': (r'{{ i|add:"napis" }}', {
            'i': 2000
        }, ''),
        'add03': (r'{{ i|add:16 }}', {
            'i': 'not_an_int'
        }, ''),
        'add04': (r'{{ i|add:"16" }}', {
            'i': 'not_an_int'
        }, 'not_an_int16'),
        'add05': (r'{{ l1|add:l2 }}', {
            'l1': [1, 2],
            'l2': [3, 4]
        }, '[1, 2, 3, 4]'),
        'add06': (r'{{ t1|add:t2 }}', {
            't1': (3, 4),
            't2': (1, 2)
        }, '(3, 4, 1, 2)'),
        'add07': (r'{{ d|add:t }}', {
            'd': date(2000, 1, 1),
            't': timedelta(10)
        }, 'Jan. 11, 2000'),
    }
コード例 #27
0
ファイル: dateformat.py プロジェクト: bramd/django-podcast
class DateFormat(TimeFormat):
    year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]

    def __init__(self, dt):
        # Accepts either a datetime or date object.
        self.data = dt
        self.timezone = getattr(dt, 'tzinfo', None)
        if hasattr(self.data, 'hour') and not self.timezone:
            self.timezone = LocalTimezone(dt)

    def b(self):
        "Month, textual, 3 letters, lowercase; e.g. 'jan'"
        return MONTHS_3[self.data.month]

    def d(self):
        "Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
        return u'%02d' % self.data.day

    def D(self):
        "Day of the week, textual, 3 letters; e.g. 'Fri'"
        return WEEKDAYS_ABBR[self.data.weekday()]

    def F(self):
        "Month, textual, long; e.g. 'January'"
        return MONTHS[self.data.month]

    def I(self):
        "'1' if Daylight Savings Time, '0' otherwise."
        if self.timezone and self.timezone.dst(self.data):
            return u'1'
        else:
            return u'0'

    def j(self):
        "Day of the month without leading zeros; i.e. '1' to '31'"
        return self.data.day

    def l(self):
        "Day of the week, textual, long; e.g. 'Friday'"
        return WEEKDAYS[self.data.weekday()]

    def L(self):
        "Boolean for whether it is a leap year; i.e. True or False"
        return calendar.isleap(self.data.year)

    def m(self):
        "Month; i.e. '01' to '12'"
        return u'%02d' % self.data.month

    def M(self):
        "Month, textual, 3 letters; e.g. 'Jan'"
        return MONTHS_3[self.data.month].title()

    def n(self):
        "Month without leading zeros; i.e. '1' to '12'"
        return self.data.month

    def N(self):
        "Month abbreviation in Associated Press style. Proprietary extension."
        return MONTHS_AP[self.data.month]

    def O(self):
        "Difference to Greenwich time in hours; e.g. '+0200'"
        seconds = self.Z()
        return u"%+03d%02d" % (seconds // 3600, (seconds // 60) % 60)

    def r(self):
        "RFC 2822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
        timestamp = time.mktime(self.data.timetuple())
        return formatdate(timestamp, True)

    def S(self):
        "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
            return u'th'
        last = self.data.day % 10
        if last == 1:
            return u'st'
        if last == 2:
            return u'nd'
        if last == 3:
            return u'rd'
        return u'th'

    def t(self):
        "Number of days in the given month; i.e. '28' to '31'"
        return u'%02d' % calendar.monthrange(self.data.year, self.data.month)[1]

    def T(self):
        "Time zone of this machine; e.g. 'EST' or 'MDT'"
        name = self.timezone and self.timezone.tzname(self.data) or None
        if name is None:
            name = self.format('O')
        return unicode(name)

    def U(self):
        "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
        if getattr(self.data, 'tzinfo', None):
            return int(calendar.timegm(self.data.utctimetuple()))
        else:
            return int(time.mktime(self.data.timetuple()))

    def w(self):
        "Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)"
        return (self.data.weekday() + 1) % 7

    def W(self):
        "ISO-8601 week number of year, weeks starting on Monday"
        # Algorithm from http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt
        week_number = None
        jan1_weekday = self.data.replace(month=1, day=1).weekday() + 1
        weekday = self.data.weekday() + 1
        day_of_year = self.z()
        if day_of_year <= (8 - jan1_weekday) and jan1_weekday > 4:
            if jan1_weekday == 5 or (jan1_weekday == 6 and calendar.isleap(self.data.year-1)):
                week_number = 53
            else:
                week_number = 52
        else:
            if calendar.isleap(self.data.year):
                i = 366
            else:
                i = 365
            if (i - day_of_year) < (4 - weekday):
                week_number = 1
            else:
                j = day_of_year + (7 - weekday) + (jan1_weekday - 1)
                week_number = j // 7
                if jan1_weekday > 4:
                    week_number -= 1
        return week_number

    def y(self):
        "Year, 2 digits; e.g. '99'"
        return unicode(self.data.year)[2:]

    def Y(self):
        "Year, 4 digits; e.g. '1999'"
        return self.data.year

    def z(self):
        "Day of the year; i.e. '0' to '365'"
        doy = self.year_days[self.data.month] + self.data.day
        if self.L() and self.data.month > 2:
            doy += 1
        return doy

    def Z(self):
        """
        Time zone offset in seconds (i.e. '-43200' to '43200'). The offset for
        timezones west of UTC is always negative, and for those east of UTC is
        always positive.
        """
        if not self.timezone:
            return 0
        offset = self.timezone.utcoffset(self.data)
        # Only days can be negative, so negative offsets have days=-1 and
        # seconds positive. Positive offsets have days=0
        return offset.days * 86400 + offset.seconds
コード例 #28
0
    def test_templates(self):
        # NOW and NOW_tz are used by timesince tag tests.
        NOW = datetime.now()
        NOW_tz = datetime.now(LocalTimezone(datetime.now()))

        # SYNTAX --
        # 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class)
        TEMPLATE_TESTS = {

            ### BASIC SYNTAX ##########################################################

            # Plain text should go through the template parser untouched
            'basic-syntax01': ("something cool", {}, "something cool"),

            # Variables should be replaced with their value in the current context
            'basic-syntax02': ("{{ headline }}", {'headline':'Success'}, "Success"),

            # More than one replacement variable is allowed in a template
            'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"),

            # Fail silently when a variable is not found in the current context
            'basic-syntax04': ("as{{ missing }}df", {}, ("asdf","asINVALIDdf")),

            # A variable may not contain more than one word
            'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError),

            # Raise TemplateSyntaxError for empty variable tags
            'basic-syntax07': ("{{ }}",        {}, template.TemplateSyntaxError),
            'basic-syntax08': ("{{        }}", {}, template.TemplateSyntaxError),

            # Attribute syntax allows a template to call an object's attribute
            'basic-syntax09': ("{{ var.method }}", {"var": SomeClass()}, "SomeClass.method"),

            # Multiple levels of attribute access are allowed
            'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"),

            # Fail silently when a variable's attribute isn't found
            'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, ("","INVALID")),

            # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
            'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError),

            # Raise TemplateSyntaxError when trying to access a variable containing an illegal character
            'basic-syntax13': ("{{ va>r }}", {}, template.TemplateSyntaxError),
            'basic-syntax14': ("{{ (var.r) }}", {}, template.TemplateSyntaxError),
            'basic-syntax15': ("{{ sp%am }}", {}, template.TemplateSyntaxError),
            'basic-syntax16': ("{{ eggs! }}", {}, template.TemplateSyntaxError),
            'basic-syntax17': ("{{ moo? }}", {}, template.TemplateSyntaxError),

            # Attribute syntax allows a template to call a dictionary key's value
            'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"),

            # Fail silently when a variable's dictionary key isn't found
            'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, ("","INVALID")),

            # Fail silently when accessing a non-simple method
            'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ("","INVALID")),

            # Don't get confused when parsing something that is almost, but not
            # quite, a template tag.
            'basic-syntax21': ("a {{ moo %} b", {}, "a {{ moo %} b"),
            'basic-syntax22': ("{{ moo #}", {}, "{{ moo #}"),

            # Will try to treat "moo #} {{ cow" as the variable. Not ideal, but
            # costly to work around, so this triggers an error.
            'basic-syntax23': ("{{ moo #} {{ cow }}", {"cow": "cow"}, template.TemplateSyntaxError),

            # Embedded newlines make it not-a-tag.
            'basic-syntax24': ("{{ moo\n }}", {}, "{{ moo\n }}"),

            # List-index syntax allows a template to access a certain item of a subscriptable object.
            'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"),

            # Fail silently when the list index is out of range.
            'list-index02': ("{{ var.5 }}", {"var": ["first item", "second item"]}, ("", "INVALID")),

            # Fail silently when the variable is not a subscriptable object.
            'list-index03': ("{{ var.1 }}", {"var": None}, ("", "INVALID")),

            # Fail silently when variable is a dict without the specified key.
            'list-index04': ("{{ var.1 }}", {"var": {}}, ("", "INVALID")),

            # Dictionary lookup wins out when dict's key is a string.
            'list-index05': ("{{ var.1 }}", {"var": {'1': "hello"}}, "hello"),

            # But list-index lookup wins out when dict's key is an int, which
            # behind the scenes is really a dictionary lookup (for a dict)
            # after converting the key to an int.
            'list-index06': ("{{ var.1 }}", {"var": {1: "hello"}}, "hello"),

            # Dictionary lookup wins out when there is a string and int version of the key.
            'list-index07': ("{{ var.1 }}", {"var": {'1': "hello", 1: "world"}}, "hello"),

            # Basic filter usage
            'filter-syntax01': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"),

            # Chained filters
            'filter-syntax02': ("{{ var|upper|lower }}", {"var": "Django is the greatest!"}, "django is the greatest!"),

            # Raise TemplateSyntaxError for space between a variable and filter pipe
            'filter-syntax03': ("{{ var |upper }}", {}, template.TemplateSyntaxError),

            # Raise TemplateSyntaxError for space after a filter pipe
            'filter-syntax04': ("{{ var| upper }}", {}, template.TemplateSyntaxError),

            # Raise TemplateSyntaxError for a nonexistent filter
            'filter-syntax05': ("{{ var|does_not_exist }}", {}, template.TemplateSyntaxError),

            # Raise TemplateSyntaxError when trying to access a filter containing an illegal character
            'filter-syntax06': ("{{ var|fil(ter) }}", {}, template.TemplateSyntaxError),

            # Raise TemplateSyntaxError for invalid block tags
            'filter-syntax07': ("{% nothing_to_see_here %}", {}, template.TemplateSyntaxError),

            # Raise TemplateSyntaxError for empty block tags
            'filter-syntax08': ("{% %}", {}, template.TemplateSyntaxError),

            # Chained filters, with an argument to the first one
            'filter-syntax09': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "<b><i>Yes</i></b>"}, "yes"),

            # Escaped string as argument
            'filter-syntax10': (r'{{ var|default_if_none:" endquote\" hah" }}', {"var": None}, ' endquote" hah'),

            # Variable as argument
            'filter-syntax11': (r'{{ var|default_if_none:var2 }}', {"var": None, "var2": "happy"}, 'happy'),

            # Default argument testing
            'filter-syntax12': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'),

            # Fail silently for methods that raise an exception with a
            # "silent_variable_failure" attribute
            'filter-syntax13': (r'1{{ var.method3 }}2', {"var": SomeClass()}, ("12", "1INVALID2")),

            # In methods that raise an exception without a
            # "silent_variable_attribute" set to True, the exception propagates
            'filter-syntax14': (r'1{{ var.method4 }}2', {"var": SomeClass()}, SomeOtherException),

            # Escaped backslash in argument
            'filter-syntax15': (r'{{ var|default_if_none:"foo\bar" }}', {"var": None}, r'foo\bar'),

            # Escaped backslash using known escape char
            'filter-syntax16': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'),

            # Empty strings can be passed as arguments to filters
            'filter-syntax17': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'),

            # If a variable has a __str__() that returns a Unicode object, the
            # value will be converted to a bytestring.
            'filter-syntax18': (r'{{ var }}', {'var': UnicodeInStrClass()}, '\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91'),

            ### COMMENT SYNTAX ########################################################
            'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"),
            'comment-syntax02': ("{# this is hidden #}hello{# foo #}", {}, "hello"),

            # Comments can contain invalid stuff.
            'comment-syntax03': ("foo{#  {% if %}  #}", {}, "foo"),
            'comment-syntax04': ("foo{#  {% endblock %}  #}", {}, "foo"),
            'comment-syntax05': ("foo{#  {% somerandomtag %}  #}", {}, "foo"),
            'comment-syntax06': ("foo{# {% #}", {}, "foo"),
            'comment-syntax07': ("foo{# %} #}", {}, "foo"),
            'comment-syntax08': ("foo{# %} #}bar", {}, "foobar"),
            'comment-syntax09': ("foo{# {{ #}", {}, "foo"),
            'comment-syntax10': ("foo{# }} #}", {}, "foo"),
            'comment-syntax11': ("foo{# { #}", {}, "foo"),
            'comment-syntax12': ("foo{# } #}", {}, "foo"),

            ### COMMENT TAG ###########################################################
            'comment-tag01': ("{% comment %}this is hidden{% endcomment %}hello", {}, "hello"),
            'comment-tag02': ("{% comment %}this is hidden{% endcomment %}hello{% comment %}foo{% endcomment %}", {}, "hello"),

            # Comment tag can contain invalid stuff.
            'comment-tag03': ("foo{% comment %} {% if %} {% endcomment %}", {}, "foo"),
            'comment-tag04': ("foo{% comment %} {% endblock %} {% endcomment %}", {}, "foo"),
            'comment-tag05': ("foo{% comment %} {% somerandomtag %} {% endcomment %}", {}, "foo"),

            ### CYCLE TAG #############################################################
            'cycle01': ('{% cycle a %}', {}, template.TemplateSyntaxError),
            'cycle02': ('{% cycle a,b,c as abc %}{% cycle abc %}', {}, 'ab'),
            'cycle03': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}', {}, 'abc'),
            'cycle04': ('{% cycle a,b,c as abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}', {}, 'abca'),
            'cycle05': ('{% cycle %}', {}, template.TemplateSyntaxError),
            'cycle06': ('{% cycle a %}', {}, template.TemplateSyntaxError),
            'cycle07': ('{% cycle a,b,c as foo %}{% cycle bar %}', {}, template.TemplateSyntaxError),
            'cycle08': ('{% cycle a,b,c as foo %}{% cycle foo %}{{ foo }}{{ foo }}{% cycle foo %}{{ foo }}', {}, 'abbbcc'),

            ### EXCEPTIONS ############################################################

            # Raise exception for invalid template name
            'exception01': ("{% extends 'nonexistent' %}", {}, template.TemplateSyntaxError),

            # Raise exception for invalid template name (in variable)
            'exception02': ("{% extends nonexistent %}", {}, template.TemplateSyntaxError),

            # Raise exception for extra {% extends %} tags
            'exception03': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% extends 'inheritance16' %}", {}, template.TemplateSyntaxError),

            # Raise exception for custom tags used in child with {% load %} tag in parent, not in child
            'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError),

            ### FILTER TAG ############################################################
            'filter01': ('{% filter upper %}{% endfilter %}', {}, ''),
            'filter02': ('{% filter upper %}django{% endfilter %}', {}, 'DJANGO'),
            'filter03': ('{% filter upper|lower %}django{% endfilter %}', {}, 'django'),
            'filter04': ('{% filter cut:remove %}djangospam{% endfilter %}', {'remove': 'spam'}, 'django'),

            ### FIRSTOF TAG ###########################################################
            'firstof01': ('{% firstof a b c %}', {'a':0,'b':0,'c':0}, ''),
            'firstof02': ('{% firstof a b c %}', {'a':1,'b':0,'c':0}, '1'),
            'firstof03': ('{% firstof a b c %}', {'a':0,'b':2,'c':0}, '2'),
            'firstof04': ('{% firstof a b c %}', {'a':0,'b':0,'c':3}, '3'),
            'firstof05': ('{% firstof a b c %}', {'a':1,'b':2,'c':3}, '1'),
            'firstof06': ('{% firstof %}', {}, template.TemplateSyntaxError),

            ### FOR TAG ###############################################################
            'for-tag01': ("{% for val in values %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "123"),
            'for-tag02': ("{% for val in values reversed %}{{ val }}{% endfor %}", {"values": [1, 2, 3]}, "321"),
            'for-tag-vars01': ("{% for val in values %}{{ forloop.counter }}{% endfor %}", {"values": [6, 6, 6]}, "123"),
            'for-tag-vars02': ("{% for val in values %}{{ forloop.counter0 }}{% endfor %}", {"values": [6, 6, 6]}, "012"),
            'for-tag-vars03': ("{% for val in values %}{{ forloop.revcounter }}{% endfor %}", {"values": [6, 6, 6]}, "321"),
            'for-tag-vars04': ("{% for val in values %}{{ forloop.revcounter0 }}{% endfor %}", {"values": [6, 6, 6]}, "210"),

            ### IF TAG ################################################################
            'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
            'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
            'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"),

            # AND
            'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
            'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
            'if-tag-and03': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
            'if-tag-and04': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
            'if-tag-and05': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'),
            'if-tag-and06': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'),
            'if-tag-and07': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
            'if-tag-and08': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': True}, 'no'),

            # OR
            'if-tag-or01': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
            'if-tag-or02': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
            'if-tag-or03': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
            'if-tag-or04': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),
            'if-tag-or05': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'),
            'if-tag-or06': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'),
            'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'),
            'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'),

            # TODO: multiple ORs

            # NOT
            'if-tag-not01': ("{% if not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'yes'),
            'if-tag-not02': ("{% if not %}yes{% else %}no{% endif %}", {'foo': True}, 'no'),
            'if-tag-not03': ("{% if not %}yes{% else %}no{% endif %}", {'not': True}, 'yes'),
            'if-tag-not04': ("{% if not not %}no{% else %}yes{% endif %}", {'not': True}, 'yes'),
            'if-tag-not05': ("{% if not not %}no{% else %}yes{% endif %}", {}, 'no'),

            'if-tag-not06': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {}, 'no'),
            'if-tag-not07': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
            'if-tag-not08': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
            'if-tag-not09': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
            'if-tag-not10': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),

            'if-tag-not11': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {}, 'no'),
            'if-tag-not12': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
            'if-tag-not13': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
            'if-tag-not14': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
            'if-tag-not15': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'),

            'if-tag-not16': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
            'if-tag-not17': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
            'if-tag-not18': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
            'if-tag-not19': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
            'if-tag-not20': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),

            'if-tag-not21': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {}, 'yes'),
            'if-tag-not22': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'),
            'if-tag-not23': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
            'if-tag-not24': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
            'if-tag-not25': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),

            'if-tag-not26': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
            'if-tag-not27': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
            'if-tag-not28': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'),
            'if-tag-not29': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'),
            'if-tag-not30': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),

            'if-tag-not31': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'),
            'if-tag-not32': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'),
            'if-tag-not33': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'),
            'if-tag-not34': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'),
            'if-tag-not35': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'),

            # AND and OR raises a TemplateSyntaxError
            'if-tag-error01': ("{% if foo or bar and baz %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, template.TemplateSyntaxError),
            'if-tag-error02': ("{% if foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
            'if-tag-error03': ("{% if foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
            'if-tag-error04': ("{% if not foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),
            'if-tag-error05': ("{% if not foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError),

            ### IFCHANGED TAG #########################################################
            'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'),
            'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'),
            'ifchanged03': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,1) }, '1'),
            'ifchanged04': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 2, 3), 'numx': (2, 2, 2)}, '122232'),
            'ifchanged05': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (1, 2, 3)}, '1123123123'),
            'ifchanged06': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2)}, '1222'),
            'ifchanged07': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% for x in numx %}{% ifchanged %}{{ x }}{% endifchanged %}{% for y in numy %}{% ifchanged %}{{ y }}{% endifchanged %}{% endfor %}{% endfor %}{% endfor %}', { 'num': (1, 1, 1), 'numx': (2, 2, 2), 'numy': (3, 3, 3)}, '1233323332333'),

            # Test one parameter given to ifchanged.
            'ifchanged-param01': ('{% for n in num %}{% ifchanged n %}..{% endifchanged %}{{ n }}{% endfor %}', { 'num': (1,2,3) }, '..1..2..3'),
            'ifchanged-param02': ('{% for n in num %}{% for x in numx %}{% ifchanged n %}..{% endifchanged %}{{ x }}{% endfor %}{% endfor %}', { 'num': (1,2,3), 'numx': (5,6,7) }, '..567..567..567'),

            # Test multiple parameters to ifchanged.
            'ifchanged-param03': ('{% for n in num %}{{ n }}{% for x in numx %}{% ifchanged x n %}{{ x }}{% endifchanged %}{% endfor %}{% endfor %}', { 'num': (1,1,2), 'numx': (5,6,6) }, '156156256'),

            # Test a date+hour like construct, where the hour of the last day
            # is the same but the date had changed, so print the hour anyway.
            'ifchanged-param04': ('{% for d in days %}{% ifchanged %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}', {'days':[{'day':1, 'hours':[1,2,3]},{'day':2, 'hours':[3]},] }, '112323'),

            # Logically the same as above, just written with explicit
            # ifchanged for the day.
            'ifchanged-param04': ('{% for d in days %}{% ifchanged d.day %}{{ d.day }}{% endifchanged %}{% for h in d.hours %}{% ifchanged d.day h %}{{ h }}{% endifchanged %}{% endfor %}{% endfor %}', {'days':[{'day':1, 'hours':[1,2,3]},{'day':2, 'hours':[3]},] }, '112323'),

            ### IFEQUAL TAG ###########################################################
            'ifequal01': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 2}, ""),
            'ifequal02': ("{% ifequal a b %}yes{% endifequal %}", {"a": 1, "b": 1}, "yes"),
            'ifequal03': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 2}, "no"),
            'ifequal04': ("{% ifequal a b %}yes{% else %}no{% endifequal %}", {"a": 1, "b": 1}, "yes"),
            'ifequal05': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "test"}, "yes"),
            'ifequal06': ("{% ifequal a 'test' %}yes{% else %}no{% endifequal %}", {"a": "no"}, "no"),
            'ifequal07': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "test"}, "yes"),
            'ifequal08': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {"a": "no"}, "no"),
            'ifequal09': ('{% ifequal a "test" %}yes{% else %}no{% endifequal %}', {}, "no"),
            'ifequal10': ('{% ifequal a b %}yes{% else %}no{% endifequal %}', {}, "yes"),

            # SMART SPLITTING
            'ifequal-split01': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {}, "no"),
            'ifequal-split02': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'foo'}, "no"),
            'ifequal-split03': ('{% ifequal a "test man" %}yes{% else %}no{% endifequal %}', {'a': 'test man'}, "yes"),
            'ifequal-split04': ("{% ifequal a 'test man' %}yes{% else %}no{% endifequal %}", {'a': 'test man'}, "yes"),
            'ifequal-split05': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': ''}, "no"),
            'ifequal-split06': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i "love" you'}, "yes"),
            'ifequal-split07': ("{% ifequal a 'i \"love\" you' %}yes{% else %}no{% endifequal %}", {'a': 'i love you'}, "no"),
            'ifequal-split08': (r"{% ifequal a 'I\'m happy' %}yes{% else %}no{% endifequal %}", {'a': "I'm happy"}, "yes"),
            'ifequal-split09': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slash\man"}, "yes"),
            'ifequal-split10': (r"{% ifequal a 'slash\man' %}yes{% else %}no{% endifequal %}", {'a': r"slashman"}, "no"),

            # NUMERIC RESOLUTION
            'ifequal-numeric01': ('{% ifequal x 5 %}yes{% endifequal %}', {'x': '5'}, ''),
            'ifequal-numeric02': ('{% ifequal x 5 %}yes{% endifequal %}', {'x': 5}, 'yes'),
            'ifequal-numeric03': ('{% ifequal x 5.2 %}yes{% endifequal %}', {'x': 5}, ''),
            'ifequal-numeric04': ('{% ifequal x 5.2 %}yes{% endifequal %}', {'x': 5.2}, 'yes'),
            'ifequal-numeric05': ('{% ifequal x 0.2 %}yes{% endifequal %}', {'x': .2}, 'yes'),
            'ifequal-numeric06': ('{% ifequal x .2 %}yes{% endifequal %}', {'x': .2}, 'yes'),
            'ifequal-numeric07': ('{% ifequal x 2. %}yes{% endifequal %}', {'x': 2}, ''),
            'ifequal-numeric08': ('{% ifequal x "5" %}yes{% endifequal %}', {'x': 5}, ''),
            'ifequal-numeric09': ('{% ifequal x "5" %}yes{% endifequal %}', {'x': '5'}, 'yes'),
            'ifequal-numeric10': ('{% ifequal x -5 %}yes{% endifequal %}', {'x': -5}, 'yes'),
            'ifequal-numeric11': ('{% ifequal x -5.2 %}yes{% endifequal %}', {'x': -5.2}, 'yes'),
            'ifequal-numeric12': ('{% ifequal x +5 %}yes{% endifequal %}', {'x': 5}, 'yes'),

            ### IFNOTEQUAL TAG ########################################################
            'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
            'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""),
            'ifnotequal03': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
            'ifnotequal04': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 1}, "no"),

            ### INCLUDE TAG ###########################################################
            'include01': ('{% include "basic-syntax01" %}', {}, "something cool"),
            'include02': ('{% include "basic-syntax02" %}', {'headline': 'Included'}, "Included"),
            'include03': ('{% include template_name %}', {'template_name': 'basic-syntax02', 'headline': 'Included'}, "Included"),
            'include04': ('a{% include "nonexistent" %}b', {}, "ab"),

            ### NAMED ENDBLOCKS #######################################################

            # Basic test
            'namedendblocks01': ("1{% block first %}_{% block second %}2{% endblock second %}_{% endblock first %}3", {}, '1_2_3'),

            # Unbalanced blocks
            'namedendblocks02': ("1{% block first %}_{% block second %}2{% endblock first %}_{% endblock second %}3", {}, template.TemplateSyntaxError),
            'namedendblocks03': ("1{% block first %}_{% block second %}2{% endblock %}_{% endblock second %}3", {}, template.TemplateSyntaxError),
            'namedendblocks04': ("1{% block first %}_{% block second %}2{% endblock second %}_{% endblock third %}3", {}, template.TemplateSyntaxError),
            'namedendblocks05': ("1{% block first %}_{% block second %}2{% endblock first %}", {}, template.TemplateSyntaxError),

            # Mixed named and unnamed endblocks
            'namedendblocks06': ("1{% block first %}_{% block second %}2{% endblock %}_{% endblock first %}3", {}, '1_2_3'),
            'namedendblocks07': ("1{% block first %}_{% block second %}2{% endblock second %}_{% endblock %}3", {}, '1_2_3'),

            ### INHERITANCE ###########################################################

            # Standard template with no inheritance
            'inheritance01': ("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}", {}, '1_3_'),

            # Standard two-level inheritance
            'inheritance02': ("{% extends 'inheritance01' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),

            # Three-level with no redefinitions on third level
            'inheritance03': ("{% extends 'inheritance02' %}", {}, '1234'),

            # Two-level with no redefinitions on second level
            'inheritance04': ("{% extends 'inheritance01' %}", {}, '1_3_'),

            # Two-level with double quotes instead of single quotes
            'inheritance05': ('{% extends "inheritance02" %}', {}, '1234'),

            # Three-level with variable parent-template name
            'inheritance06': ("{% extends foo %}", {'foo': 'inheritance02'}, '1234'),

            # Two-level with one block defined, one block not defined
            'inheritance07': ("{% extends 'inheritance01' %}{% block second %}5{% endblock %}", {}, '1_35'),

            # Three-level with one block defined on this level, two blocks defined next level
            'inheritance08': ("{% extends 'inheritance02' %}{% block second %}5{% endblock %}", {}, '1235'),

            # Three-level with second and third levels blank
            'inheritance09': ("{% extends 'inheritance04' %}", {}, '1_3_'),

            # Three-level with space NOT in a block -- should be ignored
            'inheritance10': ("{% extends 'inheritance04' %}      ", {}, '1_3_'),

            # Three-level with both blocks defined on this level, but none on second level
            'inheritance11': ("{% extends 'inheritance04' %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {}, '1234'),

            # Three-level with this level providing one and second level providing the other
            'inheritance12': ("{% extends 'inheritance07' %}{% block first %}2{% endblock %}", {}, '1235'),

            # Three-level with this level overriding second level
            'inheritance13': ("{% extends 'inheritance02' %}{% block first %}a{% endblock %}{% block second %}b{% endblock %}", {}, '1a3b'),

            # A block defined only in a child template shouldn't be displayed
            'inheritance14': ("{% extends 'inheritance01' %}{% block newblock %}NO DISPLAY{% endblock %}", {}, '1_3_'),

            # A block within another block
            'inheritance15': ("{% extends 'inheritance01' %}{% block first %}2{% block inner %}inner{% endblock %}{% endblock %}", {}, '12inner3_'),

            # A block within another block (level 2)
            'inheritance16': ("{% extends 'inheritance15' %}{% block inner %}out{% endblock %}", {}, '12out3_'),

            # {% load %} tag (parent -- setup for exception04)
            'inheritance17': ("{% load testtags %}{% block first %}1234{% endblock %}", {}, '1234'),

            # {% load %} tag (standard usage, without inheritance)
            'inheritance18': ("{% load testtags %}{% echo this that theother %}5678", {}, 'this that theother5678'),

            # {% load %} tag (within a child template)
            'inheritance19': ("{% extends 'inheritance01' %}{% block first %}{% load testtags %}{% echo 400 %}5678{% endblock %}", {}, '140056783_'),

            # Two-level inheritance with {{ block.super }}
            'inheritance20': ("{% extends 'inheritance01' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'),

            # Three-level inheritance with {{ block.super }} from parent
            'inheritance21': ("{% extends 'inheritance02' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '12a34'),

            # Three-level inheritance with {{ block.super }} from grandparent
            'inheritance22': ("{% extends 'inheritance04' %}{% block first %}{{ block.super }}a{% endblock %}", {}, '1_a3_'),

            # Three-level inheritance with {{ block.super }} from parent and grandparent
            'inheritance23': ("{% extends 'inheritance20' %}{% block first %}{{ block.super }}b{% endblock %}", {}, '1_ab3_'),

            # Inheritance from local context without use of template loader
            'inheritance24': ("{% extends context_template %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")}, '1234'),

            # Inheritance from local context with variable parent template
            'inheritance25': ("{% extends context_template.1 %}{% block first %}2{% endblock %}{% block second %}4{% endblock %}", {'context_template': [template.Template("Wrong"), template.Template("1{% block first %}_{% endblock %}3{% block second %}_{% endblock %}")]}, '1234'),

            ### I18N ##################################################################

            # {% spaceless %} tag
            'spaceless01': ("{% spaceless %} <b>    <i> text </i>    </b> {% endspaceless %}", {}, "<b><i> text </i></b>"),
            'spaceless02': ("{% spaceless %} <b> \n <i> text </i> \n </b> {% endspaceless %}", {}, "<b><i> text </i></b>"),
            'spaceless03': ("{% spaceless %}<b><i>text</i></b>{% endspaceless %}", {}, "<b><i>text</i></b>"),

            # simple translation of a string delimited by '
            'i18n01': ("{% load i18n %}{% trans 'xxxyyyxxx' %}", {}, "xxxyyyxxx"),

            # simple translation of a string delimited by "
            'i18n02': ('{% load i18n %}{% trans "xxxyyyxxx" %}', {}, "xxxyyyxxx"),

            # simple translation of a variable
            'i18n03': ('{% load i18n %}{% blocktrans %}{{ anton }}{% endblocktrans %}', {'anton': 'xxxyyyxxx'}, "xxxyyyxxx"),

            # simple translation of a variable and filter
            'i18n04': ('{% load i18n %}{% blocktrans with anton|lower as berta %}{{ berta }}{% endblocktrans %}', {'anton': 'XXXYYYXXX'}, "xxxyyyxxx"),

            # simple translation of a string with interpolation
            'i18n05': ('{% load i18n %}{% blocktrans %}xxx{{ anton }}xxx{% endblocktrans %}', {'anton': 'yyy'}, "xxxyyyxxx"),

            # simple translation of a string to german
            'i18n06': ('{% load i18n %}{% trans "Page not found" %}', {'LANGUAGE_CODE': 'de'}, "Seite nicht gefunden"),

            # translation of singular form
            'i18n07': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 1}, "singular"),

            # translation of plural form
            'i18n08': ('{% load i18n %}{% blocktrans count number as counter %}singular{% plural %}plural{% endblocktrans %}', {'number': 2}, "plural"),

            # simple non-translation (only marking) of a string to german
            'i18n09': ('{% load i18n %}{% trans "Page not found" noop %}', {'LANGUAGE_CODE': 'de'}, "Page not found"),

            # translation of a variable with a translated filter
            'i18n10': ('{{ bool|yesno:_("ja,nein") }}', {'bool': True}, 'ja'),

            # translation of a variable with a non-translated filter
            'i18n11': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'),

            # usage of the get_available_languages tag
            'i18n12': ('{% load i18n %}{% get_available_languages as langs %}{% for lang in langs %}{% ifequal lang.0 "de" %}{{ lang.0 }}{% endifequal %}{% endfor %}', {}, 'de'),

            # translation of a constant string
            'i18n13': ('{{ _("Page not found") }}', {'LANGUAGE_CODE': 'de'}, 'Seite nicht gefunden'),

            ### HANDLING OF TEMPLATE_TAG_IF_INVALID ###################################

            'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')),
            'invalidstr02': ('{{ var|default_if_none:"Foo" }}', {}, ('','INVALID')),
            'invalidstr03': ('{% for v in var %}({{ v }}){% endfor %}', {}, ''),
            'invalidstr04': ('{% if var %}Yes{% else %}No{% endif %}', {}, 'No'),
            'invalidstr04': ('{% if var|default:"Foo" %}Yes{% else %}No{% endif %}', {}, 'Yes'),
            'invalidstr05': ('{{ var }}', {}, ('', 'INVALID %s', 'var')),
            'invalidstr06': ('{{ var.prop }}', {'var': {}}, ('', 'INVALID %s', 'var.prop')),

            ### MULTILINE #############################################################

            'multiline01': ("""
                            Hello,
                            boys.
                            How
                            are
                            you
                            gentlemen.
                            """,
                            {},
                            """
                            Hello,
                            boys.
                            How
                            are
                            you
                            gentlemen.
                            """),

            ### REGROUP TAG ###########################################################
            'regroup01': ('{% regroup data by bar as grouped %}' + \
                          '{% for group in grouped %}' + \
                          '{{ group.grouper }}:' + \
                          '{% for item in group.list %}' + \
                          '{{ item.foo }}' + \
                          '{% endfor %},' + \
                          '{% endfor %}',
                          {'data': [ {'foo':'c', 'bar':1},
                                     {'foo':'d', 'bar':1},
                                     {'foo':'a', 'bar':2},
                                     {'foo':'b', 'bar':2},
                                     {'foo':'x', 'bar':3}  ]},
                          '1:cd,2:ab,3:x,'),

            # Test for silent failure when target variable isn't found
            'regroup02': ('{% regroup data by bar as grouped %}' + \
                          '{% for group in grouped %}' + \
                          '{{ group.grouper }}:' + \
                          '{% for item in group.list %}' + \
                          '{{ item.foo }}' + \
                          '{% endfor %},' + \
                          '{% endfor %}',
                          {}, ''),

            ### TEMPLATETAG TAG #######################################################
            'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
            'templatetag02': ('{% templatetag closeblock %}', {}, '%}'),
            'templatetag03': ('{% templatetag openvariable %}', {}, '{{'),
            'templatetag04': ('{% templatetag closevariable %}', {}, '}}'),
            'templatetag05': ('{% templatetag %}', {}, template.TemplateSyntaxError),
            'templatetag06': ('{% templatetag foo %}', {}, template.TemplateSyntaxError),
            'templatetag07': ('{% templatetag openbrace %}', {}, '{'),
            'templatetag08': ('{% templatetag closebrace %}', {}, '}'),
            'templatetag09': ('{% templatetag openbrace %}{% templatetag openbrace %}', {}, '{{'),
            'templatetag10': ('{% templatetag closebrace %}{% templatetag closebrace %}', {}, '}}'),
            'templatetag11': ('{% templatetag opencomment %}', {}, '{#'),
            'templatetag12': ('{% templatetag closecomment %}', {}, '#}'),

            ### WIDTHRATIO TAG ########################################################
            'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'),
            'widthratio02': ('{% widthratio a b 100 %}', {'a':0,'b':0}, ''),
            'widthratio03': ('{% widthratio a b 100 %}', {'a':0,'b':100}, '0'),
            'widthratio04': ('{% widthratio a b 100 %}', {'a':50,'b':100}, '50'),
            'widthratio05': ('{% widthratio a b 100 %}', {'a':100,'b':100}, '100'),

            # 62.5 should round to 63
            'widthratio06': ('{% widthratio a b 100 %}', {'a':50,'b':80}, '63'),

            # 71.4 should round to 71
            'widthratio07': ('{% widthratio a b 100 %}', {'a':50,'b':70}, '71'),

            # Raise exception if we don't have 3 args, last one an integer
            'widthratio08': ('{% widthratio %}', {}, template.TemplateSyntaxError),
            'widthratio09': ('{% widthratio a b %}', {'a':50,'b':100}, template.TemplateSyntaxError),
            'widthratio10': ('{% widthratio a b 100.0 %}', {'a':50,'b':100}, template.TemplateSyntaxError),

            ### WITH TAG ########################################################
            'with01': ('{% with dict.key as key %}{{ key }}{% endwith %}', {'dict': {'key':50}}, '50'),
            'with02': ('{{ key }}{% with dict.key as key %}{{ key }}-{{ dict.key }}-{{ key }}{% endwith %}{{ key }}', {'dict': {'key':50}}, ('50-50-50', 'INVALID50-50-50INVALID')),

            'with-error01': ('{% with dict.key xx key %}{{ key }}{% endwith %}', {'dict': {'key':50}}, template.TemplateSyntaxError),
            'with-error02': ('{% with dict.key as %}{{ key }}{% endwith %}', {'dict': {'key':50}}, template.TemplateSyntaxError),

            ### NOW TAG ########################################################
            # Simple case
            'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)),

            # Check parsing of escaped and special characters
            'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError),
            #    'now03' : ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)),
            #    'now04' : ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year))

            ### TIMESINCE TAG ##################################################
            # Default compare with datetime.now()
            'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'),
            'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1, minutes = 1))}, '1 day'),
            'timesince03' : ('{{ a|timesince }}', {'a':(datetime.now() -
                timedelta(hours=1, minutes=25, seconds = 10))}, '1 hour, 25 minutes'),

            # Compare to a given parameter
            'timesince04' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2), 'b':NOW + timedelta(days=1)}, '1 day'),
            'timesince05' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2, minutes=1), 'b':NOW + timedelta(days=2)}, '1 minute'),

            # Check that timezone is respected
            'timesince06' : ('{{ a|timesince:b }}', {'a':NOW_tz + timedelta(hours=8), 'b':NOW_tz}, '8 hours'),

            ### TIMEUNTIL TAG ##################################################
            # Default compare with datetime.now()
            'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'),
            'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'),
            'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10, seconds = 10))}, '8 hours, 10 minutes'),

            # Compare to a given parameter
            'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'),
            'timeuntil05' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=2), 'b':NOW - timedelta(days=2, minutes=1)}, '1 minute'),

            ### URL TAG ########################################################
            # Successes
            'url01' : ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
            'url02' : ('{% url regressiontests.templates.views.client_action client.id, action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
            'url03' : ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
            'url04' : ('{% url named-client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),

            # Failures
            'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError),
            'url-fail02' : ('{% url no_such_view %}', {}, ''),
            'url-fail03' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
        }

        # Register our custom template loader.
        def test_template_loader(template_name, template_dirs=None):
            "A custom template loader that loads the unit-test templates."
            try:
                return (TEMPLATE_TESTS[template_name][0],
                        "test:%s" % template_name)
            except KeyError:
                raise template.TemplateDoesNotExist, template_name

        old_template_loaders = loader.template_source_loaders
        loader.template_source_loaders = [test_template_loader]

        failures = []
        tests = TEMPLATE_TESTS.items()
        tests.sort()

        # Turn TEMPLATE_DEBUG off, because tests assume that.
        old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False

        # Set TEMPLATE_STRING_IF_INVALID to a known string
        old_invalid = settings.TEMPLATE_STRING_IF_INVALID
        expected_invalid_str = 'INVALID'

        for name, vals in tests:
            install()

            if isinstance(vals[2], tuple):
                normal_string_result = vals[2][0]
                invalid_string_result = vals[2][1]
                if '%s' in invalid_string_result:
                    expected_invalid_str = 'INVALID %s'
                    invalid_string_result = invalid_string_result % vals[2][2]
                    template.invalid_var_format_string = True
            else:
                normal_string_result = vals[2]
                invalid_string_result = vals[2]

            if 'LANGUAGE_CODE' in vals[1]:
                activate(vals[1]['LANGUAGE_CODE'])
            else:
                activate('en-us')

            for invalid_str, result in [('', normal_string_result),
                                        (expected_invalid_str,
                                         invalid_string_result)]:
                settings.TEMPLATE_STRING_IF_INVALID = invalid_str
                try:
                    output = loader.get_template(name).render(
                        template.Context(vals[1]))
                except Exception, e:
                    if e.__class__ != result:
                        failures.append(
                            "Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s"
                            % (invalid_str, name, e.__class__, e))
                    continue
                if output != result:
                    failures.append(
                        "Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r"
                        % (invalid_str, name, result, output))

            if 'LANGUAGE_CODE' in vals[1]:
                deactivate()

            if template.invalid_var_format_string:
                expected_invalid_str = 'INVALID'
                template.invalid_var_format_string = False
コード例 #29
0
ファイル: dateformat.py プロジェクト: AlfredFu/django
class DateFormat(TimeFormat):
    year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]

    def __init__(self, dt):
        # Accepts either a datetime or date object.
        self.data = dt
        self.timezone = None
        if isinstance(dt, datetime.datetime):
            if is_naive(dt):
                self.timezone = LocalTimezone(dt)
            else:
                self.timezone = dt.tzinfo

    def b(self):
        "Month, textual, 3 letters, lowercase; e.g. 'jan'"
        return MONTHS_3[self.data.month]

    def c(self):
        """
        ISO 8601 Format
        Example : '2008-01-02T10:30:00.000123'
        """
        return self.data.isoformat()

    def d(self):
        "Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
        return u'%02d' % self.data.day

    def D(self):
        "Day of the week, textual, 3 letters; e.g. 'Fri'"
        return WEEKDAYS_ABBR[self.data.weekday()]

    def e(self):
        "Timezone name if available"
        try:
            if hasattr(self.data, 'tzinfo') and self.data.tzinfo:
                # Have to use tzinfo.tzname and not datetime.tzname
                # because datatime.tzname does not expect Unicode
                return self.data.tzinfo.tzname(self.data) or ""
        except NotImplementedError:
            pass
        return ""

    def E(self):
        "Alternative month names as required by some locales. Proprietary extension."
        return MONTHS_ALT[self.data.month]

    def F(self):
        "Month, textual, long; e.g. 'January'"
        return MONTHS[self.data.month]

    def I(self):
        "'1' if Daylight Savings Time, '0' otherwise."
        if self.timezone and self.timezone.dst(self.data):
            return u'1'
        else:
            return u'0'

    def j(self):
        "Day of the month without leading zeros; i.e. '1' to '31'"
        return self.data.day

    def l(self):
        "Day of the week, textual, long; e.g. 'Friday'"
        return WEEKDAYS[self.data.weekday()]

    def L(self):
        "Boolean for whether it is a leap year; i.e. True or False"
        return calendar.isleap(self.data.year)

    def m(self):
        "Month; i.e. '01' to '12'"
        return u'%02d' % self.data.month

    def M(self):
        "Month, textual, 3 letters; e.g. 'Jan'"
        return MONTHS_3[self.data.month].title()

    def n(self):
        "Month without leading zeros; i.e. '1' to '12'"
        return self.data.month

    def N(self):
        "Month abbreviation in Associated Press style. Proprietary extension."
        return MONTHS_AP[self.data.month]

    def o(self):
        "ISO 8601 year number matching the ISO week number (W)"
        return self.data.isocalendar()[0]

    def O(self):
        "Difference to Greenwich time in hours; e.g. '+0200', '-0430'"
        seconds = self.Z()
        sign = '-' if seconds < 0 else '+'
        seconds = abs(seconds)
        return u"%s%02d%02d" % (sign, seconds // 3600, (seconds // 60) % 60)

    def r(self):
        "RFC 2822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
        return self.format('D, j M Y H:i:s O')

    def S(self):
        "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
            return u'th'
        last = self.data.day % 10
        if last == 1:
            return u'st'
        if last == 2:
            return u'nd'
        if last == 3:
            return u'rd'
        return u'th'

    def t(self):
        "Number of days in the given month; i.e. '28' to '31'"
        return u'%02d' % calendar.monthrange(self.data.year, self.data.month)[1]

    def T(self):
        "Time zone of this machine; e.g. 'EST' or 'MDT'"
        name = self.timezone and self.timezone.tzname(self.data) or None
        if name is None:
            name = self.format('O')
        return unicode(name)

    def U(self):
        "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
        if isinstance(self.data, datetime.datetime) and is_aware(self.data):
            return int(calendar.timegm(self.data.utctimetuple()))
        else:
            return int(time.mktime(self.data.timetuple()))

    def w(self):
        "Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)"
        return (self.data.weekday() + 1) % 7

    def W(self):
        "ISO-8601 week number of year, weeks starting on Monday"
        # Algorithm from http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt
        week_number = None
        jan1_weekday = self.data.replace(month=1, day=1).weekday() + 1
        weekday = self.data.weekday() + 1
        day_of_year = self.z()
        if day_of_year <= (8 - jan1_weekday) and jan1_weekday > 4:
            if jan1_weekday == 5 or (jan1_weekday == 6 and calendar.isleap(self.data.year-1)):
                week_number = 53
            else:
                week_number = 52
        else:
            if calendar.isleap(self.data.year):
                i = 366
            else:
                i = 365
            if (i - day_of_year) < (4 - weekday):
                week_number = 1
            else:
                j = day_of_year + (7 - weekday) + (jan1_weekday - 1)
                week_number = j // 7
                if jan1_weekday > 4:
                    week_number -= 1
        return week_number

    def y(self):
        "Year, 2 digits; e.g. '99'"
        return unicode(self.data.year)[2:]

    def Y(self):
        "Year, 4 digits; e.g. '1999'"
        return self.data.year

    def z(self):
        "Day of the year; i.e. '0' to '365'"
        doy = self.year_days[self.data.month] + self.data.day
        if self.L() and self.data.month > 2:
            doy += 1
        return doy

    def Z(self):
        """
        Time zone offset in seconds (i.e. '-43200' to '43200'). The offset for
        timezones west of UTC is always negative, and for those east of UTC is
        always positive.
        """
        if not self.timezone:
            return 0
        offset = self.timezone.utcoffset(self.data)
        # `offset` is a datetime.timedelta. For negative values (to the west of
        # UTC) only days can be negative (days=-1) and seconds are always
        # positive. e.g. UTC-1 -> timedelta(days=-1, seconds=82800, microseconds=0)
        # Positive offsets have days=0
        return offset.days * 86400 + offset.seconds
コード例 #30
0
ファイル: dateformat.py プロジェクト: streeter/django
class TimeFormat(Formatter):
    def __init__(self, obj):
        self.data = obj
        self.timezone = None

        # We only support timezone when formatting datetime objects,
        # not date objects (timezone information not appropriate),
        # or time objects (against established django policy).
        if isinstance(obj, datetime.datetime):
            if is_naive(obj):
                self.timezone = LocalTimezone(obj)
            else:
                self.timezone = obj.tzinfo

    def a(self):
        "'a.m.' or 'p.m.'"
        if self.data.hour > 11:
            return _("p.m.")
        return _("a.m.")

    def A(self):
        "'AM' or 'PM'"
        if self.data.hour > 11:
            return _("PM")
        return _("AM")

    def B(self):
        "Swatch Internet time"
        raise NotImplementedError

    def e(self):
        """
        Timezone name.

        If timezone information is not available, this method returns
        an empty string.
        """
        if not self.timezone:
            return ""

        try:
            if hasattr(self.data, "tzinfo") and self.data.tzinfo:
                # Have to use tzinfo.tzname and not datetime.tzname
                # because datatime.tzname does not expect Unicode
                return self.data.tzinfo.tzname(self.data) or ""
        except NotImplementedError:
            pass
        return ""

    def f(self):
        """
        Time, in 12-hour hours and minutes, with minutes left off if they're
        zero.
        Examples: '1', '1:30', '2:05', '2'
        Proprietary extension.
        """
        if self.data.minute == 0:
            return self.g()
        return "%s:%s" % (self.g(), self.i())

    def g(self):
        "Hour, 12-hour format without leading zeros; i.e. '1' to '12'"
        if self.data.hour == 0:
            return 12
        if self.data.hour > 12:
            return self.data.hour - 12
        return self.data.hour

    def G(self):
        "Hour, 24-hour format without leading zeros; i.e. '0' to '23'"
        return self.data.hour

    def h(self):
        "Hour, 12-hour format; i.e. '01' to '12'"
        return "%02d" % self.g()

    def H(self):
        "Hour, 24-hour format; i.e. '00' to '23'"
        return "%02d" % self.G()

    def i(self):
        "Minutes; i.e. '00' to '59'"
        return "%02d" % self.data.minute

    def O(self):
        """
        Difference to Greenwich time in hours; e.g. '+0200', '-0430'.

        If timezone information is not available, this method returns
        an empty string.
        """
        if not self.timezone:
            return ""

        seconds = self.Z()
        sign = "-" if seconds < 0 else "+"
        seconds = abs(seconds)
        return "%s%02d%02d" % (sign, seconds // 3600, (seconds // 60) % 60)

    def P(self):
        """
        Time, in 12-hour hours, minutes and 'a.m.'/'p.m.', with minutes left off
        if they're zero and the strings 'midnight' and 'noon' if appropriate.
        Examples: '1 a.m.', '1:30 p.m.', 'midnight', 'noon', '12:30 p.m.'
        Proprietary extension.
        """
        if self.data.minute == 0 and self.data.hour == 0:
            return _("midnight")
        if self.data.minute == 0 and self.data.hour == 12:
            return _("noon")
        return "%s %s" % (self.f(), self.a())

    def s(self):
        "Seconds; i.e. '00' to '59'"
        return "%02d" % self.data.second

    def T(self):
        """
        Time zone of this machine; e.g. 'EST' or 'MDT'.

        If timezone information is not available, this method returns
        an empty string.
        """
        if not self.timezone:
            return ""

        name = self.timezone.tzname(self.data) if self.timezone else None
        if name is None:
            name = self.format("O")
        return six.text_type(name)

    def u(self):
        "Microseconds; i.e. '000000' to '999999'"
        return "%06d" % self.data.microsecond

    def Z(self):
        """
        Time zone offset in seconds (i.e. '-43200' to '43200'). The offset for
        timezones west of UTC is always negative, and for those east of UTC is
        always positive.

        If timezone information is not available, this method returns
        an empty string.
        """
        if not self.timezone:
            return ""

        offset = self.timezone.utcoffset(self.data)
        # `offset` is a datetime.timedelta. For negative values (to the west of
        # UTC) only days can be negative (days=-1) and seconds are always
        # positive. e.g. UTC-1 -> timedelta(days=-1, seconds=82800, microseconds=0)
        # Positive offsets have days=0
        return offset.days * 86400 + offset.seconds
コード例 #31
0
ファイル: humanize.py プロジェクト: xtrqt/django
def naturaltime(value):
    """
    For date and time values shows how many seconds, minutes or hours ago
    compared to current timestamp returns representing string.
    """
    try:
        value = datetime(value.year, value.month, value.day, value.hour,
                         value.minute, value.second)
    except AttributeError:
        return value
    except ValueError:
        return value

    if getattr(value, 'tzinfo', None):
        now = datetime.now(LocalTimezone(value))
    else:
        now = datetime.now()
    now = now - timedelta(0, 0, now.microsecond)
    if value < now:
        delta = now - value
        if delta.days != 0:
            return pgettext('naturaltime', '%(delta)s ago') % {
                'delta': defaultfilters.timesince(value)
            }
        elif delta.seconds == 0:
            return _(u'now')
        elif delta.seconds < 60:
            return ungettext(u'a second ago', u'%(count)s seconds ago',
                             delta.seconds) % {
                                 'count': delta.seconds
                             }
        elif delta.seconds / 60 < 60:
            count = delta.seconds / 60
            return ungettext(u'a minute ago', u'%(count)s minutes ago',
                             count) % {
                                 'count': count
                             }
        else:
            count = delta.seconds / 60 / 60
            return ungettext(u'an hour ago', u'%(count)s hours ago', count) % {
                'count': count
            }
    else:
        delta = value - now
        if delta.days != 0:
            return pgettext('naturaltime', '%(delta)s from now') % {
                'delta': defaultfilters.timeuntil(value)
            }
        elif delta.seconds == 0:
            return _(u'now')
        elif delta.seconds < 60:
            return ungettext(u'a second from now',
                             u'%(count)s seconds from now', delta.seconds) % {
                                 'count': delta.seconds
                             }
        elif delta.seconds / 60 < 60:
            count = delta.seconds / 60
            return ungettext(u'a minute from now',
                             u'%(count)s minutes from now', count) % {
                                 'count': count
                             }
        else:
            count = delta.seconds / 60 / 60
            return ungettext(u'an hour from now', u'%(count)s hours from now',
                             count) % {
                                 'count': count
                             }
コード例 #32
0
 def test_pickling_unpickling(self):
     now = datetime.datetime.now()
     self.assertIsInstance(pickle.loads(pickle.dumps(FixedOffset(90))),
                           FixedOffset)
     self.assertIsInstance(pickle.loads(pickle.dumps(LocalTimezone(now))),
                           LocalTimezone)
コード例 #33
0
ファイル: dateformat.py プロジェクト: bramd/django-podcast
 def __init__(self, dt):
     # Accepts either a datetime or date object.
     self.data = dt
     self.timezone = getattr(dt, 'tzinfo', None)
     if hasattr(self.data, 'hour') and not self.timezone:
         self.timezone = LocalTimezone(dt)
コード例 #34
0
ファイル: dateformat.py プロジェクト: LAMike310/ecommerce
class DateFormat(TimeFormat):
    year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]

    def __init__(self, dt):
        # Accepts either a datetime or date object.
        self.data = dt
        self.timezone = None
        if isinstance(dt, datetime.datetime):
            if is_naive(dt):
                self.timezone = LocalTimezone(dt)
            else:
                self.timezone = dt.tzinfo

    def b(self):
        "Month, textual, 3 letters, lowercase; e.g. 'jan'"
        return MONTHS_3[self.data.month]

    def c(self):
        """
        ISO 8601 Format
        Example : '2008-01-02T10:30:00.000123'
        """
        return self.data.isoformat()

    def d(self):
        "Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
        return '%02d' % self.data.day

    def D(self):
        "Day of the week, textual, 3 letters; e.g. 'Fri'"
        return WEEKDAYS_ABBR[self.data.weekday()]

    def e(self):
        "Timezone name if available"
        try:
            if hasattr(self.data, 'tzinfo') and self.data.tzinfo:
                # Have to use tzinfo.tzname and not datetime.tzname
                # because datatime.tzname does not expect Unicode
                return self.data.tzinfo.tzname(self.data) or ""
        except NotImplementedError:
            pass
        return ""

    def E(self):
        "Alternative month names as required by some locales. Proprietary extension."
        return MONTHS_ALT[self.data.month]

    def F(self):
        "Month, textual, long; e.g. 'January'"
        return MONTHS[self.data.month]

    def I(self):
        "'1' if Daylight Savings Time, '0' otherwise."
        if self.timezone and self.timezone.dst(self.data):
            return '1'
        else:
            return '0'

    def j(self):
        "Day of the month without leading zeros; i.e. '1' to '31'"
        return self.data.day

    def l(self):
        "Day of the week, textual, long; e.g. 'Friday'"
        return WEEKDAYS[self.data.weekday()]

    def L(self):
        "Boolean for whether it is a leap year; i.e. True or False"
        return calendar.isleap(self.data.year)

    def m(self):
        "Month; i.e. '01' to '12'"
        return '%02d' % self.data.month

    def M(self):
        "Month, textual, 3 letters; e.g. 'Jan'"
        return MONTHS_3[self.data.month].title()

    def n(self):
        "Month without leading zeros; i.e. '1' to '12'"
        return self.data.month

    def N(self):
        "Month abbreviation in Associated Press style. Proprietary extension."
        return MONTHS_AP[self.data.month]

    def o(self):
        "ISO 8601 year number matching the ISO week number (W)"
        return self.data.isocalendar()[0]

    def O(self):
        "Difference to Greenwich time in hours; e.g. '+0200', '-0430'"
        seconds = self.Z()
        sign = '-' if seconds < 0 else '+'
        seconds = abs(seconds)
        return "%s%02d%02d" % (sign, seconds // 3600, (seconds // 60) % 60)

    def r(self):
        "RFC 2822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
        return self.format('D, j M Y H:i:s O')

    def S(self):
        "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
            return 'th'
        last = self.data.day % 10
        if last == 1:
            return 'st'
        if last == 2:
            return 'nd'
        if last == 3:
            return 'rd'
        return 'th'

    def t(self):
        "Number of days in the given month; i.e. '28' to '31'"
        return '%02d' % calendar.monthrange(self.data.year, self.data.month)[1]

    def T(self):
        "Time zone of this machine; e.g. 'EST' or 'MDT'"
        name = self.timezone.tzname(self.data) if self.timezone else None
        if name is None:
            name = self.format('O')
        return six.text_type(name)

    def U(self):
        "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
        if isinstance(self.data, datetime.datetime) and is_aware(self.data):
            return int(calendar.timegm(self.data.utctimetuple()))
        else:
            return int(time.mktime(self.data.timetuple()))

    def w(self):
        "Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)"
        return (self.data.weekday() + 1) % 7

    def W(self):
        "ISO-8601 week number of year, weeks starting on Monday"
        # Algorithm from http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt
        week_number = None
        jan1_weekday = self.data.replace(month=1, day=1).weekday() + 1
        weekday = self.data.weekday() + 1
        day_of_year = self.z()
        if day_of_year <= (8 - jan1_weekday) and jan1_weekday > 4:
            if jan1_weekday == 5 or (jan1_weekday == 6
                                     and calendar.isleap(self.data.year - 1)):
                week_number = 53
            else:
                week_number = 52
        else:
            if calendar.isleap(self.data.year):
                i = 366
            else:
                i = 365
            if (i - day_of_year) < (4 - weekday):
                week_number = 1
            else:
                j = day_of_year + (7 - weekday) + (jan1_weekday - 1)
                week_number = j // 7
                if jan1_weekday > 4:
                    week_number -= 1
        return week_number

    def y(self):
        "Year, 2 digits; e.g. '99'"
        return six.text_type(self.data.year)[2:]

    def Y(self):
        "Year, 4 digits; e.g. '1999'"
        return self.data.year

    def z(self):
        "Day of the year; i.e. '0' to '365'"
        doy = self.year_days[self.data.month] + self.data.day
        if self.L() and self.data.month > 2:
            doy += 1
        return doy

    def Z(self):
        """
        Time zone offset in seconds (i.e. '-43200' to '43200'). The offset for
        timezones west of UTC is always negative, and for those east of UTC is
        always positive.
        """
        if not self.timezone:
            return 0
        offset = self.timezone.utcoffset(self.data)
        # `offset` is a datetime.timedelta. For negative values (to the west of
        # UTC) only days can be negative (days=-1) and seconds are always
        # positive. e.g. UTC-1 -> timedelta(days=-1, seconds=82800, microseconds=0)
        # Positive offsets have days=0
        return offset.days * 86400 + offset.seconds
コード例 #35
0
def timesince(d=None, now=None, abbreviate=False, separator=','):
    """
  Takes two datetime objects and returns the time between d and now
  as a nicely formatted string, e.g. "10 minutes".  If d occurs after now,
  then "0 seconds" is returned. If abbreviate is True, it truncates values to,
  for example, "10m" or "4m 30s". Alternately it can take a second value
  and return the proper count.

  Units used are years, months, weeks, days, hours, minutes, and seconds.
  Microseconds are ignored.  Up to two adjacent units will be
  displayed.  For example, "2 weeks, 3 days" and "1 year, 3 months" are
  possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.

  Adapted from the timesince filter in Django:
  http://docs.djangoproject.com/en/dev/ref/templates/builtins/#timesince
  """

    if abbreviate:
        chunks = (
            (60 * 60 * 24 * 365, lambda n: 'y'),
            (60 * 60 * 24 * 30, lambda n: 'm'),
            (60 * 60 * 24 * 7, lambda n: 'w'),
            (60 * 60 * 24, lambda n: 'd'),
            (60 * 60, lambda n: 'h'),
            (60, lambda n: 'm'),
            (1, lambda n: 's'),
        )
    else:
        chunks = (
            (60 * 60 * 24 * 365, lambda n: ungettext('year', 'years', n)),
            (60 * 60 * 24 * 30, lambda n: ungettext('month', 'months', n)),
            (60 * 60 * 24 * 7, lambda n: ungettext('week', 'weeks', n)),
            (60 * 60 * 24, lambda n: ungettext('day', 'days', n)),
            (60 * 60, lambda n: ungettext('hour', 'hours', n)),
            (60, lambda n: ungettext('minute', 'minutes', n)),
            (1, lambda n: ungettext('second', 'seconds', n)),
        )

    # Convert datetime.date to datetime.datetime for comparison.
    if not isinstance(d, datetime.datetime):
        d = datetime.datetime(d.year, d.month, d.day)
    if now and not isinstance(now, datetime.datetime):
        now = datetime.datetime(now.year, now.month, now.day)

    if not now:
        if d.tzinfo:
            now = datetime.datetime.now(LocalTimezone(d))
        else:
            now = datetime.datetime.now()

    # ignore microsecond part of 'd' since we removed it from 'now'
    delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
    since = delta.days * 24 * 60 * 60 + delta.seconds
    if since <= 0:
        # d is in the future compared to now, stop processing.
        if abbreviate:
            return u'0' + ugettext('s')
        else:
            return u'0 ' + ugettext('seconds')
    for i, (seconds, name) in enumerate(chunks):
        count = since // seconds
        if count != 0:
            break
    if abbreviate:
        s = ugettext('%(number)d%(type)s') % {
            'number': count,
            'type': name(count)
        }
    else:
        s = ugettext('%(number)d %(type)s') % {
            'number': count,
            'type': name(count)
        }
    if i + 1 < len(chunks):
        # Now get the second item
        seconds2, name2 = chunks[i + 1]
        count2 = (since - (seconds * count)) // seconds2
        if count2 != 0:
            if abbreviate:
                s += ugettext('%(separator)s %(number)d%(type)s') % {
                    'separator': separator,
                    'number': count2,
                    'type': name2(count2)
                }
            else:
                s += ugettext('%(separator)s %(number)d %(type)s') % {
                    'separator': separator,
                    'number': count2,
                    'type': name2(count2)
                }
    return s
コード例 #36
0
 def __init__(self, dt):
     # Accepts either a datetime or date object.
     self.data = dt
     self.timezone = getattr(dt, 'tzinfo', None)
     if hasattr(self.data, 'hour') and not self.timezone:
         self.timezone = LocalTimezone(dt)
コード例 #37
0
class DateFormat(TimeFormat):
    year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]

    def __init__(self, dt):
        # Accepts either a datetime or date object.
        self.data = dt
        self.timezone = getattr(dt, 'tzinfo', None)
        if hasattr(self.data, 'hour') and not self.timezone:
            self.timezone = LocalTimezone(dt)

    def b(self):
        "Month, textual, 3 letters, lowercase; e.g. 'jan'"
        return MONTHS_3[self.data.month]

    def d(self):
        "Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
        return u'%02d' % self.data.day

    def D(self):
        "Day of the week, textual, 3 letters; e.g. 'Fri'"
        return WEEKDAYS_ABBR[self.data.weekday()]

    def F(self):
        "Month, textual, long; e.g. 'January'"
        return MONTHS[self.data.month]

    def I(self):
        "'1' if Daylight Savings Time, '0' otherwise."
        if self.timezone and self.timezone.dst(self.data):
            return u'1'
        else:
            return u'0'

    def j(self):
        "Day of the month without leading zeros; i.e. '1' to '31'"
        return self.data.day

    def l(self):
        "Day of the week, textual, long; e.g. 'Friday'"
        return WEEKDAYS[self.data.weekday()]

    def L(self):
        "Boolean for whether it is a leap year; i.e. True or False"
        return isleap(self.data.year)

    def m(self):
        "Month; i.e. '01' to '12'"
        return u'%02d' % self.data.month

    def M(self):
        "Month, textual, 3 letters; e.g. 'Jan'"
        return MONTHS_3[self.data.month].title()

    def n(self):
        "Month without leading zeros; i.e. '1' to '12'"
        return self.data.month

    def N(self):
        "Month abbreviation in Associated Press style. Proprietary extension."
        return MONTHS_AP[self.data.month]

    def O(self):
        "Difference to Greenwich time in hours; e.g. '+0200'"
        seconds = self.Z()
        return u"%+03d%02d" % (seconds // 3600, (seconds // 60) % 60)

    def r(self):
        "RFC 2822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
        return self.format('D, j M Y H:i:s O')

    def S(self):
        "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
            return u'th'
        last = self.data.day % 10
        if last == 1:
            return u'st'
        if last == 2:
            return u'nd'
        if last == 3:
            return u'rd'
        return u'th'

    def t(self):
        "Number of days in the given month; i.e. '28' to '31'"
        return u'%02d' % monthrange(self.data.year, self.data.month)[1]

    def T(self):
        "Time zone of this machine; e.g. 'EST' or 'MDT'"
        name = self.timezone and self.timezone.tzname(self.data) or None
        if name is None:
            name = self.format('O')
        return unicode(name)

    def U(self):
        "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
        off = self.timezone and self.timezone.utcoffset(self.data) or 0
        return int(time.mktime(self.data.timetuple())) + off.seconds * 60

    def w(self):
        "Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)"
        return (self.data.weekday() + 1) % 7

    def W(self):
        "ISO-8601 week number of year, weeks starting on Monday"
        # Algorithm from http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt
        week_number = None
        jan1_weekday = self.data.replace(month=1, day=1).weekday() + 1
        weekday = self.data.weekday() + 1
        day_of_year = self.z()
        if day_of_year <= (8 - jan1_weekday) and jan1_weekday > 4:
            if jan1_weekday == 5 or (jan1_weekday == 6
                                     and isleap(self.data.year - 1)):
                week_number = 53
            else:
                week_number = 52
        else:
            if isleap(self.data.year):
                i = 366
            else:
                i = 365
            if (i - day_of_year) < (4 - weekday):
                week_number = 1
            else:
                j = day_of_year + (7 - weekday) + (jan1_weekday - 1)
                week_number = j // 7
                if jan1_weekday > 4:
                    week_number -= 1
        return week_number

    def y(self):
        "Year, 2 digits; e.g. '99'"
        return unicode(self.data.year)[2:]

    def Y(self):
        "Year, 4 digits; e.g. '1999'"
        return self.data.year

    def z(self):
        "Day of the year; i.e. '0' to '365'"
        doy = self.year_days[self.data.month] + self.data.day
        if self.L() and self.data.month > 2:
            doy += 1
        return doy

    def Z(self):
        """
        Time zone offset in seconds (i.e. '-43200' to '43200'). The offset for
        timezones west of UTC is always negative, and for those east of UTC is
        always positive.
        """
        if not self.timezone:
            return 0
        offset = self.timezone.utcoffset(self.data)
        # Only days can be negative, so negative offsets have days=-1 and
        # seconds positive. Positive offsets have days=0
        return offset.days * 86400 + offset.seconds