diff --git a/ezt.py b/ezt.py index 6fbbea7..64529e0 100644 --- a/ezt.py +++ b/ezt.py @@ -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.]+') @@ -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 = [ ] @@ -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() @@ -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) @@ -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): @@ -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) @@ -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 @@ -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)): @@ -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: @@ -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()) diff --git a/tests/ezt_test.py b/tests/ezt_test.py index 22297c6..a6ae110 100755 --- a/tests/ezt_test.py +++ b/tests/ezt_test.py @@ -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. @@ -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.