Why the heck do automations require Jinja templates instead of real Python?

I have also noticed that a lot of people love to make stuff overly complicated. Trying to cram as many conditions and corner cases into a single script or automation, instead of just spltting stuff up in smaller, more readable and more easily maintainable pieces.

2 Likes

Or create a template sensor for intermediate storage instead of overly complex computations in jinja.

I love python. It’s great. I’ve been using it for 13 years now. But it would be a step down from Jinja.

You have plenty of options to get what you want without templates changing to python. Hell, with python scripts, you pretty much have this capability.

Lets take the simplest functionality that people use and compare it to is jinja counterpart:

{{ states('x.y') }}

vs

return states('x.y')

Seems pretty straight forward, maybe this will work. Lets try getting a state ad adding 1 to it.

{{ states('x.y') | int + 1 }}

vs

try:
  myint = int(states('x.y'))
except ValueError:
  myint = 0
return myint + 1

Which one is more readable for any user?

2 Likes

That’s the problem, as soon as you introduce python you introduce non-syntactical issues as well, which are most of the time way harder to explain. Just take a look at petros excellent example. Do you think it’s easier to write exception handling in python or using a simple filter “|” in Jinja?

But then when state = None you end up getting a return of 1, which is also confusing to novices.

It’s also trivial to overload | so that the original code works as is, or just modify the state object to support method chaining, like

states('x.y').int() + 1
1 Like

States returns string not a state object, so you’d be overloading the str classes __int__ method, which is not straight forward and can cause other issues. Where this is all just built into jinja without needing to change everything.

Some really good arguments here (I’m cheering from the side lines)

I have a question for @roger2 .

How would you define your python segment ?
What is it to be passed to the sandbox ?

For a template the curly brackets sort of give you a clue, not so in your examples they just start

You might say that the *_template bit is the first indicator, but it’s not.
Messages for example don’t (and never have) cared.

Also Frenck has just submitted a PR to dispense with the _template bit (whilst making it backward compatible). A lot of the people involved in this thread up voted that PR.

In terms of passing data in/out, maybe the template defines the body of a function along with a return statement:

value_template: |
    for state in states.sensor:
        if 'blah' in state.name:
            return state

    return ''

or

value_template: |
    return states('mysensor.val') + ' is too high'

The Mako folks probably already have an approach too.

I’m curious about that PR – link?

How would that separate from a non-templated form? All the | does is say “multi line”. It still wouldn’t know it’s a template. What happens if you want to add the word return to a field and it just be a string?

Have you considered that complex templates are probably an edge case and not the majority of templates?

Perhaps, but why not have something that scales to more complicated templates in a reasonable way (perhaps with a slight sacrifice to simpler one-liners)?

I’d say both of your examples are simpler/cleaner in pure Python:

trigger.to_entity.attributes.friendly_name + " is home!"
if is_state('person.a', 'home'):
  # do stuff for home
else:
   # do stuff for not home

With the added benefit that Python is the most popular programming language in the world while Jinja is fairly esoteric.

I assumed the _template part conveyed that, but I see that’s not the case.

Okay wrap it in <% and %> like Mako does.

So now that takes simple cases from this:

{{ states('x.y') }}

to this

<% return states('x.y') %>

or in the last example you gave:

<% return trigger.to_entity.attributes.friendly_name + " is home!" %>

opposed to this

{{ trigger.to_entity.attributes.friendly_name }} is home!

So, it seems the trend for the 99% use case just got harder to read and more verbose, where the ‘harder to do’ stuff stayed about the same.

For the record, my code looks like this, when I copy pasted it into the other topic, the forum software seriously screwed with the layout :slight_smile:

Seven characters is a small sacrifice compared to the syntactical benefits for anything that’s more substantial than a one liner.

(Of course can also just make the return statement optional for a one liner.)

Sorry I didn’t mean to critique your code specifically, I just find most non-trivial Jinja templates unnecessarily hard to grok!

What you found isn’t technically fair because the syntax you see is littered with raw characters added by the yaml parser.

One other key consideration here I forgot about in my first post:

This is a key point, rendering a template cannot have side effects. If you changed from Jinja to Python how would you enforce this? Python’s power works against it here, the fact that it can do so much would make it tough to ensure there cannot be side effects caused by rendering a template. By using a templating engine like Jinja this can be enforced since the utilities exposed ensure it is literally incapable of creating side effects.

I’m not familiar enough with the internals of Python to know how this could be done. I know there is a way to create a sandbox since the HA team has leveraged that capability in the python_script integration. But can that sandbox actually be tight enough to guarantee no side effects? And how much work would it take to do that?

Sorry, I have no idea what you mean by " when I copy pasted it into the other topic".

Did I miss something?

I think it’s a miss understanding. The forum didn’t screw up his format, he copied it from the UI, which screwed up the formatting.

2 Likes

I wasn’t aware you couldn’t search the forum.
But I do see that you have read a full 6 hrs