Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 27 additions & 29 deletions ezt.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ def readtext(fname):
# BRACKET). Since the COMMENT matches are not placed into a group, they are
# considered a "splitting" value and simply dropped.
#
_item = r'(?:"(?:[^\\"]|\\.)*"|[A-Za-z_][-\w.]*)'
_arg = r'(?:"(?:[^\\"]|\\.)*"|[-\w.]+)'
_re_parse = re.compile(r'(\r?\n)|\[(%s(?: +%s)*)\]|(\[\[\])|\[#[^\]]*\]' %
(_item, _arg))
_ITEM = r'(?:"(?:[^\\"]|\\.)*"|[A-Za-z_][-\w.]*)'
_ARG = r'(?:"(?:[^\\"]|\\.)*"|[-\w.]+)'
_RE_PARSE = re.compile(r'(\r?\n)|\[(%s(?: +%s)*)\]|(\[\[\])|\[#[^\]]*\]' %
(_ITEM, _ARG))

_re_args = re.compile(r'"(?:[^\\"]|\\.)*"|[-\w.]+')

Expand Down Expand Up @@ -169,12 +169,12 @@ def _parse(self, reader, for_names=None, file_args=(), base_printer=None):
It returns the parsed template as a 'program'. This program is a sequence
made out of strings or (function, argument) 2-tuples.

Note: comment directives [# ...] are automatically dropped by _re_parse.
Note: comment directives [# ...] are automatically dropped by _RE_PARSE.
"""

filename = reader.filename()
# parse the template program into: (TEXT NEWLINE DIRECTIVE BRACKET)* TEXT
parts = _re_parse.split(reader.text)
parts = _RE_PARSE.split(reader.text)

program = [ ]
stack = [ ]
Expand Down Expand Up @@ -230,9 +230,9 @@ def _parse(self, reader, for_names=None, file_args=(), base_printer=None):
raise ArgCountSyntaxError(str(args[1:]), filename, line_number)
# note: true-section may be None
try:
cmd, idx, args, true_section, start_line_number = stack.pop()
except IndexError:
raise UnmatchedEndError(None, filename, line_number)
cmd, idx, args, true_section, _start_line_number = stack.pop()
except IndexError as exc:
raise UnmatchedEndError(None, filename, line_number) from exc
else_section = program[idx:]
if cmd == 'format':
printers.pop()
Expand Down Expand Up @@ -376,7 +376,7 @@ def _cmd_include(self, valref_reader_printer, fp, ctx, filename,

def _cmd_insertfile(self, valref_reader_printer, fp, ctx, filename,
line_number):
(valref, reader, printer) = valref_reader_printer
(valref, reader, _printer) = valref_reader_printer
fname = _get_value(valref, ctx, filename, line_number)
fp.write(reader.read_other(fname).text)

Expand Down Expand Up @@ -424,7 +424,7 @@ def _do_if(self, value, t_section, f_section, fp, ctx):
self._execute(section, fp, ctx)

def _cmd_for(self, args, fp, ctx, filename, line_number):
((valref,), unused, section) = args
((valref,), _unused, section) = args
items = _get_value(valref, ctx, filename, line_number)
refname = valref[0]
if isinstance(items, basestring):
Expand All @@ -436,7 +436,7 @@ def _cmd_for(self, args, fp, ctx, filename, line_number):
del ctx.for_index[refname]

def _cmd_define(self, args, _fp, ctx, _filename, _line_number):
((name,), unused, section) = args
((name,), _unused, section) = args
valfp = StringIO()
if section is not None:
self._execute(section, valfp, ctx)
Expand Down Expand Up @@ -472,7 +472,7 @@ def _prepare_ref(refname, for_names, file_args):
pass
else:
if idx < len(file_args):
orig_refname, start, more_rest = file_args[idx]
_orig_refname, start, more_rest = file_args[idx]
if more_rest is None:
# the include-argument was a string constant
return None, start, None
Expand Down Expand Up @@ -525,8 +525,8 @@ def _get_value(refname_start_rest, ctx, filename, line_number):
for attr in rest:
try:
ob = getattr(ob, attr)
except AttributeError:
raise UnknownReference(refname, filename, line_number)
except AttributeError as exc:
raise UnknownReference(refname, filename, line_number) from exc

# make sure we return a string instead of some various Python types
if isinstance(ob, (int, long, float)):
Expand Down Expand Up @@ -593,8 +593,8 @@ def _parse_format(format_string=FORMAT_RAW):
format_func = FORMATTERS[fspec]
if format_func is not None:
format_funcs.append(format_func)
except KeyError:
raise UnknownFormatConstantError(format_string)
except KeyError as exc:
raise UnknownFormatConstantError(format_string) from exc
return format_funcs

class _context:
Expand Down Expand Up @@ -670,24 +670,22 @@ class UnknownFormatConstantError(EZTException):

# --- standard test environment ---
def test_parse():
assert _re_parse.split('[a]') == ['', '[a]', None, '']
assert _re_parse.split('[a] [b]') == \
assert _RE_PARSE.split('[a]') == ['', '[a]', None, '']
assert _RE_PARSE.split('[a] [b]') == \
['', '[a]', None, ' ', '[b]', None, '']
assert _re_parse.split('[a c] [b]') == \
assert _RE_PARSE.split('[a c] [b]') == \
['', '[a c]', None, ' ', '[b]', None, '']
assert _re_parse.split('x [a] y [b] z') == \
assert _RE_PARSE.split('x [a] y [b] z') == \
['x ', '[a]', None, ' y ', '[b]', None, ' z']
assert _re_parse.split('[a "b" c "d"]') == \
assert _RE_PARSE.split('[a "b" c "d"]') == \
['', '[a "b" c "d"]', None, '']
assert _re_parse.split(r'["a \"b[foo]" c.d f]') == \
assert _RE_PARSE.split(r'["a \"b[foo]" c.d f]') == \
['', '["a \\"b[foo]" c.d f]', None, '']

def _test(argv):
import doctest, ezt
verbose = "-v" in argv
return doctest.testmod(ezt, verbose=verbose)
def _test():
import doctest
return doctest.testmod()

if __name__ == "__main__":
# invoke unit test for this module:
import sys
sys.exit(_test(sys.argv)[0])
sys.exit(_test())
2 changes: 2 additions & 0 deletions tests/ezt_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def testSimpleReplacement(self):
d = self._runTemplate('this is a [X].', {'X': 'test'})
self.assertEqual('this is a test.', d)

@unittest.skipIf(sys.version_info[0] >= 3, 'Does not work on Python3')
def testSimpleReplacementUtf8Encoded(self):
### fails because _runTemplate changes the bytes back to
### a unicode string so that _parse() can .split() it.
Expand Down Expand Up @@ -73,6 +74,7 @@ def testLiteral(self):
d = self._runTemplate('this is a ["trivial test"].', {})
self.assertEqual('this is a trivial test.', d)

@unittest.skipIf(sys.version_info[0] >= 3, 'Does not work on Python3')
def testLiteralUtf8Encoded(self):
### fails because _runTemplate changes the bytes back to
### a unicode string so that _parse() can .split() it.
Expand Down