Como listar todos os caminhos de objetos em um serviço dbus?

16

Esta é uma pergunta de acompanhamento para Uma lista de serviços DBus disponíveis .

O código python a seguir listará todos os serviços DBus disponíveis.

import dbus
for service in dbus.SystemBus().list_names():
    print(service)

Como listamos os caminhos de objetos nos serviços em python? Tudo bem se a resposta não envolver python, embora seja preferido.

Estou usando o Ubuntu 14.04

user768421
fonte
Tudo bem se a resposta não envolver python, embora seja preferido.
User768421 15/05

Respostas:

15

Conforme os documentos oficiais (em interfaces padrão ):

Existem algumas interfaces padrão que podem ser úteis em vários aplicativos D-Bus.

org.freedesktop.DBus.Introspectable

Essa interface possui um método:

org.freedesktop.DBus.Introspectable.Introspect (out STRING xml_data)

Podem ser implementadas instâncias de objetos Introspectque retornam uma descrição XML do objeto, incluindo suas interfaces (com sinais e métodos), objetos abaixo dele na árvore de caminhos do objeto e suas propriedades.

Então, aqui está um exemplo muito simplista que deve ajudá-lo a começar. Usa xml.etree.ElementTreee dbus:

#!/usr/bin/env python

import dbus
from xml.etree import ElementTree

def rec_intro(bus, service, object_path):
    print(object_path)
    obj = bus.get_object(service, object_path)
    iface = dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')
    xml_string = iface.Introspect()
    for child in ElementTree.fromstring(xml_string):
        if child.tag == 'node':
            if object_path == '/':
                object_path = ''
            new_path = '/'.join((object_path, child.attrib['name']))
            rec_intro(bus, service, new_path)

bus = dbus.SystemBus()
rec_intro(bus, 'org.freedesktop.UPower', '/org/freedesktop/UPower')

Introspecta recursivamente a org.freedesktop.UPowerpartir de, por exemplo, /org/freedesktop/UPowere imprime todos os caminhos de objetos (nomes de nós):

/org/freedesktop/UPower
/org/freedesktop/UPower/Wakeups
/org/freedesktop/UPower/devices
/org/freedesktop/UPower/devices/DisplayDevice
/org/freedesktop/UPower/devices/battery_BAT0
/org/freedesktop/UPower/devices/line_power_ADP0

que é praticamente o que você obteria se usasse d-feet(não que fosse necessário):

insira a descrição da imagem aqui


Claro, você pode facilmente obter os caminhos dos objetos via linha de comando, por exemplo, com gdbus:

introspect gdbus --system --dest org.freedesktop.UPower --object-path \
/ org / freedesktop / UPower --recurse | awk '/ ^ * node / {print $ 2}'
/ org / freedesktop / UPower
/ org / freedesktop / UPower / Despertar
/ org / freedesktop / UPower / devices
/ org / freedesktop / UPower / devices / DisplayDevice
/ org / freedesktop / UPower / devices / battery_BAT0
/ org / freedesktop / UPower / devices / line_power_ADP0

Não tenho qdbusinstalado, mas de acordo com esta página

qdbus --system org.freedesktop.UPower

deve produzir um resultado semelhante.

don_crissti
fonte
Como crio uma lista de caminhos de objetos rec_intro(bus, 'org.freedesktop.UPower', '/org/freedesktop/UPower')?
Khurshid Alam
Não, quero dizer criar uma lista python de caminhos de objetos, para que eu possa verificar (no meu script) se existe algum caminho específico na lista. Ele imprime o caminho do objeto certo., Mas eu quero algo parecido k = rec_intro(bus, 'org.freedesktop.UPower', '/org/freedesktop/UPower'). Suponho que seja possível modificando um pouco a função.
Khurshid Alam
Exemplo de código com qbus:bus = dbus.SessionBus()..... obj_path = '/org/gnome/Gnote/RemoteControl'.......... cmd = 'qdbus org.gnome.Gnote'......... while obj_path not in ((subprocess.check_output(cmd, shell=True)).decode("utf-8")).split("\n"): ........pass
Khurshid Alam
@KhurshidAlam - inicialize uma lista antes da função, por exemplo mylist=[], substitua printpor mylist.appende, em seguida, como o último comando nesse bloco de funções return mylist- é praticamente o que existe ... você pode iterar sobre a lista ou qualquer outra coisa, por exemplo, adicionar na parte inferior do script for x in mylist: print("OBJ_PATH", x)para tê-los impressos com um OBJ_PATHprefixo ...
don_crissti
4

