sambhav / cookiecutter-advanced-demo

Cookiecutter demo-ing how to modify cookiecutter context from hooks
21 stars 2 forks source link

Pre Gen Hook script update context not working #2

Open prowler0305 opened 2 years ago

prowler0305 commented 2 years ago

Hello,

I ran across your suggestion on solving the cookiecutter pre_gen hook script context update solution. I have read you README.md stuff and tried to implement it but only get exceptions of 'Undefined' in the template type errors.

I'm hoping maybe you could fill in the blanks of what I'm doing wrong?

pre_gen_project.py

import sys
from cookiecutter import prompt
"""
This pre-gen script is to perform pre generation logic needed.
"""

if "{{ cookiecutter.database_integration }}" == "True":
    database_dialect = prompt.read_user_choice("database_dialect", ["postgres", "cx_oracle", "impyla"])
    {{ cookiecutter.update({"database_dialect": database_dialect}) }}

sys.exit(0)

cookiecutter.json

{
  "project_name": "my_project_name",
  "flask_app_name": "{{ cookiecutter.project_name|lower|replace(' ', '_') }}",
  "need_api_component": [true, false],
  "__flask_api_name": "{{cookiecutter.flask_app_name}}_api",
  "database_integration": [true, false],
  "_database_dialect": "default",
  "_copy_without_render": [
    "{{cookiecutter.flask_app_name}}/templates/*",
    "{{cookiecutter.flask_app_name}}/app_helpers/app_helpers.py"
  ]
}

Contents of the file that is using the database_dialect variable

config.py

import os
from distutils.util import strtobool

class BaseConfig:
    SECRET_KEY = os.environ.get("{{cookiecutter.flask_app_name}}_secret_key") or "brent_did_it"
    PROPAGATE_EXCEPTIONS = True
    THREADED = True
    PREFERRED_URL_SCHEME = "https"
    USE_RELOADER = False
{% if cookiecutter.database_integration == 'True' %}
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_DATABASE_URI = '{{cookiecutter._database_dialect}}://{}:{}@{}:{}/{}'.format(os.environ.get('db_user'),
                                                                                          os.environ.get('db_pass'),
                                                                                          os.environ.get('db_host'),
                                                                                          os.environ.get('db_port'),
                                                                                          os.environ.get('db_name')){% endif %}

The output of running my cookiecutter template

project_name [my_project_name]: test_flask
flask_app_name [test_flask]:
Select need_api_component:
1 - True
2 - False
Choose from 1, 2 [1]:
Select database_integration:
1 - True
2 - False
Choose from 1, 2 [1]:
Select database_dialect:
1 - postgres
2 - cx_oracle
3 - impyla
Choose from 1, 2, 3 [1]:
Unable to create file 'config.py'
Error message: 'database_dialect' is undefined
Traceback (most recent call last):
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/cookiecutter/generate.py", line 374, in generate_files
    project_dir, infile, context, env, skip_if_file_exists
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/cookiecutter/generate.py", line 179, in generate_file
    rendered_file = tmpl.render(**context)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "config.py", line 13, in top-level template code
jinja2.exceptions.UndefinedError: 'database_dialect' is undefined

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/cookiecutter/cli.py", line 207, in main
    accept_hooks=_accept_hooks,
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/cookiecutter/main.py", line 120, in cookiecutter
    accept_hooks=accept_hooks,
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/cookiecutter/generate.py", line 380, in generate_files
    raise UndefinedVariableInTemplate(msg, err, context)
cookiecutter.exceptions.UndefinedVariableInTemplate: Unable to create file 'config.py'. Error message: 'database_dialect' is undefined. Context: OrderedDict([('cookiecutter', OrderedDict([('project_name', 'test_flask'), ('flask_app_name', 'test_flask'), ('need_api_component', 'True'), ('__flask_api_name', 'test_flask_api'), ('database_integration', 'True'), ('_database_dialect', Undefined), ('_copy_without_render', ['{{cookiecutter.flask_app_name}}/templates/*', '{{cookiecutter.flask_app_name}}/app_helpers/app_helpers.py']), ('_template', 'IdeaProjects/cookiecutter_tutorial/'), ('_output_dir', '/home/aspea002')]))])

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/bin/cookiecutter", line 8, in <module>
    sys.exit(main())
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/site-packages/cookiecutter/cli.py", line 225, in main
    context_str = json.dumps(undefined_err.context, indent=4, sort_keys=True)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/json/encoder.py", line 201, in encode
    chunks = list(chunks)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/json/encoder.py", line 431, in _iterencode
    yield from _iterencode_dict(o, _current_indent_level)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/json/encoder.py", line 405, in _iterencode_dict
    yield from chunks
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/json/encoder.py", line 405, in _iterencode_dict
    yield from chunks
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/json/encoder.py", line 438, in _iterencode
    o = _default(o)
  File "/home/aspea002/miniconda3/envs/cookiecutter_tutorial/lib/python3.7/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type StrictUndefined is not JSON serializable
connewm commented 1 year ago

Hello, I also just stubmled across this solution and am receiving the same error in the exact same manner, that the value as seen in this code snippet is undefined: {{ cookiecutter.update({ "model_name": model_name }) }}

Did you ever find a solution to this issue?