Skip to content

Conversation

sisp
Copy link
Member

@sisp sisp commented Aug 22, 2025

Currently, if a question is skipped, its answer is not recorded, but its default value is available in the render context. This makes sense for computed values and conditionally skipped questions with meaningful default values, but there are use cases where a question should be skipped and its Jinja variable should be undefined (i.e., not present in the render context) because there is no meaningful default value. For example:

database_engine:
  type: str
  help: Database engine
  choices:
    - postgres
    - mysql
    - none
  default: postgres

database_url:
  type: str
  help: Database URL
  default: >-
    {%- if database_engine == 'postgres' -%}
    postgresql://user:pass@localhost:5432/dbname
    {%- elif database_engine == 'mysql' -%}
    mysql://user:pass@localhost:3306/dbname
    {%- endif -%}
  when: "{{ database_engine != 'none' }}"
  # Simplified for illustration purposes
  validator: "{% if '://' not in database_url %}Invalid{% endif %}"

Here, the default value of the database_url question is only defined for the database engines "postgres" and "mysql" but not for "none", and we can't render, e.g., an empty string as the default value for "none" because the validator would fail. We could surround the actual validator condition with {% if database_engine != 'none' %}...{% endif %}, but that feels hacky and redundant with the when expression. What we'd actually want is to fully skip this question – I'd say by declaring the default value as unset. An unset default value of a skipped question means that there is no answer, so the validator isn't applied. Copier already behaves this way when the default field is not present.

To support this scenario, I've added a special Jinja variable UNSET which is available in the render context of the default field. When this value is rendered, Copier behaves as if the default field isn't present. The example from above would look like this now:

 database_engine:
   type: str
   help: Database engine
   choices:
     - postgres
     - mysql
     - none
   default: postgres

 database_url:
   type: str
   help: Database URL
   default: >-
     {%- if database_engine == 'postgres' -%}
     postgresql://user:pass@localhost:5432/dbname
     {%- elif database_engine == 'mysql' -%}
     mysql://user:pass@localhost:3306/dbname
+    {%- else -%}
+    {{ UNSET }}
     {%- endif -%}
   when: "{{ database_engine != 'none' }}"
   # Simplified for illustration purposes
   validator: "{% if '://' not in database_url %}Invalid{% endif %}"

Related to #2278 (comment).

WDYT, @copier-org/maintainers?

Copy link

codecov bot commented Aug 22, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.00%. Comparing base (165c85a) to head (3c964a7).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2286   +/-   ##
=======================================
  Coverage   98.00%   98.00%           
=======================================
  Files          55       55           
  Lines        6160     6172   +12     
=======================================
+ Hits         6037     6049   +12     
  Misses        123      123           
Flag Coverage Δ
unittests 98.00% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

Successfully merging this pull request may close these issues.

1 participant