@@ -194,7 +194,7 @@ def _replace_amp_or_semi(match: re.Match):
194
194
r"{% comment ('.*?' |\".*?\" )?%}[\s\S]*?{% endcomment %}"
195
195
)
196
196
_TOKEN_PATTERN = re .compile (r"{{ .+? }}|{% .+? %}" )
197
- _LSTRIP_BLOCK_PATTERN = re .compile (r"\n( ) +$" )
197
+ _LSTRIP_BLOCK_PATTERN = re .compile (r"\n +$" )
198
198
199
199
200
200
def _find_extends (template : str ):
@@ -476,8 +476,12 @@ def _create_template_rendering_function( # pylint: disable=,too-many-locals,too
476
476
template = _remove_comments (template )
477
477
478
478
# Create definition of the template function
479
- function_string = f"def { function_name } ({ context_name } ):\n "
480
- indent , indentation_level = " " , 1
479
+ function_def = f"def { function_name } ({ context_name } ):\n "
480
+ indent_level = 1
481
+
482
+ def indented (fragment : str , end : str = "\n " ) -> str :
483
+ nonlocal indent_level
484
+ return " " * indent_level + fragment + end
481
485
482
486
# Keep track of the template state
483
487
nested_if_statements : "list[Token]" = []
@@ -506,11 +510,9 @@ def _create_template_rendering_function( # pylint: disable=,too-many-locals,too
506
510
text_before_token = text_before_token [1 :]
507
511
508
512
if text_before_token :
509
- function_string += (
510
- indent * indentation_level + f"yield { repr (text_before_token )} \n "
511
- )
513
+ function_def += indented (f"yield { repr (text_before_token )} " )
512
514
else :
513
- function_string += indent * indentation_level + "pass\n "
515
+ function_def += indented ( "pass" )
514
516
515
517
# Token is an expression
516
518
if token .content .startswith (r"{{ " ):
@@ -523,97 +525,82 @@ def _create_template_rendering_function( # pylint: disable=,too-many-locals,too
523
525
524
526
# Expression should be escaped
525
527
if autoescape :
526
- function_string += (
527
- indent * indentation_level
528
- + f"yield safe_html({ token .content [3 :- 3 ]} )\n "
529
- )
528
+ function_def += indented (f"yield safe_html({ token .content [3 :- 3 ]} )" )
530
529
# Expression should not be escaped
531
530
else :
532
- function_string += (
533
- indent * indentation_level + f"yield str({ token .content [3 :- 3 ]} )\n "
534
- )
531
+ function_def += indented (f"yield { token .content [3 :- 3 ]} " )
535
532
536
533
# Token is a statement
537
534
elif token .content .startswith (r"{% " ):
538
535
last_token_was_block = True
539
536
540
537
# Token is a some sort of if statement
541
538
if token .content .startswith (r"{% if " ):
542
- function_string += (
543
- indent * indentation_level + f"{ token .content [3 :- 3 ]} :\n "
544
- )
545
- indentation_level += 1
539
+ function_def += indented (f"if { token .content [6 :- 3 ]} :" )
540
+ indent_level += 1
546
541
547
542
nested_if_statements .append (token )
548
543
elif token .content .startswith (r"{% elif " ):
549
544
if not nested_if_statements :
550
545
raise TemplateSyntaxError (token , "No matching {% if ... %}" )
551
546
552
- indentation_level -= 1
553
- function_string += (
554
- indent * indentation_level + f"{ token .content [3 :- 3 ]} :\n "
555
- )
556
- indentation_level += 1
547
+ indent_level -= 1
548
+ function_def += indented (f"elif { token .content [8 :- 3 ]} :" )
549
+ indent_level += 1
557
550
elif token .content == r"{% else %}" :
558
551
if not nested_if_statements :
559
552
raise TemplateSyntaxError (token , "No matching {% if ... %}" )
560
553
561
- indentation_level -= 1
562
- function_string += indent * indentation_level + "else:\n "
563
- indentation_level += 1
554
+ indent_level -= 1
555
+ function_def += indented ( "else:" )
556
+ indent_level += 1
564
557
elif token .content == r"{% endif %}" :
565
558
if not nested_if_statements :
566
559
raise TemplateSyntaxError (token , "No matching {% if ... %}" )
567
560
568
- indentation_level -= 1
561
+ indent_level -= 1
569
562
nested_if_statements .pop ()
570
563
571
564
# Token is a for loop
572
565
elif token .content .startswith (r"{% for " ):
573
- function_string += (
574
- indent * indentation_level + f"{ token .content [3 :- 3 ]} :\n "
575
- )
576
- indentation_level += 1
566
+ function_def += indented (f"for { token .content [7 :- 3 ]} :" )
567
+ indent_level += 1
577
568
578
569
nested_for_loops .append (token )
579
570
elif token .content == r"{% empty %}" :
580
571
if not nested_for_loops :
581
572
raise TemplateSyntaxError (token , "No matching {% for ... %}" )
582
573
583
- indentation_level -= 1
584
574
last_forloop_iterable = (
585
575
nested_for_loops [- 1 ].content [3 :- 3 ].split (" in " , 1 )[1 ]
586
576
)
587
- function_string += (
588
- indent * indentation_level + f"if not { last_forloop_iterable } : \n "
589
- )
590
- indentation_level += 1
577
+
578
+ indent_level -= 1
579
+ function_def += indented ( f"if not { last_forloop_iterable } :" )
580
+ indent_level += 1
591
581
elif token .content == r"{% endfor %}" :
592
582
if not nested_for_loops :
593
583
raise TemplateSyntaxError (token , "No matching {% for ... %}" )
594
584
595
- indentation_level -= 1
585
+ indent_level -= 1
596
586
nested_for_loops .pop ()
597
587
598
588
# Token is a while loop
599
589
elif token .content .startswith (r"{% while " ):
600
- function_string += (
601
- indent * indentation_level + f"{ token .content [3 :- 3 ]} :\n "
602
- )
603
- indentation_level += 1
590
+ function_def += indented (f"while { token .content [9 :- 3 ]} :" )
591
+ indent_level += 1
604
592
605
593
nested_while_loops .append (token )
606
594
elif token .content == r"{% endwhile %}" :
607
595
if not nested_while_loops :
608
596
raise TemplateSyntaxError (token , "No matching {% while ... %}" )
609
597
610
- indentation_level -= 1
598
+ indent_level -= 1
611
599
nested_while_loops .pop ()
612
600
613
601
# Token is a Python code
614
602
elif token .content .startswith (r"{% exec " ):
615
- expression = token .content [8 :- 3 ]
616
- function_string += indent * indentation_level + f"{ expression } \n "
603
+ function_def += indented (f"{ token .content [8 :- 3 ]} " )
617
604
618
605
# Token is a autoescape mode change
619
606
elif token .content .startswith (r"{% autoescape " ):
@@ -668,12 +655,10 @@ def _create_template_rendering_function( # pylint: disable=,too-many-locals,too
668
655
if trim_blocks and text_after_last_token .startswith ("\n " ):
669
656
text_after_last_token = text_after_last_token [1 :]
670
657
671
- function_string += (
672
- indent * indentation_level + f"yield { repr (text_after_last_token )} \n "
673
- )
658
+ function_def += indented (f"yield { repr (text_after_last_token )} " )
674
659
675
660
# Create and return the template function
676
- exec (function_string ) # pylint: disable=exec-used
661
+ exec (function_def ) # pylint: disable=exec-used
677
662
return locals ()[function_name ]
678
663
679
664
0 commit comments