Skip to content

fix async constraints #950

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 23, 2021
Merged

fix async constraints #950

merged 2 commits into from
Jan 23, 2021

Conversation

Mithras
Copy link
Contributor

@Mithras Mithras commented Mar 29, 2020

This fix allows using async constraints.
Example:

Test:
  module: test
  class: Test
  constrain_sync: qwe
  constrain_async: rty
import hassapi as hass


class Test(hass.Hass):
    async def initialize(self):
        self.log("initialize()")
        self.register_constraint("constrain_sync")
        self.register_constraint("constrain_async")
        self.run_in(self.timer_callback, 1)

    def constrain_sync(self, value):
        self.log(f"constrain_sync({value})")
        return True

    async def constrain_async(self, value):
        self.log(f"constrain_async({value})")
        await self.sleep(1)
        return True

    async def timer_callback(self, kwargs):
        self.log(f"timer_callback({kwargs})")

@homeassistant
Copy link

Hi @Mithras,

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

@ReneTode
Copy link
Contributor

does the async constraint work with listen_state?

i think its pretty useless to have the ability to sleep inside a constaint.
constraints should result a value ASAP at all time.

@Mithras
Copy link
Contributor Author

Mithras commented Mar 29, 2020

does the async constraint work with listen_state?

I dont't see any difference between awaiting sleep and awaiting listen_state, so it probably does. I don't see why anybody would do that though as you'd end up with exponentially growing callbacks.

i think its pretty useless to have the ability to sleep inside a constaint.
constraints should result a value ASAP at all time.

Agree.

Anyway, a valid use case is described here #921 (comment)
And an example is here https://github.com/Mithras/ha/blob/tmp/appdaemon/apps/globals.py#L49-L57

@ReneTode
Copy link
Contributor

I dont't see any difference between awaiting sleep and awaiting listen_state, so it probably does. I don't see why anybody would do that though as you'd end up with exponentially growing callbacks.

the only use for constraints is to constrain an event. (listen_state or listen_event)
in a constraint you should never await anything.

@Mithras
Copy link
Contributor Author

Mithras commented Mar 29, 2020

Whatever dude.

@ReneTode
Copy link
Contributor

i guess you dont care if AD keeps running.

i think its quite normal to test at least the normal usecase for a function.

def init():
  self.register_constraint("test")
  self.listen_state(self.cb, entity, test = "something")

async def test(self, value):
  if value == "something":
    return True
  else:
    return False

def cb():
  # do something

@Mithras
Copy link
Contributor Author

Mithras commented Mar 29, 2020

I'm using the fix for a couple weeks already. I sent a link to my repo above https://github.com/Mithras/ha/blob/tmp/appdaemon/apps/globals.py#L49-L57
It's just a couple lines bugfix for async constraints, it doesn't introduce anything new.
If you try the code you suggested in current dev branch, AD won't even execute the test() constraint and cb() will be always called. With the fix test() constraint will be executed and the result will be used to skip/call the callback as expected.

@ReneTode
Copy link
Contributor

hmm, perhaps i understand things wrong.

i asked: does it work with listen_state?
you answered: i dont see why anyone would do that.
i say: its normal usecase
you say: i already use it for weeks.

sorry if im confused, but i dont get your first or second answer, because they contradict.

your test show an applevel constrain, but custom constraints are mostly used on callback level.
so i just wanted to know if it works on callback level.

@Mithras
Copy link
Contributor Author

Mithras commented Mar 29, 2020

i asked: does it work with listen_state?

My first thought was that you are asking if it would work if I await listen_state instead of sleep because immediately after you were talking about how sleep is useless. So my answer was about doing listen_state inside constraint.

your test show an applevel constrain, but custom constraints are mostly used on callback level.
so i just wanted to know if it works on callback level.

I showed how to test it. I did run_in which will make AD execute callback. That exact same as listen_state will. Anyway, it'll work for anything for what sync constraints work today: run_in, listen_state, listen_event, etc. I don't think source of callbacks makes any difference in how constraints work.

@ReneTode
Copy link
Contributor

miscommunication ;)

i didnt say sleep is useless, but i did say sleep is useless in a constraint. ;)
anything that holds up a constraint is bad, so also sleep ;)

I showed how to test it.

but only on applevel( if you add the constrain to the app yaml, the whole app is constraint). the common way is on event level like:

self.register_constraint("test")
self.run_in(self.cb, 10, test = "something")

thats why i asked.

sorry for the miscommunication.

@Mithras
Copy link
Contributor Author

Mithras commented Mar 29, 2020

sorry for the miscommunication

No worries.

self.register_constraint("test")
self.run_in(self.cb, 10, test = "something")

Yes, it works in this case as well

@Odianosen25
Copy link
Collaborator

@Mithras,

Will like to merge this, but can we agree on a like better naming for the new util function instead of just run_fn_or_coro?

Seems a bit rushed.

Thanks

@Mithras
Copy link
Contributor Author

Mithras commented Jan 12, 2021

@Odianosen25 Sure, I have no issues renaming it. Do you have a better idea for the name?

@Odianosen25
Copy link
Collaborator

Honestly I don’t, if I had I would have suggested it already. Maybe something in the likes of “run_async_sync_func” or something fancier. I am out of my depths here

@Odianosen25
Copy link
Collaborator

@Mithras,

I think we should go with either run_async_sync_func or run_async_sync_method. If you fine, please change it, then I can merge it. As its quite a significant bug for those on pure async systems.

Regards

@Odianosen25
Copy link
Collaborator

@Mithras,

Can you make the changes pls so I can merge this? Or no more interested in it? I want this to be part of the merges I make this weekend.

thanks

@Mithras
Copy link
Contributor Author

Mithras commented Jan 22, 2021

@Odianosen25 Just rename run_fn_or_coro to run_async_sync_func? I can do it today.

@Odianosen25 Odianosen25 merged commit da7bb28 into AppDaemon:dev Jan 23, 2021
@Mithras Mithras deleted the mithras/check_constraint branch January 23, 2021 00:21
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.

4 participants