copier
copier copied to clipboard
`placeholder` with no `default` does not force the user to answer
Describe the problem
According to the docs, default should be left empty to force the user to answer. However, even with no default, if placeholder is set then the user is not forced to answer the prompt.
Template
# copier.yml
---
required_var:
placeholder: foo
_message_after_copy: |
required_var is {{ required_var }}
To Reproduce
Run copier with the copier.yml from the previous section. When prompted for required_var, simply hit enter.
Example:
copier copy -n . dir
🎤 required_var (yaml)
foo
Copying from template version None
create .
required_var is None
Logs
No response
Expected behavior
When prompted, the user should be forced to enter a value and not be able to just hit enter, which effectively sets the value to None, "", etc. depending on the type.
Screenshots/screencasts/logs
No response
Operating system
macOS
Operating system distribution and version
Sonoma 14.6.1
Copier version
copier 9.3.1
Python version
Python 3.12.4
Installation method
pip+pypi
Additional context
This behavior can be worked-around with something like this:
validator: >-
{% if not required_var %}
INVALID - you must enter a value
{% endif %}
... but that is a lot of boilerplate to add.
Interactive prompting is a little tricky because for type: str/type: yaml questions there is no clear distinction between no answer and an empty answer.
Let's assume the following copier.yml file:
str_1: ""
str_2:
default: ""
str_3:
type: str
All three questions are (implicit or explicit) type: str questions. When you enter no answer during interactive prompting, the answer will be an empty string because there is no way provide no answer (when you hit Enter, the answer is an empty string in all cases).
It's similar for type: yaml questions:
yaml_1: null
yaml_2:
default: null
yaml_3:
type: yaml
All three questions are (implicit or explicit) type: yaml questions. When you enter no answer during interactive prompting, the answer will be null because an empty string gets parsed as null by the YAML parser and there is no way to provide no answer (same as above).
So, your discovery is in fact not related to the use of placeholder with no default but rather the behavior of type: str/type: yaml questions with an implicit default value during interactive prompting.
I don't see how we could change the current behavior, but I'm all ears if you have an idea. Your proposed workaround using a validator does not precisely catch an unanswered question but constrains the answer to not be falsy, which coincidentally means it must not be "" or null.
I've done some more testing, and I see what you are saying now. It works as I would expect for types other than yaml or str. I guess my confusion was mainly because I assumed "force the user to answer" also meant "with a non-empty response".
I don't have a better idea other than adding a new supported key for advanced prompts such as mandatory: False or allow_empty: True. I could see why you would be hesitant to do that though since the same could be achieved with validators.
I really liked the idea of placeholders to show example answers, but I can always hard-code examples in help where it makes sense.
Thanks
I think the MVP would be to document this behavior, and how validators can be used for this use case, so it's not surprising to users.