0

My Cookiecutter project is structured like this

├── project
│   ├── {{Cookiecutter.client_name}}
│   │   ├── {{Cookiecutter.account_name}}
│   │   │   │── some-folder  
│   │   │   ├── {{Cookiecutter.account_name}}.py

cookiecutter.json looks like this

{
    "client_name": "client",
    "account_name": "account"
}

Now, in place of one account_name. I want to add multiple account_names so that when Cookiecutter generates the project {{Cookiecutter.client_name}} should have multiple folders like account1, account2, account3 and so on..

I have went through the Cookiecutter docs couldn't find anything meaningful or on how to go about it.

Yaman Ahlawat
  • 477
  • 6
  • 17

1 Answers1

2

AFAIK this is not possible with cookiecutter if the number of accounts is not fixed in advance. But you can achieve the same effect with a hook. Something like this: (n.b. untested)

├── project
│   ├── {{ client_name }}
│   │   ├── account_name
│   │   │   │── some-folder  
│   │   │   ├── account_name.py
|   |-- hooks
|   |   |-- post_gen_project.py
# post_gen_project.py
# runs from the *generated* project
from pathlib import Path
from shutil import copy, rmtree
accounts = [x.strip() for x in {{ accounts }}.split(",")] # cookiecutter will render this for you
client_name = {{ client_name }}
src = Path(client_name)
for account in accounts:
    copy(src / "account_name", src/account)
    fn = src/ f"account/account_name.py"
    fn.rename(fn.with_name(f"{account}.py"))
rmtree(src)

If you have lots of this to do, you might be better off just writing a deploy script yourself and avoiding cookiecutter.

I am assuming that your accounts are entered , separated: I can't remember if there's any way to get a raw list type in cookiecutter.

Yet another option is to use nested cookiecutters---specifically, calling a cookiecutter for account from the post_gen hook, in a loop until the user no longer wants to add accounts. Something like this (again untested, provided as a starting point):

├── project
│   ├── {{ client_name }}
│   │   ├── account_template
|   |   |   |-- {{ account_name }}
│   |   │   │   │── some-folder  
│   |   │   │   ├── {{ account_name }}.py
|   |-- hooks
|   |   |-- post_gen_project.py
# cookiecutter_project.json
...
"_copy_without_render": ["account_template/"]

This gets our inner cookiecutter deployed where we want it without rendering it. Then in the inner cookiecutter:

# account_template/cookiecutter.json
{ "account_name": "default account", "client_name": "default client"}

And then finally, in the outer cookiecutter's hook:

# hooks/post_gen_project.py
from shutil import rmtree
from cookiecutter.main import cookiecutter

client_name = {{ client_name }}
cont = True
while cont:
    account_name = input("Enter account name: ")
    cookiecutter(
                 "template_account", 
                  no_input=True,
                  extra_content=dict(
                                     account_name=account_name,
                                     client_name=client_name
                                     )
                )
    cont = not input("Press enter to continue").strip()

rmtree("template_account")

If the number of accounts is fixed in advance it's easy---just name one set account1, the next account2 and so on.

References:

https://cookiecutter.readthedocs.io/en/1.7.3/advanced/hooks.html https://cookiecutter.readthedocs.io/en/1.7.3/advanced/suppressing_prompts.html#suppressing-command-line-prompts

2e0byo
  • 5,305
  • 1
  • 6
  • 26
  • Thanks. I thought of doing this. But I have multiple Cookiecutter/jinja variables inside account_name.py which also needs to be changed when project is generated (variables are based on account and client name). Also, the accounts are not fixed it can be 3,4 5 or any. – Yaman Ahlawat Sep 28 '21 at 10:43
  • In that case I really would use recursive cookiecutters, horrible as that sounds.... – 2e0byo Sep 28 '21 at 10:45
  • Thanks. I'll try the horrible approach. :P any reference on how to do this? – Yaman Ahlawat Sep 28 '21 at 11:00
  • @YamanAhlawat I've added an (untested, sorry!) skeleton for how I'd go about it. – 2e0byo Sep 28 '21 at 11:47