"将值转换为正确包装的dbus-python对象"
项目描述
将存在于核心Python类型(例如,列表、整数、字典)中的对象转换为基于指定dbus签名的存在于dbus-python类型(例如,dbus.Array、dbus.UInt32、dbus.Dictionary)中的对象的工具。
动机
dbus-python库是libdbus的Python绑定库。它不提供确保客户端代码放置在D-Bus上的值类型符合所需签名的功能。客户端代码可能是一个D-Bus服务,因此它放置在D-Bus上的值应符合它指定的签名,或者在某些情况下,是服务的客户端,它必须符合服务的规范。
如果一个服务在其对象上实现了Introspectable接口,dbus-python将使用签名信息将客户端消息转换成正确的dbus类型。如果Introspectable接口不可用,dbus-python将通过递归检查参数的值来猜测签名,然后继续之前的操作。如果签名包含一个‘v’,表示变体类型,dbus-python必须猜测相应值的类型。可以通过将适当方法中的introspect参数设置为false来指示dbus-python不使用dbus introspection。
此库提供了一种确保放置在D-Bus上的值符合给定签名的机制,通过将这些值封装在相应签名的构造函数中来实现的。它为任何有效的签名生成正确的函数。
使用和实现提示
库的使用相当简单
>>> from into_dbus_python import xformers >>> funcs = xformers("adq") >>> len(funcs) 2
请注意,函数列表的长度与签名中完整类型的数量相同。函数列表中的每个元素都是一个元组。
>>> funcs[0] (<function ToDbusXformer._handleArray.<locals>.the_func at 0x7f4542f2d730>, 'ad')
第一个元素是该函数本身,第二个是一个字符串,与函数产生的正确类型签名相匹配。应用此函数会产生实际值
>>> funcs[0][0]([2.3, 37.5]) (dbus.Array([dbus.Double(2.3), dbus.Double(37.5)], signature=dbus.Signature('d')), 0)
在这个例子中,签名是“ad”,所以产生的值是dbus.Double对象的dbus.Array。签名参数具有适当的值;它只是“d”,表示数组中元素类型的符号,即double。请注意,该函数还产生一个元组,转换的值和一个int,表示变体级别。由于签名中没有“v”,变体级别为0。
如果传递了无效的参数,生成的函数将失败并抛出IntoDPError。
>>> try: ... funcs[0][0](True) ... except IntoDPError as err: ... print("bad arg") ... bad arg
如果任何函数抛出的异常不是IntoDPError的子类型,则这构成一个bug,并且不是公共API的一部分。
便利性
解析器本身返回一个元组列表,其中通常只有元组中的第一个元素对客户端感兴趣。第二个元素,匹配的字符串,是递归实现的必要结果,但通常对客户端没有太大用处。生成的函数每个都返回一个包含转换值和变体级别的元组,通常只有转换值对客户端感兴趣。
因此,库提供了一个便利函数xformer(),它接受一个签名并返回一个函数,该函数接受一个对象列表,并返回一个列表,将其转换为适当的dbus类型。它可以如下使用
>>> from into_dbus_python import xformer >>> func = xformer("adq") >>> func([[2.3, 34.0], 3]) [dbus.Array([dbus.Double(2.3), dbus.Double(34.0)], signature=dbus.Signature('d')), dbus.UInt16(3)]
请注意,该函数必须接受一个值列表,每个值对应于签名中的每个完整类型。这里,有两个完整类型“ad”和“q”,有两个结果值。
如果签名包含一个“v”,表示变体类型,则值必须是一个签名和值的对,该值存在于该类型中。例如,
>>> func = xformer("v") >>> func([("aq", [0, 1])]) [dbus.Array([dbus.UInt16(0), dbus.UInt16(1)], signature=dbus.Signature('q'), variant_level=1)]
请注意,构造的Array对象的变体级别为1。在dbus对象中,非零的变体级别表示该对象是一个变体。在这个例子中,变体级别只是1。变体的进一步嵌套是允许的,变体级别在每个级别上增加1。
>>> func([("av", [("q", 0)])]) [dbus.Array([dbus.UInt16(0, variant_level=1)], signature=dbus.Signature('v'), variant_level=2)]
这里,数组中变体元素的变体级别为0,但整个数组的变体级别为2,因为数组包含一个变体元素,并且居住在一个变体类型中。
核心类型的限制
生成的函数对要转换的值的类型施加尽可能少的限制。一般来说,元组与列表一样好,因为两者都是可迭代的。
>>> func = xformer("adq") >>> func([(2.3, 34.0), 3]) [dbus.Array([dbus.Double(2.3), dbus.Double(34.0)], signature=dbus.Signature('d')), dbus.UInt16(3)]
但是,dbus.Dictionary类型的居住者必须是一个具有items()方法的对象,该方法产生键和值的对,例如字典。
签名()函数
这个库还公开了一个函数,signature(),它接受一个dbus-python类型中的值,计算其签名。它与xformer()函数有以下关系。
令S为一个签名。令C为Python核心类型中的值列表。令V = xformer(S)(C)。那么" "".join(signature(v) for v in V) 等于S。
技术说明
此软件包通过使用setParseAction()方法向各个解析器添加动作,扩展了在dbus-signature-pyparsing软件包中实现的dbus签名解析器(https://github.com/stratis-storage/dbus-signature-pyparsing)。
该软件包已使用Hypothesis测试库(http://hypothesis.works/)和hs-dbus-signature软件包中实现的外部Hypothesis策略进行了大量测试(https://github.com/stratis-storage/hs-dbus-signature)。
对于下游打包者,如果将测试纳入其打包,建议只使用test_deterministic.py模块中的测试,以避免由于Hypothesis测试的非确定性行为而可能出现的测试失败。
项目详情
下载文件
下载适合您平台的应用程序。如果您不确定选择哪个,请了解有关安装包的更多信息。