jinja2: including script, replacing {{variable}} and json encoding the result
<p>I'm attempting to build a json document using Jinja2 and the document has a nested script. The script contains <code>{{&lt;variables&gt;}}</code> that I need to replace along with non-json characters. Therefore, the script needs to be json-escaped afterwards using <code>json.dumps()</code>.</p>

<p><code>str = '{
  "nestedScript" : {% include "scripts/sc.ps1" | json %}
}'</code></p>

<p>The <code>escape</code> function isn't enough, since the finished product contains characters that are valid HTML, but not JSON.</p>

<p>I'm thinking something along the lines of:</p>

<p><code>str = '{
  "nestedScript" : {{ include("scripts/sc.ps1") | json}} %}
}'</code></p>

<p>using some a custom filter or something, but I can't seem to write the include function such that it also does variable replacement in the script. This is my script so far that I am including as a global:</p>

<h1>Complete example</h1>

<p>Folder structure:</p>

<pre><code> .
 âââ templates
     âââ test.json
     âââ scripts
     Â  Â  âââ script.ps1
</code></pre>

<p>template-file:</p>

<pre><code>test.json = '{
  "nestedScript" : {{ include("scripts/script.ps1") | json}}
}'
</code></pre>

<p>Script:</p>

<pre><code>loader = jinja2.FileSystemLoader("templates")
env = jinja2.Environment(loader=self.loader)
template = env.get_template("test.json")
template.render({
        'service_name': 'worker',
        'context_name': 'googlesellerratings',
    })
</code></pre>

<p>result:</p>

<pre><code>{
  "nestedScript" : "echo {{service_name}}"
}
</code></pre>

<p>Solved this in a way that feels a little hackish, so I'd love some feedback. When instantiating my class, I defined a global function called <code>include_script</code>:</p>

<pre><code>loader = jinja2.FileSystemLoader(templates_folder)
env = inja2.Environment(loader=self.loader)

env.globals['include_script'] = render_script_func(env)
</code></pre>

<p>the <code>render_script_func</code> returns a function that retrieves the context from the environment and uses it to render the file I referenced:</p>

<pre><code>def render_script_func(env):
    def render_script(name):
        ctx = env.globals['context']
        tmpl = env.get_template(name)
        raw = tmpl.render(ctx)            
        return json.dumps(raw)
    return render_script
</code></pre>

<p>Now, before rendering, all one has to do, is add the context for the rendering to the global <code>context</code> object:</p>

<pre><code>template = env.get_template(template_name)
template.environment.globals["context"] = ctx
renderedData = template.render(ctx)
</code></pre>

<p>And when a template uses <code>{{ include_script("path/to/script") }}</code> the script is both rendered and then json encoded.</p>

<p>Still feels a bit wrong, but so be it.</p>

python json jinja2