diff options
author | Martin von Gagern <gagern@google.com> | 2019-07-01 14:35:54 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-07-01 15:14:41 -0400 |
commit | 06d67cf4677e10e5c42581c02f293101e1c39a3a (patch) | |
tree | bf5355518d8b14d79fd822c357a14e29d2b575c7 | |
parent | f384df792ae5eeeaa4bd622191b3ca33d9b86a4d (diff) | |
download | mako-06d67cf4677e10e5c42581c02f293101e1c39a3a.tar.gz |
Correctly track line numbers for multi-line code blocks
Improved the line-number tracking for source lines inside of Python ``<%
... %>`` blocks, such that text- and HTML-formatted exception traces such
as that of :func:`.html_error_template` now report the correct source line
inside the block, rather than the first line of the block itself.
Exceptions in ``<%! ... %>`` blocks which get raised while loading the
module are still not reported correctly, as these are handled before the
Mako code is generated. Pull request courtesy Martin von Gagern.
Closes: #297
Pull-request: https://github.com/sqlalchemy/mako/pull/297
Pull-request-sha: 60ad749604f8de0a9b8133430995045a93d0939c
Change-Id: I2086e4370e8e2db7099de01743840286f0160efc
-rw-r--r-- | doc/build/unreleased/codeerr.rst | 10 | ||||
-rw-r--r-- | mako/codegen.py | 8 | ||||
-rw-r--r-- | mako/pygen.py | 6 | ||||
-rw-r--r-- | test/test_exceptions.py | 48 |
4 files changed, 66 insertions, 6 deletions
diff --git a/doc/build/unreleased/codeerr.rst b/doc/build/unreleased/codeerr.rst new file mode 100644 index 0000000..2497896 --- /dev/null +++ b/doc/build/unreleased/codeerr.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, exceptions + + Improved the line-number tracking for source lines inside of Python ``<% + ... %>`` blocks, such that text- and HTML-formatted exception traces such + as that of :func:`.html_error_template` now report the correct source line + inside the block, rather than the first line of the block itself. + Exceptions in ``<%! ... %>`` blocks which get raised while loading the + module are still not reported correctly, as these are handled before the + Mako code is generated. Pull request courtesy Martin von Gagern. diff --git a/mako/codegen.py b/mako/codegen.py index 733d264..1acc5e6 100644 --- a/mako/codegen.py +++ b/mako/codegen.py @@ -354,8 +354,7 @@ class _GenerateRenderMethod(object): """write module-level template code, i.e. that which is enclosed in <%! %> tags in the template.""" for n in module_code: - self.printer.start_source(n.lineno) - self.printer.write_indented_block(n.text) + self.printer.write_indented_block(n.text, starting_lineno=n.lineno) def write_inherit(self, node): """write the module-level inheritance-determination callable.""" @@ -896,8 +895,9 @@ class _GenerateRenderMethod(object): def visitCode(self, node): if not node.ismodule: - self.printer.start_source(node.lineno) - self.printer.write_indented_block(node.text) + self.printer.write_indented_block( + node.text, starting_lineno=node.lineno + ) if not self.in_def and len(self.identifiers.locally_assigned) > 0: # if we are the "template" def, fudge locally diff --git a/mako/pygen.py b/mako/pygen.py index 265c0b0..603676d 100644 --- a/mako/pygen.py +++ b/mako/pygen.py @@ -54,14 +54,16 @@ class PythonPrinter(object): self.stream.write("\n" * num) self._update_lineno(num) - def write_indented_block(self, block): + def write_indented_block(self, block, starting_lineno=None): """print a line or lines of python which already contain indentation. The indentation of the total block of lines will be adjusted to that of the current indent level.""" self.in_indent_lines = False - for l in re.split(r"\r?\n", block): + for i, l in enumerate(re.split(r"\r?\n", block)): self.line_buffer.append(l) + if starting_lineno is not None: + self.start_source(starting_lineno + i) self._update_lineno(1) def writelines(self, *lines): diff --git a/test/test_exceptions.py b/test/test_exceptions.py index c904d65..46fbcdd 100644 --- a/test/test_exceptions.py +++ b/test/test_exceptions.py @@ -383,3 +383,51 @@ ${foobar} "local variable 'y' referenced before assignment" in html_error ) + + def test_code_block_line_number(self): + l = TemplateLookup() + l.put_string( + "foo.html", + """ +<% +msg = "Something went wrong." +raise RuntimeError(msg) # This is the line. +%> + """, + ) + t = l.get_template("foo.html") + try: + t.render() + assert False + except: + text_error = exceptions.text_error_template().render_unicode() + assert 'File "foo_html", line 4, in render_body' in text_error + assert "raise RuntimeError(msg) # This is the line." in text_error + else: + assert False + + def test_module_block_line_number(self): + l = TemplateLookup() + l.put_string( + "foo.html", + """ +<%! +def foo(): + msg = "Something went wrong." + raise RuntimeError(msg) # This is the line. +%> +${foo()} + """, + ) + t = l.get_template("foo.html") + try: + t.render() + assert False + except: + text_error = exceptions.text_error_template().render_unicode() + sys.stderr.write(text_error) + assert 'File "foo_html", line 7, in render_body' in text_error + assert 'File "foo_html", line 5, in foo' in text_error + assert "raise RuntimeError(msg) # This is the line." in text_error + else: + assert False |