Code

Ticket #3453: resolve-variable.2.patch

File resolve-variable.2.patch, 15.4 KB (added by (removed), 7 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: