Code

Ticket #7462: simple_tag_takes_context.diff

File simple_tag_takes_context.diff, 7.2 KB (added by julien, 6 years ago)
Line 
1Index: E:/Software/workspace/django/django/template/__init__.py
2===================================================================
3--- E:/Software/workspace/django/django/template/__init__.py    (revision 7661)
4+++ E:/Software/workspace/django/django/template/__init__.py    (working copy)
5@@ -49,7 +49,7 @@
6 u'<html></html>'
7 """
8 import re
9-from inspect import getargspec
10+from inspect import getargspec, isfunction
11 from django.conf import settings
12 from django.template.context import Context, RequestContext, ContextPopException
13 from django.utils.itercompat import is_iterable
14@@ -859,22 +859,44 @@
15         self.filters[getattr(func, "_decorated_function", func).__name__] = func
16         return func
17 
18-    def simple_tag(self,func):
19-        params, xx, xxx, defaults = getargspec(func)
20+    def simple_tag(self, *args, **kwargs):
21+        def dec(func):
22+            params, xx, xxx, defaults = getargspec(func)
23+            if takes_context:
24+                if params[0] == 'context':
25+                    params = params[1:]
26+                else:
27+                    raise TemplateSyntaxError("Any tag function decorated with takes_context=True must have a first argument of 'context'")
28 
29-        class SimpleNode(Node):
30-            def __init__(self, vars_to_resolve):
31-                self.vars_to_resolve = map(Variable, vars_to_resolve)
32+            class SimpleNode(Node):
33+                def __init__(self, vars_to_resolve):
34+                    self.vars_to_resolve = map(Variable, vars_to_resolve)
35+   
36+                def render(self, context):
37+                    resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
38+                    if takes_context:
39+                        func_args = [context] + resolved_vars
40+                    else:
41+                        func_args = resolved_vars
42+                    return func(*func_args)
43 
44-            def render(self, context):
45-                resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
46-                return func(*resolved_vars)
47+            compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode)
48+            compile_func.__doc__ = func.__doc__
49+            self.tag(getattr(func, "_decorated_function", func).__name__, compile_func)
50+            return func
51+       
52+        if len(args) == 1 and len(kwargs) == 0 and isfunction(args[0]):
53+            takes_context = False
54+            return dec(args[0])
55+        elif len(args) == 0 and len(kwargs) == 0:
56+            takes_context = False
57+            return dec
58+        elif len(args) == 0 and len(kwargs) == 1 and 'takes_context' in kwargs:
59+            takes_context = kwargs['takes_context']
60+            return dec
61+        else:
62+            raise TemplateSyntaxError("Incorrect parameters for simple_tag")
63 
64-        compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode)
65-        compile_func.__doc__ = func.__doc__
66-        self.tag(getattr(func, "_decorated_function", func).__name__, compile_func)
67-        return func
68-
69     def inclusion_tag(self, file_name, context_class=Context, takes_context=False):
70         def dec(func):
71             params, xx, xxx, defaults = getargspec(func)
72Index: E:/Software/workspace/django/tests/regressiontests/templates/tests.py
73===================================================================
74--- E:/Software/workspace/django/tests/regressiontests/templates/tests.py       (revision 7641)
75+++ E:/Software/workspace/django/tests/regressiontests/templates/tests.py       (working copy)
76@@ -17,6 +17,7 @@
77 from django.utils.safestring import mark_safe
78 from django.utils.tzinfo import LocalTimezone
79 
80+from decorators import DecoratorsTest
81 from unicode import unicode_tests
82 from context import context_tests
83 
84Index: E:/Software/workspace/django/tests/regressiontests/templates/decorators.py
85===================================================================
86--- E:/Software/workspace/django/tests/regressiontests/templates/decorators.py  (revision 0)
87+++ E:/Software/workspace/django/tests/regressiontests/templates/decorators.py  (revision 0)
88@@ -0,0 +1,42 @@
89+from unittest import TestCase
90+from sys import version_info
91+
92+from django import template
93+
94+register = template.Library()
95+
96+def a_simple_tag(arg):
97+    """Expected __doc__"""
98+    return "Expected result"
99+a_simple_tag.anything = "Expected __dict__"
100+
101+a_simple_tag = register.simple_tag(a_simple_tag)
102+
103+
104+def a_simple_tag_with_context(context, arg):
105+    """Expected __doc__"""
106+    return "Expected result"
107+a_simple_tag_with_context.anything = "Expected __dict__"
108+
109+a_simple_tag_with_context = register.simple_tag(takes_context=True)(a_simple_tag_with_context)
110+
111+
112+
113+class DecoratorsTest(TestCase):
114+
115+    def test_simple_tag(self):
116+        # Only check __name__ on Python 2.4 or later since __name__ can't be
117+        # assigned to in earlier Python versions.
118+        if version_info[0] >= 2 and version_info[1] >= 4:
119+            self.assertEquals(a_simple_tag.__name__, 'a_simple_tag')
120+        self.assertEquals(a_simple_tag.__doc__, 'Expected __doc__')
121+        self.assertEquals(a_simple_tag.__dict__['anything'], 'Expected __dict__')
122+
123+
124+    def test_simple_tag_with_context(self):
125+        # Only check __name__ on Python 2.4 or later since __name__ can't be
126+        # assigned to in earlier Python versions.
127+        if version_info[0] >= 2 and version_info[1] >= 4:
128+            self.assertEquals(a_simple_tag_with_context.__name__, 'a_simple_tag_with_context')
129+        self.assertEquals(a_simple_tag_with_context.__doc__, 'Expected __doc__')
130+        self.assertEquals(a_simple_tag_with_context.__dict__['anything'], 'Expected __dict__')
131\ No newline at end of file
132Index: E:/Software/workspace/django/docs/templates_python.txt
133===================================================================
134--- E:/Software/workspace/django/docs/templates_python.txt      (revision 7641)
135+++ E:/Software/workspace/django/docs/templates_python.txt      (working copy)
136@@ -1169,7 +1169,7 @@
137 In Python 2.4, the decorator syntax also works::
138 
139     @register.simple_tag
140-    def current_time(token):
141+    def current_time(format_string):
142         ...
143 
144 A couple of things to note about the ``simple_tag`` helper function:
145@@ -1184,6 +1184,26 @@
146 function to work with the input values and using the ``simple_tag`` helper is
147 the easiest way to create a new tag.
148 
149+If your template tag *does* need to access the current context, you can use the
150+``takes_context`` option as follows::
151+
152+    # The first argument *must* be called "context" here.
153+    def current_time(context, format_string):
154+        timezone = context['timezone']
155+        ...
156+
157+    register.simple_tag(takes_context=True)(current_time)
158+
159+You can also use the decorator syntax if running in Python 2.4::
160+
161+    @register.simple_tag(takes_context=True)
162+    def current_time(context, format_string):
163+
164+For more information on how the ``takes_context`` option works, see the section
165+on `inclusion tags`_.
166+
167+.. _inclusion tags: #inclusion-tags
168+
169 Inclusion tags
170 ~~~~~~~~~~~~~~
171