Jak wyświetlić listę wszystkich ścieżek obiektów w ramach usługi dbus?


16

To pytanie uzupełniające do Listy dostępnych usług DBus .

Poniższy kod python wyświetli listę wszystkich dostępnych usług DBus.

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

Jak wylistować ścieżki do obiektów w usługach w Pythonie? Jest ok, jeśli odpowiedź nie dotyczy Pythona, chociaż jest preferowana.

Używam Ubuntu 14.04


Jest ok, jeśli odpowiedź nie dotyczy Pythona, chociaż jest preferowana.
user768421

Odpowiedzi:


15

Zgodnie z oficjalnymi dokumentami (w standardowych interfejsach ):

Istnieje kilka standardowych interfejsów, które mogą być przydatne w różnych aplikacjach D-Bus.

org.freedesktop.DBus.Introspectable

Ten interfejs ma jedną metodę:

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

Instancje obiektów mogą implementować, Introspectktóra zwraca opis XML obiektu, w tym jego interfejsów (z sygnałami i metodami), obiektów pod nim w drzewie ścieżki obiektu i jego właściwości.

Oto więc bardzo uproszczony przykład, który powinien zacząć. Wykorzystuje xml.etree.ElementTreei 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')

Rekurencyjnie introspektuje, org.freedesktop.UPowerzaczynając od np. /org/freedesktop/UPowerI drukuje wszystkie ścieżki obiektów (nazwy węzłów):

/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

co jest prawie tym, co byś otrzymał, gdybyś go użył d-feet(nie żebyś go potrzebował):

wprowadź opis zdjęcia tutaj


Pewnie, możesz łatwo uzyskać ścieżki obiektu za pomocą wiersza poleceń, np. Za pomocą gdbus:

gdbus introspect --system --dest org.freedesktop.UPower --object-path \
/ org / freedesktop / UPower --recurse | awk '/ ^ * node / {print $ 2}'
/ 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

Nie qdbuszainstalowałem, ale zgodnie z tą stroną

qdbus --system org.freedesktop.UPower

powinien dać podobny wynik.


Jak utworzyć listę ścieżek obiektów rec_intro(bus, 'org.freedesktop.UPower', '/org/freedesktop/UPower')?
Khurshid Alam

Nie, mam na myśli utworzenie pytonowej listy ścieżek obiektów, aby móc sprawdzić (w moim skrypcie), czy na liście istnieje określona ścieżka obiektu. Drukuje ścieżkę obiektu w porządku., Ale chcę coś takiego k = rec_intro(bus, 'org.freedesktop.UPower', '/org/freedesktop/UPower'). Podejrzewam, że jest to możliwe poprzez nieznaczne zmodyfikowanie funkcji.
Khurshid Alam

Przykładowy kod z 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 - zainicjować listę zanim funkcja np mylist=[]następnie zastąpić printz mylist.appendczym jako ostatniego polecenia w tym bloku return mylist- to dość dużo, co jest ... można następnie iteracyjne nad listy lub cokolwiek np dodatku na dole skryptu for x in mylist: print("OBJ_PATH", x)wydrukować je z OBJ_PATHprefiksem ...
don_crissti 28.04.17

4

Nie jestem pewien, czy możesz to zrobić programowo w Pythonie. Być może, ale wymyślenie tego będzie ogromnym bólem głowy. Próbowałem to zrobić wcześniej i ostatecznie nienawidziłem Dbus. W każdym razie polecam używać d-stóp, jeśli chcesz zbadać różne rzeczy. Poniżej zrzut ekranu, który ukradłem z mojego bloga .

wprowadź opis zdjęcia tutaj

Gdy znasz nazwę programu, ścieżkę obiektu itp., Możesz użyć Pythona, aby uzyskać dostęp do tych rzeczy.

Przykład

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

Jak widzisz, trudno jest zrobić prostą rzecz. Ale to najłatwiejszy przepływ pracy, jaki można uzyskać dzięki Dbus!

Więc użyj narzędzia GUI, aby znaleźć ścieżki obiektu, interfejsy itp. Następnie użyj powyższego fragmentu kodu jako szablonu, aby uzyskać dostęp do tych rzeczy. Sugeruję również, abyś zrobił to za pomocą interpretera IPython, aby zobaczyć, jakie metody, właściwości itp. Ma każdy obiekt (po wciśnięciu klawisza).



1

To, co wiem z mojego doświadczenia, aby uzyskać ścieżki obiektu nazwy magistrali (usługi), umożliwia introspekcję ze ścieżką obiektu „/” tj. (Używając powyższego przykładu)

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

to powinno zwrócić:

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

następnie introspekcja ze ścieżką „/ org”

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

to powinno zwrócić:

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

i tak dalej:

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

To jest jak przejście przez strukturę folderów na dysku twardym, gdzie ścieżka obiektu „/” jest katalogiem głównym, a każdy węzeł jest podfolderem. Wydaje się to najlepszym sposobem na pobranie ścieżek obiektów konkretnej nazwy magistrali (usługi) i zbudowanie kolekcji zawierającej ścieżki obiektów


1

Zgodnie z odpowiedziami #don_crissti , zaimplementowałem, To rozwiązanie podaje nazwę interfejsu oraz informacje o metodzie i sygnałach

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)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.