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

Unable to Access collections.OrderedDict Variables in cookiecutter.json despite proper Key Definition #2005

Open
nitishagar opened this issue Jan 27, 2024 · 4 comments

Comments

@nitishagar
Copy link

  • Cookiecutter version: 2.5.0
  • Template project url: NA
  • Python version: 3.12.1
  • Operating System: mac OS Sonoma 14.2.1

Description:

I'm attempting to retrieve collections.OrderedDict variables from cookiecutter.json. However, despite having the key specified at the beginning, the attribute cannot be located. Please refer to the provided example of cookiecutter.json for clarification:

{
  "app": {
    "name": "",
    "org": "",
    "description": "A short description of the project.",
    "project_id": "TBD"
  },
  "author": "Email ID of author",
  "team_name": "Unique Name for the data engineering project team, value of this parameter will be used as default input for sceptre_project_code",
  "repo_name": "{{ cookiecutter.app.name.lower().replace(' ', '-') }}",
  "aws_team_name": "Unique identifier only one per AWS account, output of $(aws ssm get-parameter --name /AdminParams/Team/Name --query Parameter.Value --output text)",
  ...

The error I get running the template is the following:

$> cookiecutter .
  [1/20] author (Email ID of author): sample
  [2/20] team_name (Unique Name for the data engineering project team, value of this parameter will be used as default input for sceptre_project_code): samplek
Unable to render variable 'repo_name'
Error message: 'collections.OrderedDict object' has no attribute 'app'
Context: {
    "_cookiecutter": {
        "app": {
            "description": "A short description of the project.",
            "name": "",
            "org": "",
            "project_id": "TBD"
        },
        "author": "Email ID of author",
...
@JamesParrott
Copy link

JamesParrott commented Jan 29, 2024

Cookiecutter checks the values of cookiecutter.json, to see if any are Jinja2 templates or strings.
https://cookiecutter.readthedocs.io/en/latest/advanced/templates_in_context.html

From experimenting, it seems cookiecutter does not recurse through arbitrary many levels of nested dictionaries, looking for all possible values in the tree that are Jinja2 templates (e.g. strings).

There's no error for me with a flat JSON mapping:

Test file and directory structure

tmp_cookiecutter
  {{ cookiecutter.project_slug }}
  cookiecutter.json

cookiecutter.json

{
  "project_name": "Tmp Cookiecutter",
  "app_name" : "",
  "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_') }}",
  "author": "Anonymous",
  "repo_name": "{{ cookiecutter.app_name.lower().replace(' ', '-') }}"
}
C:\....\tmp_cookiecutter>cookiecutter .
project_name [Tmp Cookiecutter]: fghj
app_name []: erty
project_slug [fghj]: 567
author [Anonymous]: dfgh
repo_name [erty]: ert

C:\....\tmp_cookiecutter>

@jundai-godaddy
Copy link

It looks like you can reference a dictionary variable inside another dictionary variable, but you can't reference it when resolving a root-level level variable. So this works:

{
  "app": {
    "name": "foo"
  },
  "test": {
    "name": "{{ cookiecutter.app.name }}"
  }
}

but this does not:

{
  "app": {
    "name": "foo"
  },
  "test_name": "{{ cookiecutter.app.name }}"
}

@jundai-godaddy
Copy link

Ok, I see what's happening:

  • Cookiecutter goes through the same "prompt" logic whether you are using prompts or inputs. You can see it here: https://github.com/cookiecutter/cookiecutter/blob/main/cookiecutter/prompt.py#L312
  • It "renders" each default value based on the dictionary it is building up, as it is building up
  • As a consequence of this ^^^, if you reference a variable later in the config file, it will fail
  • Dictionaries are saved for last, so if you reference a dictionary in a root-level variable, even though the dictionary is at the top of the cookiecutter.json file, it will not be available yet in cookiecutter_dict

Presumably this is a consequence of the fact that it's sort of nice to have the JSON inputs last when you are prompting the user to supply values, since they are structured differently. But it leads to this unintuitive behaviour when you are using --no-input.

I think there's no quick fix, it would require reworking the behaviour of the whole prompting function.

@JamesParrott
Copy link

JamesParrott commented Feb 1, 2024

Nice work Jun-Dai. :)

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

3 participants