Reputation: 580
I'm playing with dbus-python and I need to get the reponses (f.e dbus.Dictionary - but generally any response) as native Python type. Yes, one can write recursive converter but I think I must have been missing something obvious? There must be a way how to convert these monstrosities back to Python native types using dbus. Or it is not?
dbus.Dictionary({dbus.String(u'CanGoNext'): dbus.Boolean(True, variant_level=1), dbus.String(u'CanPause'): dbus.String(u'MinimumRate'): dbus.Int32(14, variant_level=1) ...
Upvotes: 6
Views: 3596
Reputation: 389
While Martin is right, it doesn't work with booleans which are casted to int by python (since bool cannot be subclassed).
In [3]: print(dbus.Boolean(False))
0
Unfortunately, a recursive converter is the only way to preserve booleans.
Here is an example implementation:
import dbus
def python_to_dbus(data):
'''
convert python data types to dbus data types
'''
if isinstance(data, str):
data = dbus.String(data)
elif isinstance(data, bool):
# python bools are also ints, order is important !
data = dbus.Boolean(data)
elif isinstance(data, int):
data = dbus.Int64(data)
elif isinstance(data, float):
data = dbus.Double(data)
elif isinstance(data, list):
data = dbus.Array([python_to_dbus(value) for value in data], signature='v')
elif isinstance(data, dict):
data = dbus.Dictionary(data, signature='sv')
for key in data.keys():
data[key] = python_to_dbus(data[key])
return data
def dbus_to_python(data):
'''
convert dbus data types to python native data types
'''
if isinstance(data, dbus.String):
data = str(data)
elif isinstance(data, dbus.Boolean):
data = bool(data)
elif isinstance(data, dbus.Int64):
data = int(data)
elif isinstance(data, dbus.Double):
data = float(data)
elif isinstance(data, dbus.Array):
data = [dbus_to_python(value) for value in data]
elif isinstance(data, dbus.Dictionary):
new_data = dict()
for key in data.keys():
new_data[dbus_to_python(key)] = dbus_to_python(data[key])
data = new_data
return data
To make it easier to use in a class that processes dbus-originating data, you can use a decorator:
def convert_to_python(func):
def wrapper(*args, **kwargs):
return dbus_to_python(func(*args, **kwargs))
return wrapper
...
@convert_to_python
def dbus_method_call(self):
return self.dbus_proxy.Method()
That way, any data returned by dbus_method_call above will be converted to native python.
See this related question: dbus Variant: How to preserve boolean datatype in Python?
Upvotes: 3
Reputation: 59
florent-thiery's code above was useful for converting from dbus type to python native type and vice-versa. However it required a small change in the
dbus_to_python
as under:
elif isinstance(data, dbus.Dictionary):
new_data = dict()
for key in data.keys():
# key below is a dbus type and needs coversion
# before using it in the dict as key
pkey = dbus_to_python(key)
new_data[pkey] = dbus_to_python(data[key])
data = new_data
Upvotes: 0
Reputation: 414875
In your code you don't need to do anything to use them as @Martin Vidner said.
To pretty print you could use an existing "recursive converter" such as json
:
import json
print(json.dumps(d, indent=2))
{
"MinimumRate": 14,
"CanGoNext": 1,
"CanPause": 0
}
It looses information about types.
Upvotes: 1
Reputation: 2337
You don't need to. They are subclasses of the native types, so you just use them as if they were native types:
>>> import dbus
>>> v = dbus.Dictionary({dbus.String(u'CanGoNext'): dbus.Boolean(True, variant_level=1), dbus.String(u'CanPause'): dbus.Boolean(False, variant_level=1), dbus.String(u'MinimumRate'): dbus.Int32(14, variant_level=1)})
>>> print v['MinimumRate']
14
>>> if v['CanGoNext']: print 'Go'
...
Go
>>> if v['CanPause']: print 'Pause'
...
>>>
Upvotes: 1