Adds Django template linter.

This adds Django template linter that
would check for all trans/blocktrans
tag expressions for escaping.

PROD-465
This commit is contained in:
Adeel Khan
2019-07-25 18:45:17 +05:00
parent 82a010b3b2
commit 37c6b60fc8
4 changed files with 827 additions and 3 deletions

View File

@@ -10,7 +10,11 @@ from unittest import TestCase
from ddt import data, ddt
from six.moves import range, zip
from xsslint.linters import JavaScriptLinter, MakoTemplateLinter, PythonLinter, UnderscoreTemplateLinter
from xsslint.linters import (
JavaScriptLinter, MakoTemplateLinter,
PythonLinter, UnderscoreTemplateLinter,
DjangoTemplateLinter
)
from xsslint.reporting import FileResults
from xsslint.utils import ParseString
@@ -28,6 +32,10 @@ def _build_mako_linter():
)
def _build_django_linter():
return DjangoTemplateLinter()
class TestLinter(TestCase):
"""
Test Linter base class
@@ -1443,3 +1451,255 @@ class TestMakoTemplateLinter(TestLinter):
start_inner_index = parse_string.start_index + parse_string.quote_length
end_inner_index = parse_string.end_index - parse_string.quote_length
self.assertEqual(data['template'][start_inner_index:end_inner_index], parse_string.string_inner)
@ddt
class TestDjangoTemplateLinter(TestLinter):
"""
Test DjangoTemplateLinter
"""
ruleset = (
DjangoTemplateLinter.ruleset
)
@data(
{'expression': '{% trans "whatever" as tmsg %}{{tmsg|force_escape}}',
'rule': None},
{'expression': '{% trans "whatever" as tmsgx %}{{tmsg|force_escape}}',
'rule': ruleset.django_trans_escape_variable_mismatch},
{'expression': '{% trans "whatever" as tmsgx %}{{tmsgx|force_escap}}',
'rule': ruleset.django_trans_invalid_escape_filter},
{'expression': '{% trans "whatever" as tmsg %}',
'rule': ruleset.django_trans_missing_escape},
{'expression': '{% trans "whatever" %}',
'rule': ruleset.django_trans_missing_escape},
{'expression': '{% trans "{span_start} whatever {span_end}" as tmsg %}',
'rule': ruleset.django_html_interpolation_missing},
{'expression': '{% trans "{span_start} whatever {span_end}" as tmsg %}{{tmsg|force_filter}}',
'rule': ruleset.django_html_interpolation_missing},
{'expression': """
{% trans "{span_start} whatever {span_end}" as tmsg %}
{% interpolate_html tmsg user_name=user_data.name start_span='<span class="a">'|safe end_span='</span>'|safe %}
""", 'rule': None},
{'expression': """
{% trans "{span_start} whatever {span_end}" as tmsg %}
{% interpolate_html %}
""", 'rule': [ruleset.django_html_interpolation_missing, ruleset.django_html_interpolation_invalid_tag]},
{'expression': """
{% trans "{span_start} whatever {span_end}" as tmsg %}
{% interpolate_html t start_span='<span class="a">'|safe end_span='</span>'|safe %}
""", 'rule': ruleset.django_html_interpolation_missing},
{'expression': """
{% trans "{span_start} whatever {span_end}" as tmsg %}
{% interpolate_html tmsg start_span='<span class="a">'|unknown end_span='</span>'|safe %}
""", 'rule': ruleset.django_html_interpolation_missing_safe_filter},
{'expression': """
{% trans "<span 'a'='b' 'c'='d'> whatever </span>" as tmsg %}
""", 'rule': ruleset.django_html_interpolation_missing},
{'expression': """
{% trans "<span 'a'='b' 'c'='d'> whatever </span>" %}
""", 'rule': ruleset.django_html_interpolation_missing},
{'expression': """
{% filter force_escape %}
{% blocktrans %}
Some translation string
{% endblocktrans %}
{% endfilter %}
""", 'rule': None},
{'expression': """
{% filter force_escape
{% blocktrans %}
Some translation string
{% endblocktrans %}
{% endfilter %}
""", 'rule': ruleset.django_blocktrans_escape_filter_parse_error},
{'expression': """
{% filter someother_filter %}
{% blocktrans %}
Some translation strubg
{% endblocktrans %}
{% endfilter %}
""", 'rule': ruleset.django_blocktrans_missing_escape_filter},
{'expression': """
{% filter force_escape xyz %}
{% blocktrans %}
Some translation string
{% endblocktrans %}
{% endfilter %}
""", 'rule': ruleset.django_blocktrans_missing_escape_filter},
{'expression': """
{% blocktrans %}
Some translation string
{% endblocktrans %}
""", 'rule': ruleset.django_blocktrans_missing_escape_filter},
{'expression': """
{% blocktrans %}
Some translation <span 'a'='b' 'c'='d'> whatever </span>
{% endblocktrans %}
""", 'rule': ruleset.django_html_interpolation_missing},
)
def test_check_django_expressions_in_html(self, data):
"""
Test _check_django_file_is_safe in html context provides appropriate violations
"""
linter = _build_django_linter()
results = FileResults('')
django_template = textwrap.dedent(
"""
{load_i18n}
{load_django_html}
{expression}
""".format(expression=data['expression'],
load_i18n='{% load i18n %}',
load_django_html='{% load django_html %}'))
linter._check_django_file_is_safe(django_template, results)
self._validate_data_rules(data, results)
def test_check_django_trans_expression_disabled(self):
"""
Test _check_django_file_is_safe with disable pragma results in no
violation
"""
linter = _build_django_linter()
results = FileResults('')
django_template = textwrap.dedent(
"""
{load_i18n}
{load_django_html}
{expression}
""".format(expression="""
{# xss-lint: disable=django-trans-missing-escape #}
{% trans 'Documentation' as tmsg%}
""",
load_i18n='{% load i18n %}',
load_django_html='{% load django_html %}'))
linter._check_django_file_is_safe(django_template, results)
self.assertEqual(len(results.violations), 1)
self.assertTrue(results.violations[0].is_disabled)
def test_check_django_blocktrans_expression_disabled(self):
"""
Test _check_django_file_is_safe with disable pragma results in no
violation
"""
linter = _build_django_linter()
results = FileResults('')
django_template = textwrap.dedent(
"""
{load_i18n}
{load_django_html}
{expression}
""".format(expression="""
{# xss-lint: disable=django-blocktrans-missing-escape-filter #}
{% blocktrans %}
sometext
{% endblocktrans %}
""",
load_i18n='{% load i18n %}',
load_django_html='{% load django_html %}'))
linter._check_django_file_is_safe(django_template, results)
self.assertEqual(len(results.violations), 1)
self.assertTrue(results.violations[0].is_disabled)
def test_check_django_trans_expression_commented(self):
"""
Test _check_django_file_is_safe with comment results in no
violation
"""
linter = _build_django_linter()
results = FileResults('')
django_template = textwrap.dedent(
"""
{load_i18n}
{load_django_html}
{expression}
""".format(expression="""
{# trans 'Documentation' as tmsg #}
""",
load_i18n='{% load i18n %}',
load_django_html='{% load django_html %}'))
linter._check_django_file_is_safe(django_template, results)
self.assertEqual(len(results.violations), 0)
def test_check_django_blocktrans_expression_commented(self):
"""
Test _check_django_file_is_safe with comment results in no
violation
"""
linter = _build_django_linter()
results = FileResults('')
django_template = textwrap.dedent(
"""
{load_i18n}
{load_django_html}
{expression}
""".format(expression="""
{% comment %}
{% blocktrans %}
{% endblocktrans %}
{% endcomment %}
""",
load_i18n='{% load i18n %}',
load_django_html='{% load django_html %}'))
linter._check_django_file_is_safe(django_template, results)
self.assertEqual(len(results.violations), 0)
def test_check_django_interpolate_tag_expression_commented(self):
"""
Test _check_django_file_is_safe with comment results in no
violation
"""
linter = _build_django_linter()
results = FileResults('')
django_template = textwrap.dedent(
"""
{load_i18n}
{load_django_html}
{expression}
""".format(expression="""
{% comment %}
{% interpolate_html %}
{% endcomment %}
""",
load_i18n='{% load i18n %}',
load_django_html='{% load django_html %}'))
linter._check_django_file_is_safe(django_template, results)
self.assertEqual(len(results.violations), 0)

View File

@@ -1,7 +1,11 @@
# Default xsslint config module.
from __future__ import absolute_import
from xsslint.linters import JavaScriptLinter, MakoTemplateLinter, PythonLinter, UnderscoreTemplateLinter
from xsslint.linters import (
JavaScriptLinter, MakoTemplateLinter,
PythonLinter, UnderscoreTemplateLinter,
DjangoTemplateLinter
)
# Define the directories that should be ignored by the script.
SKIP_DIRS = (
@@ -45,6 +49,10 @@ MAKO_LINTER = MakoTemplateLinter(
skip_dirs=MAKO_SKIP_DIRS
)
DJANGO_SKIP_DIRS = SKIP_DIRS
DJANGO_LINTER = DjangoTemplateLinter(
skip_dirs=DJANGO_SKIP_DIRS
)
# (Required) Define the linters (code-checkers) that should be run by the script.
LINTERS = (MAKO_LINTER, UNDERSCORE_LINTER, JAVASCRIPT_LINTER, PYTHON_LINTER)
LINTERS = (DJANGO_LINTER, MAKO_LINTER, UNDERSCORE_LINTER, JAVASCRIPT_LINTER, PYTHON_LINTER)

View File

@@ -0,0 +1,402 @@
"""
Classes for Django Template Linting.
"""
import re
from xsslint.utils import Expression, StringLines
from xsslint.reporting import ExpressionRuleViolation
class TransExpression(Expression):
"""
The expression handling trans tag
"""
def __init__(self, ruleset, results, *args, **kwargs):
super(TransExpression, self).__init__(*args, **kwargs)
self.string_lines = StringLines(kwargs['template'])
self.ruleset = ruleset
self.results = results
def validate_expression(self, template_file, expressions=None):
"""
Validates trans tag expression for missing escaping filter
Arguments:
template_file: The content of the Django template.
results: Violations to be generated.
Returns:
None
"""
trans_expr = self.expression_inner
# extracting translation string message
trans_var_name_used, trans_expr_msg = self.process_translation_string(trans_expr)
if not trans_var_name_used or not trans_expr_msg:
return
# Checking if trans tag has interpolated variables eg {} in translations string.
# and testing for possible interpolate_html tag used for it.
if self.check_string_interpolation(trans_expr_msg,
trans_var_name_used,
expressions,
template_file):
return
escape_expr_start_pos, escape_expr_end_pos = self.find_filter_tag(template_file)
if not escape_expr_start_pos or not escape_expr_end_pos:
return
self.process_escape_filter_tag(template_file=template_file,
escape_expr_start_pos=escape_expr_start_pos,
escape_expr_end_pos=escape_expr_end_pos,
trans_var_name_used=trans_var_name_used)
def process_translation_string(self, trans_expr):
"""
Process translation string into string and variable name used
Arguments:
trans_expr: Translation expression inside {% %}
Returns:
None
"""
quote = re.search(r"""\s*['"].*['"]\s*""", trans_expr, re.I)
if not quote:
_add_violations(self.results,
self.ruleset.django_trans_escape_filter_parse_error,
self)
return None, None
trans_expr_msg = trans_expr[quote.start():quote.end()].strip()
if _check_is_string_has_html(trans_expr_msg):
_add_violations(self.results,
self.ruleset.django_html_interpolation_missing,
self)
return None, None
pos = trans_expr.find('as', quote.end())
if pos == -1:
_add_violations(self.results, self.ruleset.django_trans_missing_escape, self)
return None, None
trans_var_name_used = trans_expr[pos + len('as'):].strip()
return trans_var_name_used, trans_expr_msg
def check_string_interpolation(self, trans_expr_msg, trans_var_name_used, expressions, template_file):
"""
Checks if the translation string has used interpolation variable eg {variable} but not
used interpolate_html tag to escape them
Arguments:
trans_expr_msg: Translation string in quotes
trans_var_name_used: Translation variable used
expressions: List of expressions found during django file processing
template_file: django template file
Returns:
True: In case it finds interpolated variables
False: No interpolation variables found
"""
if _check_is_string_has_variables(trans_expr_msg):
interpolate_tag, html_interpolated = _is_html_interpolated(trans_var_name_used,
expressions)
if not html_interpolated:
_add_violations(self.results, self.ruleset.django_html_interpolation_missing, self)
if interpolate_tag:
interpolate_tag.validate_expression(template_file, expressions)
return True
return
def find_filter_tag(self, template_file):
"""
Finds if there is force_filter tag applied
Arguments:
template_file: django template file
Returns:
(None, None): In case there is a violations
(start, end): Found filter tag start and end position
"""
trans_expr_lineno = self.string_lines.index_to_line_number(self.start_index)
escape_expr_start_pos = template_file.find('{{', self.end_index)
if escape_expr_start_pos == -1:
_add_violations(self.results,
self.ruleset.django_trans_missing_escape,
self)
return None, None
# {{ found but should be on the same line as trans tag
trans_expr_filter_lineno = self.string_lines.index_to_line_number(escape_expr_start_pos)
if trans_expr_filter_lineno != trans_expr_lineno:
_add_violations(self.results,
self.ruleset.django_trans_missing_escape,
self)
return None, None
escape_expr_end_pos = template_file.find('}}', escape_expr_start_pos)
# couldn't find matching }}
if escape_expr_end_pos == -1:
_add_violations(self.results,
self.ruleset.django_trans_missing_escape,
self)
return None, None
# }} should be also on the same line
trans_expr_filter_lineno = self.string_lines.index_to_line_number(escape_expr_end_pos)
if trans_expr_filter_lineno != trans_expr_lineno:
_add_violations(self.results,
self.ruleset.django_trans_missing_escape,
self)
return None, None
return escape_expr_start_pos, escape_expr_end_pos
def process_escape_filter_tag(self, **kwargs):
"""
Checks if the escape filter and process it for violations
Arguments:
kwargs: Having force_filter expression start, end, trans expression variable
used and templates
Returns:
None: If found any violations
"""
template_file = kwargs['template_file']
escape_expr_start_pos = kwargs['escape_expr_start_pos']
escape_expr_end_pos = kwargs['escape_expr_end_pos']
trans_var_name_used = kwargs['trans_var_name_used']
escape_expr = template_file[escape_expr_start_pos + len('{{'):
escape_expr_end_pos].strip(' ')
# check escape expression has the right variable and its escaped properly
# with force_escape filter
if '|' not in escape_expr or len(escape_expr.split('|')) != 2:
_add_violations(self.results,
self.ruleset.django_trans_invalid_escape_filter,
self)
return
escape_expr_var_used, escape_filter = \
escape_expr.split('|')[0].strip(' '), escape_expr.split('|')[1].strip(' ')
if trans_var_name_used != escape_expr_var_used:
_add_violations(self.results,
self.ruleset.django_trans_escape_variable_mismatch,
self)
return
if escape_filter != 'force_escape':
_add_violations(self.results,
self.ruleset.django_trans_invalid_escape_filter,
self)
return
class BlockTransExpression(Expression):
"""
The expression handling blocktrans tag
"""
def __init__(self, ruleset, results, *args, **kwargs):
super(BlockTransExpression, self).__init__(*args, **kwargs)
self.string_lines = StringLines(kwargs['template'])
self.ruleset = ruleset
self.results = results
def validate_expression(self, template_file, expressions=None):
"""
Validates blocktrans tag expression for missing escaping filter
Arguments:
template_file: The content of the Django template.
results: Violations to be generated.
Returns:
None
"""
if not self._process_block(template_file, expressions):
return
filter_start_pos = template_file.rfind('{%', 0, self.start_index)
if filter_start_pos == -1:
_add_violations(self.results,
self.ruleset.django_blocktrans_missing_escape_filter,
self)
return
filter_end_pos = template_file.find('%}', filter_start_pos)
if filter_end_pos > self.start_index:
_add_violations(self.results,
self.ruleset.django_blocktrans_escape_filter_parse_error,
self)
return
escape_filter = template_file[filter_start_pos:filter_end_pos + 2]
if len(escape_filter) < len('{%filter force_escape%}'):
_add_violations(self.results,
self.ruleset.django_blocktrans_missing_escape_filter,
self)
return
escape_filter = escape_filter[2:-2].strip()
escape_filter = escape_filter.split(' ')
if len(escape_filter) != 2:
_add_violations(self.results,
self.ruleset.django_blocktrans_missing_escape_filter,
self)
return
if escape_filter[0] != 'filter' or escape_filter[1] != 'force_escape':
_add_violations(self.results,
self.ruleset.django_blocktrans_missing_escape_filter,
self)
return
def _process_block(self, template_file, expressions):
"""
Process blocktrans..endblocktrans block
Arguments:
template_file: The content of the Django template.
Returns:
None
"""
blocktrans_string = self._extract_translation_msg(template_file)
# if no string extracted might have hit a parse error just return
if not blocktrans_string:
return
if _check_is_string_has_html(blocktrans_string):
_add_violations(self.results, self.ruleset.django_html_interpolation_missing, self)
return
# Checking if blocktrans tag has interpolated variables eg {}
# in translations string. Would be tested for
# possible html interpolation done somewhere else.
if _check_is_string_has_variables(blocktrans_string):
blocktrans_expr = self.expression_inner
pos = blocktrans_expr.find('asvar')
if pos == -1:
_add_violations(self.results, self.ruleset.django_html_interpolation_missing, self)
return
trans_var_name_used = blocktrans_expr[pos + len('asvar'):].strip()
# check for interpolate_html expression for the variable in trans expression
interpolate_tag, html_interpolated = _is_html_interpolated(trans_var_name_used,
expressions)
if not html_interpolated:
_add_violations(self.results, self.ruleset.django_html_interpolation_missing, self)
if interpolate_tag:
interpolate_tag.validate_expression(template_file, expressions)
return
return True
def _extract_translation_msg(self, template_file):
endblocktrans = re.compile(r'{%\s*endblocktrans.*?%}').search(template_file,
self.end_index)
if not endblocktrans.start():
_add_violations(self.results,
self.ruleset.django_blocktrans_parse_error,
self)
return
return template_file[self.end_index + 2: endblocktrans.start()].strip(' ')
class HtmlInterpolateExpression(Expression):
"""
The expression handling interplate_html tag
"""
def __init__(self, ruleset, results, *args, **kwargs):
super(HtmlInterpolateExpression, self).__init__(*args, **kwargs)
self.string_lines = StringLines(kwargs['template'])
self.ruleset = ruleset
self.results = results
self.validated = False
self.interpolated_string_var = None
trans_expr = self.expression_inner
# extracting interpolated variable string name
expr_list = trans_expr.split(' ')
if len(expr_list) < 2:
_add_violations(self.results,
self.ruleset.django_html_interpolation_invalid_tag,
self)
return
self.interpolated_string_var = expr_list[1]
def validate_expression(self, template_file, expressions=None):
"""
Validates interpolate_html tag expression for missing safe filter for html tags
Arguments:
template_file: The content of the Django template.
results: Violations to be generated.
Returns:
None
"""
# if the expression is already validated, we would not be processing it again
if not self.interpolated_string_var or self.validated:
return
self.validated = True
trans_expr = self.expression_inner
html_tags = re.finditer(r"""\s*['"]</?[a-zA-Z0-9 =\-'_"]+.*?>['"]""",
trans_expr, re.I)
for html_tag in html_tags:
tag_end = html_tag.end()
escape_filter = trans_expr[tag_end:tag_end + len('|safe')]
if escape_filter != '|safe':
_add_violations(self.results,
self.ruleset.django_html_interpolation_missing_safe_filter,
self)
return
return True
def _check_is_string_has_html(trans_expr):
html_tags = re.search(r"""</?[a-zA-Z0-9 =\-'_":]+>""", trans_expr, re.I)
if html_tags:
return True
def _check_is_string_has_variables(trans_expr):
var_tags = re.search(r"""(?<!{){(?!{)[a-zA-Z0-9 =\-'_":]+(?<!})}(?!})""", trans_expr, re.I)
if var_tags:
return True
def _is_html_interpolated(trans_var_name_used, expressions):
html_interpolated = False
interpolate_tag_expr = None
for expr in expressions:
if isinstance(expr, HtmlInterpolateExpression):
if expr.interpolated_string_var == trans_var_name_used:
html_interpolated = True
interpolate_tag_expr = expr
return interpolate_tag_expr, html_interpolated
def _add_violations(results, rule_violation, self):
results.violations.append(ExpressionRuleViolation(
rule_violation, self
))

View File

@@ -12,6 +12,7 @@ from xsslint import visitors
from xsslint.reporting import ExpressionRuleViolation, FileResults, RuleViolation
from xsslint.rules import RuleSet
from xsslint.utils import Expression, ParseString, StringLines, is_skip_dir
from xsslint.django_linter import TransExpression, BlockTransExpression, HtmlInterpolateExpression
class BaseLinter(object):
@@ -1484,3 +1485,156 @@ class MakoTemplateLinter(BaseLinter):
start_index = expression.end_index
expressions.append(expression)
return expressions
class DjangoTemplateLinter(BaseLinter):
"""
The linter for Django template files
"""
LINE_COMMENT_DELIM = "{#"
ruleset = RuleSet(
django_trans_missing_escape='django-trans-missing-escape',
django_trans_invalid_escape_filter='django-trans-invalid-escape-filter',
django_trans_escape_variable_mismatch='django-trans-escape-variable-mismatch',
django_blocktrans_missing_escape_filter='django-blocktrans-missing-escape-filter',
django_blocktrans_parse_error='django-blocktrans-parse-error',
django_blocktrans_escape_filter_parse_error='django-blocktrans-escape-filter-parse-error',
django_html_interpolation_missing_safe_filter='django-html-interpolation-missing-safe-filter',
django_html_interpolation_missing='django-html-interpolation-missing',
django_html_interpolation_invalid_tag='django-html-interpolation-invalid-tag',
)
def __init__(self, skip_dirs=None):
"""
Init method.
"""
super(DjangoTemplateLinter, self).__init__()
self._skip_django_dirs = skip_dirs or ()
def process_file(self, directory, file_name):
"""
Process file to determine if it is a Django template file and
if it is safe.
Arguments:
directory (string): The directory of the file to be checked
file_name (string): A filename for a potential Django file
Returns:
The file results containing any violations.
"""
django_file_full_path = os.path.normpath(directory + '/' + file_name)
results = FileResults(django_file_full_path)
if not results.is_file:
return results
if not self._is_valid_directory(directory):
return results
if not (file_name.lower().endswith('.html')):
return results
return self._load_and_check_file_is_safe(django_file_full_path, self._check_django_file_is_safe, results)
def _is_valid_directory(self, directory):
"""
Determines if the provided directory is a directory that could contain
Django template files that need to be linted.
Arguments:
directory: The directory to be linted.
Returns:
True if this directory should be linted for Django template violations
and False otherwise.
"""
if is_skip_dir(self._skip_django_dirs, directory):
return False
if ('/templates/' in directory) or directory.endswith('/templates'):
return True
return False
def _is_django_template(self, django_template):
"""
Determines if the template is actually a Django template.
Arguments:
mako_template: The template code.
Returns:
True if this is really a Django template, and False otherwise.
"""
if re.search('({%.*%})|({{.*}})|({#.*#})', django_template) is not None:
return True
return False
def _check_django_file_is_safe(self, django_template, results):
if not self._is_django_template(django_template):
return
self._check_django_expression(django_template, results)
results.prepare_results(django_template, line_comment_delim=self.LINE_COMMENT_DELIM)
def _check_django_expression(self, django_template, results):
"""
Searches for django trans and blocktrans expression and then checks
if they contain violations
Arguments:
django_template: The contents of the Django template.
results: A list of results into which violations will be added.
"""
expressions = []
self._find_django_expressions(django_template, results, expressions)
for expr in expressions:
expr.validate_expression(django_template, expressions)
def _find_django_expressions(self, django_template, results, expressions):
"""
Finds all the Django trans/blocktrans expressions in a Django template
and creates a list of dicts for each expression.
Arguments:
django_template: The content of the Django template.
Returns:
A list of Expressions.
"""
comments = list(re.finditer(r'{% comment .*%}', django_template, re.I))
endcomments = list(re.finditer(r'{% endcomment .*%}', django_template, re.I))
trans_iterator = re.finditer(r'{% trans .*?%}', django_template, re.I)
for t in trans_iterator:
if self._check_expression_not_commented(t, comments, endcomments):
continue
trans_expr = TransExpression(self.ruleset, results, t.start(), t.end(),
start_delim='{%', end_delim='%}',
template=django_template)
if trans_expr:
expressions.append(trans_expr)
block_trans_iterator = re.finditer(r'{% blocktrans .*?%}', django_template, re.I)
for bt in block_trans_iterator:
if self._check_expression_not_commented(bt, comments, endcomments):
continue
trans_expr = BlockTransExpression(self.ruleset, results, bt.start(), bt.end(),
start_delim='{%', end_delim='%}',
template=django_template)
if trans_expr:
expressions.append(trans_expr)
interpolation_iterator = re.finditer(r'{% interpolate_html .*?%}', django_template, re.I)
for it in interpolation_iterator:
if self._check_expression_not_commented(it, comments, endcomments):
continue
trans_expr = HtmlInterpolateExpression(self.ruleset, results,
it.start(), it.end(),
start_delim='{%', end_delim='%}',
template=django_template)
if trans_expr:
expressions.append(trans_expr)
def _check_expression_not_commented(self, expr, comments, endcomments):
for i in range(len(endcomments)):
start_comment = comments[i]
end_comment = endcomments[i]
if (expr.start() >= start_comment.start()) and \
(expr.start() <= end_comment.start()):
return True