Template with filters is returning null dict when string is "none"

Hi all,

I have tried searching for this but it has been super hard to find because of the None keyword.

Somewhat complicated story made short: I have a string that is equal to none that I’m trying to use in a template. When I use an if and also pass it through a filter, it seems to be getting treated as if it’s None / null and is being converted from a string to a null dict.

My examples below are very limited compared to what I’m trying to do but I’m wanting to keep it simple.

{% set test1 = 'none' %}

{{ test1 }}                     <-- ok: returns a string of 'none'
{{ test1|title }}               <-- ok: returns a string of 'None'

{% if test1 == 'none' %}
  {{ test1 }}                   <-- ok: returns a string of 'none'
  {{ test1|title }}             <-- bad: this returns a null dict
  {{ test1|title }}!            <-- ok: returns a string of 'None!'
  {{ test1|title|string }}      <-- bad: returns a null dict
  {{ test1|capitalize }}        <-- bad: returns a null dict
{% endif %} 

Am I doing something wrong? I’ve tried countless variations and I can’t get it to work as expected.

Thanks!

You’re definitely doing something wrong as everything works perfectly fine in the template editor.

I have a feeling you’re miss understanding the roll of a template (jinja syntax) and the roll of the template editor.

  1. All jinja return a string. Always.

    So, when you use {{ }}, no matter what is inside it, it returns a string.

    The template editor will take that resulting string and it will try to assign a python type to it. The native python types are:

    • int
    • float
    • string
    • boolean
    • dict
    • list
    • None (Shows up as null in template editor after resolution)

    So, when you look at the output of your jinja, one of those types will be assigned to it by the template editor. That is what you’ll see in Result Type. Just keep in mind that int or float will show as Number for result type.

  2. If you want to test the type that template editor will resolve. Do not include ANY other text.

    Your first 2 tests you most likely tripped yourself up on the 2nd attempt and it showed up “correctly” in your eyes. When in fact it would show as null.

    Had you just tested a single item e.g. {{ test1 | title }} the output would have shown null. This is because None is a native python type that the template editor will always resolve to None.

  3. If you want to see the raw output of your jinja, including all whitespace of any output… Trick the template editor by adding text in front. e.g.

    x
    {{ test1|title }}
    

Thank you for the quick and detailed reply!

I was using the template editor to test things out as I wrote this. If I copy/paste my whole code example then my result looks the same as yours, but it’s different if you limit it to just one of the “bad” ones.

Here are some examples.

{% set test1 = 'none' %}
{% if test1 == 'none' %}
  {{ test1|title }}
{% endif %} 

{% set test1 = 'none' %}
{% if test1 == 'none' %}
  {{ test1|capitalize }}
{% endif %} 

Do you see something different when you run them? Thanks.

I still don’t think you understand.

Both of those jinja syntax return the string None. The template editor then resolves that to the python native type None. This makes the result of the template editor null.

Jinja that returns a string that looks like a number will resolve a number.
Jinja that returns a string that looks like a boolean will resolve a boolean. (True or False)
Jinja that returns a string that looks like a dictionary will resolve a dictionary. ({'x': 1})
Jinja that returns a string that looks like a dictionary will resolve a list. ([1,2,3] or 1,2,3 or (1,2,3))
Jinja that returns a string that looks like a bunch of random crap will resolve a string. (this None is in the middle of words so it remains None)
Jinja that returns a string that looks like None will resolve null. (None)

It’s a feature / bug (take your pick) of the template editor.

It’s definitely a feature. It shows you what will resolve if you use them in variables inside an automation. Because the native python types are then useable in later variables.

I definitely understand that, but that’s my problem. Haha. Is there a way to make it not do that?

I’m using this to display the current pollen count on a mushroom template card. The range on the pollen count goes from none to very_high. I’m taking the value and displaying it on the card but also wanting to remove the underscore and capitalize the first letter of each word.

This can easily be done with: {{ states(entity)|replace('_', ' ')|title }}.

That works for every single status except for when the count is none, because it gets resolved as null after it passes through title. And I know that’s because it changed to None which is the equivalent to null. I was just asking if there’s some way to escape that behavior because it takes a 1 line template that does what I want and turns it in to a more complicated one where I have to check for and replace the word none.

It isn’t a huge deal, I just wanted to ask and see if there was a way to escape that behavior or see if I was doing something wrong.

Edit: it’s worth noting that this also happens in a mushroom template card, not just in the template editor. I’m saying that just so it isn’t misunderstood as something specific to the template editor.

No. This resolver is applied everywhere a template is used. You can only get around it when outputting complex objects like dict or lists because the resolver is not recursive. Items inside lists or dicts remain unchanged because the resolver only looks at the top object. Which you cannot do in this instance.

Change your template to

{{ states(entity)|replace('_', ' ')|replace('none', 'no pollen')|title }}

I simplified my explanation to things that anyone would understand. There’s a template resolver that is attached to all templates. It resolves the resulting type. The template editor displays those results.

Wherever you use a template, the resolver is trying to figure out the result type.

This as written resulted in TemplateSyntaxError: expected token 'end of print statement', got '.' but I changed it to {{ states(entity)|replace('_', ' ')|replace('none', 'no pollen')|title }} and that is working as expected.

That is the same fix I came up with but I was using an if statement to check for none. I didn’t think to do it this way to keep it as a nice one-liner and I like that much better. Thanks for the help!

There was another thread I posted about something very similar a long time back.

Here it is if it can help you: