starenka
starenka

Reputation: 580

dbus-python how to get response with native types?

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

Answers (4)

Florent Thiery
Florent Thiery

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

ugmurthy
ugmurthy

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

jfs
jfs

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))

Output

{
  "MinimumRate": 14, 
  "CanGoNext": 1, 
  "CanPause": 0
}

It looses information about types.

Upvotes: 1

Martin Vidner
Martin Vidner

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

Related Questions