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

Prompt self-templating #90

Closed
yajo opened this issue Oct 30, 2019 · 10 comments · Fixed by #190
Closed

Prompt self-templating #90

yajo opened this issue Oct 30, 2019 · 10 comments · Fixed by #190
Milestone

Comments

@yajo
Copy link
Member

yajo commented Oct 30, 2019

We need to go from:

# copier.yml
smtp_host: example.com
smtp_user: [email protected]

To:

# copier.yml
smtp_host: example.com
smtp_user: postmaster@[[smtp_host]]
This was referenced Oct 31, 2019
@pykong
Copy link
Collaborator

pykong commented Nov 20, 2019

Makes total sense to have it. This feature would make a nice addtion to copier.
I would accept a PR for it. ;-)

@pykong pykong added this to the 3.0.0 milestone Nov 20, 2019
@pykong
Copy link
Collaborator

pykong commented Feb 28, 2020

With:

smtp_user: "[[smtp_user]]@example.com"

I get the following prompt:

  smtp_user? Format: yaml
🎤 [[[smtp_user]]@example.com]: 

@yajo So, this is already implemented and we can close this issue now?

@yajo
Copy link
Member Author

yajo commented Feb 28, 2020

No, this is missing still. I noticed the description was misleading so I updated the example. It makes sense now 🤣

@yajo yajo modified the milestones: 3.0.0, 4.0.0 Mar 13, 2020
@yajo
Copy link
Member Author

yajo commented Mar 13, 2020

I moved this to next milestone, v3 seems ready to go for me.

@pawamoy
Copy link
Contributor

pawamoy commented Apr 17, 2020

I'd like to work on this, could you give me hints?

I guess the default value must be rendered using the previous answers in query_user_data, and that I should use code similar to Renderer.string method:

default = answers_data.get(question, details.get("default"))
tmpl = env.from_string(default)  # how do I get 'env'?
default = tmpl.render(**results)
answer = default

Question is: how do I get access to the Jinja env from within this function?

@yajo
Copy link
Member Author

yajo commented Apr 20, 2020

I bet you'd have to create a new env for each loop, because the values would differ as the user keeps answering.

In any case, you have to at least create a new temporary env, because the normal env is not created until we have all answers in place, and at this point we still don't have them.

Also you shouldn't just render default but all values in the question dict: default, help and maybe even choices (key and value in this case, if it's a dict).

One thing you have to think is that there could be templating errors if one answer is not yet given while asking the previous one.

You can take a look at #161 also, which depends on this one and shouldn't be very hard to implement once this is fixed.

🤔 This is trickier than it seems, but your help will be very appreciated! 😊 🙌

@pawamoy
Copy link
Contributor

pawamoy commented Apr 20, 2020

I bet you'd have to create a new env for each loop, because the values would differ as the user keeps answering.

I don't think so. You don't need a new env when the context changes. The env just contains the filters, some configuration, and templates loader (and in this case templates are strings). At each iteration, new values are added to results and these values are used as context to render the values for the next iteration.

In any case, you have to at least create a new temporary env, because the normal env is not created until we have all answers in place, and at this point we still don't have them.

OK!

Also you shouldn't just render default but all values in the question dict: default, help and maybe even choices (key and value in this case, if it's a dict).

Makes sense, I will try 🙂

One thing you have to think is that there could be templating errors if one answer is not yet given while asking the previous one.

I guess it's the user responsibility to write their copier.yml fields in the right order. We could indeed print a warning if the value is templated but was not rendered. Not sure if there's a Jinja method allowing to tell if a string is "templated" or not.

@yajo
Copy link
Member Author

yajo commented Apr 22, 2020

I guess it's the user responsibility to write their copier.yml fields in the right order.

I agree.

We could indeed print a warning if the value is templated but was not rendered. Not sure if there's a Jinja method allowing to tell if a string is "templated" or not.

That'd be nice. Gotta see if Jinja allows that. Otherwise, an exception would be acceptable for what you said before.

@pawamoy
Copy link
Contributor

pawamoy commented Apr 22, 2020

Otherwise, an exception would be acceptable for what you said before.

Oh silly me. In strict mode, if the string cannot be rendered (due to variables not being defined or else), it will trigger an exception. That's how we'll know. For some reason when writing this I was thinking that, if the string couldn't be rendered, it would be returned as-is, but it's not true. Instead it would be returned empty (or partially empty), and that would be hard to detect.

Strict mode it is! And catch the exception to abort and print a readable warning?

@yajo
Copy link
Member Author

yajo commented Apr 22, 2020

And catch the exception to abort and print a readable warning?

Just reraise it as copier.config.objects.UserMessageError and it should be enough.

@pawamoy pawamoy mentioned this issue Apr 23, 2020
3 tasks
@yajo yajo closed this as completed in #190 Apr 30, 2020
@yajo yajo modified the milestones: v4.0.0, v3.1.0 Apr 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants