=== modified file 'django/contrib/admin/templatetags/admin_modify.py'
|
|
|
71 | 71 | default = None |
72 | 72 | |
73 | 73 | def __init__(self, bound_field_var): |
74 | | self.bound_field_var = bound_field_var |
| 74 | self.bound_field_var = template.Variable(bound_field_var) |
75 | 75 | |
76 | 76 | def get_nodelist(cls, klass): |
77 | 77 | if klass not in cls.nodelists: |
… |
… |
|
95 | 95 | get_nodelist = classmethod(get_nodelist) |
96 | 96 | |
97 | 97 | def render(self, context): |
98 | | bound_field = template.resolve_variable(self.bound_field_var, context) |
| 98 | bound_field = self.bound_field_var.resolve(context) |
99 | 99 | |
100 | 100 | context.push() |
101 | 101 | context['bound_field'] = bound_field |
… |
… |
|
155 | 155 | |
156 | 156 | class EditInlineNode(template.Node): |
157 | 157 | def __init__(self, rel_var): |
158 | | self.rel_var = rel_var |
| 158 | self.rel_var = template.Variable(rel_var) |
159 | 159 | |
160 | 160 | def render(self, context): |
161 | | relation = template.resolve_variable(self.rel_var, context) |
| 161 | relation = self.rel_var.resolve(context) |
162 | 162 | context.push() |
163 | 163 | if relation.field.rel.edit_inline == models.TABULAR: |
164 | 164 | bound_related_object_class = TabularBoundRelatedObject |
=== modified file 'django/contrib/comments/templatetags/comments.py'
|
|
|
18 | 18 | ratings_optional=False, ratings_required=False, rating_options='', |
19 | 19 | is_public=True): |
20 | 20 | self.content_type = content_type |
| 21 | if obj_id_lookup is not None: |
| 22 | obj_id_lookup = template.Variable |
21 | 23 | self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free |
22 | 24 | self.photos_optional, self.photos_required = photos_optional, photos_required |
23 | 25 | self.ratings_optional, self.ratings_required = ratings_optional, ratings_required |
… |
… |
|
31 | 33 | context.push() |
32 | 34 | if self.obj_id_lookup_var is not None: |
33 | 35 | 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) |
35 | 37 | except template.VariableDoesNotExist: |
36 | 38 | return '' |
37 | 39 | # Validate that this object ID is valid for this content-type. |
… |
… |
|
74 | 76 | class CommentCountNode(template.Node): |
75 | 77 | def __init__(self, package, module, context_var_name, obj_id, var_name, free): |
76 | 78 | self.package, self.module = package, module |
| 79 | if context_var_name is not None: |
| 80 | context_var_name = template.Variable(context_var_name) |
77 | 81 | self.context_var_name, self.obj_id = context_var_name, obj_id |
78 | 82 | self.var_name, self.free = var_name, free |
79 | 83 | |
… |
… |
|
81 | 85 | from django.conf import settings |
82 | 86 | manager = self.free and FreeComment.objects or Comment.objects |
83 | 87 | 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) |
85 | 89 | comment_count = manager.filter(object_id__exact=self.obj_id, |
86 | 90 | content_type__app_label__exact=self.package, |
87 | 91 | content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count() |
… |
… |
|
91 | 95 | class CommentListNode(template.Node): |
92 | 96 | def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None): |
93 | 97 | self.package, self.module = package, module |
| 98 | if context_var_name is not None: |
| 99 | context_var_name = template.Variable(context_var_name) |
94 | 100 | self.context_var_name, self.obj_id = context_var_name, obj_id |
95 | 101 | self.var_name, self.free = var_name, free |
96 | 102 | self.ordering = ordering |
… |
… |
|
101 | 107 | get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma |
102 | 108 | if self.context_var_name is not None: |
103 | 109 | try: |
104 | | self.obj_id = template.resolve_variable(self.context_var_name, context) |
| 110 | self.obj_id = self.context_var_name.resolve(context) |
105 | 111 | except template.VariableDoesNotExist: |
106 | 112 | return '' |
107 | 113 | kwargs = { |
=== modified file 'django/template/__init__.py'
|
|
|
91 | 91 | tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), |
92 | 92 | re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END), |
93 | 93 | 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+)$') |
96 | 94 | |
97 | 95 | # global dictionary of libraries that have been loaded using get_library |
98 | 96 | libraries = {} |
… |
… |
|
562 | 560 | elif constant_arg is not None: |
563 | 561 | args.append((False, constant_arg.replace(r'\"', '"'))) |
564 | 562 | elif var_arg: |
565 | | args.append((True, var_arg)) |
| 563 | args.append((True, Variable(var_arg))) |
566 | 564 | filter_func = parser.find_filter(filter_name) |
567 | 565 | self.args_check(filter_name,filter_func, args) |
568 | 566 | filters.append( (filter_func,args)) |
569 | 567 | upto = match.end() |
570 | 568 | if upto != len(token): |
571 | 569 | 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) |
573 | 572 | |
574 | 573 | def resolve(self, context, ignore_failures=False): |
575 | 574 | try: |
576 | | obj = resolve_variable(self.var, context) |
| 575 | obj = self.var.resolve(context) |
577 | 576 | except VariableDoesNotExist: |
578 | 577 | if ignore_failures: |
579 | 578 | obj = None |
… |
… |
|
593 | 592 | if not lookup: |
594 | 593 | arg_vals.append(arg) |
595 | 594 | else: |
596 | | arg_vals.append(resolve_variable(arg, context)) |
| 595 | arg_vals.append(arg.resolve(context)) |
597 | 596 | obj = func(obj, *arg_vals) |
598 | 597 | return obj |
599 | 598 | |
… |
… |
|
652 | 651 | |
653 | 652 | (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') |
654 | 653 | """ |
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 | |
| 656 | class 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 | |
| 667 | def 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 | |
| 684 | class ChainedLookupVariable(object): |
| 685 | |
| 686 | def __init__(self, val): |
| 687 | self.lookups = tuple(val.split(VARIABLE_ATTRIBUTE_SEPARATOR)) |
| 688 | |
| 689 | def resolve(self, context): |
661 | 690 | current = context |
662 | | bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) |
663 | | while bits: |
| 691 | for bit in self.lookups: |
664 | 692 | try: # dictionary lookup |
665 | | current = current[bits[0]] |
| 693 | current = current[bit] |
666 | 694 | except (TypeError, AttributeError, KeyError): |
667 | 695 | try: # attribute lookup |
668 | | current = getattr(current, bits[0]) |
| 696 | current = getattr(current, bit) |
669 | 697 | if callable(current): |
670 | 698 | if getattr(current, 'alters_data', False): |
671 | 699 | current = settings.TEMPLATE_STRING_IF_INVALID |
… |
… |
|
683 | 711 | raise |
684 | 712 | except (TypeError, AttributeError): |
685 | 713 | try: # list-index lookup |
686 | | current = current[int(bits[0])] |
| 714 | current = current[int(bit)] |
687 | 715 | except (IndexError, # list index out of range |
688 | 716 | 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 |
690 | 718 | TypeError, # unsubscriptable object |
691 | 719 | ): |
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 |
693 | 721 | except Exception, e: |
694 | 722 | if getattr(e, 'silent_variable_failure', False): |
695 | 723 | current = settings.TEMPLATE_STRING_IF_INVALID |
696 | 724 | else: |
697 | 725 | raise |
698 | | del bits[0] |
699 | | return current |
| 726 | return current |
| 727 | |
| 728 | def __str__(self): |
| 729 | return VARIABLE_ATTRIBUTE_SEPARATOR.join(self.lookups) |
700 | 730 | |
701 | 731 | class Node(object): |
702 | 732 | def render(self, context): |
… |
… |
|
867 | 897 | |
868 | 898 | class SimpleNode(Node): |
869 | 899 | def __init__(self, vars_to_resolve): |
870 | | self.vars_to_resolve = vars_to_resolve |
| 900 | self.vars_to_resolve = map(Variable, vars_to_resolve) |
871 | 901 | |
872 | 902 | 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]) |
875 | 904 | |
876 | 905 | compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode) |
877 | 906 | compile_func.__doc__ = func.__doc__ |
… |
… |
|
889 | 918 | |
890 | 919 | class InclusionNode(Node): |
891 | 920 | def __init__(self, vars_to_resolve): |
892 | | self.vars_to_resolve = vars_to_resolve |
| 921 | self.vars_to_resolve = map(Variable, vars_to_resolve) |
893 | 922 | |
894 | 923 | 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] |
896 | 925 | if takes_context: |
897 | 926 | args = [context] + resolved_vars |
898 | 927 | else: |
=== modified file 'django/template/defaulttags.py'
|
|
|
1 | 1 | "Default tags used by the template system, available to all templates." |
2 | 2 | |
3 | | from django.template import Node, NodeList, Template, Context, resolve_variable |
| 3 | from django.template import Node, NodeList, Template, Context, Variable |
4 | 4 | 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 |
5 | 5 | from django.template import get_library, Library, InvalidTemplateLibrary |
6 | 6 | from django.conf import settings |
… |
… |
|
48 | 48 | |
49 | 49 | class FirstOfNode(Node): |
50 | 50 | def __init__(self, vars): |
51 | | self.vars = vars |
| 51 | self.vars = map(Variable, vars) |
52 | 52 | |
53 | 53 | def render(self, context): |
54 | 54 | for var in self.vars: |
55 | 55 | try: |
56 | | value = resolve_variable(var, context) |
| 56 | value = var.resolve(context) |
57 | 57 | except VariableDoesNotExist: |
58 | 58 | continue |
59 | 59 | if value: |
… |
… |
|
130 | 130 | def __init__(self, nodelist, *varlist): |
131 | 131 | self.nodelist = nodelist |
132 | 132 | self._last_seen = None |
133 | | self._varlist = varlist |
| 133 | self._varlist = map(Variable, varlist) |
134 | 134 | |
135 | 135 | def render(self, context): |
136 | 136 | if 'forloop' in context and context['forloop']['first']: |
… |
… |
|
139 | 139 | if self._varlist: |
140 | 140 | # Consider multiple parameters. |
141 | 141 | # 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] |
143 | 143 | else: |
144 | 144 | compare_to = self.nodelist.render(context) |
145 | 145 | except VariableDoesNotExist: |
… |
… |
|
158 | 158 | |
159 | 159 | class IfEqualNode(Node): |
160 | 160 | 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) |
162 | 162 | self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false |
163 | 163 | self.negate = negate |
164 | 164 | |
… |
… |
|
167 | 167 | |
168 | 168 | def render(self, context): |
169 | 169 | try: |
170 | | val1 = resolve_variable(self.var1, context) |
| 170 | val1 = self.var1.resolve(context) |
171 | 171 | except VariableDoesNotExist: |
172 | 172 | val1 = None |
173 | 173 | try: |
174 | | val2 = resolve_variable(self.var2, context) |
| 174 | val2 = self.var2.resolve(context) |
175 | 175 | except VariableDoesNotExist: |
176 | 176 | val2 = None |
177 | 177 | if (self.negate and val1 != val2) or (not self.negate and val1 == val2): |
=== modified file 'django/template/loader_tags.py'
|
|
|
1 | | from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable |
| 1 | from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable |
2 | 2 | from django.template import Library, Node |
3 | 3 | from django.template.loader import get_template, get_template_from_string, find_template_source |
4 | 4 | from django.conf import settings |
… |
… |
|
99 | 99 | |
100 | 100 | class IncludeNode(Node): |
101 | 101 | def __init__(self, template_name): |
102 | | self.template_name = template_name |
| 102 | self.template_name = Variable(template_name) |
103 | 103 | |
104 | 104 | def render(self, context): |
105 | 105 | try: |
106 | | template_name = resolve_variable(self.template_name, context) |
| 106 | template_name = self.template_name.resolve(context) |
107 | 107 | t = get_template(template_name) |
108 | 108 | return t.render(context) |
109 | 109 | except TemplateSyntaxError, e: |
=== modified file 'django/templatetags/i18n.py'
|
|
|
1 | | from django.template import Node, resolve_variable |
| 1 | from django.template import Node, Variable |
2 | 2 | from django.template import TemplateSyntaxError, TokenParser, Library |
3 | 3 | from django.template import TOKEN_TEXT, TOKEN_VAR |
4 | 4 | from django.utils import translation |
… |
… |
|
32 | 32 | |
33 | 33 | class TranslateNode(Node): |
34 | 34 | def __init__(self, value, noop): |
35 | | self.value = value |
| 35 | self.value = Variable(value) |
36 | 36 | self.noop = noop |
37 | 37 | |
38 | 38 | def render(self, context): |
39 | | value = resolve_variable(self.value, context) |
| 39 | value = self.value.resolve(context) |
40 | 40 | if self.noop: |
41 | 41 | return value |
42 | 42 | else: |