Ticket #1400: templates_r2738.diff

File templates_r2738.diff, 38.1 KB (added by django@…, 9 years ago)

Updated patch for template extension requirement

  • django/contrib/admin/templatetags/admin_list.py

    === django/contrib/admin/templatetags/admin_list.py
    ==================================================================
     
    6565        'ALL_VAR': ALL_VAR,
    6666        '1': 1,
    6767    }
    68 pagination = register.inclusion_tag('admin/pagination.html')(pagination)
     68pagination = register.inclusion_tag(pagination, 'admin/pagination.html')
    6969
    7070def result_headers(cl):
    7171    lookup_opts = cl.lookup_opts
     
    185185    return {'cl': cl,
    186186            'result_headers': list(result_headers(cl)),
    187187            'results': list(results(cl))}
    188 result_list = register.inclusion_tag("admin/change_list_results.html")(result_list)
     188result_list = register.inclusion_tag(result_list, 'admin/change_list_results.html')
    189189
    190190def date_hierarchy(cl):
    191191    if cl.lookup_opts.admin.date_hierarchy:
     
    245245                    'title': year.year
    246246                } for year in years]
    247247            }
    248 date_hierarchy = register.inclusion_tag('admin/date_hierarchy.html')(date_hierarchy)
     248date_hierarchy = register.inclusion_tag(date_hierarchy, 'admin/date_hierarchy.html')
    249249
    250250def search_form(cl):
    251251    return {
     
    253253        'show_result_count': cl.result_count != cl.full_result_count and not cl.opts.one_to_one_field,
    254254        'search_var': SEARCH_VAR
    255255    }
    256 search_form = register.inclusion_tag('admin/search_form.html')(search_form)
     256search_form = register.inclusion_tag(search_form, 'admin/search_form.html')
    257257
    258258def filter(cl, spec):
    259259    return {'title': spec.title(), 'choices' : list(spec.choices(cl))}
    260 filter = register.inclusion_tag('admin/filter.html')(filter)
     260filter = register.inclusion_tag(filter, 'admin/filter.html')
    261261
    262262def filters(cl):
    263263    return {'cl': cl}
    264 filters = register.inclusion_tag('admin/filters.html')(filters)
     264filters = register.inclusion_tag(filters, 'admin/filters.html')
  • django/contrib/admin/templatetags/admin_modify.py

    === django/contrib/admin/templatetags/admin_modify.py
    ==================================================================
     
    2222include_admin_script = register.simple_tag(include_admin_script)
    2323
    2424def submit_row(context):
    25     opts = context['opts']
    26     change = context['change']
    27     is_popup = context['is_popup']
     25    opts = context.get('opts')
     26    change = context.get('change')
     27    is_popup = context.get('is_popup')
    2828    return {
    2929        'onclick_attrib': (opts.get_ordered_objects() and change
    3030                            and 'onclick="submitOrderForm();"' or ''),
     
    3535        'show_save_and_continue': not is_popup and context['has_change_permission'],
    3636        'show_save': True
    3737    }
    38 submit_row = register.inclusion_tag('admin/submit_line.html', takes_context=True)(submit_row)
     38submit_row = register.inclusion_tag(submit_row, 'admin/submit_line.html', takes_context=True)
    3939
    4040def field_label(bound_field):
    4141    class_names = []
     
    229229        'bound_fields': bound_fields,
    230230        'class_names': " ".join(class_names),
    231231    }
    232 admin_field_line = register.inclusion_tag('admin/field_line.html', takes_context=True)(admin_field_line)
     232admin_field_line = register.inclusion_tag(admin_field_line, 'admin/field_line.html', takes_context=True)
  • django/contrib/admin/templatetags/adminapplist.py

    === django/contrib/admin/templatetags/adminapplist.py
    ==================================================================
     
    6161        raise template.TemplateSyntaxError, "First argument to '%s' tag must be 'as'" % tokens[0]
    6262    return AdminApplistNode(tokens[2])
    6363
    64 register.tag('get_admin_app_list', get_admin_app_list)
     64register.tag(get_admin_app_list, name='get_admin_app_list')
  • django/contrib/admin/templatetags/log.py

    === django/contrib/admin/templatetags/log.py
    ==================================================================
     
    5050                raise template.TemplateSyntaxError, "Fourth argument in '%s' must be 'for_user'" % self.tag_name
    5151        return AdminLogNode(limit=tokens[1], varname=tokens[3], user=(len(tokens) > 5 and tokens[5] or None))
    5252
    53 register.tag('get_admin_log', DoGetAdminLog('get_admin_log'))
     53register.tag(DoGetAdminLog('get_admin_log'), name='get_admin_log')
  • django/contrib/admin/views/template.py

    === django/contrib/admin/views/template.py
    ==================================================================
     
    5656            node.template_dirs = settings_module.TEMPLATE_DIRS
    5757            return node
    5858        register = template.Library()
    59         register.tag('extends', new_do_extends)
     59        register.tag(new_do_extends, name='extends')
    6060        template.builtins.append(register)
    6161
    6262        # Now validate the template using the new template dirs
  • django/contrib/comments/templatetags/comments.py

    === django/contrib/comments/templatetags/comments.py
    ==================================================================
     
    313313        return CommentListNode(package, module, var_name, obj_id, tokens[5], self.free, ordering)
    314314
    315315# registration comments
    316 register.tag('get_comment_list', DoGetCommentList(False))
    317 register.tag('comment_form', DoCommentForm(False))
    318 register.tag('get_comment_count', DoCommentCount(False))
     316register.tag(DoGetCommentList(False), name='get_comment_list')
     317register.tag(DoCommentForm(False), name='comment_form')
     318register.tag(DoCommentCount(False), name='get_comment_count')
    319319# free comments
    320 register.tag('get_free_comment_list', DoGetCommentList(True))
    321 register.tag('free_comment_form', DoCommentForm(True))
    322 register.tag('get_free_comment_count', DoCommentCount(True))
     320register.tag(DoGetCommentList(True), name='get_free_comment_list')
     321register.tag(DoCommentForm(True), name='free_comment_form')
     322register.tag(DoCommentCount(True), name='get_free_comment_count')
  • django/template/__init__.py

    === django/template/__init__.py
    ==================================================================
     
    5454>>> t.render(c)
    5555'\n<html>\n\n</html>\n'
    5656"""
     57import keyword
    5758import re
    5859from inspect import getargspec
    5960from django.utils.functional import curry
     
    7677VARIABLE_TAG_END = '}}'
    7778
    7879ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.'
     80BOOLEANS = ['False', 'True']
    7981
    8082# what to report as the origin for templates that come from non-loader sources
    8183# (e.g. strings)
     
    223225            elif token.token_type == TOKEN_VAR:
    224226                if not token.contents:
    225227                    self.empty_variable(token)
    226                 filter_expression = self.compile_filter(token.contents)
     228                filter_expression = self.compile_filter(token.contents, default=settings.TEMPLATE_STRING_IF_INVALID)
    227229                var_node = self.create_variable_node(filter_expression)
    228230                self.extend_nodelist(nodelist, var_node,token)
    229231            elif token.token_type == TOKEN_BLOCK:
     
    305307        self.tags.update(lib.tags)
    306308        self.filters.update(lib.filters)
    307309
    308     def compile_filter(self,token):
     310    def compile_filter(self, token, default=None):
    309311        "Convenient wrapper for FilterExpression"
    310         return FilterExpression(token, self)
     312        return FilterExpression(token, self, default)
    311313
    312314    def find_filter(self, filter_name):
    313315        if self.filters.has_key(filter_name):
     
    492494    This class should never be instantiated outside of the
    493495    get_filters_from_token helper function.
    494496    """
    495     def __init__(self, token, parser):
     497    def __init__(self, token, parser, default=None):
    496498        self.token = token
    497         matches = filter_re.finditer(token)
     499        self.default = default
    498500        var = None
    499501        filters = []
    500502        upto = 0
    501         for match in matches:
     503        for match in filter_re.finditer(token):
    502504            start = match.start()
    503505            if upto != start:
    504506                raise TemplateSyntaxError, "Could not parse some characters: %s|%s|%s"  % \
     
    530532                upto = match.end()
    531533        if upto != len(token):
    532534            raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:]
    533         self.var , self.filters = var, filters
     535        self.var, self.filters = var, filters
    534536
    535537    def resolve(self, context):
    536538        try:
    537539            obj = resolve_variable(self.var, context)
    538540        except VariableDoesNotExist:
    539             obj = settings.TEMPLATE_STRING_IF_INVALID
     541            return self.default
    540542        for func, args in self.filters:
    541543            arg_vals = []
    542544            for lookup, arg in args:
     
    584586    """
    585587    Returns the resolved variable, which may contain attribute syntax, within
    586588    the given context. The variable may be a hard-coded string (if it begins
    587     and ends with single or double quote marks).
     589    and ends with single or double quote marks), a boolean literal, or an
     590    integer or float literal.
    588591
    589592    >>> c = {'article': {'section':'News'}}
    590593    >>> resolve_variable('article.section', c)
     
    600603
    601604    (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
    602605    """
    603     if path[0] in '0123456789':
     606    if path[0].isdigit():
    604607        number_type = '.' in path and float or int
    605         try:
    606             current = number_type(path)
    607         except ValueError:
    608             current = settings.TEMPLATE_STRING_IF_INVALID
    609     elif path[0] in ('"', "'") and path[0] == path[-1]:
    610         current = path[1:-1]
    611     else:
    612         current = context
    613         bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR)
    614         while bits:
    615             try: # dictionary lookup
    616                 current = current[bits[0]]
    617             except (TypeError, AttributeError, KeyError):
    618                 try: # attribute lookup
    619                     current = getattr(current, bits[0])
    620                     if callable(current):
    621                         if getattr(current, 'alters_data', False):
    622                             current = settings.TEMPLATE_STRING_IF_INVALID
    623                         else:
    624                             try: # method call (assuming no args required)
    625                                 current = current()
    626                             except TypeError: # arguments *were* required
    627                                 # GOTCHA: This will also catch any TypeError
    628                                 # raised in the function itself.
    629                                 current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call
    630                             except Exception, e:
    631                                 if getattr(e, 'silent_variable_failure', False):
    632                                     current = settings.TEMPLATE_STRING_IF_INVALID
    633                                 else:
    634                                     raise
    635                 except (TypeError, AttributeError):
    636                     try: # list-index lookup
    637                         current = current[int(bits[0])]
    638                     except (IndexError, ValueError, KeyError):
    639                         raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bits[0], current) # missing attribute
    640                 except Exception, e:
    641                     if getattr(e, 'silent_variable_failure', False):
    642                         current = settings.TEMPLATE_STRING_IF_INVALID
    643                     else:
    644                         raise       
    645             del bits[0]
    646     return current
     608        return number_type(path)
     609    if path in BOOLEANS:
     610        return bool(BOOLEANS.index(path))
     611    if path[0] in ('"', "'"):
     612        if path[0] == path[-1]:
     613            return path[1:-1]
     614        raise VariableDoesNotExist, "Missing quotes in string literal %s" % (path,)
     615    for bit in path.split(VARIABLE_ATTRIBUTE_SEPARATOR):
     616        try: # dictionary lookup
     617            context = context[bit]
     618        except (TypeError, AttributeError, KeyError):
     619            try: # attribute lookup
     620                context = getattr(context, bit)
     621            except (TypeError, AttributeError):
     622                try: # list-index lookup
     623                    context = context[int(bit)]
     624                except (IndexError, ValueError, KeyError):
     625                    raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bit, context) # missing attribute
     626            else:
     627                if callable(context):
     628                    if getattr(context, 'alters_data', False):
     629                        raise VariableDoesNotExist("Failed lookup for key [%s] in %r" % (bit, context))
     630                    try: # method call (assuming no args required)
     631                        context = context()
     632                    except Exception, e:
     633                        if getattr(e, 'silent_variable_failure', False):
     634                            raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bit, context) # missing attribute
     635                        raise
     636    return context
    647637
     638tag_tokens_re = re.compile(r"""
     639(?:\s*)                           # ignore preceeding whitespace
     640(                                 # token group
     641    (?:[A-Za-z_][0-9A-Za-z_]*=)?" # optional name and open double-quote
     642    [^"\\]*                       # normal characters
     643    (?:\\.                        # chew up backslash and following char
     644        (?:|[^"\\])*              # normal characters
     645    )*                            # repeat as needed to chew up the backslashes
     646    "                             # close double-quote
     647|
     648    (?:[A-Za-z_][0-9A-Za-z_]*=)?' # optional name and open single-quote
     649    [^'\\]*                       # normal characters
     650    (?:\\.                        # chew up backslash and following char
     651        (?:|[^'\\])*              # normal characters
     652    )*                            # repeat as needed to chew up the backslashes
     653    '                             # close single-quote
     654|
     655    (?:[A-Za-z_][0-9A-Za-z_]*=)?  # optional name
     656    [^"'\s][^\s]*                 # unquoted token
     657)
     658(?:\s+|$)                         # chew up following ws until next token
     659""", re.VERBOSE)
     660
     661def tokenize_tag_contents(contents):
     662
     663    """ Parse tag contents into (tag_name, args_to_resolve, kwds_to_resolve).
     664    If an argument name is a Python keyword append an underscore.
     665
     666    >>> tokenize_tag_contents("An 'easy' one.")
     667    ('An', ["'easy'", 'one.'], {})
     668    >>> tokenize_tag_contents(r'''Please don't try 'thi\\'s at' named="hom\\"e."''')
     669    ('Please', ["don't", 'try', "'thi\'s at'"], {'named': '"hom\\\\"e."'})
     670    """
     671
     672    bits = []
     673    i, n = 0, len(contents)
     674    while i < n:
     675        m = tag_tokens_re.match(contents, i)
     676        if not m:
     677            raise ValueError("Can't parse string %s at index %s" %(repr(contents), i))
     678        bit = m.group(1)
     679        if bit.startswith('"'):
     680            bit = bit.replace('\\"', '"')
     681        elif bit.startswith("'"):
     682            bit = bit.replace("\\'", "'")
     683        bits.append(bit)
     684        i = m.end()
     685    tag_name = bits[0]
     686    args_to_resolve = []
     687    kwds_to_resolve = {}
     688    for bit in bits[1:]:
     689        if bit[0] in ("'", '"'):
     690            if kwds_to_resolve:
     691                raise SyntaxError("template tag syntax error: non-keyword arguments must come before keyword arguments")
     692            args_to_resolve.append(bit)
     693        else:
     694            try:
     695                name, value = bit.split('=', 1)
     696                if keyword.iskeyword(name):
     697                    name += '_'
     698                kwds_to_resolve[name] = value
     699            except ValueError:
     700                if kwds_to_resolve:
     701                    raise SyntaxError("template tag syntax error: non-keyword arguments must come before keyword arguments")
     702                args_to_resolve.append(bit)
     703    return tag_name, args_to_resolve, kwds_to_resolve
     704
     705def resolve_tag_arguments(context, args_to_resolve, kwds_to_resolve):
     706    resolved_args = [resolve_variable(var, context) for var in args_to_resolve]
     707    resolved_kwds = dict([(name, resolve_variable(var, context)) for name, var in kwds_to_resolve.items()])
     708    return resolved_args, resolved_kwds
     709
    648710class Node:
    649711    def render(self, context):
    650712        "Return the node rendered as a string"
     
    738800            raise
    739801        return self.encode_output(output)
    740802
    741 def generic_tag_compiler(params, defaults, name, node_class, parser, token):
    742     "Returns a template.Node subclass."
    743     bits = token.contents.split()[1:]
    744     bmax = len(params)
    745     def_len = defaults and len(defaults) or 0
    746     bmin = bmax - def_len
    747     if(len(bits) < bmin or len(bits) > bmax):
    748         if bmin == bmax:
    749             message = "%s takes %s arguments" % (name, bmin)
    750         else:
    751             message = "%s takes between %s and %s arguments" % (name, bmin, bmax)
    752         raise TemplateSyntaxError, message
    753     return node_class(bits)
     803class SimpleNode(Node):
     804    def __init__(self, func, takes_context, block_nodelist, args_to_resolve, kwds_to_resolve):
     805        self.func = func
     806        self.takes_context = takes_context
     807        self.block_nodelist = block_nodelist
     808        self.args_to_resolve = args_to_resolve
     809        self.kwds_to_resolve = kwds_to_resolve
    754810
    755 class Library(object):
    756     def __init__(self):
    757         self.filters = {}
    758         self.tags = {}
     811    def render(self, context):
     812        resolved_args, resolved_kwds = resolve_tag_arguments(context, self.args_to_resolve, self.kwds_to_resolve)
     813        if self.block_nodelist:
     814            resolved_args.insert(0, self.block_nodelist)
     815        if self.takes_context:
     816            resolved_args.insert(0, context)
     817        return self.func(*resolved_args, **resolved_kwds) or ''
    759818
    760     def tag(self, name=None, compile_function=None):
    761         if name == None and compile_function == None:
    762             # @register.tag()
    763             return self.tag_function
    764         elif name != None and compile_function == None:
    765             if(callable(name)):
    766                 # @register.tag
    767                 return self.tag_function(name)
    768             else:
    769                 # @register.tag('somename') or @register.tag(name='somename')
    770                 def dec(func):
    771                     return self.tag(name, func)
    772                 return dec
    773         elif name != None and compile_function != None:
    774             # register.tag('somename', somefunc)
    775             self.tags[name] = compile_function
    776             return compile_function
    777         else:
    778             raise InvalidTemplateLibrary, "Unsupported arguments to Library.tag: (%r, %r)", (name, compile_function)
     819class SimpleNodeFactory(object):
     820    def __init__(self, func, takes_context=False, takes_block=False):
     821        self.func = func
     822        self.__doc__ = func.__doc__
     823        self.takes_context = takes_context
     824        self.takes_block = takes_block
    779825
    780     def tag_function(self,func):
    781         self.tags[func.__name__] = func
    782         return func
     826    def __call__(self, parser, token):
     827        tag_name, args_to_resolve, kwds_to_resolve = tokenize_tag_contents(token.contents)
     828        block_nodelist = None
     829        if self.takes_block:
     830            block_nodelist = parser.parse(('end' +  tag_name,))
     831            parser.delete_first_token()
     832        return SimpleNode(self.func, self.takes_context, block_nodelist, args_to_resolve, kwds_to_resolve)
    783833
    784     def filter(self, name=None, filter_func=None):
    785         if name == None and filter_func == None:
    786             # @register.filter()
    787             return self.filter_function
    788         elif filter_func == None:
    789             if(callable(name)):
    790                 # @register.filter
    791                 return self.filter_function(name)
    792             else:
    793                 # @register.filter('somename') or @register.filter(name='somename')
    794                 def dec(func):
    795                     return self.filter(name, func)
    796                 return dec
    797         elif name != None and filter_func != None:
    798             # register.filter('somename', somefunc)
    799             self.filters[name] = filter_func
    800             return filter_func
    801         else:
    802             raise InvalidTemplateLibrary, "Unsupported arguments to Library.filter: (%r, %r, %r)", (name, compile_function, has_arg)
     834class InclusionNode(Node):
     835    def __init__(self, func, template, context_class, takes_context, args_to_resolve, kwds_to_resolve):
     836        self.func = func
     837        self.template = template
     838        self.context_class = context_class
     839        self.takes_context = takes_context
     840        self.args_to_resolve = args_to_resolve
     841        self.kwds_to_resolve = kwds_to_resolve
    803842
    804     def filter_function(self, func):
    805         self.filters[func.__name__] = func
    806         return func
     843    def render(self, context):
     844        resolved_args, resolved_kwds = resolve_tag_arguments(context, self.args_to_resolve, self.kwds_to_resolve)
     845        if self.takes_context:
     846            resolved_args.insert(0, context)
     847        if not getattr(self, 'nodelist', None):
     848            from django.template.loader import get_template
     849            t = get_template(self.template)
     850            self.nodelist = t.nodelist
     851        context = self.context_class(self.func(*resolved_args, **resolved_kwds))
     852        return self.nodelist.render(context)
    807853
    808     def simple_tag(self,func):
    809         (params, xx, xxx, defaults) = getargspec(func)
     854class InclusionNodeFactory(object):
     855    def __init__(self, func, template, context_class=Context, takes_context=False):
     856        self.func = func
     857        self.__doc__ = func.__doc__
     858        self.template = template
     859        self.context_class = context_class
     860        self.takes_context = takes_context
    810861
    811         class SimpleNode(Node):
    812             def __init__(self, vars_to_resolve):
    813                 self.vars_to_resolve = vars_to_resolve
     862    def __call__(self, parser, token):
     863        tag_name, args_to_resolve, kwds_to_resolve = tokenize_tag_contents(token.contents)
     864        return InclusionNode(self.func, self.template, self.context_class, self.takes_context, args_to_resolve, kwds_to_resolve)
    814865
    815             def render(self, context):
    816                 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
    817                 return func(*resolved_vars)
     866class Library(object):
     867    def __init__(self):
     868        self.filters = {}
     869        self.tags = {}
    818870
    819         compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, SimpleNode)
    820         compile_func.__doc__ = func.__doc__
    821         self.tag(func.__name__, compile_func)
    822         return func
     871    def tag(self, func=None, name=None):
     872        if callable(func):
     873            self.tags[name or func.__name__] = func
     874            return func
     875        elif func is None:
     876            return curry(self.tag, name=name)
     877        raise InvalidTemplateLibrary("Unsupported argument to Library.tag: (%r)" % (func,))
    823878
    824     def inclusion_tag(self, file_name, context_class=Context, takes_context=False):
    825         def dec(func):
    826             (params, xx, xxx, defaults) = getargspec(func)
    827             if takes_context:
    828                 if params[0] == 'context':
    829                     params = params[1:]
    830                 else:
    831                     raise TemplateSyntaxError, "Any tag function decorated with takes_context=True must have a first argument of 'context'"
     879    def filter(self, func=None, name=None):
     880        if callable(func):
     881            self.filters[name or func.__name__] = func
     882            return func
     883        elif func is None:
     884            return curry(self.filter, name=name)
     885        raise InvalidTemplateLibrary("Unsupported argument to Library.filter: (%r)" % (func,))
    832886
    833             class InclusionNode(Node):
    834                 def __init__(self, vars_to_resolve):
    835                     self.vars_to_resolve = vars_to_resolve
     887    def simple_tag(self, func=None, takes_context=False, takes_block=False, name=None):
     888        if callable(func):
     889            self.tags[name or func.__name__] = SimpleNodeFactory(func, takes_context, takes_block)
     890            return func
     891        elif func is None:
     892            return curry(self.simple_tag, takes_context=takes_context, takes_block=takes_block, name=name)
     893        raise InvalidTemplateLibrary("Unsupported argument to Library.simple_tag: (%r)" % (func,))
    836894
    837                 def render(self, context):
    838                     resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
    839                     if takes_context:
    840                         args = [context] + resolved_vars
    841                     else:
    842                         args = resolved_vars
    843 
    844                     dict = func(*args)
    845 
    846                     if not getattr(self, 'nodelist', False):
    847                         from django.template.loader import get_template
    848                         t = get_template(file_name)
    849                         self.nodelist = t.nodelist
    850                     return self.nodelist.render(context_class(dict))
    851 
    852             compile_func = curry(generic_tag_compiler, params, defaults, func.__name__, InclusionNode)
    853             compile_func.__doc__ = func.__doc__
    854             self.tag(func.__name__, compile_func)
     895    def inclusion_tag(self, func=None, template=None, context_class=Context, takes_context=False, name=None):
     896        if callable(func):
     897            self.tags[name or func.__name__] = InclusionNodeFactory(func, template, context_class, takes_context)
    855898            return func
    856         return dec
     899        elif func is None:
     900            return curry(self.inclusion_tag, template=template, context_class=context_class, takes_context=takes_context, name=name)
     901        raise InvalidTemplateLibrary("Unsupported argument to Library.inclusion_tag: (%r)" % (func,))
    857902
    858903def get_library(module_name):
    859904    lib = libraries.get(module_name, None)
  • django/template/context.py

    === django/template/context.py
    ==================================================================
     
    3737        for d in self.dicts:
    3838            if d.has_key(key):
    3939                return d[key]
    40         return settings.TEMPLATE_STRING_IF_INVALID
     40        raise KeyError("Context key not found: %s" % key)
    4141
    4242    def __delitem__(self, key):
    4343        "Delete a variable from the current context"
     
    4949                return True
    5050        return False
    5151
    52     def get(self, key, otherwise):
     52    def get(self, key, otherwise=None):
    5353        for d in self.dicts:
    5454            if d.has_key(key):
    5555                return d[key]
  • django/template/defaultfilters.py

    === django/template/defaultfilters.py
    ==================================================================
     
    469469register.filter(removetags)
    470470register.filter(random)
    471471register.filter(rjust)
    472 register.filter('slice', slice_)
     472register.filter(slice_, name='slice')
    473473register.filter(slugify)
    474474register.filter(stringformat)
    475475register.filter(striptags)
  • django/template/defaulttags.py

    === django/template/defaulttags.py
    ==================================================================
     
    4545
    4646    def render(self, context):
    4747        for var in self.vars:
    48             value = resolve_variable(var, context)
     48            try:
     49                value = resolve_variable(var, context)
     50            except VariableDoesNotExist:
     51                continue
    4952            if value:
    5053                return str(value)
    5154        return ''
     
    142145        return "<IfEqualNode>"
    143146
    144147    def render(self, context):
    145         val1 = resolve_variable(self.var1, context)
    146         val2 = resolve_variable(self.var2, context)
     148        try:
     149            val1 = resolve_variable(self.var1, context)
     150        except VariableDoesNotExist:
     151            val1 = None
     152        try:
     153            val2 = resolve_variable(self.var2, context)
     154        except VariableDoesNotExist:
     155            val2 = None
    147156        if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
    148157            return self.nodelist_true.render(context)
    149158        return self.nodelist_false.render(context)
     
    187196
    188197    def render(self, context):
    189198        obj_list = self.target.resolve(context)
    190         if obj_list == '': # target_var wasn't found in context; fail silently
     199        if obj_list is None:
    191200            context[self.var_name] = []
    192201            return ''
    193202        output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]}
     
    391400    nodelist = parser.parse(('endfilter',))
    392401    parser.delete_first_token()
    393402    return FilterNode(filter_expr, nodelist)
    394 filter = register.tag("filter", do_filter)
     403filter = register.tag(do_filter, name='filter')
    395404
    396405#@register.tag
    397406def firstof(parser, token):
     
    469478    nodelist_loop = parser.parse(('endfor',))
    470479    parser.delete_first_token()
    471480    return ForNode(loopvar, sequence, reversed, nodelist_loop)
    472 do_for = register.tag("for", do_for)
     481do_for = register.tag(do_for, name='for')
    473482
    474483def do_ifequal(parser, token, negate):
    475484    """
     
    579588    else:
    580589        nodelist_false = NodeList()
    581590    return IfNode(boolvars, nodelist_true, nodelist_false)
    582 do_if = register.tag("if", do_if)
     591do_if = register.tag(do_if, name='if')
    583592
    584593#@register.tag
    585594def ifchanged(parser, token):
  • django/template/loader_tags.py

    === django/template/loader_tags.py
    ==================================================================
     
    169169        return ConstantIncludeNode(path[1:-1])
    170170    return IncludeNode(bits[1])
    171171
    172 register.tag('block', do_block)
    173 register.tag('extends', do_extends)
    174 register.tag('include', do_include)
     172register.tag(do_block, name='block')
     173register.tag(do_extends, name='extends')
     174register.tag(do_include, name='include')
  • django/templatetags/i18n.py

    === django/templatetags/i18n.py
    ==================================================================
     
    215215
    216216    return BlockTranslateNode(extra_context, singular, plural, countervar, counter)
    217217
    218 register.tag('get_available_languages', do_get_available_languages)
    219 register.tag('get_current_language', do_get_current_language)
    220 register.tag('trans', do_translate)
    221 register.tag('blocktrans', do_block_translate)
     218register.tag(do_get_available_languages, name='get_available_languages')
     219register.tag(do_get_current_language, name='get_current_language')
     220register.tag(do_translate, name='trans')
     221register.tag(do_block_translate, name='blocktrans')
  • docs/templates_python.txt

    === docs/templates_python.txt
    ==================================================================
     
    561561Most filters don't take arguments. In this case, just leave the argument out of
    562562your function. Example::
    563563
    564     def lower(value): # Only one argument.
     564    def do_lower(value): # Only one argument.
    565565        "Converts a string into all lowercase"
    566566        return value.lower()
    567567
    568568When you've written your filter definition, you need to register it with
    569569your ``Library`` instance, to make it available to Django's template language::
    570570
    571     register.filter('cut', cut)
    572     register.filter('lower', lower)
     571    register.filter(cut)
     572    register.filter(do_lower, name='lower')
    573573
    574 The ``Library.filter()`` method takes two arguments:
     574The ``Library.filter()`` method takes the following arguments:
    575575
    576     1. The name of the filter -- a string.
    577     2. The compilation function -- a Python function (not the name of the
     576    1. The filter function -- a Python function (not the name of the
    578577       function as a string).
     578    2. An optional alternative name for the filter -- a string).  By default
     579       it is the same as the function name.
    579580
    580581If you're using Python 2.4 or above, you can use ``register.filter()`` as a
    581582decorator instead::
    582583
    583     @register.filter(name='cut')
     584    @register.filter
    584585    def cut(value, arg):
    585586        return value.replace(arg, '')
    586587
    587     @register.filter
    588     def lower(value):
     588    @register.filter(name=lower)
     589    def do_lower(value):
    589590        return value.lower()
    590591
    591 If you leave off the ``name`` argument, as in the second example above, Django
    592 will use the function's name as the filter name.
     592If you use the filter decorator without the ``name`` argument, as in the first
     593example above, Django will use the function's name as the filter name.
    593594
    594595Writing custom template tags
    595596----------------------------
     
    709710Finally, register the tag with your module's ``Library`` instance, as explained
    710711in "Writing custom template filters" above. Example::
    711712
    712     register.tag('current_time', do_current_time)
     713    register.tag(do_current_time, name='current_time')
    713714
    714715The ``tag()`` method takes two arguments:
    715716
    716     1. The name of the template tag -- a string. If this is left out, the
    717        name of the compilation function will be used.
    718     2. The compilation function -- a Python function (not the name of the
     717    1. The tag function -- a Python function (not the name of the
    719718       function as a string).
     719    2. An optional alternative name for the template tag -- a string. If this
     720       is left out, the name of the tag function will be used.
    720721
    721722As with filter registration, it is also possible to use this as a decorator, in
    722723Python 2.4 and above::
  • tests/othertests/templates.py

    === tests/othertests/templates.py
    ==================================================================
     
    11from django.conf import settings
     2settings.TEMPLATE_STRING_IF_INVALID = "[undefined]"
    23
    3 
    44from django import template
    55from django.template import loader
    66from django.utils.translation import activate, deactivate, install
     
    2323def do_echo(parser, token):
    2424    return EchoNode(token.contents.split()[1:])
    2525
    26 register.tag("echo", do_echo)
     26register.tag(do_echo, name='echo')
    2727
    2828template.libraries['django.templatetags.testtags'] = register
    2929
     
    7373    'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"),
    7474
    7575    # Fail silently when a variable is not found in the current context
    76     'basic-syntax04': ("as{{ missing }}df", {}, "asdf"),
     76    'basic-syntax04': ("as{{ missing }}df", {}, "as%sdf" % settings.TEMPLATE_STRING_IF_INVALID),
    7777
    7878    # A variable may not contain more than one word
    7979    'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError),
     
    8989    'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"),
    9090
    9191    # Fail silently when a variable's attribute isn't found
    92     'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, ""),
     92    'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "%s" % settings.TEMPLATE_STRING_IF_INVALID),
    9393
    9494    # Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
    9595    'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError),
     
    105105    'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"),
    106106
    107107    # Fail silently when a variable's dictionary key isn't found
    108     'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, ""),
     108    'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "%s" % settings.TEMPLATE_STRING_IF_INVALID),
    109109
    110110    # Fail silently when accessing a non-simple method
    111     'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ""),
     111    'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "%s" % settings.TEMPLATE_STRING_IF_INVALID),
    112112
    113113    # Basic filter usage
    114114    'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"),
     
    147147    'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'),
    148148
    149149    # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute
    150     'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "12"),
     150    'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1%s2" % settings.TEMPLATE_STRING_IF_INVALID),
    151151
    152152    # In methods that raise an exception without a "silent_variable_attribute" set to True,
    153153    # the exception propogates
  • tests/othertests/tokenize_tag_contents.py

    === tests/othertests/tokenize_tag_contents.py
    ==================================================================
     
     1"""
     2# positional argument
     3>>> tok('tag arg1')
     4('tag', ['arg1'], {})
     5
     6# single-quoted positional argument
     7>>> tok("tag 'arg1 with spaces'")
     8('tag', ["'arg1 with spaces'"], {})
     9
     10# double-quoted positional argument
     11>>> tok('tag "arg1 with spaces"')
     12('tag', ['"arg1 with spaces"'], {})
     13
     14# named argument
     15>>> tok('tag name1=arg1')
     16('tag', [], {'name1': 'arg1'})
     17
     18# single-quoted named argument
     19>>> tok("tag name1='arg1 with spaces'")
     20('tag', [], {'name1': "'arg1 with spaces'"})
     21
     22# double-quoted named argument
     23>>> tok('tag name1="arg1 with spaces"')
     24('tag', [], {'name1': '"arg1 with spaces"'})
     25
     26# positional argument and named argument
     27>>> tok('tag arg1 name1=arg2')
     28('tag', ['arg1'], {'name1': 'arg2'})
     29
     30# mixed arguments
     31>>> tok('tag arg1 "arg2 with spaces" name1=arg3 name2="arg4 with spaces"')
     32('tag', ['arg1', '"arg2 with spaces"'], {'name2': '"arg4 with spaces"', 'name1': 'arg3'})
     33
     34# double quotes in single-quoted string
     35>>> tok("tag 'arg1 \\"with quotes\\"'")
     36('tag', ['\\'arg1 "with quotes"\\''], {})
     37
     38# single quotes in double-quoted string
     39>>> tok('tag "arg1 \\'with quotes\\'"')
     40('tag', ['"arg1 \\'with quotes\\'"'], {})
     41
     42# single quotes in single-quoted string
     43>>> tok("tag 'arg1 \\\\'with quotes\\\\''")
     44('tag', ["'arg1 'with quotes''"], {})
     45
     46# double quotes in double-quoted string
     47>>> tok('tag "arg1 \\\\"with quotes\\\\""')
     48('tag', ['"arg1 "with quotes""'], {})
     49
     50# positional argument after named argument not allowed
     51>>> tok('tag name1=arg1 arg2')
     52Traceback (most recent call last):
     53...
     54SyntaxError: template tag syntax error: non-keyword arguments must come before keyword arguments
     55
     56"""
     57
     58from django.template import tokenize_tag_contents as tok
     59
     60if __name__ == "__main__":
     61    import doctest
     62    doctest.testmod()
Back to Top