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
|
import codecs
import os
import sys
from docutils import nodes
from docutils.parsers.rst import Directive
from docutils.parsers.rst import directives
from docutils.statemachine import StringList
from jinja2 import FileSystemLoader, Environment
import sphinx.util
try:
from urllib.request import url2pathname
except ImportError:
from urllib import url2pathname
class JinjaDirective(Directive):
has_content = True
optional_arguments = 1
option_spec = {
"file": directives.path,
"header_char": directives.unchanged,
"header_update_levels": directives.flag,
"debug": directives.unchanged,
}
app = None
def run(self):
node = nodes.Element()
node.document = self.state.document
docname = self.state.document.settings.env.docname
conf = self.app.config
template_filename = self.options.get("file")
debug_template = self.options.get("debug")
cxt = (conf.jinja_contexts[self.arguments[0]].copy()
if self.arguments else {})
cxt["options"] = {
"header_char": self.options.get("header_char"),
}
env = Environment(
loader=FileSystemLoader(conf.jinja_base, followlinks=True),
**conf.jinja_env_kwargs
)
env.filters.update(conf.jinja_filters)
env.tests.update(conf.jinja_tests)
env.globals.update(conf.jinja_globals)
env.policies.update(conf.jinja_policies)
if template_filename:
if debug_template is not None:
reference_uri = directives.uri(template_filename)
template_path = os.path.join(
os.path.abspath(conf.jinja_base),
url2pathname(reference_uri),
)
encoded_path = template_path.encode(sys.getfilesystemencoding())
with codecs.open(encoded_path, encoding='utf-8') as f:
debug_print(
'Template Before Processing',
'******* From {} *******\n{}'.format(docname, f.read()),
)
tpl = env.get_template(template_filename)
else:
content = '\n'.join(self.content)
if debug_template is not None:
debug_print('Template Before Processing', content)
tpl = env.from_string(content)
new_content = tpl.render(**cxt)
if debug_template is not None:
debug_print('Template After Processing', new_content)
if "header_update_levels" in self.options:
self.state_machine.insert_input(new_content.splitlines(), source='')
return []
else:
new_content = StringList(new_content.splitlines(), source='')
sphinx.util.nested_parse_with_titles(self.state, new_content, node)
return node.children
def debug_print(title, content):
stars = '*' * 10
print('\n{1} Begin Debug Output: {0} {1}'.format(title, stars))
print(content)
print('\n{1} End Debug Output: {0} {1}'.format(title, stars))
def setup(app):
JinjaDirective.app = app
app.add_directive('jinja', JinjaDirective)
app.add_config_value('jinja_contexts', {}, 'env')
app.add_config_value('jinja_base', app.srcdir, 'env')
app.add_config_value('jinja_env_kwargs', {}, 'env')
app.add_config_value('jinja_filters', {}, 'env')
app.add_config_value('jinja_tests', {}, 'env')
app.add_config_value('jinja_globals', {}, 'env')
app.add_config_value('jinja_policies', {}, 'env')
return {'parallel_read_safe': True, 'parallel_write_safe': True}
|