Não tenho certeza se você pode fazer isso programaticamente em Python. Você pode, mas será uma enorme dor de cabeça para descobrir como. Eu tentei fazer isso antes e acabei odiando o Dbus. De qualquer forma, eu recomendo usar d-feet se você quiser investigar as coisas. Abaixo está uma captura de tela que eu roubei do meu blog .

insira a descrição da imagem aqui

Depois de saber o nome do programa, o caminho do objeto etc., você poderá usar o Python para acessar essas coisas.

Exemplo

progname = 'org.freedesktop.NetworkManager'
objpath  = '/org/freedesktop/NetworkManager'
intfname = 'org.freedesktop.NetworkManager'
methname = 'GetDevices'

bus = dbus.SystemBus()

obj  = bus.get_object(progname, objpath)  # Here we get object
intf = dbus.Interface(obj, intfname)      # Here we get interface
meth = inf.get_dbus_method(methname)      # Here we get method

meth()                                    # And finally calling the method

Como você vê, é uma dor de cabeça fazer uma coisa simples. Mas este é o fluxo de trabalho mais fácil que você pode obter com o Dbus!

Portanto, use uma ferramenta da GUI para descobrir os caminhos do objeto, interfaces, etc. Em seguida, use o snippet de código acima como modelo para acessar essas coisas. Também sugiro que você faça isso através do intérprete do IPython para ver quais métodos, propriedades, etc. cada objeto possui (pressionando a guia).

Pithikos
fonte
1

O que sei da minha experiência para obter os caminhos de objetos de um nome de barramento (serviço), é possível fazer uma introspecção com o caminho de objeto '/' ou seja, (usando o exemplo acima)

introspectfunc('org.freedesktop.UPower', '/') 

isso deve retornar:

<node name="/"> 
<node name="org"/>
<node name="org"/>
<node name="org"/>
<node name="org"/>
<node name="org"/>
<node name="org"/></node>

em seguida, verifique com o caminho '/ org'

introspectfunc('org.freedesktop.UPower', '/org')

isso deve retornar:

<node name="/org"> 
<node name="freedesktop"/>
<node name="freedesktop"/>
<node name="freedesktop"/>
<node name="freedesktop"/>
<node name="freedesktop"/>
<node name="freedesktop"/></node>

e assim por diante:

introspectfunc('org.freedesktop.UPower', '/org/freedesktop')
introspectfunc('org.freedesktop.UPower', '/org/freedesktop/UPower')
etc.

É como passar pela estrutura de pastas do disco rígido, onde o caminho do objeto '/' é a raiz e todos os nós são subpastas. Essa parece a melhor maneira de recuperar os caminhos do objeto de um nome de barramento (serviço) específico e construir uma coleção que contém os caminhos do objeto

qnbibiqn
fonte
1

Conforme as respostas #don_crissti , implementei, esta solução fornece o nome da interface e o método e sinaliza informações

import dbus
from xml.etree import ElementTree
bus = dbus.SystemBus()

def busNames():
    return [ name for name in  bus.list_names() if not name.startswith(":") ]


def pathNames(service,object_path="/",paths=None,serviceDict=None):
    if paths == None:
        paths = {}
    paths[object_path] = {}
    obj = bus.get_object(service, object_path)
    iface = dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')
    xml_string = iface.Introspect()
    root = ElementTree.fromstring(xml_string)
    for child in root:
        if child.tag == 'node':
            if object_path == '/':
                    object_path = ''
            new_path = '/'.join((object_path, child.attrib['name']))
            pathNames(service, new_path,paths)
        else:
            if object_path == "":
                object_path = "/"
            functiondict = {}
            paths[object_path][child.attrib["name"]] = functiondict
            for func in child.getchildren():
                if func.tag not in functiondict.keys():
                    functiondict[func.tag] =[]
                functiondict[func.tag].append(func.attrib["name"])
    if serviceDict == None:
        serviceDict = {}
    serviceDict[service] = paths
    return serviceDict



import json
import random
service=random.sample(busNames(),1).pop()
print service
print json.dumps(pathNames(service),indent=3)
Reegan Miranda
fonte