Skip to content

Commit

Permalink
Merge pull request #34 from shklqm/fix/sm/unmatched-tags
Browse files Browse the repository at this point in the history
fix: fail on unmatched tags
  • Loading branch information
bakert authored Dec 24, 2024
2 parents 06ab57d + 1d82da5 commit ff177c4
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 13 deletions.
20 changes: 10 additions & 10 deletions pystache/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@
# TODO: add some unit tests for this.
# TODO: add a test case that checks for spurious spaces.
# TODO: add test cases for delimiters.
def parse(template, delimiters=None):
def parse(template, delimiters=None, raise_on_mismatch=False):
"""
Parse a unicode template string and return a ParsedTemplate instance.
Arguments:
template: a unicode template string.
delimiters: a 2-tuple of delimiters. Defaults to the package default.
raise_on_mismatch: a boolean indicating whether to raise an exception when parsing fails.
Examples:
Expand All @@ -36,7 +35,7 @@ def parse(template, delimiters=None):
"""
if type(template) is not str:
raise Exception('Template is not unicode: %s' % type(template))
parser = _Parser(delimiters)
parser = _Parser(delimiters, raise_on_mismatch=raise_on_mismatch)
return parser.parse(template)


Expand Down Expand Up @@ -220,12 +219,14 @@ def render(self, engine, context):
class _Parser(object):
_delimiters = None
_template_re = None
_raise_on_mismatch = False

def __init__(self, delimiters=None):
def __init__(self, delimiters=None, raise_on_mismatch=False):
if delimiters is None:
delimiters = defaults.DELIMITERS

self._delimiters = delimiters
self._raise_on_mismatch = raise_on_mismatch

def _compile_delimiters(self):
self._template_re = _compile_template_re(self._delimiters)
Expand All @@ -237,17 +238,12 @@ def _change_delimiters(self, delimiters):
def parse(self, template):
"""
Parse a template string starting at some index.
This method uses the current tag delimiter.
Arguments:
template: a unicode string that is the template to parse.
index: the index at which to start parsing.
Returns:
a ParsedTemplate instance.
"""
Expand Down Expand Up @@ -337,6 +333,10 @@ def parse(self, template):

parsed_template.add(node)

# Some open/close tags were mismatched.
if self._raise_on_mismatch and states:
raise ParsingError('Tag mismatch.')

# Avoid adding spurious empty strings to the parse tree.
if start_index != len(template):
parsed_template.add(template[start_index:])
Expand Down
37 changes: 34 additions & 3 deletions pystache/tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,50 @@
import unittest

from pystache.defaults import DELIMITERS
from pystache.parser import _compile_template_re as make_re
from pystache.parser import _compile_template_re as make_re, parse, ParsingError


class RegularExpressionTestCase(unittest.TestCase):

"""Tests the regular expression returned by _compile_template_re()."""

def test_re(self):
"""
Test getting a key from a dictionary.
"""
re = make_re(DELIMITERS)
match = re.search("b {{test}}")

self.assertEqual(match.start(), 1)


class ParseTestCase(unittest.TestCase):
"""Tests the parse() function."""

def test_parse_okay(self):
"""
Test parsing templates in the cases there are no errors.
"""
ts = [
'<div>{{>A}}</div>',
'{{#A}}<div> some text</div>',
'{{^A}}<div> some text</div>{{/A}}',
'{{#A}} {{^B}} {{/B}} {{/A}}',
'{{#A}} {{^B}} {{/B}} {{/A}} {{#C}} {{/C}}',
]
for t in ts:
with self.subTest(template=t):
parse(t)

def test_parse_fail(self):
"""
Test parsing templates in the cases there are errors.
"""
ts = [
'{{#A}}<div> some text</div>',
'{{#A}}<div> some text</div>{{/A}} <div> TEXT </div> {{/B}}',
'{{#A}} {{#B}} {{/A}} {{/B}}',
]
for t in ts:
with self.subTest(template=t):
with self.assertRaises(ParsingError):
parse(t, raise_on_mismatch=True)

0 comments on commit ff177c4

Please sign in to comment.