summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin von Gagern <gagern@google.com>2019-07-01 14:35:54 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2019-07-01 15:14:41 -0400
commit06d67cf4677e10e5c42581c02f293101e1c39a3a (patch)
treebf5355518d8b14d79fd822c357a14e29d2b575c7
parentf384df792ae5eeeaa4bd622191b3ca33d9b86a4d (diff)
downloadmako-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.rst10
-rw-r--r--mako/codegen.py8
-rw-r--r--mako/pygen.py6
-rw-r--r--test/test_exceptions.py48
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 &#39;y&#39; 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