test_debug.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. # -*- coding: utf-8 -*-
  2. import pickle
  3. import re
  4. from traceback import format_exception
  5. import pytest
  6. from jinja2 import ChoiceLoader
  7. from jinja2 import DictLoader
  8. from jinja2 import Environment
  9. from jinja2 import TemplateSyntaxError
  10. @pytest.fixture
  11. def fs_env(filesystem_loader):
  12. """returns a new environment."""
  13. return Environment(loader=filesystem_loader)
  14. class TestDebug(object):
  15. def assert_traceback_matches(self, callback, expected_tb):
  16. with pytest.raises(Exception) as exc_info:
  17. callback()
  18. tb = format_exception(exc_info.type, exc_info.value, exc_info.tb)
  19. m = re.search(expected_tb.strip(), "".join(tb))
  20. assert m is not None, "Traceback did not match:\n\n%s\nexpected:\n%s" % (
  21. "".join(tb),
  22. expected_tb,
  23. )
  24. def test_runtime_error(self, fs_env):
  25. def test():
  26. tmpl.render(fail=lambda: 1 / 0)
  27. tmpl = fs_env.get_template("broken.html")
  28. self.assert_traceback_matches(
  29. test,
  30. r"""
  31. File ".*?broken.html", line 2, in (top-level template code|<module>)
  32. \{\{ fail\(\) \}\}
  33. File ".*debug?.pyc?", line \d+, in <lambda>
  34. tmpl\.render\(fail=lambda: 1 / 0\)
  35. ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
  36. """,
  37. )
  38. def test_syntax_error(self, fs_env):
  39. # The trailing .*? is for PyPy 2 and 3, which don't seem to
  40. # clear the exception's original traceback, leaving the syntax
  41. # error in the middle of other compiler frames.
  42. self.assert_traceback_matches(
  43. lambda: fs_env.get_template("syntaxerror.html"),
  44. """(?sm)
  45. File ".*?syntaxerror.html", line 4, in (template|<module>)
  46. \\{% endif %\\}.*?
  47. (jinja2\\.exceptions\\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja \
  48. was looking for the following tags: 'endfor' or 'else'. The innermost block that needs \
  49. to be closed is 'for'.
  50. """,
  51. )
  52. def test_regular_syntax_error(self, fs_env):
  53. def test():
  54. raise TemplateSyntaxError("wtf", 42)
  55. self.assert_traceback_matches(
  56. test,
  57. r"""
  58. File ".*debug.pyc?", line \d+, in test
  59. raise TemplateSyntaxError\("wtf", 42\)
  60. (jinja2\.exceptions\.)?TemplateSyntaxError: wtf
  61. line 42""",
  62. )
  63. def test_pickleable_syntax_error(self, fs_env):
  64. original = TemplateSyntaxError("bad template", 42, "test", "test.txt")
  65. unpickled = pickle.loads(pickle.dumps(original))
  66. assert str(original) == str(unpickled)
  67. assert original.name == unpickled.name
  68. def test_include_syntax_error_source(self, filesystem_loader):
  69. e = Environment(
  70. loader=ChoiceLoader(
  71. [
  72. filesystem_loader,
  73. DictLoader({"inc": "a\n{% include 'syntaxerror.html' %}\nb"}),
  74. ]
  75. )
  76. )
  77. t = e.get_template("inc")
  78. with pytest.raises(TemplateSyntaxError) as exc_info:
  79. t.render()
  80. assert exc_info.value.source is not None
  81. def test_local_extraction(self):
  82. from jinja2.debug import get_template_locals
  83. from jinja2.runtime import missing
  84. locals = get_template_locals(
  85. {
  86. "l_0_foo": 42,
  87. "l_1_foo": 23,
  88. "l_2_foo": 13,
  89. "l_0_bar": 99,
  90. "l_1_bar": missing,
  91. "l_0_baz": missing,
  92. }
  93. )
  94. assert locals == {"foo": 13, "bar": 99}
  95. def test_get_corresponding_lineno_traceback(self, fs_env):
  96. tmpl = fs_env.get_template("test.html")
  97. assert tmpl.get_corresponding_lineno(1) == 1