Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature-Request: Templates in context variables should support boolean values #2025

Open
avidspartan1 opened this issue Feb 28, 2024 · 8 comments

Comments

@avidspartan1
Copy link

avidspartan1 commented Feb 28, 2024

  • Cookiecutter version: 2.6.0
  • Python version: 3.9.16
  • Operating System: RHEL 8

This issue is a reopening of #1738.

Description:

As described here, we expect template authors to be able to reuse values of previous keys from cookiecutter.json, but currently that is not possible if you are working with boolean values. I believe it would be very important to support this use case or describe an alternative way to do it in docs. Example:

cookiecutter.json:

{
"likes_potatoes": false,
"likes_mashed_potatoes": "{{ cookiecutter.likes_potatoes }}"
}

Template example using above variables:

#!/bin/bash

{% if cookiecutter.likes_mashed_potatoes %}
echo "I like mashed potatoes!"
{% endif %}

The echo "I like mashed potatoes" line always renders, even when likes_potatoes is false.

@JamesParrott
Copy link

There's no simple functionality in Jinja2 to base this on.

>>> import jinja2
>>> t = jinja2.Template(' context.val(: {{context.val}}) is {% if context.val %} truthy {% else %} falsey {% endif %}')
>>> t.render(context={'other': False, 'val': '{{ context.other }}'})
' context.val(: {{ context.other }}) is  truthy '

Cookiecutter would need to make two rendering passes to support this.

@avidspartan1
Copy link
Author

What would you think of adding a metadata variable to cookiecutter.json (similar to _copy_without_render) to indicate a variable should have a certain type? e.g.

{
"_variable_types": {
  "likes_mashed_potatoes": "Boolean"
},
"likes_potatoes": false,
"likes_mashed_potatoes": "{{ cookiecutter.likes_potatoes }}"
}

@JamesParrott
Copy link

JamesParrott commented Feb 28, 2024

I didn't quite notice at first, that currently Cookiecutter already makes multiple rendering passes over the values in cookiecutter.json that are templates, to pick up self references. But by definition, a text templating language like Jinja2 can only render strings in those passes, not booleans. So cookiecuter would have to read the metadata and remove it from the rendering context itself

If it supported cookiecutter.yml, wouldn't you be able to achieve the same thing with Yaml Anchors, Aliases, or even Tags, with much less new code required in Cookiecutter, without altering the way thw code treats existing templates that use cookiecutter.json?

@avidspartan1
Copy link
Author

You're suggesting something like the following if YAML was supported?

likes_potatoes: false
likes_mashed_potatoes: !!bool "{{ cookiecutter.likes_potatoes }}"

If so, I think that would work for me. I just need cookiecutter to know that likes_mashed_potatoes's value is a Boolean when using a template for the value.

@JamesParrott
Copy link

I'm suggesting Yaml anchors, and that cookiecutter just lets a good Yaml library handle everything:

anchored_content: &anchor_name This string will appear as the value of two keys.
other_anchor: *anchor_name

https://learnxinyminutes.com/docs/yaml/

@avidspartan1
Copy link
Author

avidspartan1 commented Feb 28, 2024

The problem with YAML anchors is that I need the second value to be a template, so I can accomplish something like:

potato_preference: ['mashed', 'boiled', 'roasted', 'raw']
should_boil_water: "{{ cookiecutter.potato_preference == 'boiled' }}"

I'd like should_boil_water to be a Boolean.

I don't see a way to use YAML anchors to accomplish that, unless I'm missing something.

@JamesParrott
Copy link

JamesParrott commented Feb 28, 2024

Fair enough. It's still a huge change to start processing different data types, within what's essentially a sophisticated text/string global search/replace program, that delegates much of the text/string handling to Jinja2.

Does it just need to be a Boolean, only for that test within Jinja? Or does something else also use your cookiecutter.json?

Other templates avoid the need for Booleans by simply writing a more explicit test, e.g. using 'y', or anything else.

  {%- if cookiecutter.use_celery == 'y' %}

  celeryworker:
    <<: *django
    image: {{ cookiecutter.project_slug }}_production_celeryworker
    command: /start-celeryworker

  celerybeat:
    <<: *django
    image: {{ cookiecutter.project_slug }}_production_celerybeat
    command: /start-celerybeat

  flower:
    <<: *django
    image: {{ cookiecutter.project_slug }}_production_flower
    command: /start-flower
  {%- endif %}

https://github.com/cookiecutter/cookiecutter-django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/production.yml

@avidspartan1
Copy link
Author

avidspartan1 commented Feb 28, 2024

Fair enough. It's still a huge change to start processing different data types, within what's essentially a sophisticated text/string global search/replace program, that delegates much of the text/string handling to Jinja2.

Does it just need to be a Boolean, only for that test within Jinja? Or does something else also use your cookiecutter.json?

Other templates avoid the need for Booleans by simply writing a more explicit test, e.g. using 'y', or anything else.

  {%- if cookiecutter.use_celery == 'y' %}

  celeryworker:
    <<: *django
    image: {{ cookiecutter.project_slug }}_production_celeryworker
    command: /start-celeryworker

  celerybeat:
    <<: *django
    image: {{ cookiecutter.project_slug }}_production_celerybeat
    command: /start-celerybeat

  flower:
    <<: *django
    image: {{ cookiecutter.project_slug }}_production_flower
    command: /start-flower
  {%- endif %}

https://github.com/cookiecutter/cookiecutter-django/blob/master/%7B%7Bcookiecutter.project_slug%7D%7D/production.yml

This was the solution we ended up going with for now, comparing the variable's value with "yes"/"no" strings. Just nice to use Booleans where we can (also nice to get the [y/n] input prompt). 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants