Home > other >  How to replace NaN with Jinja default filter?
How to replace NaN with Jinja default filter?

Time:04-26

I am trying to use the default filter in Jinja2 to replace missing values with default values.

It turns out that my data source has some NaNs, not just missing values. For my use case, I want to replace NaNs with a default value. But the default filter just passes NaN through without substitution.

Are there any filters in Jinja2 which would allow me to replace NaN values with something else, easily? (Of course I could write a custom filter, I'm just wondering if there's a simpler solution.)

For context, I'm doing this from Ansible, which has a few more filters available than plain Jinja2.

MWE

playbook.yaml

---
- hosts: localhost
  connection: local
  tasks:
  - name: generate cloudformation template
    template:
      src: input.j2
      dest: output.txt
    vars:
      data:
        - value: 123
          comment: this is an integer
        - value: None
          comment: This is None
        - value: NaN
          comment: This is NaN
        - comment: this is missing
        - value: ''
          comment: empty string

input.j2

{% for row in data %}
{{ row['comment'] }}
{{ row['value'] | default('default') }}
{{ row['value'] | default('default', boolean=True) }}

{% endfor %}

Run with:

ansible-playbook playbook.yaml
cat output.txt

Actual behavior

this is an integer
123
123
123

This is None
None
None
default

This is NaN
NaN
default
default

this is missing
default
default
default

empty string

default
default

Desired behavior

...

This is NaN
NaN
default
default

...

(It would be good to also have a solution that replaces Nones. I'm not sure why None | default('x', boolean=True) doesn't do that, since None is falsey.)

CodePudding user response:

The default filter won't help you here. A custom filter might be a good idea to simplify the code. But, you can convert the data also using current filters.

For example, add the default value first if the attribute is missing

_data_default:
  - value: default
_data: "{{ _data_default|product(data)|map('combine')|list }}"
_data:
  - comment: this is an integer
    value: 123
  - comment: This is None
    value: None
  - comment: This is NaN
    value: NaN
  - comment: this is missing
    value: default
  - comment: empty string
    value: ''

Replace the values

_regex: '^NaN|None|null$'
_regex_empty: '^$'
_replace: default
_data_values: "{{ _data|map(attribute='value')|
                  map('regex_replace', _regex, _replace)|
                  map('regex_replace', _regex_empty, _replace)|
                  map('community.general.dict_kv', 'value')|list }}"
_data_values:
  - value: '123'
  - value: default
  - value: default
  - value: default
  - value: default

and combine the items of the lists

data2: "{{ data|zip(_data_values)|map('combine')|list }}"
data2:
  - comment: this is an integer
    value: '123'
  - comment: This is None
    value: default
  - comment: This is NaN
    value: default
  - comment: this is missing
    value: default
  - comment: empty string
    value: default

Fit the options to your needs and put the variables as appropriate.

  • Related