@saw_tooth

Как вернуть значения из синхронного колбека в corotine несколько раз?

Нужно реализовать удобний интерфейс асертинга значений dbus библиотеки
iface = await IFaceClient(bus_name, path, interface)
await iface.call_method('bla')
await iface.wait_property('bla_property').equal(30)

сама библиотека возвращает проперти велью как значение колбека
...interface initialisation....

    def _prop_change(prop: dict):
        print(f'Property changed dict')

    interface.on_property_changed(_prop_change)

Пробовал event/future/queue возвращать в корутину через подписку на колбек, но каждий раз вижу что внутри корутини состояние об'екта разнится и очередь (в данном случае) всегда пуста
def wait_property(self, prop_name):
        q = asyncio.Queue(10)
        comp = Comparer(q)

        def property_changed(prop):
            q.put_nowait(prop.get(prop_name))
            print(f'callback: {q.qsize()}') #<- тут все будет правильно

        self._iface.on_property_changed(property_changed)
        return comp

lass Comparer:

    timeout = 5

    def __init__(self, q):
        self.q = q

    def until(self, t):
        self.timeout = t
        return self

    async def _eq(self, expected):
        f = asyncio.get_event_loop().create_future()
        while True:
            try:
                value = await self.q.get() #<- тут будем ожидать бесконечно потому что очередь пуста
                print(f'item: {value}')
                assert value == expected
                f.set_result(value)
                break
            except AssertionError:
                await asyncio.sleep(0)
            self.q.task_done()
        return f

    async def equal(self, value):
        try:
            return await asyncio.wait_for(self._eq(value), timeout=self.timeout)
        except asyncio.TimeoutError:
            raise AssertionError(f'Values isn`t equal: {await self.q.get()} != {value}')


Нужна подсказка, как из call-back домена перейти з асинхронний
  • Вопрос задан
  • 156 просмотров
Пригласить эксперта
Ответы на вопрос 2
Vindicar
@Vindicar
RTFM!
Я вижу два потенциальных источника проблем.
1. Ты говоришь, что библиотека будет дёргать callback при изменении значения свойства. А когда она будет это делать?
Ей ведь нужно выполнить для этого какой-то код, причём наверняка синхронный. Пусть какой-то метод, который проверит очередь событий, извлечёт оттуда новые и дёрнет соответствующие callbak'и. Этот код точно вызывается?
2. Ты делаешь await iface.call_method('bla'). Ты уверен, что обновление свойства произойдёт после завершения await? Если оно произойдёт до, то твой вызов wait_property() не увидит обновлений. Возможно, стоит вешать callback до вызова call_method()?
Ответ написан
Комментировать
@saw_tooth Автор вопроса
1. Я может не верно выразился: колбек-хендлер вызывается тогда, когда приходит сигнал о изменении какого-то проперти, и собственно `prop` является тем самым проперти, которое изменилось (key:value)
def property_changed(prop):
            q.put_nowait(prop.get(prop_name))
            print(f'callback: {q.qsize()}')

2. Да, я уверен, посути вызов метода это "неждущая" процедура (под капотом там очередь сообщений и сама отсылка не ждущая) но реализаторы решили наружу выставить этот интерфейс, я так же уверен что перехватываю проперти чендж сигнал так как я вижу принты в хендлере и то как увеличивается размер очереди, но в корутине - она пуста

У меня есть подозрение на неверный контект выполнения, но я не знаю как это можно решить
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы