Runs the Jinja templating engine.
jinja
.*
.*
Setting | Description | Default |
---|---|---|
add-new-files | Boolean or list of extensions/patterns to match. | False |
added-in-version | Dexy version when this filter was first available. | |
additional-doc-filters | Filters to apply to additional documents created as side effects. | {} |
additional-doc-settings | Settings to apply to additional documents created as side effects. | {} |
assertion-passed-indicator | Extra text to return with a passed assertion. | |
block-end-string | Tag to indicate the start of a block. | %} |
block-start-string | Tag to indicate the start of a block. | {% |
changetags | Automatically change from { to < based tags for .tex and .wiki files. | True |
comment-end-string | Tag to indicate the start of a comment. | #} |
comment-start-string | Tag to indicate the start of a comment. | {# |
data-type | Alias of custom data class to use to store filter output. | generic |
examples | Templates which should be used as examples for this filter. | [] |
exclude-add-new-files | List of patterns to skip even if they match add-new-files. | [] |
exclude-new-files-from-dir | List of directories to skip when adding new files. | [] |
ext | File extension to output. | None |
extension-map | Dictionary mapping input extensions to default output extensions. | None |
filters | List of template plugins to make into jinja filters. | ['assertions', 'highlight', 'head', 'tail', 'rstcode', 'stripjavadochtml', 'replacejinjafilters', 'bs4'] |
help | Helpstring for plugin. | Runs the Jinja templating engine. |
input-extensions | List of extensions which this filter can accept as input. | ['.*'] |
jinja-extensions | List of jinja extensions to activate. | ['jinja2.ext.do'] |
jinja-path | List of additional directories to pass to jinja loader. | [] |
keep-originals | Whether, if additional-doc-filters are specified, the original unmodified docs should also be added. | False |
mkdir | A directory which should be created in working dir. | None |
mkdirs | A list of directories which should be created in working dir. | [] |
nodoc | Whether filter should be excluded from documentation. | False |
output | Whether to output results of this filter by default by reporters such as 'output' or 'website'. | True |
output-extensions | List of extensions which this filter can produce as output. | ['.*'] |
override-workspace-exclude-filters | If True, document will be populated to other workspaces ignoring workspace-exclude-filters. | False |
plugins | List of plugins for run_plugins to use. | [] |
preserve-prior-data-class | Whether output data class should be set to match the input data class. | False |
require-output | Should dexy raise an exception if no output is produced by this filter? | True |
skip-plugins | List of plugins which run_plugins should not use. | [] |
tags | Tags which describe the filter. | [] |
variable-end-string | Tag to indicate the start of a variable. | }} |
variable-start-string | Tag to indicate the start of a variable. | {{ |
variables | Variables to be made available to document. | {} |
vars | Variables to be made available to document. | {} |
workspace-exclude-filters | Filters whose output should be excluded from workspace. | ['pyg'] |
workspace-includes | If set to a list of filenames or extensions, only these will be populated to working dir. | ['.jinja'] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | class JinjaFilter(TemplateFilter):
"""
Runs the Jinja templating engine.
"""
aliases = ['jinja']
_settings = {
'block-start-string' : ("Tag to indicate the start of a block.", "{%"),
'block-end-string' : ("Tag to indicate the start of a block.", "%}"),
'variable-start-string' : ("Tag to indicate the start of a variable.", "{{"),
'variable-end-string' : ("Tag to indicate the start of a variable.", "}}"),
'comment-start-string' : ("Tag to indicate the start of a comment.", "{#"),
'comment-end-string' : ("Tag to indicate the start of a comment.", "#}"),
'changetags' : ("Automatically change from { to < based tags for .tex and .wiki files.", True),
'jinja-path' : ("List of additional directories to pass to jinja loader.", []),
'jinja-extensions' : ("List of jinja extensions to activate.", ['jinja2.ext.do']),
'workspace-includes' : [".jinja"],
'assertion-passed-indicator' : (
"Extra text to return with a passed assertion.",
""),
'filters' : (
"List of template plugins to make into jinja filters.",
['assertions', 'highlight', 'head', 'tail', 'rstcode', 'stripjavadochtml',
'replacejinjafilters', 'bs4']
)
}
_not_jinja_settings = (
'changetags',
'jinja-path',
'workspace-includes',
'filters',
'assertion-passed-indicator',
'jinja-extensions'
)
TEX_TAGS = {
'block_start_string': '<%',
'block_end_string': '%>',
'variable_start_string': '<<',
'variable_end_string': '>>',
'comment_start_string': '<#',
'comment_end_string': '#>'
}
LYX_TAGS = {
'block_start_string': '<%',
'block_end_string': '%>',
'variable_start_string': '<<',
'variable_end_string': '>>',
'comment_start_string': '<<#',
'comment_end_string': '#>>'
}
def setup_jinja_env(self, loader=None):
env_attrs = {}
for k, v in self.setting_values().items():
underscore_k = k.replace("-", "_")
if k in self.__class__._settings and not k in self._not_jinja_settings:
env_attrs[underscore_k] = v
env_attrs['undefined'] = PassThroughWhitelistUndefined
if self.ext in (".tex", ".wiki") and self.setting('changetags'):
if 'lyxjinja' in self.doc.filter_aliases:
tags = self.LYX_TAGS
else:
tags = self.TEX_TAGS
self.log_debug("Changing tags to latex/wiki format: %s" % ' '.join(tags))
for underscore_k, v in tags.items():
hyphen_k = underscore_k.replace("_", "-")
if env_attrs[underscore_k] == self.__class__._settings[hyphen_k][1]:
self.log_debug("setting %s to %s" % (underscore_k, v))
env_attrs[underscore_k] = v
if loader:
env_attrs['loader'] = loader
extensions = []
for ext in self.setting('jinja-extensions'):
self.log_debug("attempting to activate %s" % ext)
if ext.startswith("jinja2.ext"):
ref = jinja2.ext.__dict__[ext.lstrip("jinja2.ext")]
extensions.append(ref)
env_attrs['extensions'] = extensions
debug_attr_string = ", ".join("%s: %r" % (k, v) for k, v in env_attrs.items())
self.log_debug("creating jinja2 environment with: %s" % debug_attr_string)
return jinja2.Environment(**env_attrs)
def handle_jinja_exception(self, e, input_text, template_data):
result = []
input_lines = input_text.splitlines()
# Try to parse line number from stack trace...
if isinstance(e, UndefinedError) or isinstance(e, TypeError):
# try to get the line number
m = re.search(r"File \"<template>\", line ([0-9]+), in top\-level template code", traceback.format_exc())
if m:
e.lineno = int(m.groups()[0])
else:
print((traceback.format_exc()))
e.lineno = 0
self.log_warn("unable to parse line number from traceback")
args = {
'error_type' : e.__class__.__name__,
'key' : self.key,
'lineno' : e.lineno,
'message' : getattr(e, 'message', str(e)),
'name' : self.output_data.name,
'workfile' : self.input_data.storage.data_file()
}
result.append("a %(error_type)s problem was detected: %(message)s" % args)
if isinstance(e, UndefinedError):
match_has_no_attribute = re.match("^'[\w\s\.]+' has no attribute '(.+)'$", e.message)
match_is_undefined = re.match("^'([\w\s]+)' is undefined$", e.message)
if match_has_no_attribute:
undefined_object = match_has_no_attribute.groups()[0]
match_lines = []
for i, line in enumerate(input_lines):
if (".%s" % undefined_object in line) or ("'%s'" % undefined_object in line) or ("\"%s\"" % undefined_object in line):
result.append("line %04d: %s" % (i+1, line))
match_lines.append(i)
if len(match_lines) == 0:
self.log_info("Tried to automatically find source of error: %s. Could not find match for '%s'" % (e.message, undefined_object))
elif match_is_undefined:
undefined_object = match_is_undefined.groups()[0]
for i, line in enumerate(input_lines):
if undefined_object in line:
result.append("line %04d: %s" % (i+1, line))
else:
self.log_debug("Tried to automatically find where the error was in the template, but couldn't.")
else:
result.append("line %04d: %s" % (e.lineno, input_lines[e.lineno-1]))
raise dexy.exceptions.UserFeedback("\n".join(result))
def jinja_template_filters(self):
filters = {}
for alias in self.setting('filters'):
self.log_debug(" creating filters from template plugin %s" % alias)
template_plugin = TemplatePlugin.create_instance(alias)
if not template_plugin.is_active():
self.log_debug(" skipping %s - not active" % alias)
continue
methods = template_plugin.run()
for k, v in methods.items():
if not k in template_plugin.setting('no-jinja-filter'):
self.log_debug(" creating jinja filter for method %s" % k)
filters[k] = v[1]
return filters
def process(self):
self.populate_workspace()
wd = self.parent_work_dir()
macro_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'macros'))
dirs = ['.', wd, os.path.dirname(self.doc.name), macro_dir] + self.setting('jinja-path')
self.log_debug("setting up jinja FileSystemLoader with dirs %s" % ", ".join(dirs))
loader = FileSystemLoader(dirs)
self.log_debug("setting up jinja environment")
env = self.setup_jinja_env(loader=loader)
self.log_debug("setting up jinja template filters")
env.filters.update(self.jinja_template_filters())
self.log_debug("initializing template")
template_data = self.template_data()
self.log_debug("jinja template data keys are %s" % ", ".join(sorted(template_data)))
try:
self.log_debug("about to create jinja template")
template = env.get_template(self.work_input_filename())
self.log_debug("about to process jinja template")
template.stream(template_data).dump(self.output_filepath(), encoding="utf-8")
except (TemplateSyntaxError, UndefinedError, TypeError) as e:
self.log_debug("%s error while running jinja... %s" % (e.__class__.__name__, str(e)))
try:
self.log_debug("removing %s since jinja had an error" % self.output_filepath())
os.remove(self.output_filepath())
except os.error:
pass
self.handle_jinja_exception(e, str(self.input_data), template_data)
except TemplateNotFound as e:
msg = "Jinja couldn't find the template '%s', make sure this file is an input to %s"
msgargs = (e.message, self.doc.key)
raise dexy.exceptions.UserFeedback(msg % msgargs)
except Exception as e:
try:
self.log_debug("removing %s since jinja had an error" % self.output_filepath())
os.remove(self.output_filepath())
except os.error:
pass
self.log_debug(str(e))
raise
|
Content © 2020 Dr. Ana Nelson | Site Design © Copyright 2011 Andre Gagnon | All Rights Reserved.