From: Shaheed Haque Date: Sun, 14 Jan 2018 14:01:22 +0000 (+0000) Subject: Add support for a {% debug %} extension tag. X-Git-Tag: 2.11.0~55^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=017c8d3509c694398093797ee2ed019f1eb02221;p=thirdparty%2Fjinja.git Add support for a {% debug %} extension tag. This dumps the available variables, filters and tests. --- diff --git a/jinja2/ext.py b/jinja2/ext.py index eed3f210..6e21570a 100644 --- a/jinja2/ext.py +++ b/jinja2/ext.py @@ -4,13 +4,19 @@ ~~~~~~~~~~ Jinja extensions allow to add custom tags similar to the way django custom - tags work. By default two example extensions exist: an i18n and a cache - extension. + tags work. The following default example extensions are included: + + - a i18n support {% trans %} tag + - a {% do %} tag + - loop control {% break %} and {% continue %} tags + - a {% debug %} tag :copyright: (c) 2017 by the Jinja Team. :license: BSD. """ +import pprint import re +from sys import version_info from jinja2 import nodes from jinja2.defaults import BLOCK_START_STRING, \ @@ -19,10 +25,12 @@ from jinja2.defaults import BLOCK_START_STRING, \ LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \ KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS from jinja2.environment import Environment +from jinja2.nodes import ContextReference from jinja2.runtime import concat from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError from jinja2.utils import contextfunction, import_string, Markup from jinja2._compat import with_metaclass, string_types, iteritems +from markupsafe import escape # the only real useful gettext functions for a Jinja template. Note @@ -434,6 +442,59 @@ class AutoEscapeExtension(Extension): pass +class DebugExtension(Extension): + """ + A ``{% debug %}`` tag that dumps the available variables, filters and tests. + Typical usage like this: + + .. codeblock:: html+jinja +
{% debug %}
+ + produces output like this: + + :: + {'context': {'_': , + 'csrf_token': , + 'cycler': , + ... + 'view': }, + 'filters': ['abs', 'add', 'addslashes', 'attr', 'batch', 'bootstrap', + 'bootstrap_classes', 'bootstrap_horizontal', + 'bootstrap_inline', ... 'yesno'], + 'tests': ['callable', 'checkbox_field', 'defined', 'divisibleby', + 'escaped', 'even', 'iterable', 'lower', 'mapping', + 'multiple_checkbox_field', ... 'string', 'undefined', 'upper']} + + """ + tags = {'debug'} + + def __init__(self, environment): + super(DebugExtension, self).__init__(environment) + + def parse(self, parser): + lineno = parser.stream.expect('name:debug').lineno + context = ContextReference() + call = self.call_method('_render', [context], lineno=lineno) + return nodes.Output([nodes.MarkSafe(call)]) + + def _render(self, context): + result = { + 'filters': sorted(self.environment.filters.keys()), + 'tests': sorted(self.environment.tests.keys()), + 'context': context.get_all() + } + # + # We set the depth since the intent is basically to show the top few + # names. TODO: provide user control over this? + # + if version_info[:2] >= (3,4): + text = pprint.pformat(result, depth=3, compact=True) + else: + text = pprint.pformat(result, depth=3) + text = escape(text) + return text + + def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS, babel_style=True): """Extract localizable strings from the given template node. Per @@ -625,3 +686,4 @@ do = ExprStmtExtension loopcontrols = LoopControlExtension with_ = WithExtension autoescape = AutoEscapeExtension +debug = DebugExtension diff --git a/tests/test_ext.py b/tests/test_ext.py index c3b028ff..1f26373d 100644 --- a/tests/test_ext.py +++ b/tests/test_ext.py @@ -240,6 +240,22 @@ class TestExtensions(object): assert ext[0].__class__ is T1 assert ext[1].__class__ is T2 + def test_debug(self): + """Test for {% debug %}""" + env = Environment(extensions=['jinja2.ext.debug']) + tmpl = env.from_string('''Hello{% debug %}Bye''') + out = tmpl.render() + out = out.replace(''', "'").replace('<', '<').replace('>', '>') + # + # Check that some of the built-in items exist in the debug output... + # + assert "'context'" in out + assert "'cycler'" in out + assert "'filters'" in out + assert "'abs'" in out + assert "'tests'" in out + assert "'!='" in out + @pytest.mark.ext class TestInternationalization(object):