Python cookiecutter loop over list
Asked Answered
D

1

6

I am trying to loop over all items in a Python cookiecutter json list and run a bash command based on each item.

Setup

I have the following cookiecutter.json:

{
    "directory_name": "df-sharp",
    "servers": ["db", "web"],
    "myweb_provisioner": "webck"
}

I have {{cookiecutter.myweb_provisioner}}.sh, which contains this jinja2 code:

{% for server in cookiecutter.servers %}
mkdir -p ~/myproj/host_types/{{ server }}
{% endfor %}

Problem

When I run cookiecutter create-server-tree, I get the following:

Select servers:
1 - db
2 - web
Choose from 1, 2 [1]: 2

and the contents in webck.sh are:

mkdir -p ~/myproj/host_types/w
mkdir -p ~/myproj/host_types/e
mkdir -p ~/myproj/host_types/b

The Select menu should not appear. I do not want to choose between the 2 elements in the list. I want to loop over them and construct 2 bash commands - one command per element. I am trying to loop over the list like shown here or here.

What I want

This is what I want: cookiecutter create-server-tree should produce webck.sh which contains the following:

mkdir -p ~/myproj/host_types/db
mkdir -p ~/myproj/host_types/web

How can I iterate over the servers list and use each of the list elements (instead of one character at a time)?

Deloris answered 24/11, 2017 at 4:3 Comment(0)
D
3

It turns out that I was using the wrong terminology. If the value in a key-value pair is a plain list, then cookiecutter calls that value (list) as providing "Multiple Choice options". So if I put in a plain list as the value for the key "servers", then I should expect to get the list of choices that I got above:

Select servers:
1 - db
2 - web
Choose from 1, 2 [1]: 2

What I needed was a nested dictionary as the value for the key servers, like they show here - it is called Dictionary Variables. To use this to answer my question, I changed my cookiecutter.json file to this:

{
    "directory_name": "df-sharp",
    "servers": {"server_list": ["db", "web"],
                "server_ips: ["123", "456"]"
               },
    "myweb_provisioner": "webck"
}

and then I used jinja2 as shown below:

{% for server in cookiecutter.servers.server_list %}
mkdir -p ~/myproj/host_types/{{ server }}
{% endfor %}

and this gave me what I wanted.

However, I had to use cookiecutter create-server-tree --no-input(link). This is because I have not been able to suppress only the prompt for a dictionary variable. I would have wanted this:

directory_name[df-sharp]: 
myweb_provisioner[webck]: 

and some way of specifying the key servers as a default argument. Actually, they have a default option here. It would be something like this and requires using their API:

cookiecutter('create-server-tree/',
             no_input=True,
             extra_context={"servers": {"server_list":['db','web'],
                                        "server_ips": ["123", "456"]
                                       }
                           }
            )

However, how should a user incorporate this extra_content={...} argument into an actual cookiecutter project and refer to "server_list" in jinja2 templated script? I don't know.

Deloris answered 28/11, 2017 at 4:8 Comment(2)
you can suppress prompts for specific options by making nested cookiecutters - the outer one which should be directly used by your user would render the cookiecutter.json with the extra context, the inner one would then be called with these rendered optioins and --no-input by the outer one's post gen hook cookiecutter.readthedocs.io/en/latest/advanced/hooks.html (although this is kinda ugly, but the cookiecutter is neither very flexible nor sophisticated at this point)Disclosure
It would be quite unwieldly but that's an interesting idea. It would have the advantage that the extra context would not be required. Thanks!Deloris

© 2022 - 2024 — McMap. All rights reserved.