diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index f1fcf5fe90..2c7e00172d 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -1,11 +1,12 @@ -"Default variable filters" +"""Default variable filters.""" + +import re +import random as random_module from django.template import Variable, Library from django.conf import settings from django.utils.translation import ugettext, ungettext -from django.utils.encoding import force_unicode, smart_str, iri_to_uri -import re -import random as random_module +from django.utils.encoding import force_unicode, iri_to_uri register = Library() @@ -36,17 +37,17 @@ def stringfilter(func): def addslashes(value): - "Adds slashes - useful for passing strings to JavaScript, for example." + """Adds slashes - useful for passing strings to JavaScript, for example.""" return value.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'") addslashes = stringfilter(addslashes) def capfirst(value): - "Capitalizes the first character of the value" + """Capitalizes the first character of the value.""" return value and value[0].upper() + value[1:] capfirst = stringfilter(capfirst) def fix_ampersands(value): - "Replaces ampersands with ``&`` entities" + """Replaces ampersands with ``&`` entities.""" from django.utils.html import fix_ampersands return fix_ampersands(value) fix_ampersands = stringfilter(fix_ampersands) @@ -86,15 +87,16 @@ def floatformat(text, arg=-1): return formatstr % f def iriencode(value): - "Escapes an IRI value for use in a URL" + """Escapes an IRI value for use in a URL.""" return force_unicode(iri_to_uri(value)) iriencode = stringfilter(iriencode) def linenumbers(value): - "Displays text with line numbers" + """Displays text with line numbers.""" from django.utils.html import escape lines = value.split(u'\n') - # Find the maximum width of the line count, for use with zero padding string format command + # Find the maximum width of the line count, for use with zero padding + # string format command. width = unicode(len(unicode(len(lines)))) for i, line in enumerate(lines): lines[i] = (u"%0" + width + u"d. %s") % (i + 1, escape(line)) @@ -102,22 +104,24 @@ def linenumbers(value): linenumbers = stringfilter(linenumbers) def lower(value): - "Converts a string into all lowercase" + """Converts a string into all lowercase.""" return value.lower() lower = stringfilter(lower) def make_list(value): """ - Returns the value turned into a list. For an integer, it's a list of - digits. For a string, it's a list of characters. + Returns the value turned into a list. + + For an integer, it's a list of digits. + For a string, it's a list of characters. """ return list(value) make_list = stringfilter(make_list) def slugify(value): """ - Normalizes string, converts to lowercase, removes non-alpha chars and - converts spaces to hyphens. + Normalizes string, converts to lowercase, removes non-alpha characters, + and converts spaces to hyphens. """ import unicodedata value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore') @@ -127,7 +131,8 @@ slugify = stringfilter(slugify) def stringformat(value, arg): """ - Formats the variable according to the argument, a string formatting specifier. + Formats the variable according to the arg, a string formatting specifier. + This specifier uses Python string formating syntax, with the exception that the leading "%" is dropped. @@ -140,29 +145,29 @@ def stringformat(value, arg): return u"" def title(value): - "Converts a string into titlecase" + """Converts a string into titlecase.""" return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title()) title = stringfilter(title) def truncatewords(value, arg): """ - Truncates a string after a certain number of words + Truncates a string after a certain number of words. - Argument: Number of words to truncate after + Argument: Number of words to truncate after. """ from django.utils.text import truncate_words try: length = int(arg) - except ValueError: # invalid literal for int() + except ValueError: # Invalid literal for int(). return value # Fail silently. return truncate_words(value, length) truncatewords = stringfilter(truncatewords) def truncatewords_html(value, arg): """ - Truncates HTML after a certain number of words + Truncates HTML after a certain number of words. - Argument: Number of words to truncate after + Argument: Number of words to truncate after. """ from django.utils.text import truncate_html_words try: @@ -173,26 +178,26 @@ def truncatewords_html(value, arg): truncatewords_html = stringfilter(truncatewords_html) def upper(value): - "Converts a string into all uppercase" + """Converts a string into all uppercase.""" return value.upper() upper = stringfilter(upper) def urlencode(value): - "Escapes a value for use in a URL" + """Escapes a value for use in a URL.""" from django.utils.http import urlquote return urlquote(value) urlencode = stringfilter(urlencode) def urlize(value): - "Converts URLs in plain text into clickable links" + """Converts URLs in plain text into clickable links.""" from django.utils.html import urlize return urlize(value, nofollow=True) urlize = stringfilter(urlize) def urlizetrunc(value, limit): """ - Converts URLs into clickable links, truncating URLs to the given character limit, - and adding 'rel=nofollow' attribute to discourage spamming. + Converts URLs into clickable links, truncating URLs to the given character + limit, and adding 'rel=nofollow' attribute to discourage spamming. Argument: Length to truncate URLs to. """ @@ -201,13 +206,13 @@ def urlizetrunc(value, limit): urlizetrunc = stringfilter(urlizetrunc) def wordcount(value): - "Returns the number of words" + """Returns the number of words.""" return len(value.split()) wordcount = stringfilter(wordcount) def wordwrap(value, arg): """ - Wraps words at specified line length + Wraps words at specified line length. Argument: number of characters to wrap the text at. """ @@ -217,29 +222,29 @@ wordwrap = stringfilter(wordwrap) def ljust(value, arg): """ - Left-aligns the value in a field of a given width + Left-aligns the value in a field of a given width. - Argument: field size + Argument: field size. """ return value.ljust(int(arg)) ljust = stringfilter(ljust) def rjust(value, arg): """ - Right-aligns the value in a field of a given width + Right-aligns the value in a field of a given width. - Argument: field size + Argument: field size. """ return value.rjust(int(arg)) rjust = stringfilter(rjust) def center(value, arg): - "Centers the value in a field of a given width" + """Centers the value in a field of a given width.""" return value.center(int(arg)) center = stringfilter(center) def cut(value, arg): - "Removes all values of arg from the given string" + """Removes all values of arg from the given string.""" return value.replace(arg, u'') cut = stringfilter(cut) @@ -272,7 +277,7 @@ def linebreaksbr(value): linebreaksbr = stringfilter(linebreaksbr) def removetags(value, tags): - "Removes a space separated list of [X]HTML tags from the output" + """Removes a space separated list of [X]HTML tags from the output.""" tags = [re.escape(tag) for tag in tags.split()] tags_re = u'(%s)' % u'|'.join(tags) starttag_re = re.compile(ur'<%s(/?>|(\s+[^>]*>))' % tags_re, re.U) @@ -283,7 +288,7 @@ def removetags(value, tags): removetags = stringfilter(removetags) def striptags(value): - "Strips all [X]HTML tags" + """Strips all [X]HTML tags.""" from django.utils.html import strip_tags return strip_tags(value) striptags = stringfilter(striptags) @@ -314,29 +319,29 @@ def dictsortreversed(value, arg): return [item[1] for item in decorated] def first(value): - "Returns the first item in a list" + """Returns the first item in a list.""" try: return value[0] except IndexError: return u'' def join(value, arg): - "Joins a list with a string, like Python's ``str.join(list)``" + """Joins a list with a string, like Python's ``str.join(list)``.""" try: return arg.join(map(force_unicode, value)) except AttributeError: # fail silently but nicely return value def length(value): - "Returns the length of the value - useful for lists" + """Returns the length of the value - useful for lists.""" return len(value) def length_is(value, arg): - "Returns a boolean of whether the value's length is the argument" + """Returns a boolean of whether the value's length is the argument.""" return len(value) == int(arg) def random(value): - "Returns a random item from the list" + """Returns a random item from the list.""" return random_module.choice(value) def slice_(value, arg): @@ -416,7 +421,7 @@ def unordered_list(value): sublist = '' sublist_item = None if isinstance(title, (list, tuple)): - sublist_item = title + sublist_item = title title = '' elif i < list_length - 1: next_item = list_[i+1] @@ -424,7 +429,7 @@ def unordered_list(value): # The next item is a sub-list. sublist_item = next_item # We've processed the next item now too. - i += 1 + i += 1 if sublist_item: sublist = _helper(sublist_item, tabs+1) sublist = '\n%s\n%s' % (indent, sublist, @@ -433,7 +438,7 @@ def unordered_list(value): sublist)) i += 1 return '\n'.join(output) - value, converted = convert_old_style_list(value) + value, converted = convert_old_style_list(value) return _helper(value) ################### @@ -441,7 +446,7 @@ def unordered_list(value): ################### def add(value, arg): - "Adds the arg to the value" + """Adds the arg to the value.""" return int(value) + int(arg) def get_digit(value, arg): @@ -468,7 +473,7 @@ def get_digit(value, arg): ################### def date(value, arg=None): - "Formats a date according to the given format" + """Formats a date according to the given format.""" from django.utils.dateformat import format if not value: return u'' @@ -477,7 +482,7 @@ def date(value, arg=None): return format(value, arg) def time(value, arg=None): - "Formats a time according to the given format" + """Formats a time according to the given format.""" from django.utils.dateformat import time_format if value in (None, u''): return u'' @@ -486,7 +491,7 @@ def time(value, arg=None): return time_format(value, arg) def timesince(value, arg=None): - 'Formats a date as the time since that date (i.e. "4 days, 6 hours")' + """Formats a date as the time since that date (i.e. "4 days, 6 hours").""" from django.utils.timesince import timesince if not value: return u'' @@ -495,7 +500,7 @@ def timesince(value, arg=None): return timesince(value) def timeuntil(value, arg=None): - 'Formats a date as the time until that date (i.e. "4 days, 6 hours")' + """Formats a date as the time until that date (i.e. "4 days, 6 hours").""" from django.utils.timesince import timesince from datetime import datetime if not value: @@ -509,17 +514,17 @@ def timeuntil(value, arg=None): ################### def default(value, arg): - "If value is unavailable, use given default" + """If value is unavailable, use given default.""" return value or arg def default_if_none(value, arg): - "If value is None, use given default" + """If value is None, use given default.""" if value is None: return arg return value def divisibleby(value, arg): - "Returns true if the value is devisible by the argument" + """Returns True if the value is devisible by the argument.""" return int(value) % int(arg) == 0 def yesno(value, arg=None): @@ -544,7 +549,8 @@ def yesno(value, arg=None): return value # Invalid arg. try: yes, no, maybe = bits - except ValueError: # unpack list of wrong size (no "maybe" value provided) + except ValueError: + # Unpack list of wrong size (no "maybe" value provided). yes, no, maybe = bits[0], bits[1], bits[1] if value is None: return maybe @@ -558,8 +564,8 @@ def yesno(value, arg=None): def filesizeformat(bytes): """ - Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102 - bytes, etc). + Formats the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, + 102 bytes, etc). """ try: bytes = float(bytes) @@ -591,23 +597,23 @@ def pluralize(value, arg=u's'): try: if int(value) != 1: return plural_suffix - except ValueError: # invalid string that's not a number + except ValueError: # Invalid string that's not a number. pass - except TypeError: # value isn't a string or a number; maybe it's a list? + except TypeError: # Value isn't a string or a number; maybe it's a list? try: if len(value) != 1: return plural_suffix - except TypeError: # len() of unsized object + except TypeError: # len() of unsized object. pass return singular_suffix def phone2numeric(value): - "Takes a phone number and converts it in to its numerical equivalent" + """Takes a phone number and converts it in to its numerical equivalent.""" from django.utils.text import phone2numeric return phone2numeric(value) def pprint(value): - "A wrapper around pprint.pprint -- for debugging, really" + """A wrapper around pprint.pprint -- for debugging, really.""" from pprint import pformat try: return pformat(value) diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 927667c812..d3c18897eb 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -1,6 +1,12 @@ -"Default tags used by the template system, available to all templates." +"""Default tags used by the template system, available to all templates.""" +import sys +import re from itertools import cycle as itertools_cycle +try: + reversed +except NameError: + from django.utils.itercompat import reversed # Python 2.3 fallback from django.template import Node, NodeList, Template, Context, Variable from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END @@ -8,13 +14,6 @@ from django.template import get_library, Library, InvalidTemplateLibrary from django.conf import settings from django.utils.encoding import smart_str, smart_unicode from django.utils.itercompat import groupby -import sys -import re - -try: - reversed -except NameError: - from django.utils.itercompat import reversed # Python 2.3 fallback register = Library() @@ -48,7 +47,7 @@ class FilterNode(Node): def render(self, context): output = self.nodelist.render(context) - # apply filters + # Apply filters. context.update({'var': output}) filtered = self.filter_expr.resolve(context) context.pop() @@ -80,7 +79,8 @@ class ForNode(Node): else: reversed = '' return "" % \ - (', '.join( self.loopvars ), self.sequence, len(self.nodelist_loop), reversed) + (', '.join(self.loopvars), self.sequence, len(self.nodelist_loop), + reversed) def __iter__(self): for node in self.nodelist_loop: @@ -114,19 +114,20 @@ class ForNode(Node): unpack = len(self.loopvars) > 1 for i, item in enumerate(values): context['forloop'] = { - # shortcuts for current loop iteration number + # Shortcuts for current loop iteration number. 'counter0': i, 'counter': i+1, - # reverse counter iteration numbers + # Reverse counter iteration numbers. 'revcounter': len_values - i, 'revcounter0': len_values - i - 1, - # boolean values designating first and last times through loop + # Boolean values designating first and last times through loop. 'first': (i == 0), 'last': (i == len_values - 1), 'parentloop': parentloop, } if unpack: - # If there are multiple loop variables, unpack the item into them. + # If there are multiple loop variables, unpack the item into + # them. context.update(dict(zip(self.loopvars, item))) else: context[self.loopvars[0]] = item @@ -153,8 +154,8 @@ class IfChangedNode(Node): self._last_seen = None try: if self._varlist: - # Consider multiple parameters. - # This automatically behaves like a OR evaluation of the multiple variables. + # Consider multiple parameters. This automatically behaves + # like an OR evaluation of the multiple variables. compare_to = [var.resolve(context) for var in self._varlist] else: compare_to = self.nodelist.render(context) @@ -248,13 +249,17 @@ class RegroupNode(Node): def render(self, context): obj_list = self.target.resolve(context, True) - if obj_list == None: # target_var wasn't found in context; fail silently + if obj_list == None: + # target variable wasn't found in context; fail silently. context[self.var_name] = [] return '' - # List of dictionaries in the format + # List of dictionaries in the format: # {'grouper': 'key', 'list': [list of contents]}. - context[self.var_name] = [{'grouper':key, 'list':list(val)} for key, val in - groupby(obj_list, lambda v, f=self.expression.resolve: f(v, True))] + context[self.var_name] = [ + {'grouper': key, 'list': list(val)} + for key, val in + groupby(obj_list, lambda v, f=self.expression.resolve: f(v, True)) + ] return '' def include_is_allowed(filepath): @@ -338,13 +343,15 @@ class URLNode(Node): def render(self, context): from django.core.urlresolvers import reverse, NoReverseMatch args = [arg.resolve(context) for arg in self.args] - kwargs = dict([(smart_str(k,'ascii'), v.resolve(context)) for k, v in self.kwargs.items()]) + kwargs = dict([(smart_str(k,'ascii'), v.resolve(context)) + for k, v in self.kwargs.items()]) try: return reverse(self.view_name, args=args, kwargs=kwargs) except NoReverseMatch: try: project_name = settings.SETTINGS_MODULE.split('.')[0] - return reverse(project_name + '.' + self.view_name, args=args, kwargs=kwargs) + return reverse(project_name + '.' + self.view_name, + args=args, kwargs=kwargs) except NoReverseMatch: return '' @@ -388,7 +395,7 @@ class WithNode(Node): #@register.tag def comment(parser, token): """ - Ignore everything between ``{% comment %}`` and ``{% endcomment %}`` + Ignores everything between ``{% comment %}`` and ``{% endcomment %}``. """ parser.skip_past('endcomment') return CommentNode() @@ -397,7 +404,7 @@ comment = register.tag(comment) #@register.tag def cycle(parser, token): """ - Cycle among the given strings each time this tag is encountered + Cycles among the given strings each time this tag is encountered. Within a loop, cycles among the given strings each time through the loop:: @@ -416,14 +423,14 @@ def cycle(parser, token): ... You can use any number of values, seperated by spaces. Commas can also - be used to separate values; if a comma is used, the cycle values are + be used to separate values; if a comma is used, the cycle values are interpreted as literal strings. """ - # Note: This returns the exact same node on each {% cycle name %} call; that - # is, the node object returned from {% cycle a b c as name %} and the one - # returned from {% cycle name %} are the exact same object. This shouldn't - # cause problems (heh), but if it does, now you know. + # Note: This returns the exact same node on each {% cycle name %} call; + # that is, the node object returned from {% cycle a b c as name %} and the + # one returned from {% cycle name %} are the exact same object. This + # shouldn't cause problems (heh), but if it does, now you know. # # Ugly hack warning: this stuffs the named template dict into parser so # that names are only unique within each template (as opposed to using @@ -441,10 +448,11 @@ def cycle(parser, token): args[1:2] = ['"%s"' % arg for arg in args[1].split(",")] if len(args) == 2: - # {% cycle foo %} case + # {% cycle foo %} case. name = args[1] if not hasattr(parser, '_namedCycleNodes'): - raise TemplateSyntaxError("No named cycles in template: '%s' is not defined" % name) + raise TemplateSyntaxError("No named cycles in template." + " '%s' is not defined" % name) if not name in parser._namedCycleNodes: raise TemplateSyntaxError("Named cycle '%s' does not exist" % name) return parser._namedCycleNodes[name] @@ -462,7 +470,8 @@ cycle = register.tag(cycle) def debug(parser, token): """ - Output a whole load of debugging information, including the current context and imported modules. + Outputs a whole load of debugging information, including the current + context and imported modules. Sample usage:: @@ -476,7 +485,7 @@ debug = register.tag(debug) #@register.tag(name="filter") def do_filter(parser, token): """ - Filter the contents of the blog through variable filters. + Filters the contents of the blog through variable filters. Filters can also be piped through each other, and they can have arguments -- just like in variable syntax. @@ -525,14 +534,15 @@ def firstof(parser, token): """ bits = token.split_contents()[1:] if len(bits) < 1: - raise TemplateSyntaxError, "'firstof' statement requires at least one argument" + raise TemplateSyntaxError("'firstof' statement requires at least one" + " argument") return FirstOfNode(bits) firstof = register.tag(firstof) #@register.tag(name="for") def do_for(parser, token): """ - Loop over each item in an array. + Loops over each item in an array. For example, to display a list of athletes given ``athlete_list``:: @@ -544,9 +554,9 @@ def do_for(parser, token): You can loop over a list in reverse by using ``{% for obj in list reversed %}``. - + You can also unpack multiple values from a two-dimensional array:: - + {% for key,value in dict.items %} {{ key }}: {{ value }} {% endfor %} @@ -571,17 +581,20 @@ def do_for(parser, token): """ bits = token.contents.split() if len(bits) < 4: - raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents + raise TemplateSyntaxError("'for' statements should have at least four" + " words: %s" % token.contents) reversed = bits[-1] == 'reversed' in_index = reversed and -3 or -2 if bits[in_index] != 'in': - raise TemplateSyntaxError, "'for' statements should use the format 'for x in y': %s" % token.contents + raise TemplateSyntaxError("'for' statements should use the format" + " 'for x in y': %s" % token.contents) loopvars = re.sub(r' *, *', ',', ' '.join(bits[1:in_index])).split(',') for var in loopvars: if not var or ' ' in var: - raise TemplateSyntaxError, "'for' tag received an invalid argument: %s" % token.contents + raise TemplateSyntaxError("'for' tag received an invalid argument:" + " %s" % token.contents) sequence = parser.compile_filter(bits[in_index+1]) nodelist_loop = parser.parse(('endfor',)) @@ -606,7 +619,7 @@ def do_ifequal(parser, token, negate): #@register.tag def ifequal(parser, token): """ - Output the contents of the block if the two arguments equal each other. + Outputs the contents of the block if the two arguments equal each other. Examples:: @@ -625,7 +638,10 @@ ifequal = register.tag(ifequal) #@register.tag def ifnotequal(parser, token): - """Output the contents of the block if the two arguments are not equal. See ifequal.""" + """ + Outputs the contents of the block if the two arguments are not equal. + See ifequal. + """ return do_ifequal(parser, token, True) ifnotequal = register.tag(ifnotequal) @@ -634,9 +650,7 @@ def do_if(parser, token): """ The ``{% if %}`` tag evaluates a variable, and if that variable is "true" (i.e. exists, is not empty, and is not a false boolean value) the contents - of the block are output: - - :: + of the block are output:: {% if athlete_list %} Number of athletes: {{ athlete_list|count }} @@ -647,8 +661,8 @@ def do_if(parser, token): In the above, if ``athlete_list`` is not empty, the number of athletes will be displayed by the ``{{ athlete_list|count }}`` variable. - As you can see, the ``if`` tag can take an option ``{% else %}`` clause that - will be displayed if the test fails. + As you can see, the ``if`` tag can take an option ``{% else %}`` clause + that will be displayed if the test fails. ``if`` tags may use ``or``, ``and`` or ``not`` to test a number of variables or to negate a given variable:: @@ -673,9 +687,9 @@ def do_if(parser, token): There are some athletes and absolutely no coaches. {% endif %} - ``if`` tags do not allow ``and`` and ``or`` clauses with the same - tag, because the order of logic would be ambigous. For example, - this is invalid:: + ``if`` tags do not allow ``and`` and ``or`` clauses with the same tag, + because the order of logic would be ambigous. For example, this is + invalid:: {% if athlete_list and coach_list or cheerleader_list %} @@ -691,8 +705,8 @@ def do_if(parser, token): bits = token.contents.split() del bits[0] if not bits: - raise TemplateSyntaxError, "'if' statement requires at least one argument" - # bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d'] + raise TemplateSyntaxError("'if' statement requires at least one argument") + # Bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d'] bitstr = ' '.join(bits) boolpairs = bitstr.split(' and ') boolvars = [] @@ -727,13 +741,13 @@ do_if = register.tag("if", do_if) #@register.tag def ifchanged(parser, token): """ - Check if a value has changed from the last iteration of a loop. + Checks if a value has changed from the last iteration of a loop. The 'ifchanged' block tag is used within a loop. It has two possible uses. 1. Checks its own rendered contents against its previous state and only - displays the content if it has changed. For example, this displays a list of - days, only displaying the month if it changes:: + displays the content if it has changed. For example, this displays a + list of days, only displaying the month if it changes::

