Ticket #3453: resolve-variable.2.patch

File resolve-variable.2.patch, 15.4 KB (added by (removed), 8 years ago)

Round two, since trac doesn't seem to like bzr bundles and since some extra crap slipped into the patch

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

    === modified file 'django/contrib/admin/templatetags/admin_modify.py'
     
    7171    default = None
    7272
    7373    def __init__(self, bound_field_var):
    74         self.bound_field_var = bound_field_var
     74        self.bound_field_var = template.Variable(bound_field_var)
    7575
    7676    def get_nodelist(cls, klass):
    7777        if klass not in cls.nodelists:
     
    9595    get_nodelist = classmethod(get_nodelist)
    9696
    9797    def render(self, context):
    98         bound_field = template.resolve_variable(self.bound_field_var, context)
     98        bound_field = self.bound_field_var.resolve(context)
    9999
    100100        context.push()
    101101        context['bound_field'] = bound_field
     
    155155
    156156class EditInlineNode(template.Node):
    157157    def __init__(self, rel_var):
    158         self.rel_var = rel_var
     158        self.rel_var = template.Variable(rel_var)
    159159
    160160    def render(self, context):
    161         relation = template.resolve_variable(self.rel_var, context)
     161        relation = self.rel_var.resolve(context)
    162162        context.push()
    163163        if relation.field.rel.edit_inline == models.TABULAR:
    164164            bound_related_object_class = TabularBoundRelatedObject
  • django/contrib/comments/templatetags/comments.py

    === modified file 'django/contrib/comments/templatetags/comments.py'
     
    1818        ratings_optional=False, ratings_required=False, rating_options='',
    1919        is_public=True):
    2020        self.content_type = content_type
     21        if obj_id_lookup is not None:
     22            obj_id_lookup = template.Variable
    2123        self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free
    2224        self.photos_optional, self.photos_required = photos_optional, photos_required
    2325        self.ratings_optional, self.ratings_required = ratings_optional, ratings_required
     
    3133        context.push()
    3234        if self.obj_id_lookup_var is not None:
    3335            try:
    34                 self.obj_id = template.resolve_variable(self.obj_id_lookup_var, context)
     36                self.obj_id = self.obj_id_lookup_var.resolve(context)
    3537            except template.VariableDoesNotExist:
    3638                return ''
    3739            # Validate that this object ID is valid for this content-type.
     
    7476class CommentCountNode(template.Node):
    7577    def __init__(self, package, module, context_var_name, obj_id, var_name, free):
    7678        self.package, self.module = package, module
     79        if context_var_name is not None:
     80            context_var_name = template.Variable(context_var_name)
    7781        self.context_var_name, self.obj_id = context_var_name, obj_id
    7882        self.var_name, self.free = var_name, free
    7983
     
    8185        from django.conf import settings
    8286        manager = self.free and FreeComment.objects or Comment.objects
    8387        if self.context_var_name is not None:
    84             self.obj_id = template.resolve_variable(self.context_var_name, context)
     88            self.obj_id = self.context_var_name.resolve(context)
    8589        comment_count = manager.filter(object_id__exact=self.obj_id,
    8690            content_type__app_label__exact=self.package,
    8791            content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count()
     
    9195class CommentListNode(template.Node):
    9296    def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None):
    9397        self.package, self.module = package, module
     98        if context_var_name is not None:
     99            context_var_name = template.Variable(context_var_name)
    94100        self.context_var_name, self.obj_id = context_var_name, obj_id
    95101        self.var_name, self.free = var_name, free
    96102        self.ordering = ordering
     
    101107        get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma
    102108        if self.context_var_name is not None:
    103109            try:
    104                 self.obj_id = template.resolve_variable(self.context_var_name, context)
     110                self.obj_id = self.context_var_name.resolve(context)
    105111            except template.VariableDoesNotExist:
    106112                return ''
    107113        kwargs = {
  • django/template/__init__.py

    === modified file 'django/template/__init__.py'
     
    9191tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
    9292                                          re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
    9393                                          re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
    94 # matches if the string is valid number
    95 number_re = re.compile(r'[-+]?(\d+|\d*\.\d+)$')
    9694
    9795# global dictionary of libraries that have been loaded using get_library
    9896libraries = {}
     
    562560                elif constant_arg is not None:
    563561                    args.append((False, constant_arg.replace(r'\"', '"')))
    564562                elif var_arg:
    565                     args.append((True, var_arg))
     563                    args.append((True, Variable(var_arg)))
    566564                filter_func = parser.find_filter(filter_name)
    567565                self.args_check(filter_name,filter_func, args)
    568566                filters.append( (filter_func,args))
    569567                upto = match.end()
    570568        if upto != len(token):
    571569            raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token)
    572         self.var, self.filters = var, filters
     570        self.filters = filters
     571        self.var = Variable(var)
    573572
    574573    def resolve(self, context, ignore_failures=False):
    575574        try:
    576             obj = resolve_variable(self.var, context)
     575            obj = self.var.resolve(context)
    577576        except VariableDoesNotExist:
    578577            if ignore_failures:
    579578                obj = None
     
    593592                if not lookup:
    594593                    arg_vals.append(arg)
    595594                else:
    596                     arg_vals.append(resolve_variable(arg, context))
     595                    arg_vals.append(arg.resolve(context))
    597596            obj = func(obj, *arg_vals)
    598597        return obj
    599598
     
    652651
    653652    (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
    654653    """
    655     if number_re.match(path):
    656         number_type = '.' in path and float or int
    657         current = number_type(path)
    658     elif path[0] in ('"', "'") and path[0] == path[-1]:
    659         current = path[1:-1]
    660     else:
     654    return Variable(path).resolve(context)
     655
     656class LiteralVariable(object):
     657
     658    def __init__(self, val):
     659        self.val = val
     660
     661    def resolve(self, context):
     662        return self.val
     663
     664    def __str__(self):
     665        return self.val
     666
     667def Variable(val):
     668    try:
     669        # note we're not catching OverflowError here; point of debate on how best to handle that...
     670        current = float(val)
     671        if '.' not in val:
     672            # downside to this approach is that 1e07 becomes an int; float may be preferable still.
     673            current = int(current)
     674        elif val[-1] == '.':
     675            # 2. is invalid
     676            raise ValueError
     677        return LiteralVariable(current)
     678    except ValueError:
     679        pass
     680    if val[0] in "\"'" and val[0] == val[-1]:
     681        return LiteralVariable(val[1:-1])
     682    return ChainedLookupVariable(val)
     683   
     684class ChainedLookupVariable(object):
     685
     686    def __init__(self, val):
     687        self.lookups = tuple(val.split(VARIABLE_ATTRIBUTE_SEPARATOR))
     688   
     689    def resolve(self, context):
    661690        current = context
    662         bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR)
    663         while bits:
     691        for bit in self.lookups:
    664692            try: # dictionary lookup
    665                 current = current[bits[0]]
     693                current = current[bit]
    666694            except (TypeError, AttributeError, KeyError):
    667695                try: # attribute lookup
    668                     current = getattr(current, bits[0])
     696                    current = getattr(current, bit)
    669697                    if callable(current):
    670698                        if getattr(current, 'alters_data', False):
    671699                            current = settings.TEMPLATE_STRING_IF_INVALID
     
    683711                                    raise
    684712                except (TypeError, AttributeError):
    685713                    try: # list-index lookup
    686                         current = current[int(bits[0])]
     714                        current = current[int(bit)]
    687715                    except (IndexError, # list index out of range
    688716                            ValueError, # invalid literal for int()
    689                             KeyError,   # current is a dict without `int(bits[0])` key
     717                            KeyError,   # current is a dict without `int(bit)` key
    690718                            TypeError,  # unsubscriptable object
    691719                            ):
    692                         raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bits[0], current)) # missing attribute
     720                        raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
    693721                except Exception, e:
    694722                    if getattr(e, 'silent_variable_failure', False):
    695723                        current = settings.TEMPLATE_STRING_IF_INVALID
    696724                    else:
    697725                        raise
    698             del bits[0]
    699     return current
     726        return current
     727
     728    def __str__(self):
     729        return VARIABLE_ATTRIBUTE_SEPARATOR.join(self.lookups)
    700730
    701731class Node(object):
    702732    def render(self, context):
     
    867897
    868898        class SimpleNode(Node):
    869899            def __init__(self, vars_to_resolve):
    870                 self.vars_to_resolve = vars_to_resolve
     900                self.vars_to_resolve = map(Variable, vars_to_resolve)
    871901
    872902            def render(self, context):
    873                 resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
    874                 return func(*resolved_vars)
     903                return func(*[var.resolve(context) for var in self.vars_to_resolve])
    875904
    876905        compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode)
    877906        compile_func.__doc__ = func.__doc__
     
    889918
    890919            class InclusionNode(Node):
    891920                def __init__(self, vars_to_resolve):
    892                     self.vars_to_resolve = vars_to_resolve
     921                    self.vars_to_resolve = map(Variable, vars_to_resolve)
    893922
    894923                def render(self, context):
    895                     resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
     924                    resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
    896925                    if takes_context:
    897926                        args = [context] + resolved_vars
    898927                    else:
  • django/template/defaulttags.py

    === modified file 'django/template/defaulttags.py'
     
    11"Default tags used by the template system, available to all templates."
    22
    3 from django.template import Node, NodeList, Template, Context, resolve_variable
     3from django.template import Node, NodeList, Template, Context, Variable
    44from 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
    55from django.template import get_library, Library, InvalidTemplateLibrary
    66from django.conf import settings
     
    4848
    4949class FirstOfNode(Node):
    5050    def __init__(self, vars):
    51         self.vars = vars
     51        self.vars = map(Variable, vars)
    5252
    5353    def render(self, context):
    5454        for var in self.vars:
    5555            try:
    56                 value = resolve_variable(var, context)
     56                value = var.resolve(context)
    5757            except VariableDoesNotExist:
    5858                continue
    5959            if value:
     
    130130    def __init__(self, nodelist, *varlist):
    131131        self.nodelist = nodelist
    132132        self._last_seen = None
    133         self._varlist = varlist
     133        self._varlist = map(Variable, varlist)
    134134
    135135    def render(self, context):
    136136        if 'forloop' in context and context['forloop']['first']:
     
    139139            if self._varlist:
    140140                # Consider multiple parameters.
    141141                # This automatically behaves like a OR evaluation of the multiple variables.
    142                 compare_to = [resolve_variable(var, context) for var in self._varlist]
     142                compare_to = [var.resolve(context) for var in self._varlist]
    143143            else:
    144144                compare_to = self.nodelist.render(context)
    145145        except VariableDoesNotExist:
     
    158158
    159159class IfEqualNode(Node):
    160160    def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
    161         self.var1, self.var2 = var1, var2
     161        self.var1, self.var2 = Variable(var1), Variable(var2)
    162162        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
    163163        self.negate = negate
    164164
     
    167167
    168168    def render(self, context):
    169169        try:
    170             val1 = resolve_variable(self.var1, context)
     170            val1 = self.var1.resolve(context)
    171171        except VariableDoesNotExist:
    172172            val1 = None
    173173        try:
    174             val2 = resolve_variable(self.var2, context)
     174            val2 = self.var2.resolve(context)
    175175        except VariableDoesNotExist:
    176176            val2 = None
    177177        if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
  • django/template/loader_tags.py

    === modified file 'django/template/loader_tags.py'
     
    1 from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable
     1from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
    22from django.template import Library, Node
    33from django.template.loader import get_template, get_template_from_string, find_template_source
    44from django.conf import settings
     
    9999
    100100class IncludeNode(Node):
    101101    def __init__(self, template_name):
    102         self.template_name = template_name
     102        self.template_name = Variable(template_name)
    103103
    104104    def render(self, context):
    105105        try:
    106             template_name = resolve_variable(self.template_name, context)
     106            template_name = self.template_name.resolve(context)
    107107            t = get_template(template_name)
    108108            return t.render(context)
    109109        except TemplateSyntaxError, e:
  • django/templatetags/i18n.py

    === modified file 'django/templatetags/i18n.py'
     
    1 from django.template import Node, resolve_variable
     1from django.template import Node, Variable
    22from django.template import TemplateSyntaxError, TokenParser, Library
    33from django.template import TOKEN_TEXT, TOKEN_VAR
    44from django.utils import translation
     
    3232
    3333class TranslateNode(Node):
    3434    def __init__(self, value, noop):
    35         self.value = value
     35        self.value = Variable(value)
    3636        self.noop = noop
    3737
    3838    def render(self, context):
    39         value = resolve_variable(self.value, context)
     39        value = self.value.resolve(context)
    4040        if self.noop:
    4141            return value
    4242        else:
Back to Top