Ticket #20434: patch4.patch

File patch4.patch, 24.6 KB (added by jonathanslenders, 11 years ago)

Refactoring of the tags in contrib, to use TemplateTag and Grammar.

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

    commit c96bf1a1ecf9427cdff8eab70bb9d973221f1881
    Author: Jonathan Slenders <jonathan@slenders.be>
    Date:   Thu Jun 6 00:28:36 2013 +0200
    
        Refactoring of templatetags using the TemplateTag class in contrib.
    
    diff --git a/django/contrib/admin/templatetags/log.py b/django/contrib/admin/templatetags/log.py
    index 1b9e6aa..00a21f4 100644
    a b from django.contrib.admin.models import LogEntry  
    33
    44register = template.Library()
    55
    6 class AdminLogNode(template.Node):
    7     def __init__(self, limit, varname, user):
    8         self.limit, self.varname, self.user = limit, varname, user
    9 
    10     def __repr__(self):
    11         return "<GetAdminLog Node>"
    12 
    13     def render(self, context):
    14         if self.user is None:
    15             context[self.varname] = LogEntry.objects.all().select_related('content_type', 'user')[:self.limit]
    16         else:
    17             user_id = self.user
    18             if not user_id.isdigit():
    19                 user_id = context[self.user].pk
    20             context[self.varname] = LogEntry.objects.filter(user__pk__exact=user_id).select_related('content_type', 'user')[:int(self.limit)]
    21         return ''
    22 
    236@register.tag
    24 def get_admin_log(parser, token):
     7class AdminLogNode(template.TemplateTag):
    258    """
    269    Populates a template variable with the admin log for the given criteria.
    2710
    def get_admin_log(parser, token):  
    3922    (user ID) or the name of a template context variable containing the user
    4023    object whose ID you want.
    4124    """
    42     tokens = token.contents.split()
    43     if len(tokens) < 4:
    44         raise template.TemplateSyntaxError(
    45             "'get_admin_log' statements require two arguments")
    46     if not tokens[1].isdigit():
    47         raise template.TemplateSyntaxError(
    48             "First argument to 'get_admin_log' must be an integer")
    49     if tokens[2] != 'as':
    50         raise template.TemplateSyntaxError(
    51             "Second argument to 'get_admin_log' must be 'as'")
    52     if len(tokens) > 4:
    53         if tokens[4] != 'for_user':
     25    grammar = template.Grammar('get_admin_log')
     26
     27    def __init__(self, parser, parse_result):
     28        bits = parse_result.arguments
     29
     30        if len(bits) < 3:
    5431            raise template.TemplateSyntaxError(
    55                 "Fourth argument to 'get_admin_log' must be 'for_user'")
    56     return AdminLogNode(limit=tokens[1], varname=tokens[3], user=(tokens[5] if len(tokens) > 5 else None))
     32                "'get_admin_log' statements require two arguments")
     33        if not bits[0].isdigit():
     34            raise template.TemplateSyntaxError(
     35                "First argument to 'get_admin_log' must be an integer")
     36        if bits[1] != 'as':
     37            raise template.TemplateSyntaxError(
     38                "Second argument to 'get_admin_log' must be 'as'")
     39        if len(bits) > 3:
     40            if bits[3] != 'for_user':
     41                raise template.TemplateSyntaxError(
     42                    "Fourth argument to 'get_admin_log' must be 'for_user'")
     43
     44        self.limit, self.varname, self.user = bits[0], bits[2], (bits[4] if len(bits) > 4 else None)
     45
     46    def __repr__(self):
     47        return "<GetAdminLog Node>"
     48
     49    def render(self, context):
     50        if self.user is None:
     51            context[self.varname] = LogEntry.objects.all().select_related('content_type', 'user')[:self.limit]
     52        else:
     53            user_id = self.user
     54            if not user_id.isdigit():
     55                user_id = context[self.user].pk
     56            context[self.varname] = LogEntry.objects.filter(user__pk__exact=user_id).select_related('content_type', 'user')[:int(self.limit)]
     57        return ''
  • django/contrib/comments/templatetags/comments.py

    diff --git a/django/contrib/comments/templatetags/comments.py b/django/contrib/comments/templatetags/comments.py
    index d8eed76..f98e72f 100644
    a b class RenameBaseCommentNodeMethods(RenameMethodsBase):  
    1616    )
    1717
    1818
    19 class BaseCommentNode(six.with_metaclass(RenameBaseCommentNodeMethods, template.Node)):
     19class BaseCommentNode(six.with_metaclass(RenameBaseCommentNodeMethods, template.TemplateTag)):
    2020    """
    2121    Base helper class (abstract) for handling the get_comment_* template tags.
    2222    Looks a bit strange, but the subclasses below should make this a bit more
    class BaseCommentNode(six.with_metaclass(RenameBaseCommentNodeMethods, template.  
    2424    """
    2525
    2626    @classmethod
    27     def handle_token(cls, parser, token):
     27    def handle_parse_result(cls, parser, parse_result):
    2828        """Class method to parse get_comment_list/count/form and return a Node."""
    29         tokens = token.split_contents()
    30         if tokens[1] != 'for':
    31             raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0])
     29        tokens = parse_result.arguments
     30        tagname = parse_result.tagname
     31
     32        if tokens[0] != 'for':
     33            raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tagname)
    3234
    3335        # {% get_whatever for obj as varname %}
    34         if len(tokens) == 5:
    35             if tokens[3] != 'as':
    36                 raise template.TemplateSyntaxError("Third argument in %r must be 'as'" % tokens[0])
     36        if len(tokens) == 4:
     37            if tokens[2] != 'as':
     38                raise template.TemplateSyntaxError("Third argument in %r must be 'as'" % tagname)
    3739            return cls(
    38                 object_expr = parser.compile_filter(tokens[2]),
    39                 as_varname = tokens[4],
     40                object_expr = parser.compile_filter(tokens[1]),
     41                as_varname = tokens[3],
    4042            )
    4143
    4244        # {% get_whatever for app.model pk as varname %}
    43         elif len(tokens) == 6:
    44             if tokens[4] != 'as':
    45                 raise template.TemplateSyntaxError("Fourth argument in %r must be 'as'" % tokens[0])
     45        elif len(tokens) == 5:
     46            if tokens[3] != 'as':
     47                raise template.TemplateSyntaxError("Fourth argument in %r must be 'as'" % tagname)
    4648            return cls(
    47                 ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),
    48                 object_pk_expr = parser.compile_filter(tokens[3]),
    49                 as_varname = tokens[5]
     49                ctype = BaseCommentNode.lookup_content_type(tokens[1], tagname),
     50                object_pk_expr = parser.compile_filter(tokens[2]),
     51                as_varname = tokens[4]
    5052            )
    5153
    5254        else:
    53             raise template.TemplateSyntaxError("%r tag requires 4 or 5 arguments" % tokens[0])
     55            raise template.TemplateSyntaxError("%r tag requires 4 or 5 arguments" % tagname)
    5456
    5557    @staticmethod
    5658    def lookup_content_type(token, tagname):
    class BaseCommentNode(six.with_metaclass(RenameBaseCommentNodeMethods, template.  
    114116        """Subclasses should override this."""
    115117        raise NotImplementedError
    116118
     119@register.tag
    117120class CommentListNode(BaseCommentNode):
    118     """Insert a list of comments into the context."""
     121    """
     122    Gets the list of comments for the given params and populates the template
     123    context with a variable containing that value, whose name is defined by the
     124    'as' clause.
     125
     126    Syntax::
     127
     128        {% get_comment_list for [object] as [varname]  %}
     129        {% get_comment_list for [app].[model] [object_id] as [varname]  %}
     130
     131    Example usage::
     132
     133        {% get_comment_list for event as comment_list %}
     134        {% for comment in comment_list %}
     135            ...
     136        {% endfor %}
     137
     138    """
     139    grammar = template.Grammar('get_comment_list')
     140
    119141    def get_context_value_from_queryset(self, context, qs):
    120142        return list(qs)
    121143
     144@register.tag
    122145class CommentCountNode(BaseCommentNode):
    123     """Insert a count of comments into the context."""
     146    """
     147    Gets the comment count for the given params and populates the template
     148    context with a variable containing that value, whose name is defined by the
     149    'as' clause.
     150
     151    Syntax::
     152
     153        {% get_comment_count for [object] as [varname]  %}
     154        {% get_comment_count for [app].[model] [object_id] as [varname]  %}
     155
     156    Example usage::
     157
     158        {% get_comment_count for event as comment_count %}
     159        {% get_comment_count for calendar.event event.id as comment_count %}
     160        {% get_comment_count for calendar.event 17 as comment_count %}
     161
     162    """
     163    grammar = template.Grammar('get_comment_count')
     164
    124165    def get_context_value_from_queryset(self, context, qs):
    125166        return qs.count()
    126167
     168@register.tag
    127169class CommentFormNode(BaseCommentNode):
    128     """Insert a form for the comment model into the context."""
     170    """
     171    Get a (new) form object to post a new comment.
     172
     173    Syntax::
     174
     175        {% get_comment_form for [object] as [varname] %}
     176        {% get_comment_form for [app].[model] [object_id] as [varname] %}
     177    """
     178    grammar = template.Grammar('get_comment_form')
    129179
    130180    def get_form(self, context):
    131181        obj = self.get_object(context)
    class CommentFormNode(BaseCommentNode):  
    149199        context[self.as_varname] = self.get_form(context)
    150200        return ''
    151201
     202@register.tag
    152203class RenderCommentFormNode(CommentFormNode):
    153     """Render the comment form directly"""
     204    """
     205    Render the comment form (as returned by ``{% render_comment_form %}``) through
     206    the ``comments/form.html`` template.
     207
     208    Syntax::
     209
     210        {% render_comment_form for [object] %}
     211        {% render_comment_form for [app].[model] [object_id] %}
     212    """
     213    grammar = template.Grammar('render_comment_form')
    154214
    155215    @classmethod
    156     def handle_token(cls, parser, token):
     216    def handle_parse_result(cls, parser, parse_result):
    157217        """Class method to parse render_comment_form and return a Node."""
    158         tokens = token.split_contents()
    159         if tokens[1] != 'for':
    160             raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0])
     218        tokens = parse_result.arguments
     219        tagname = parse_result.tagname
     220
     221        if tokens[0] != 'for':
     222            raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tagname)
    161223
    162224        # {% render_comment_form for obj %}
    163         if len(tokens) == 3:
    164             return cls(object_expr=parser.compile_filter(tokens[2]))
     225        if len(tokens) == 2:
     226            return cls(object_expr=parser.compile_filter(tokens[1]))
    165227
    166228        # {% render_comment_form for app.models pk %}
    167         elif len(tokens) == 4:
     229        elif len(tokens) == 3:
    168230            return cls(
    169                 ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),
    170                 object_pk_expr = parser.compile_filter(tokens[3])
     231                ctype = BaseCommentNode.lookup_content_type(tokens[1], tagname),
     232                object_pk_expr = parser.compile_filter(tokens[2])
    171233            )
    172234
    173235    def render(self, context):
    class RenderCommentFormNode(CommentFormNode):  
    185247        else:
    186248            return ''
    187249
     250@register.tag
    188251class RenderCommentListNode(CommentListNode):
    189     """Render the comment list directly"""
     252    """
     253    Render the comment list (as returned by ``{% get_comment_list %}``)
     254    through the ``comments/list.html`` template
     255
     256    Syntax::
     257
     258        {% render_comment_list for [object] %}
     259        {% render_comment_list for [app].[model] [object_id] %}
     260
     261    Example usage::
     262
     263        {% render_comment_list for event %}
     264
     265    """
     266    grammar = template.Grammar('render_comment_list')
    190267
    191268    @classmethod
    192     def handle_token(cls, parser, token):
     269    def handle_parse_result(cls, parser, parse_result):
    193270        """Class method to parse render_comment_list and return a Node."""
    194         tokens = token.split_contents()
    195         if tokens[1] != 'for':
    196             raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0])
     271        tokens = parse_result.arguments
     272        tagname = parse_result.tagname
     273
     274        if tokens[0] != 'for':
     275            raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tagname)
    197276
    198277        # {% render_comment_list for obj %}
    199         if len(tokens) == 3:
    200             return cls(object_expr=parser.compile_filter(tokens[2]))
     278        if len(tokens) == 2:
     279            return cls(object_expr=parser.compile_filter(tokens[1]))
    201280
    202281        # {% render_comment_list for app.models pk %}
    203         elif len(tokens) == 4:
     282        elif len(tokens) == 3:
    204283            return cls(
    205                 ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),
    206                 object_pk_expr = parser.compile_filter(tokens[3])
     284                ctype = BaseCommentNode.lookup_content_type(tokens[1], tagname),
     285                object_pk_expr = parser.compile_filter(tokens[2])
    207286            )
    208287
    209288    def render(self, context):
    class RenderCommentListNode(CommentListNode):  
    228307# the automagic docstrings-into-admin-docs tricks. So each node gets a cute
    229308# wrapper function that just exists to hold the docstring.
    230309
    231 @register.tag
    232 def get_comment_count(parser, token):
    233     """
    234     Gets the comment count for the given params and populates the template
    235     context with a variable containing that value, whose name is defined by the
    236     'as' clause.
    237 
    238     Syntax::
    239 
    240         {% get_comment_count for [object] as [varname]  %}
    241         {% get_comment_count for [app].[model] [object_id] as [varname]  %}
    242 
    243     Example usage::
    244 
    245         {% get_comment_count for event as comment_count %}
    246         {% get_comment_count for calendar.event event.id as comment_count %}
    247         {% get_comment_count for calendar.event 17 as comment_count %}
    248 
    249     """
    250     return CommentCountNode.handle_token(parser, token)
    251 
    252 @register.tag
    253 def get_comment_list(parser, token):
    254     """
    255     Gets the list of comments for the given params and populates the template
    256     context with a variable containing that value, whose name is defined by the
    257     'as' clause.
    258 
    259     Syntax::
    260 
    261         {% get_comment_list for [object] as [varname]  %}
    262         {% get_comment_list for [app].[model] [object_id] as [varname]  %}
    263 
    264     Example usage::
    265 
    266         {% get_comment_list for event as comment_list %}
    267         {% for comment in comment_list %}
    268             ...
    269         {% endfor %}
    270 
    271     """
    272     return CommentListNode.handle_token(parser, token)
    273 
    274 @register.tag
    275 def render_comment_list(parser, token):
    276     """
    277     Render the comment list (as returned by ``{% get_comment_list %}``)
    278     through the ``comments/list.html`` template
    279 
    280     Syntax::
    281 
    282         {% render_comment_list for [object] %}
    283         {% render_comment_list for [app].[model] [object_id] %}
    284 
    285     Example usage::
    286 
    287         {% render_comment_list for event %}
    288 
    289     """
    290     return RenderCommentListNode.handle_token(parser, token)
    291 
    292 @register.tag
    293 def get_comment_form(parser, token):
    294     """
    295     Get a (new) form object to post a new comment.
    296 
    297     Syntax::
    298 
    299         {% get_comment_form for [object] as [varname] %}
    300         {% get_comment_form for [app].[model] [object_id] as [varname] %}
    301     """
    302     return CommentFormNode.handle_token(parser, token)
    303 
    304 @register.tag
    305 def render_comment_form(parser, token):
    306     """
    307     Render the comment form (as returned by ``{% render_comment_form %}``) through
    308     the ``comments/form.html`` template.
    309 
    310     Syntax::
    311 
    312         {% render_comment_form for [object] %}
    313         {% render_comment_form for [app].[model] [object_id] %}
    314     """
    315     return RenderCommentFormNode.handle_token(parser, token)
    316310
    317311@register.simple_tag
    318312def comment_form_target():
  • django/contrib/flatpages/templatetags/flatpages.py

    diff --git a/django/contrib/flatpages/templatetags/flatpages.py b/django/contrib/flatpages/templatetags/flatpages.py
    index a32ac7f..aad0fc0 100644
    a b from django import template  
    22from django.conf import settings
    33from django.contrib.flatpages.models import FlatPage
    44from django.contrib.sites.models import get_current_site
     5from django.template.generic import TemplateTag, Grammar
    56
    67
    78register = template.Library()
    89
    9 
    10 class FlatpageNode(template.Node):
    11     def __init__(self, context_name, starts_with=None, user=None):
    12         self.context_name = context_name
    13         if starts_with:
    14             self.starts_with = template.Variable(starts_with)
    15         else:
    16             self.starts_with = None
    17         if user:
    18             self.user = template.Variable(user)
    19         else:
    20             self.user = None
    21 
    22     def render(self, context):
    23         if 'request' in context:
    24             site_pk = get_current_site(context['request']).pk
    25         else:
    26             site_pk = settings.SITE_ID
    27         flatpages = FlatPage.objects.filter(sites__id=site_pk)
    28         # If a prefix was specified, add a filter
    29         if self.starts_with:
    30             flatpages = flatpages.filter(
    31                 url__startswith=self.starts_with.resolve(context))
    32 
    33         # If the provided user is not authenticated, or no user
    34         # was provided, filter the list to only public flatpages.
    35         if self.user:
    36             user = self.user.resolve(context)
    37             if not user.is_authenticated():
    38                 flatpages = flatpages.filter(registration_required=False)
    39         else:
    40             flatpages = flatpages.filter(registration_required=False)
    41 
    42         context[self.context_name] = flatpages
    43         return ''
    44 
    45 
    4610@register.tag
    47 def get_flatpages(parser, token):
     11class FlatpageNode(TemplateTag):
    4812    """
    4913    Retrieves all flatpage objects available for the current site and
    5014    visible to the specific user (or visible to all users if no user is
    def get_flatpages(parser, token):  
    7135        {% get_flatpages prefix as about_pages %}
    7236        {% get_flatpages '/about/' for someuser as about_pages %}
    7337    """
    74     bits = token.split_contents()
    75     syntax_message = ("%(tag_name)s expects a syntax of %(tag_name)s "
    76                        "['url_starts_with'] [for user] as context_name" %
    77                        dict(tag_name=bits[0]))
    78    # Must have at 3-6 bits in the tag
    79     if len(bits) >= 3 and len(bits) <= 6:
     38    grammar = Grammar('get_flatpages')
     39
     40    def __init__(self, parser, parse_result):
     41        bits = parse_result.arguments
     42        tagname = parse_result.tagname
     43        syntax_message = ("%(tag_name)s expects a syntax of %(tag_name)s "
     44                           "['url_starts_with'] [for user] as context_name" %
     45                           dict(tag_name=tagname))
     46        # Must have at 2-5 bits in the tag
     47        if not (len(bits) >= 2 and len(bits) <= 5):
     48            raise template.TemplateSyntaxError(syntax_message)
    8049
    8150        # If there's an even number of bits, there's no prefix
    8251        if len(bits) % 2 == 0:
    83             prefix = bits[1]
    84         else:
    8552            prefix = None
     53        else:
     54            prefix = bits[0]
    8655
    8756        # The very last bit must be the context name
    8857        if bits[-2] != 'as':
    8958            raise template.TemplateSyntaxError(syntax_message)
    90         context_name = bits[-1]
     59        self.context_name = bits[-1]
    9160
    92         # If there are 5 or 6 bits, there is a user defined
    93         if len(bits) >= 5:
     61        # If there are 4 or 5 bits, there is a user defined
     62        if len(bits) >= 4:
    9463            if bits[-4] != 'for':
    9564                raise template.TemplateSyntaxError(syntax_message)
    9665            user = bits[-3]
    9766        else:
    9867            user = None
    9968
    100         return FlatpageNode(context_name, starts_with=prefix, user=user)
    101     else:
    102         raise template.TemplateSyntaxError(syntax_message)
     69        self.starts_with = template.Variable(prefix) if prefix else None
     70        self.user = template.Variable(user) if user else None
     71
     72    def render(self, context):
     73        if 'request' in context:
     74            site_pk = get_current_site(context['request']).pk
     75        else:
     76            site_pk = settings.SITE_ID
     77        flatpages = FlatPage.objects.filter(sites__id=site_pk)
     78        # If a prefix was specified, add a filter
     79        if self.starts_with:
     80            flatpages = flatpages.filter(
     81                url__startswith=self.starts_with.resolve(context))
     82
     83        # If the provided user is not authenticated, or no user
     84        # was provided, filter the list to only public flatpages.
     85        if self.user:
     86            user = self.user.resolve(context)
     87            if not user.is_authenticated():
     88                flatpages = flatpages.filter(registration_required=False)
     89        else:
     90            flatpages = flatpages.filter(registration_required=False)
     91
     92        context[self.context_name] = flatpages
     93        return ''
     94
     95
  • django/contrib/staticfiles/templatetags/staticfiles.py

    diff --git a/django/contrib/staticfiles/templatetags/staticfiles.py b/django/contrib/staticfiles/templatetags/staticfiles.py
    index ab92275..a9a66d8 100644
    a b from django.contrib.staticfiles.storage import staticfiles_storage  
    55register = template.Library()
    66
    77
     8@register.tag
    89class StaticFilesNode(StaticNode):
    9 
    10     def url(self, context):
    11         path = self.path.resolve(context)
    12         return staticfiles_storage.url(path)
    13 
    14 
    15 @register.tag('static')
    16 def do_static(parser, token):
    1710    """
    1811    A template tag that returns the URL to a file
    1912    using staticfiles' storage backend
    def do_static(parser, token):  
    3023        {% static variable_with_path as varname %}
    3124
    3225    """
    33     return StaticFilesNode.handle_token(parser, token)
     26    grammar = template.Grammar('static')
     27
     28    def url(self, context):
     29        path = self.path.resolve(context)
     30        return staticfiles_storage.url(path)
    3431
    3532
    3633def static(path):
  • django/contrib/webdesign/templatetags/webdesign.py

    diff --git a/django/contrib/webdesign/templatetags/webdesign.py b/django/contrib/webdesign/templatetags/webdesign.py
    index b870299..1a1a68d 100644
    a b from __future__ import unicode_literals  
    22
    33from django.contrib.webdesign.lorem_ipsum import words, paragraphs
    44from django import template
     5from django.template.generic import TemplateTag, Grammar
    56
    67register = template.Library()
    78
    8 class LoremNode(template.Node):
    9     def __init__(self, count, method, common):
    10         self.count, self.method, self.common = count, method, common
    11 
    12     def render(self, context):
    13         try:
    14             count = int(self.count.resolve(context))
    15         except (ValueError, TypeError):
    16             count = 1
    17         if self.method == 'w':
    18             return words(count, common=self.common)
    19         else:
    20             paras = paragraphs(count, common=self.common)
    21         if self.method == 'p':
    22             paras = ['<p>%s</p>' % p for p in paras]
    23         return '\n\n'.join(paras)
    24 
    259@register.tag
    26 def lorem(parser, token):
     10class LoremNode(TemplateTag):
    2711    """
    2812    Creates random Latin text useful for providing test data in templates.
    2913
    def lorem(parser, token):  
    4630          and two random paragraphs each wrapped in HTML ``<p>`` tags
    4731        * ``{% lorem 2 w random %}`` will output two random latin words
    4832    """
    49     bits = list(token.split_contents())
    50     tagname = bits[0]
    51     # Random bit
    52     common = bits[-1] != 'random'
    53     if not common:
    54         bits.pop()
    55     # Method bit
    56     if bits[-1] in ('w', 'p', 'b'):
    57         method = bits.pop()
    58     else:
    59         method = 'b'
    60     # Count bit
    61     if len(bits) > 1:
    62         count = bits.pop()
    63     else:
    64         count = '1'
    65     count = parser.compile_filter(count)
    66     if len(bits) != 1:
    67         raise template.TemplateSyntaxError("Incorrect format for %r tag" % tagname)
    68     return LoremNode(count, method, common)
     33    grammar = Grammar('lorem')
     34
     35    def __init__(self, parser, parse_result):
     36        bits = parse_result.arguments[:]
     37        tagname = parse_result.tagname
     38
     39        # Random bit
     40        common = bits[-1] != 'random'
     41        if not common:
     42            bits.pop()
     43        # Method bit
     44        if bits[-1] in ('w', 'p', 'b'):
     45            method = bits.pop()
     46        else:
     47            method = 'b'
     48        # Count bit
     49        if len(bits) > 0:
     50            count = bits.pop()
     51        else:
     52            count = '1'
     53        count = parser.compile_filter(count)
     54        if len(bits) != 0:
     55            raise template.TemplateSyntaxError("Incorrect format for %r tag" % tagname)
     56
     57        self.common = common
     58        self.method = method
     59        self.count = count
     60
     61    def render(self, context):
     62        try:
     63            count = int(self.count.resolve(context))
     64        except (ValueError, TypeError):
     65            count = 1
     66        if self.method == 'w':
     67            return words(count, common=self.common)
     68        else:
     69            paras = paragraphs(count, common=self.common)
     70        if self.method == 'p':
     71            paras = ['<p>%s</p>' % p for p in paras]
     72        return '\n\n'.join(paras)
Back to Top