Archive for {{ year }}

@@ -742,9 +756,9 @@ def ifchanged(parser, token): {{ date|date:"j" }} {% endfor %} - 2. If given a variable, check whether that variable has changed. For example, the - following shows the date every time it changes, but only shows the hour if both - the hour and the date have changed:: + 2. If given a variable, check whether that variable has changed. + For example, the following shows the date every time it changes, but + only shows the hour if both the hour and the date have changed:: {% for date in days %} {% ifchanged date.date %} {{ date.date }} {% endifchanged %} @@ -762,7 +776,7 @@ ifchanged = register.tag(ifchanged) #@register.tag def ssi(parser, token): """ - Output the contents of a given file into the page. + Outputs the contents of a given file into the page. Like a simple "include" tag, the ``ssi`` tag includes the contents of another file -- which must be specified using an absolute page -- @@ -778,21 +792,24 @@ def ssi(parser, token): bits = token.contents.split() parsed = False if len(bits) not in (2, 3): - raise TemplateSyntaxError, "'ssi' tag takes one argument: the path to the file to be included" + raise TemplateSyntaxError("'ssi' tag takes one argument: the path to" + " the file to be included") if len(bits) == 3: if bits[2] == 'parsed': parsed = True else: - raise TemplateSyntaxError, "Second (optional) argument to %s tag must be 'parsed'" % bits[0] + raise TemplateSyntaxError("Second (optional) argument to %s tag" + " must be 'parsed'" % bits[0]) return SsiNode(bits[1], parsed) ssi = register.tag(ssi) #@register.tag def load(parser, token): """ - Load a custom template tag set. + Loads a custom template tag set. - For example, to load the template tags in ``django/templatetags/news/photos.py``:: + For example, to load the template tags in + ``django/templatetags/news/photos.py``:: {% load news.photos %} """ @@ -803,14 +820,15 @@ def load(parser, token): lib = get_library("django.templatetags.%s" % taglib) parser.add_library(lib) except InvalidTemplateLibrary, e: - raise TemplateSyntaxError, "'%s' is not a valid tag library: %s" % (taglib, e) + raise TemplateSyntaxError("'%s' is not a valid tag library: %s" % + (taglib, e)) return LoadNode() load = register.tag(load) #@register.tag def now(parser, token): """ - Display the date, formatted according to the given string. + Displays the date, formatted according to the given string. Uses the same format as PHP's ``date()`` function; see http://php.net/date for all the possible values. @@ -829,7 +847,7 @@ now = register.tag(now) #@register.tag def regroup(parser, token): """ - Regroup a list of alike objects by a common attribute. + Regroups a list of alike objects by a common attribute. This complex tag is best illustrated by use of an example: say that ``people`` is a list of ``Person`` objects that have ``first_name``, @@ -867,8 +885,8 @@ def regroup(parser, token): Note that `{% regroup %}`` does not work when the list to be grouped is not sorted by the key you are grouping by! This means that if your list of - people was not sorted by gender, you'd need to make sure it is sorted before - using it, i.e.:: + people was not sorted by gender, you'd need to make sure it is sorted + before using it, i.e.:: {% regroup people|dictsort:"gender" by gender as grouped %} @@ -878,10 +896,11 @@ def regroup(parser, token): raise TemplateSyntaxError, "'regroup' tag takes five arguments" target = parser.compile_filter(firstbits[1]) if firstbits[2] != 'by': - raise TemplateSyntaxError, "second argument to 'regroup' tag must be 'by'" + raise TemplateSyntaxError("second argument to 'regroup' tag must be 'by'") lastbits_reversed = firstbits[3][::-1].split(None, 2) if lastbits_reversed[1][::-1] != 'as': - raise TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'" + raise TemplateSyntaxError("next-to-last argument to 'regroup' tag must" + " be 'as'") expression = parser.compile_filter(lastbits_reversed[2][::-1]) @@ -891,8 +910,7 @@ regroup = register.tag(regroup) def spaceless(parser, token): """ - Removes whitespace between HTML tags. This includes tab - characters and newlines. + Removes whitespace between HTML tags, including tab and newline characters. Example usage:: @@ -906,8 +924,8 @@ def spaceless(parser, token):

