diff -urN django-orig/django/contrib/admin/templatetags/admin_modify.py django-new/django/contrib/admin/templatetags/admin_modify.py
old
|
new
|
|
69 | 69 | default = None |
70 | 70 | |
71 | 71 | def __init__(self, bound_field_var): |
72 | | self.bound_field_var = bound_field_var |
| 72 | self.bound_field_var = template.Variable(bound_field_var) |
73 | 73 | |
74 | 74 | def get_nodelist(cls, klass): |
75 | 75 | if not cls.nodelists.has_key(klass): |
… |
… |
|
93 | 93 | get_nodelist = classmethod(get_nodelist) |
94 | 94 | |
95 | 95 | def render(self, context): |
96 | | bound_field = template.resolve_variable(self.bound_field_var, context) |
| 96 | bound_field = self.bound_field_var.resolve(context) |
97 | 97 | |
98 | 98 | context.push() |
99 | 99 | context['bound_field'] = bound_field |
… |
… |
|
153 | 153 | |
154 | 154 | class EditInlineNode(template.Node): |
155 | 155 | def __init__(self, rel_var): |
156 | | self.rel_var = rel_var |
| 156 | self.rel_var = template.Variable(rel_var) |
157 | 157 | |
158 | 158 | def render(self, context): |
159 | | relation = template.resolve_variable(self.rel_var, context) |
| 159 | relation = self.rel_var.resolve(context) |
160 | 160 | context.push() |
161 | 161 | if relation.field.rel.edit_inline == models.TABULAR: |
162 | 162 | bound_related_object_class = TabularBoundRelatedObject |
diff -urN django-orig/django/contrib/comments/templatetags/comments.py django-new/django/contrib/comments/templatetags/comments.py
old
|
new
|
|
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_var is not None: |
| 22 | obj_id_lookup_var = template.Variable(obj_id_lookup_var) |
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 |
… |
… |
|
30 | 32 | context.push() |
31 | 33 | if self.obj_id_lookup_var is not None: |
32 | 34 | try: |
33 | | self.obj_id = template.resolve_variable(self.obj_id_lookup_var, context) |
| 35 | self.obj_id = self.obj_id_lookup_var.resolve(context) |
34 | 36 | except template.VariableDoesNotExist: |
35 | 37 | return '' |
36 | 38 | # Validate that this object ID is valid for this content-type. |
… |
… |
|
73 | 75 | def __init__(self, package, module, context_var_name, obj_id, var_name, free): |
74 | 76 | self.package, self.module = package, module |
75 | 77 | self.context_var_name, self.obj_id = context_var_name, obj_id |
| 78 | if var_name is not None: |
| 79 | var_name = template.Variable(var_name) |
76 | 80 | self.var_name, self.free = var_name, free |
77 | 81 | |
78 | 82 | def render(self, context): |
79 | 83 | from django.conf import settings |
80 | 84 | manager = self.free and FreeComment.objects or Comment.objects |
81 | 85 | if self.context_var_name is not None: |
82 | | self.obj_id = template.resolve_variable(self.context_var_name, context) |
| 86 | self.obj_id = self.var_name.resolve(context) |
83 | 87 | comment_count = manager.filter(object_id__exact=self.obj_id, |
84 | 88 | content_type__app_label__exact=self.package, |
85 | 89 | content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count() |
… |
… |
|
89 | 93 | class CommentListNode(template.Node): |
90 | 94 | def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None): |
91 | 95 | self.package, self.module = package, module |
| 96 | if context_var_name is not None: |
| 97 | context_var_name = template.Variable(context_var_name) |
92 | 98 | self.context_var_name, self.obj_id = context_var_name, obj_id |
93 | 99 | self.var_name, self.free = var_name, free |
94 | 100 | self.ordering = ordering |
… |
… |
|
99 | 105 | get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma |
100 | 106 | if self.context_var_name is not None: |
101 | 107 | try: |
102 | | self.obj_id = template.resolve_variable(self.context_var_name, context) |
| 108 | self.obj_id = self.context_var_name.resolve(context) |
103 | 109 | except template.VariableDoesNotExist: |
104 | 110 | return '' |
105 | 111 | kwargs = { |
diff -urN django-orig/django/template/__init__.py django-new/django/template/__init__.py
old
|
new
|
|
554 | 554 | upto = match.end() |
555 | 555 | if upto != len(token): |
556 | 556 | raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:] |
557 | | self.var, self.filters = var, filters |
| 557 | self.var, self.filters = Variable(var), filters |
558 | 558 | |
559 | 559 | def resolve(self, context, ignore_failures=False): |
560 | 560 | try: |
561 | | obj = resolve_variable(self.var, context) |
| 561 | obj = self.var.resolve(context) |
562 | 562 | except VariableDoesNotExist: |
563 | 563 | if ignore_failures: |
564 | 564 | obj = None |
… |
… |
|
610 | 610 | def __str__(self): |
611 | 611 | return self.token |
612 | 612 | |
613 | | def resolve_variable(path, context): |
| 613 | |
| 614 | class Variable(object): |
614 | 615 | """ |
615 | 616 | Returns the resolved variable, which may contain attribute syntax, within |
616 | 617 | the given context. The variable may be a hard-coded string (if it begins |
617 | 618 | and ends with single or double quote marks). |
618 | 619 | |
619 | 620 | >>> c = {'article': {'section':'News'}} |
620 | | >>> resolve_variable('article.section', c) |
| 621 | >>> v = Variable('article.section') |
| 622 | >>> v.resolve(c) |
621 | 623 | 'News' |
622 | | >>> resolve_variable('article', c) |
| 624 | >>> Variable('article').resolve(c) |
623 | 625 | {'section': 'News'} |
624 | 626 | >>> class AClass: pass |
625 | 627 | >>> c = AClass() |
626 | 628 | >>> c.article = AClass() |
627 | 629 | >>> c.article.section = 'News' |
628 | | >>> resolve_variable('article.section', c) |
| 630 | >>> v.resolve(c) |
629 | 631 | 'News' |
630 | 632 | |
631 | 633 | (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') |
632 | 634 | """ |
633 | | if path[0].isdigit(): |
634 | | number_type = '.' in path and float or int |
635 | | try: |
636 | | current = number_type(path) |
637 | | except ValueError: |
638 | | current = settings.TEMPLATE_STRING_IF_INVALID |
639 | | elif path[0] in ('"', "'") and path[0] == path[-1]: |
640 | | current = path[1:-1] |
641 | | else: |
| 635 | |
| 636 | def __init__(self, path): |
| 637 | if path[0].isdigit(): |
| 638 | number_type = ('.' in path and float) or int |
| 639 | try: |
| 640 | self.forced_value = number_type(path) |
| 641 | except ValueError: |
| 642 | self.forced_value = settings.TEMPLATE_STRING_IF_INVALID |
| 643 | elif path[0] in ('"', "'") and path[0] == path[-1]: |
| 644 | self.forced_value = path[1:-1] |
| 645 | else: |
| 646 | self.forced_value = None |
| 647 | self.split_path = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) |
| 648 | |
| 649 | def resolve(self, context): |
| 650 | if self.forced_value is not None: |
| 651 | return self.forced_value |
642 | 652 | current = context |
643 | | bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR) |
644 | | while bits: |
| 653 | for bit in self.split_path: |
645 | 654 | try: # dictionary lookup |
646 | | current = current[bits[0]] |
| 655 | current = current[bit] |
647 | 656 | except (TypeError, AttributeError, KeyError): |
648 | 657 | try: # attribute lookup |
649 | | current = getattr(current, bits[0]) |
| 658 | current = getattr(current, bit) |
650 | 659 | if callable(current): |
651 | 660 | if getattr(current, 'alters_data', False): |
652 | 661 | current = settings.TEMPLATE_STRING_IF_INVALID |
… |
… |
|
658 | 667 | # raised in the function itself. |
659 | 668 | current = settings.TEMPLATE_STRING_IF_INVALID # invalid method call |
660 | 669 | except Exception, e: |
661 | | if getattr(e, 'silent_variable_failure', False): |
662 | | current = settings.TEMPLATE_STRING_IF_INVALID |
663 | | else: |
| 670 | if not getattr(e, 'silent_variable_failure', False): |
664 | 671 | raise |
| 672 | current = settings.TEMPLATE_STRING_IF_INVALID |
665 | 673 | except (TypeError, AttributeError): |
666 | 674 | try: # list-index lookup |
667 | | current = current[int(bits[0])] |
| 675 | current = current[int(bit)] |
668 | 676 | except (IndexError, ValueError, KeyError): |
669 | | raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bits[0], current)) # missing attribute |
| 677 | raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute |
670 | 678 | except Exception, e: |
671 | | if getattr(e, 'silent_variable_failure', False): |
672 | | current = settings.TEMPLATE_STRING_IF_INVALID |
673 | | else: |
| 679 | if not getattr(e, 'silent_variable_failure', False): |
674 | 680 | raise |
675 | | del bits[0] |
676 | | return current |
| 681 | current = settings.TEMPLATE_STRING_IF_INVALID |
| 682 | return current |
| 683 | |
| 684 | def resolve_variable(path, context): |
| 685 | """ |
| 686 | Shortcut to resolve a variable- primary usage should be for resolving a |
| 687 | variable once. If the variable may be resolved multiple times, use the |
| 688 | Variable class. |
| 689 | |
| 690 | See Variable class for information on allowed variable names |
| 691 | |
| 692 | >>> c = {'article': {'section':'News'}} |
| 693 | >>> resolve_variable('article.section', c) |
| 694 | 'News' |
| 695 | >>> resolve_variable('article', c) |
| 696 | {'section': 'News'} |
| 697 | >>> class AClass: pass |
| 698 | >>> c = AClass() |
| 699 | >>> c.article = AClass() |
| 700 | >>> c.article.section = 'News' |
| 701 | >>> resolve_variable('article.section', c) |
| 702 | 'News' |
| 703 | |
| 704 | (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') |
| 705 | """ |
| 706 | return Variable(path).resolve(context) |
677 | 707 | |
678 | 708 | class Node(object): |
679 | 709 | def render(self, context): |
… |
… |
|
710 | 740 | return nodes |
711 | 741 | |
712 | 742 | def render_node(self, node, context): |
713 | | return(node.render(context)) |
| 743 | return node.render(context) |
714 | 744 | |
715 | 745 | class DebugNodeList(NodeList): |
716 | 746 | def render_node(self, node, context): |
diff -urN django-orig/django/template/defaultfilters.py django-new/django/template/defaultfilters.py
old
|
new
|
|
1 | 1 | "Default variable filters" |
2 | 2 | |
3 | | from django.template import resolve_variable, Library |
| 3 | from django.template import Variable, Library |
4 | 4 | from django.conf import settings |
5 | 5 | from django.utils.translation import gettext |
6 | 6 | import re |
… |
… |
|
224 | 224 | Takes a list of dicts, returns that list sorted by the property given in |
225 | 225 | the argument. |
226 | 226 | """ |
227 | | decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value] |
| 227 | var = Variable('var.%s' % arg) |
| 228 | decorated = [(var.resolve({'var' : item}), item) for item in value] |
228 | 229 | decorated.sort() |
229 | 230 | return [item[1] for item in decorated] |
230 | 231 | |
… |
… |
|
233 | 234 | Takes a list of dicts, returns that list sorted in reverse order by the |
234 | 235 | property given in the argument. |
235 | 236 | """ |
236 | | decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value] |
237 | | decorated.sort() |
238 | | decorated.reverse() |
| 237 | var = Variable('var.%s' % arg) |
| 238 | decorated = [(var.resolve({'var' : item}), item) for item in value] |
| 239 | decorated.sort(reverse=True) |
239 | 240 | return [item[1] for item in decorated] |
240 | 241 | |
241 | 242 | def first(value): |
diff -urN django-orig/django/template/defaulttags.py django-new/django/template/defaulttags.py
old
|
new
|
|
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 |
… |
… |
|
45 | 45 | |
46 | 46 | class FirstOfNode(Node): |
47 | 47 | def __init__(self, vars): |
48 | | self.vars = vars |
| 48 | self.vars = map(Variable, vars) |
49 | 49 | |
50 | 50 | def render(self, context): |
51 | 51 | for var in self.vars: |
52 | 52 | try: |
53 | | value = resolve_variable(var, context) |
| 53 | value = var.resolve(context) |
54 | 54 | except VariableDoesNotExist: |
55 | 55 | continue |
56 | 56 | if value: |
… |
… |
|
127 | 127 | def __init__(self, nodelist, *varlist): |
128 | 128 | self.nodelist = nodelist |
129 | 129 | self._last_seen = None |
130 | | self._varlist = varlist |
| 130 | self._varlist = map(Variable, varlist) |
131 | 131 | |
132 | 132 | def render(self, context): |
133 | 133 | if context.has_key('forloop') and context['forloop']['first']: |
… |
… |
|
136 | 136 | if self._varlist: |
137 | 137 | # Consider multiple parameters. |
138 | 138 | # This automatically behaves like a OR evaluation of the multiple variables. |
139 | | compare_to = [resolve_variable(var, context) for var in self._varlist] |
| 139 | compare_to = [x.resolve(context) for x in self._varlist] |
140 | 140 | else: |
141 | 141 | compare_to = self.nodelist.render(context) |
142 | 142 | except VariableDoesNotExist: |
… |
… |
|
155 | 155 | |
156 | 156 | class IfEqualNode(Node): |
157 | 157 | def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): |
158 | | self.var1, self.var2 = var1, var2 |
| 158 | self.var1, self.var2 = Variable(var1), Variable(var2) |
159 | 159 | self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false |
160 | 160 | self.negate = negate |
161 | 161 | |
… |
… |
|
164 | 164 | |
165 | 165 | def render(self, context): |
166 | 166 | try: |
167 | | val1 = resolve_variable(self.var1, context) |
| 167 | val1 = self.var1.resolve(context) |
168 | 168 | except VariableDoesNotExist: |
169 | 169 | val1 = None |
170 | 170 | try: |
171 | | val2 = resolve_variable(self.var2, context) |
| 171 | val2 = self.var2.resolve(context) |
172 | 172 | except VariableDoesNotExist: |
173 | 173 | val2 = None |
174 | 174 | if (self.negate and val1 != val2) or (not self.negate and val1 == val2): |
diff -urN django-orig/django/template/loader_tags.py django-new/django/template/loader_tags.py
old
|
new
|
|
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: |
diff -urN django-orig/django/templatetags/i18n.py django-new/django/templatetags/i18n.py
old
|
new
|
|
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: |