Jinja2 {% include file %} outside of search path doesn't work - python

This is an elementary issue which is probably related to Jinja2 PrefixLoader or ChoiceLoader.
On Python 3.6 we load with this command
jinja2.FileSystemLoader( searchpath= "\\template_folder\\")
On Windows 7, our file structure is as follows.
- folder_bbb
* subfile.txt
- template_folder
* template_file
- folder_aaa
* subfile.txt
From the template_file we are successful with this command
{% include "folder_aaa/subfile.txt" %}
Now we wish to move the file one level up, and write
{% include "../folder_bbb/subfile.txt" %}
but that doesn't work, complaining file not found.
What is the correct way to write? Thanks.

You may specify all paths in the the loader
jinja2.FileSystemLoader(["c:\\template_folder\\", "c:\\folder_bbb\\"])
and refer the including block without a specific path
{% include "subfile.txt" %}
The path will be searched in order so that as you say, moving the file one level up, the file will be found. (You need the template_folder path for the template itself.)

Related

Why download button on Python website doesn't work

I have Flask website in which I want to add download button which downloads .csv file with scraped data.
In my html file I have this code:
<a href="cms_scrape.csv" ><button>Download!</button></a>
And only output I get is error: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
File is in its proper folder.
My folder structure:
└───Project
│ cms_scrape.csv
│
└───templates
index.html
You will need to specify some sort of route on the backend of your site.
For instance, somewhere in your flask site, you probably have a route #app.route('/') for your index. You will need a similar route for your file. That route will go out onto your file system and return the file itself.
#app.route('/csv_file')
def csv_file():
return flask.send_file('path/to/file/cms_scrape.csv',
attachment_filename='cms_scrape.csv',
as_attachment=True)
You will also need to modify your html to access a route and not the file name directly (unless you create your routes dynamically, of course):
<a href="/csv_file" ><button>Download!</button></a>
Not exactly sure about this but I think the tag has a download attribute you can use. Then you don't need the button.
Usage:
<a href="/path/to/file" download>
Source: https://www.w3schools.com/tags/att_a_download.asp
You can make links to files with the
{{ url_for('static', filename='filename.foo') }}
function inside your template. You have to store the file in a folder named 'static' which should be located in the directory where the main scipt is.
The link in your template should look like this:
<a href=" {{ url_for('static', filename='cms_scrape.csv') }} " download>Download!</a>

Parsing/extracting from OrderedDict using Jinja in Salt

I am running into a rather weird issue while parsing results of a salt command. The command I am running is
{% set hostname = salt['publish.publish']('roles:*{}*'.format(role), 'grains.item', 'fqdn', 'grain') %}
And output looks below:
OrderedDict([('1.server.com', OrderedDict([('fqdn', '1.server.com')])), ('0.server.com', OrderedDict([('fqdn', '0.server.com')]))])
Now my understanding is when I do items() on above result with a line below, it should work
{% for hostname, fqdn in salt['publish.publish']('roles:*{}*'.format(role), 'grains.item', 'fqdn', 'grain').items() %}
But the moment I use items() in above line I start running into an error:
failed: Jinja variable 'None' has no attribute 'items'
I tried a couple of other ways (Doing items().items() or storing result in a variable and then running for loop over) to get the list out of OrderedDict but none of ways seem to help.
Either I don't know Python enough or there is something weird going on. Simply adding a check has made the above work. So working block looks like (Partial code of course):
{% set hostname = salt['publish.publish']('roles:*{}*'.format(role), 'grains.item', 'fqdn', 'grain') %}
{% if hostname is not none %}
{% for host, site in hostname.items() %}
My understanding is if check was only meant for checking just in case hostname is empty. But looks like even if there is data - an if check is needed. Still curious to know the mystery!

How to open a txt file in a mako template?

My tree.txt file is stored in the directory tree. I want to open it in a mako template, and get its context.
Example (should work - but doesn't):
% for i in open("tree.txt", "r").read():
i
% endfor
% for i in open("/xxx/xxxx/xxxxx/xxxxxx/tree.txt", "r").read():
${i}
% endfor
It's already resolved.When you are opening a file by using a mako template, you must use a absolute path.

SaltStack: Use regexps in pillar file

I would like to do some basic pillar value settings for all boxes so that I can use them later in a unified way. Our minions are usually named in this format:
<project>-<env>.<role>-<sequence>.<domain>
Example pillar/base/top.sls:
base:
'*':
- basics
'I#project:mycoolproject and I#role:nginx':
- etc.
Example pillar/base/basics/init.sls:
{% if '-live.' in grains['id'] %}
env: production
{% elif '-qa.' in grains['id'] %}
env: qa
{% elif '-staging.' in grains['id'] %}
env: staging
{% else %}
env:
{% endif %}
{% set role = re.match("(?:live|qa|staging)\.([a-z_\-]+)\-', grains['id']).group(1) -%}
role: {{ role }}
The env part obviously works but I can't get the regex working. As far as I understood there is no way to import python module (i.e. import re) in jinja template. Any suggestions how to get regex functionality available in the pillar file if possible at all?
The simple answer is, "no". There is not a way to inject regex functionality directly into the jinja environment (I'm sure there's a way to extend jinja, but anyway..)
The way I addressed this was with an external module function, id_info.explode() and an external pillar.
Enable external modules on the master:
external_modules: /srv/extmod
External modules do not require any sort of special infrastructure--they are just regular python modules (not packages, mind you--the loader doesn't currently know how to properly side-load a package yet)
Put your python+regex logic there. Return a dictionary, assembled to your your liking.
Your external module would go in /srv/extmod/modules. You can call call this function from your pillar.sls
{% id_info = __salt__[id_info.explode()] -%}
{% subcomponent = id_info['subcomponent'] -%}
{% project = id_info['project'] -%}
etc...
A couple things to know:
The salt-master has to be restarted when an external module is added or modified. There isn't a way that I know of to incite the equivalent of a saltutil.refresh_modules() call on the salt-master, so there ya go.
The external_modules directive is not just for execution modules. In this scenario, you would also create /srv/extmod/{pillar,runners,outputers,etc}.
These modules are only available on the master

Caught ViewDoesNotExist while rendering

I have encountered an error:
Caught ViewDoesNotExist while rendering: Tried my_view_two in module yourmodule.views. Error was: 'module' object has no attribute 'my_view_two'
The error is triggered from template tag:
{% trans "Lost your password?" %}
Earlier I have my_view_two function and added that in urls.py too. But later I deleted the URL entry and function. But it is still giving an error.
I have had similar errors reporting on {% url password_reset_link %} before - is that the first {% url %} in your template by any chance?
It looks as if that view is being imported somewhere (perhaps elsewhere from the urls.py?). Have you imported that view into another views.py file for example?). A quick way to find files containing this is to use grep (on Linux/Mac) at a command line in your site root:
$ grep -r "my_view_two" .
This will search for that string in all files of your project (if I've understood you correctly, it shouldn't be there).

Categories