Foo

- Only space between *tags* is normalized -- not space between tags and text. In - this example, the space around ``Hello`` won't be stripped:: + Only space between *tags* is normalized -- not space between tags and text. + In this example, the space around ``Hello`` won't be stripped:: {% spaceless %} @@ -923,7 +941,7 @@ spaceless = register.tag(spaceless) #@register.tag def templatetag(parser, token): """ - Output one of the bits used to compose template tags. + Outputs one of the bits used to compose template tags. Since the template system has no concept of "escaping", to display one of the bits used in template tags, you must use the ``{% templatetag %}`` tag. @@ -948,8 +966,9 @@ def templatetag(parser, token): raise TemplateSyntaxError, "'templatetag' statement takes one argument" tag = bits[1] if tag not in TemplateTagNode.mapping: - raise TemplateSyntaxError, "Invalid templatetag argument: '%s'. Must be one of: %s" % \ - (tag, TemplateTagNode.mapping.keys()) + raise TemplateSyntaxError("Invalid templatetag argument: '%s'." + " Must be one of: %s" % + (tag, TemplateTagNode.mapping.keys())) return TemplateTagNode(tag) templatetag = register.tag(templatetag) @@ -957,7 +976,8 @@ def url(parser, token): """ Returns an absolute URL matching given view with its parameters. - This is a way to define links that aren't tied to a particular URL configuration:: + This is a way to define links that aren't tied to a particular URL + configuration:: {% url path.to.some_view arg1,arg2,name1=value1 %} @@ -985,7 +1005,8 @@ def url(parser, token): """ bits = token.contents.split(' ', 2) if len(bits) < 2: - raise TemplateSyntaxError, "'%s' takes at least one argument (path to a view)" % bits[0] + raise TemplateSyntaxError("'%s' takes at least one argument" + " (path to a view)" % bits[0]) args = [] kwargs = {} if len(bits) > 2: @@ -1010,8 +1031,8 @@ def widthratio(parser, token): Above, if ``this_value`` is 175 and ``max_value`` is 200, the the image in - the above example will be 88 pixels wide (because 175/200 = .875; .875 * - 100 = 87.5 which is rounded up to 88). + the above example will be 88 pixels wide (because 175/200 = .875; + .875 * 100 = 87.5 which is rounded up to 88). """ bits = token.contents.split() if len(bits) != 4: @@ -1028,7 +1049,7 @@ widthratio = register.tag(widthratio) #@register.tag def do_with(parser, token): """ - Add a value to the context (inside of this block) for caching and easy + Adds a value to the context (inside of this block) for caching and easy access. For example:: @@ -1039,7 +1060,8 @@ def do_with(parser, token): """ bits = list(token.split_contents()) if len(bits) != 4 or bits[2] != "as": - raise TemplateSyntaxError, "%r expected format is 'value as name'" % bits[0] + raise TemplateSyntaxError("%r expected format is 'value as name'" % + bits[0]) var = parser.compile_filter(bits[1]) name = bits[3] nodelist = parser.parse(('endwith',))