copier-org / copier

Library and command-line utility for rendering projects templates.
https://readthedocs.org/projects/copier/
MIT License
1.99k stars 179 forks source link

feat: questionnaire validation #398

Closed RoyalTS closed 2 years ago

RoyalTS commented 3 years ago

I'd love a possibility to validate questionnaire inputs. Being able to validate str against regex would already be a huge help, e.g. by specifying a field appropriately in copier.yml:

project_name:
  type: str
  help: Your project name
  validate: ^[a-zA-Z][_a-zA-Z0-9]+$
yajo commented 3 years ago

This was the feature I was hoping nobody asked 🤣

Yes, gotta do it.

However, I'm more o the side of allowing a Jinja template to validate, so you can validate any data type. It'd be interesting for YAML questions for example.

eyllanesc commented 2 years ago

my 2 cents: I think "validate" should accept jinja filters, and there should be filters like regex ones, range validators, etc.

andrew-glenn commented 2 years ago

@yajo Just to clarify - you're thinking an inline jinja template, versus a path to a jinja template on the local filesystem, correct?

FWIW my team is discussing this and considering a contribution; Just want to align with maintainer desires to (hopefully) fast-track any PR that we submit. :)

yajo commented 2 years ago

I was thinking on an in-line template that, if renders to an empty (or whitespace-only) string means OK, but if it renders to some text, that text is considered the error message. Does that make sense for you?

pawamoy commented 2 years ago

@yajo, could you provide some examples of Jinja templates as validators? I'm imagining single conditions for simple values, and multiline templates for more complex ones?

project_name:
  type: str
  help: Your project name
  validator: "{% if not project_name %}project_name cannot be empty{% endif %}"

metadata:
  type: yaml
  help: Your project metadata
  validator: |
    {% if metadata is not mapping %}metadata must be a mapping, not a list or other type{% endif %}
    {% for name, value in metadata.items() %}
      {% if value is mapping %}{{ name }}: value cannot be a mapping, only simple types or lists{% endif %}
    {% endfor %}
yajo commented 2 years ago

Correct!

Another example:


your_age:
  type: int
  validator: "{% if your_age <= 0 %}Must be positive{% endif %}"
barrywhart commented 2 years ago

@yajo: This feature looks really useful! If I understand correctly, it hasn't been released yet. Will there be a new release soon? 🙏

yajo commented 2 years ago

I wanted to release sonner, but saw there's some incompatibility with dependencies that you can see in #785. I want to at least fix that before the next release, or I'll get a flood of issues.

I still didn't have time though... if someone volunteers, the next release will be sooner.

barrywhart commented 2 years ago

Thanks! I may be able to look at it early next week.

Great project, BTW. We are switching from cookiecutter soon. 🙌🏽

pawamoy commented 2 years ago

I can take a look this week as well.

barrywhart commented 2 years ago

@yajo, @pawamoy: I have a possible fix for the test failures in #785. See PR #804.

nils-borrmann-y42 commented 2 years ago

@yajo I'm a bit confused about this feature. This doesn't seem to be able to solve the original usecase of validating a regex. Obviously the validator could look something like this - but this fails since re is not available:

  validator: "{% if not re.fullmatch('[a-z-]+', project_name) %}invalid project name{% endif %}"

I tried a few things, but wasn't able to import re from the jinja template. A quick google search told me that it actually isn't possible to import modules from within a jinja template. What am I missing? How can I do a regex validation?

pawamoy commented 2 years ago

Either Copier itself could add some modules from the standard library into the Jinja context, or we could write an extension that does just that. The extension package would expose multiple extensions, one for each stdlib module of interest, and one that adds all modules of interest at once maybe? :thinking:

yajo commented 2 years ago

Copier includes https://gitlab.com/dreamer-labs/libraries/jinja2-ansible-filters, which contain regex filters.

nils-borrmann-y42 commented 2 years ago

Thanks, but I tried a few things and couldn't get this to work. Could you please give an example of what a regex validation could look like? (I guess this should also be added to the docs, considering that regex is likely one of the most common usecases for validations.)

yajo commented 2 years ago

Please would you mind to use the forum for this kind of questions? That'll be most helpful for the community, as there might be multiple ways of validating and some users would like to share them. Thanks for your understanding 😀