diff --git a/.gitignore b/.gitignore index 9f431dd..8308954 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ nosetests.xml .pytest_cache dist/ +env/ +*.iml +.python-version diff --git a/README.md b/README.md index 13579e6..e38ccbb 100644 --- a/README.md +++ b/README.md @@ -17,15 +17,20 @@ Usage: jinja2 [options] Options: --version show program's version number and exit -h, --help show this help message and exit - --format=FORMAT format of input variables: auto, ini, json, + --format=FORMAT format of input variables: auto, env, ini, json, querystring, yaml, yml -e EXTENSIONS, --extension=EXTENSIONS extra jinja2 extensions to load + -I INCLUDES, --includes=INCLUDES + extra jinja2 template directory to search for + (included) templates -D key=value Define template variable in the form of key=value -s SECTION, --section=SECTION Use only this section from the configuration --strict Disallow undefined variables to be used within the template + -o FILE, --outfile=FILE + File to use for output. Default is stdout. ``` ## Optional YAML support diff --git a/jinja2cli/cli.py b/jinja2cli/cli.py index 95a2b68..b84abf6 100644 --- a/jinja2cli/cli.py +++ b/jinja2cli/cli.py @@ -142,7 +142,7 @@ def _load_querystring(): import urllib.parse as urlparse def _parse_qs(data): - """ Extend urlparse to allow objects in dot syntax. + """Extend urlparse to allow objects in dot syntax. >>> _parse_qs('user.first_name=Matt&user.last_name=Robenolt') {'user': {'first_name': 'Matt', 'last_name': 'Robenolt'}} @@ -212,11 +212,13 @@ def _parse_env(data): } -def render(template_path, data, extensions, strict=False): +def render(template_path, data, extensions, strict=False, includes=None): + includes = [] if includes is None else includes + from jinja2 import Environment, FileSystemLoader, StrictUndefined env = Environment( - loader=FileSystemLoader(os.path.dirname(template_path)), + loader=FileSystemLoader([os.path.dirname(template_path)] + includes), extensions=extensions, keep_trailing_newline=True, ) @@ -311,7 +313,9 @@ def cli(opts, args): out = codecs.getwriter("utf8")(out) - out.write(render(template_path, data, extensions, opts.strict)) + out.write( + render(template_path, data, extensions, opts.strict, includes=opts.includes) + ) out.flush() return 0 @@ -378,6 +382,14 @@ def main(): action="append", default=["do", "with_", "autoescape", "loopcontrols"], ) + parser.add_option( + "-I", + "--includes", + help="extra jinja2 template directory to search for (included) templates", + dest="includes", + action="append", + default=[], + ) parser.add_option( "-D", help="Define template variable in the form of key=value", diff --git a/tests/files/maindir_template.j2 b/tests/files/maindir_template.j2 new file mode 100644 index 0000000..7917609 --- /dev/null +++ b/tests/files/maindir_template.j2 @@ -0,0 +1 @@ +{% include 'template.j2' %} diff --git a/tests/files/subdir/subdir_template.j2 b/tests/files/subdir/subdir_template.j2 new file mode 100644 index 0000000..7917609 --- /dev/null +++ b/tests/files/subdir/subdir_template.j2 @@ -0,0 +1 @@ +{% include 'template.j2' %} diff --git a/tests/test_jinja2cli.py b/tests/test_jinja2cli.py index 181a8bd..0b44167 100644 --- a/tests/test_jinja2cli.py +++ b/tests/test_jinja2cli.py @@ -1,4 +1,6 @@ import os +import json +import subprocess from jinja2cli import cli @@ -23,3 +25,60 @@ def test_absolute_path(): output = cli.render(path, {"title": title}, []) assert output == title assert type(output) == cli.text_type + + +def test_cmd_succeeds(): + template = "files/maindir_template.j2" + title = "Greatest Title 1" + ctx = json.dumps({"title": title}) + echo_proc = subprocess.Popen(["echo", ctx], stdout=subprocess.PIPE, shell=False) + jinja_proc = subprocess.Popen( + ["jinja2", template], + stdin=echo_proc.stdout, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, + ) + assert jinja_proc.wait() == 0 + assert jinja_proc.stderr.readlines() == [] + assert jinja_proc.stdout.readlines() == [(title + "\n").encode()] + + +def test_cmd_fails_without_includes_flag(): + template = "files/subdir/subdir_template.j2" + title = "Greatest Title 2" + context = json.dumps({"title": title}) + echo_args = ["echo", context] + jinja_args = ["jinja2", template] + echo_proc = subprocess.Popen(echo_args, stdout=subprocess.PIPE, shell=False) + jinja_proc = subprocess.Popen( + jinja_args, + stdin=echo_proc.stdout, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, + ) + assert jinja_proc.wait() == 1 + jinja_err = jinja_proc.stderr.readlines() + assert "jinja2.exceptions.TemplateNotFound" in jinja_err[-1].decode("utf-8") + assert jinja_proc.stdout.readlines() == [] + + +def test_cmd_succeeds_with_includes_flag(): + template = "files/subdir/subdir_template.j2" + title = "Greatest Title 3" + ctx = json.dumps({"title": title}) + template_root = "files" + echo_args = ["echo", ctx] + jinja_args = ["jinja2", template, "--includes", template_root] + echo_proc = subprocess.Popen(echo_args, stdout=subprocess.PIPE, shell=False) + jinja_proc = subprocess.Popen( + jinja_args, + stdin=echo_proc.stdout, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, + ) + assert jinja_proc.wait() == 0 + assert jinja_proc.stderr.readlines() == [] + assert jinja_proc.stdout.readlines() == [(title + "\n").encode()]