Cookiecutter: How to use _variable in cookiecutter.json correctly?

Created on 11 Oct 2018  路  9Comments  路  Source: cookiecutter/cookiecutter

  • Cookiecutter version: 1.6.0
  • Python version: 2.7

I'm trying to prompt the user for his desired Python Version and then extract the major and minor version to be used in my cookiecutter template

My cookiecutter.json looks sth like this:

{
"repo_name": "template",
"description": "This is Luminovo's template repository.",
"author_name": "Your Name",
"author_email": "[email protected]",
"python_version": ["3.7.0", "3.6.6", "3.5.6"],
"_major_python_version": "{{ cookiecutter.python_version[0] }}",
"_minor_python_version": "{{ cookiecutter.python_version[2] }}"
}

unfortunately the {{ cookiecutter.python_version[0] }} part does not work (when running cookiecutter and using {{ cookiecutter._major_python_version }} it gets replaced with "{{ cookiecutter.python_version[0] }}" - not with "3")

it does work when not using an underscore in cookiecutter.json, but then it prompts the user for the major_python_version (and uses "3") as the default.

sorry if this is a very basic question, but i could not find anything about this in the documentation ^^

Most helpful comment

It would really simplify things if we can have this behavior out of the box

All 9 comments

_ seems to be intended for things internal to cookie cutter rather than hidden things, subsequently {{}} expansion is not performed on _ variables, you can see this here:
https://github.com/audreyr/cookiecutter/blob/master/cookiecutter/prompt.py#L203

Then how can we prevent prompting the user on transformations we do like project_slug below?

{  
  "project_name": "my-project",  
  "git_project_name": "{{cookiecutter.project_name}}",  
  "owner_name": "owner",  
  "email": "[email protected]",  
  "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}"  
}

Afaik CookieCutter has no support for internal unprompted things. For the project I'm working on we've dealt with this by handling prompting ourselves and then running CookieCutter in no input mode. We can do this because we are invoking CookieCutter from within our own CLI. Incidentally that CLI is implemented with "click" which provides quite nice helpers for prompting.

It would really simplify things if we can have this behavior out of the box

You can do this in a slightly different way via Jinja + pre gen hooks. See my reply at - https://github.com/cookiecutter/cookiecutter/issues/364#issuecomment-678683237 and the demo repo https://github.com/samj1912/cookiecutter-advanced-demo

That allows you to modify the cookiecutter context from pre gen hooks on cookiecutter v0.7+ with some advanced jinja hackery.

Advanced context modification for cookiecutter.

The above repo is an advanced example of a cookiecutter that can modify cookiecutter's
context values from hooks. Read the pre_gen_project.py for examples and a demo on how to modify context.

To run this demo cookiecutter do -

cookiecutter https://github.com/samj1912/cookiecutter-advanced-demo

This demo shows how to do the following -

  1. Add values to the cookiecutter context.

The above is useful for a bunch of cases -

  • Being able to add values to the context independent of the user input -
    for eg. creating a valid project slug from a project name by escaping
    the values.
  • When you are sharing files between different cookiecutter
    directories and you want to define defaults in order to avoid
    Jinja from complaining the certain values are not defined.
  1. Modify existing values cookiecutter context values even after user input-

This is useful when you want to handle bad user input and instead of raising an
error, set the cookiecutter context values correct. For eg modifying the project_slug
from the user to be valid.

  1. Conditionally modify the above based on user input.

Note - You can also do this to change the name of the variable that is used to define the generated project directory. This is useful when handling inputs from the user that you want to escape.

{
"repo_name": "template",
"description": "This is Luminovo's template repository.",
"author_name": "Your Name",
"author_email": "[email protected]",
"python_version": ["3.7.0", "3.6.6", "3.5.6"],
"major_python_version": ["{{ cookiecutter.python_version[0] }}"],
"minor_python_version": ["{{ cookiecutter.python_version[2] }}"]
}

not a great solution - but the quickest I've found without having to do some Jinja wizardry if you don't want anyone modifying those last two lines...
Basically a list with only one option...

but also only using this in rough prototyping, not as an end solution

In the cookiecutter private variables documentation they note that you can use a double underscore to have the variable rendered.

I think what you want to do is as simple as renaming _minor_python_version to __minor_python_version

The docs are for an unreleased version of cookiecutter, although it has been merged to master, it has not been released on pypi.

ah good to know, thanks! looking forward to the release

Was this page helpful?
0 / 5 - 0 ratings