You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于python-dbus-next的DBus属性断言功能故障排查

问题描述

我基于python-dbus-next库开发DBus对象测试基础设施,想要实现如下形式的属性断言调用:

iface = await IFaceClient(bus_name, path, interface)
await iface.call_method('bla')
await iface.wait_property('bla_property').equal(30)

核心需求是通过wait_property监听指定属性,直到其值等于预期值。但当前实现存在问题:equal方法始终获取初始值None,无法感知回调中更新的属性值,即使属性从10→20→30变化,断言也无法识别。我试过用asyncio.Event结合同步回调,也考虑过Future但它只能生效一次,无法覆盖属性过渡状态的场景。

附当前实现代码片段:

接口中wait_property实现

def wait_property(self, prop_name):
    event = asyncio.Event()
    value = None
    
    def property_changed(prop):
        nonlocal value
        nonlocal event
        value = prop.get(prop_name)

    self._iface.on_property_changed(property_changed)
    return Comparer(event, value)

Comparer类实现

class Comparer:

    timeout = 10

    def __init__(self, event, value):
        self.event = event
        self.value = value

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

    async def _eq(self, expected):
        f = asyncio.get_event_loop().create_future()
        try:
            await self.event.wait()
            assert self.value == expected
            f.set_result(self.value)
        except AssertionError:
            self.event.clear()
        return await 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: {self.value} != {value}')
问题分析与修复方案

核心问题点

  1. Event从未被触发:property_changed回调仅更新了局部变量value,但未调用event.set(),导致await self.event.wait()永久阻塞,永远不会检查新值。
  2. 值引用不共享:Comparer初始化时接收的是value的初始值(None),回调更新的是wait_property函数内的局部变量,和Comparer实例的self.value完全无关,所以即使属性变化,Comparer拿到的还是初始值。
  3. 单次Event无法处理多次属性变更:即使触发了Event,后续属性变化不会重新触发检查,无法覆盖属性从10→20→30的过渡场景。

修复后的代码实现

修改wait_property方法

def wait_property(self, prop_name):
    comparer = Comparer(prop_name)
    
    def property_changed(props):
        # 每次属性变更时更新Comparer的当前值,并触发预期值检查
        comparer.current_value = props.get(prop_name)
        comparer._check_condition()

    self._iface.on_property_changed(property_changed)
    # 主动获取初始属性值,避免属性已为预期值时仍等待信号
    try:
        initial_props = self._iface.get_properties()
        comparer.current_value = initial_props.get(prop_name)
    except Exception:
        pass  # 处理初始值获取失败的场景
    return comparer

修改Comparer类

class Comparer:
    def __init__(self, prop_name):
        self.prop_name = prop_name
        self.current_value = None
        self.expected_value = None
        self.wait_future = None
        self.timeout = 10

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

    def _check_condition(self):
        # 若存在等待的Future且当前值符合预期,立即完成Future
        if self.wait_future and not self.wait_future.done():
            if self.current_value == self.expected_value:
                self.wait_future.set_result(self.current_value)

    async def equal(self, expected):
        self.expected_value = expected
        # 先检查当前值是否已满足预期,无需等待信号
        if self.current_value == expected:
            return self.current_value
        
        # 创建Future等待属性值符合预期
        self.wait_future = asyncio.get_event_loop().create_future()
        try:
            return await asyncio.wait_for(self.wait_future, timeout=self.timeout)
        except asyncio.TimeoutError:
            raise AssertionError(f"属性[{self.prop_name}]超时未达到预期值: 当前值={self.current_value}, 预期值={expected}")
        finally:
            # 清理Future,避免内存泄漏
            self.wait_future = None

修复说明

  • 移除冗余的Event:改用Future跟踪等待状态,每次属性变更时主动检查是否满足预期,满足则立即完成Future。
  • 共享属性值引用:让Comparer直接持有当前属性值,回调直接更新实例的current_value,确保值能实时同步。
  • 初始值预检查:创建Comparer时主动获取一次属性当前值,若已符合预期直接返回,提升效率。
  • 动态响应属性变更:每次属性变化都触发_check_condition,能处理属性多次变更的过渡场景,直到值符合预期或超时。

内容的提问来源于stack exchange,提问作者obs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 22:20:41