dbus-python 指南
- 2020 年 1 月 6 日
- 筆記
dbus-python 指南
This tutorial requires Python 2.4 or up, and dbus-python 0.80rc4 or up.
指南需要:Python 2.4 或更高的版本, dbus-python 0,80rc4或更高的版本
Connecting to the Bus (連接Bus) Making method calls (製造一個方法調用) Proxy objects (代理對像) interfaces and methods (介面和方法) See also Data types (數據類型) Basic types (基本類型) Basic type conversions (基本類型約定) Container types (容器類型) Return values, and the byte_arrays and utf8_strings options (返回值, byte_arrays 和 utf8_strings 選項) Making asynchronous method calls (使用非同步方法調用) Setting up an event loop (設置事件循環) Backwards compatibility: dbus.glib (向後兼容: dbus.glib) The Qt main loop (Qt main loop) Making asynchronous calls (創建非同步調用) See also Receiving signals (接收訊號) Signal matching (匹配訊號) Getting more information from a signal (從訊號中獲取更多資訊) String argument matching (匹配字元串參數) Receiviing signals from a proxy object (接收來自 proxy 對象的訊號) See also Claiming a bus name (聲名一個 bus name) The unique-instance idiom Exporting objects (導出對象) Inheriting from dbus.service.Object (繼承 dbus.service.Object) Exporting methods with dbus.service.method (使用 dbus.service.method 導出方法) Finding out the caller's bus name Asynchronous method implementations (非同步方法的實現) Emitting signals with dbus.service.signal Example License for this document
Connecting to the Bus (連接Bus)
使用 D-Bus 的應用程式常常連接到一個 bus 服務上,這個服務在應用程式之間傳遞消息。想要使用 D-Bus ,你需要創建一個 Bus 對象來代表一個到 bus 服務的連接。
import dbus session_bus = dbus.SessionBus()
import dbus system_bus = dbus.SystemBus()
Of course, you can connect to both in the same application.
Making method calls (製造一個方法調用)
D-Bus 應用程式能夠輸出對象讓其它應用使用。為了能夠使用另一個應用程式提供的對象,你需要知道:
- The bus name. This identifies which application you want to communicate with. You'll usually identify applications by a well-known name, which is a dot-separated string starting with a reversed domain name, such as org.freedesktop.NetworkManager or com.example.WordProcessor. bus名稱(bus name)。它標識著你想與哪個應用程式進行通訊。你會常常通過眾所周知的名稱(well-known name)來標識一個應用程式,它是反轉域名後用 `.' 分割的字元串,例如: org.freedesktop.NetworkManager 或 com.example.WordProcessor。
- The object path. Applications can export many object – for instance, example.com's word processor might provide an object representing the word processor application itself and an object for each document window opened, or it might also provide an object for each paragraph within a document. 對象路徑(object path)。應用程式可以輸出很多對象,例如, example.com 的文字處理進程會提供一個代表文字處理進程自身對象,還會為每一個打開的文檔窗口都提供一個對象。或者它還可以為一個文檔的每一段都提供一個對象。 To identify which one you want to interact with, you use an object path, a slash-separated string resembling a filename. For instance, example.com's word processor might provide an object at / representing the word processor itself, and objects at /documents /123 and /documents/345 representing opened document windows. 為了標識你想與誰通訊,你需要使用對象路徑(object path),它是一個用 `/' 分割的字元串,就像文件名一樣。例如, example.com 的文字處理進程會提供一個對像 `/' ,它代表文字進程自身, 和代其它已打開文檔窗口的對象,/documents/123 和 /document/345 。
就像你期望的,你可以通過遠程對象做的最主要的事情之一就是調用它們的方法。就像在 Python 中,方法有一些參數,它們會返回一個或多個值。
Proxy objects (代理對像)
import dbus bus = dbus.SystemBus() proxy = bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager/Devices/eth0') # proxy is a dbus.proxies.ProxyObject
interfaces and methods (介面和方法)
為了調用一個方法,在 proxy object 上調用同樣名稱的方法,通過 dbus_interface 關鍵詞參數傳遞介面的名稱。
import dbus bus = dbus.SystemBus() eth0 = bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager/Devices/eth0') props = eth0.getProperties(dbus_interface='org.freedesktop.NetworkManager.Devices') # props is a tuple of properties, the first of which is the object path
如果你要用同樣的介面調用很多的方法,作為一個快捷的辦法,你可構造一個 dbus.Interface 對像,然後在它上面調用方法,而不需要再次指定介面:
import dbus bus = dbus.SystemBus() eth0 = bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager/Devices/eth0') eth0_dev_iface = dbus.Interface(eth0, dbus_interface='org.freedesktop.NetworkManager.Devices') props = eth0_dev_iface.getProperties() # props is the same as before
See also
參考 examples/example-client.py 中的例子。在運行它之前,你需要在後台或在另一個 shell 中運行 examples/example-service.py。
Data types (數據類型)
不像 Python , D-Bus 是靜態類型 (statically typed) – 每一個方法都有一個代表它們參數類型的標識,並且不接受其它類型的參數。
Basic types (基本類型)
The following basic data types are supported.
Python type |
converted to D-Bus type |
notes |
---|---|---|
unicode or subclass |
string ('s') |
|
D-Bus proxy object |
ObjectPath (signature 'o') |
(+) |
dbus.Interface |
ObjectPath (signature 'o') |
(+) |
dbus.service.Object |
ObjectPath (signature 'o') |
(+) |
dbus.Boolean |
Boolean (signature 'b') |
a subcalss of int |
dbus.Byte |
byte (signature 'y') |
a subclass of int |
dbus.Int16 |
16-bit signed integer ('n') |
a subclass of int |
dbus.Int32 |
32-bit signed integer ('i') |
a subclass of int |
dbus.Int64 |
64-bit signed integer ('x') |
(*) |
dbus.Uint16 |
16-bit unsigned integer ('q') |
a subclass of int |
dbus.Uint32 |
32-bit unsigned integer ('u') |
(*) |
dbus.Uint64 |
64-bit unsigned integer ('t') |
(*) |
dbus.Double |
double-precision float ('d') |
a subclass of float |
dbus.ObjectPath |
object path ('o') |
a subclass of str |
dbus.Signature |
signature ('g') |
a subclass of str |
dbus.String |
string ('s') |
a subclass of unicode |
dbus.UTF*String |
string ('s') |
a subclass of str |
bool |
Boolean ('b') |
|
int or subclass |
32-bit signed inter ('i') |
|
long or subclass |
64-bit signed integer ('x') |
|
float or subclass |
double-precision float ('d') |
|
str or subclass |
string ('s') |
must be valid UTF-8 |
Types marked (*
) may be a subclass of either int or long, depending on platform.
標記為(*
)的類型是 int 或 long 的子類,平台相關。
Basic type conversions (基本類型約定)
If introspection succeeded, dbus-python will also accept:
如果 introspection 成功, dbus-python 將接受:
- for Boolean parameters, any object (converted as if via int(bool(…))) 對於 Boolean 參數,任何 object (被轉換通過 int(bool(…)))
- for byte parameters, a single-character string (converted as if via ord()) 對於 byte 參數,一個單字元串 (single-character string) (被轉換通過 ord())
- for byte and integer parameters, any integer (must be in the correct range) 對於 byte 和 integer 參數,任何 integer (必須在正確的範圍內)
- for object-path and signature parameters, any str or unicode subclass (the value must follow the appropriate syntax) 對於 object-path 和 signature 參數,任何 str 或 unicode subclass (必須有適當的語義)
Container types (容器類型)
一個數組的標識是 'ax' ,這裡的 'x' 代表一個元素的標識。例如,你可以使用 'as' (字元串數組) 或 'a(ii)' (包含兩個 32-bit 整數的結構體數組)
dbus.ByteArray是一個字元字元串的子類,被用開更有效率的代表 D-Bus的位元組數組 (標識 'ay')。
由內容的標識的構成的結構體的標識在括弧里 – 例如, '(is)' 是一個包含一個 32-bit 整數和字元串的標識。
變體 (variants) … (不會翻)。如果 non-variant 作為一個參數被傳遞,但 introspection 指示期望一個 variant ,它將會自動的包在一個變體中。
The signature of a variant is 'v'.
Return values, and the byte_arrays and utf8_strings options (返回值, byte_arrays 和 utf8_strings 選項)
If a D-Bus method returns no value, the Python proxy method will return None.
如果 D-Bus 方法沒有返回值,那麼 Python 代理方法將會返回 None.
如果 D-Bus 方法返回多個值,那麼 Python 代理方法會返回一個元組包含這些值。
如果你想要字元串作為 dbus.UTF8String (str 的子類) 傳遞關鍵詞參數 utf8_strings=True 到代理方法。
如果你要位元組數組作為 dbus.ByteArray (也是 str 的子類 – 實踐中,它常常是你想要的)傳遞關鍵詞參數 byte_arrays=True 到代理方法。
Making asynchronous method calls (使用非同步方法調用)
非同步(非阻塞)方法調用允許同時有多個方法正在調用,允許你的應用在等待結果的時候可以做一些其它的工作。為了使用非同步調用,你首先需要一個事件循環或 "main loop"。
Setting up an event loop (設置事件循環)
Currently, the only main loop supported by dbus-python is GLib.
目前,dbus-python 唯一支援的 main loop 是 GLib 。
dbus-python 有一個全局默認的 main loop ,它是使用這個功能最容易的方法。把 GLib main loop 設置為默認,使用:
from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True)
You must do this before connecting to the bus.
Actually starting the main loop is as usual for pygobject:
實際上常常為 pygobject 啟動 main loop。
import gobject loop = gobject.MainLoop() loop.run()
當 loop.run() 在運行, GLib 將會在適當的時候運行你的回調函數。調用 loop.quit() 停止。
你可以在每一個連接的基礎上設置一個 main loop,通過傳遞一個 main loop 到 Bus 構造函數。
import dbus from dbus.mainloop.glib import DBusGMainLoop dbus_loop = DBusGMainLoop() bus = dbus.SessionBus(mainloop=dbus_loop)
This isn't very useful until we support more than one main loop, though.
Backwards compatibility: dbus.glib (向後兼容: dbus.glib)
In versions of dbus-python prior to 0.80, the way to set GLib as the default main loop was:
在 dbus-python 0.80 之前的版本里,設置 GLib 作為默認 main loop 的方法是:
執行那個 import 語句將會自動的載入 GLib main loop 並設置它為默認。不贊成使用它,因為它是高不可見的,但是如果你想寫或者理解向後兼容的程式碼是有用的。
The Qt main loop (Qt main loop)
Making asynchronous calls (創建非同步調用)
- the reply_handler will be called with the method's return values as arguments; or reply_handler 將會被調用,它的參數是上面方法的返回值。
- the error_handler will be called with one argument, an instance of DBusException representing a remote exception. error_handler 將被調用,它的參數是一個代表遠程異常的 DBusException 的一個實例。
See also
Receiving signals (接收訊號)
為了收到一個訊號,Bus 需要被連接到一個事件循環 – 參考設置事件循環那章。訊號只在事件循環運行的時候才能收到。
Signal matching (匹配訊號)
為了對資訊產生響應,你要在 Bus object 上使用 add_signal_receiver 方法。當一個匹配的訊號收到後,安排好的回調函數將被調用,傳入以後參數:
- a callable (the handler_function) which will be called by the event loop when the signal is received – its parameters will be the arguments of the signal 當收到訊號時,一個可調函數 (callable) (the handler_fucntion) 將會被事件循環調用 – 它的參數是資訊的參數。
- the signal name, signal_name: here None (the default) matches all names 訊號名稱,signal_name: 這裡為 None (默認) 則匹配所有名稱。
- the D-Bus interface, dbus_interface: again None is the default, and matches all interfaces D-Bus 介面, dbus_interface: None 是默認的,匹配所有介面。
- a sender bus name (well-known or unique), bus_name: None is again the default, and matches all senders. Well-known names match signals from whatever application is currently the primary owner of that well-known name. 發送者的 bus 名稱 (well-known 或 unique),bus_name: None是默認的,匹配所有發送者。Well-known 名稱匹配來自當前擁有那個 well-known 名稱的應用程式的訊號,無論應用程式是誰。
- a sender object path, path: once again None is the default and matches all object paths 一個發送者的 object path,path: None 是默認的,匹配所有 object paths,
add_signal_receiver 返回一個 SignalMatch 對像。目前,它唯一有用的公共 API 是一個沒有參數移除方法,它用來移除從連接上匹配的連接。
Getting more information from a signal (從訊號中獲取更多資訊)
def handler(sender=None): print "got signal from %r" % sender iface.connect_to_signal("Hello", handler, sender_keyword='sender')
一個來自 com.example.Foo 的沒有參數的 Hello 訊號將會被收到,處理函數將會被調用,它的參數 sender='com.example.Foo'。
String argument matching (匹配字元串參數)
如果有關鍵詞的格式是 argn,其中 n 是一個小的非負數,它們的值必須是 unicode 對象 或 UTF-8 字元串。(後面理不清)
Receiviing signals from a proxy object (接收來自 proxy 對象的訊號)
Proxy 對象有一個特殊的方法 connect_to_signal ,當收到一個來自相應遠程對象的訊號時, connect_to_signal 將安排一個回調函數被調用。
- the name of the signal 訊號名稱
- a callable (the handler function) which will be called by the event loop when the signal is received – its parameters will be the arguments of the signal 當收到訊號時,一個可調函數 (callable) (the handler_fucntion) 將會被事件循環調用 – 它的參數是資訊的參數。
- the handler function, a callable: the same as for add_signal_receiver 處理函數 (callable): 與 add_signal_receiver 相同
- the keyword argument dbus_interface qualifies the name with its interface 關鍵詞參數 dbus_interface 限定介面的名稱。
dbus.Interface 對象有一個相似的 connect_to_signal 方法,但這種情況下,你不需要 dbus_interface 關鍵詞參數,因為使用的介面已經知道了。
對於 add_signal_receiver 而言,同樣的關鍵詞參數也是可用的,就像 add_signal_receiver , 它返回一個 SignalMatch 。
你不應該只用 proxy 對象來監聽訊號,因為當他們創建的時候也許會激活相關的服務,但如果你為了調用方法已經有一個 proxy 對象,使用它添加訊號匹配常常很方便。
See also
Claiming a bus name (聲名一個 bus name)
FIXME describe BusName – perhaps fix its API first?
The unique-instance idiom
FIXME provide exemplary code, put it in examples
Exporting objects (導出對象)
在 D-Bus 上讓另外一個應用程式可用的對像稱作導出 (exported)。所有的 dbus.service.Object 的子類是自動被 exported。
為了 export 對象, Bus 需要連接到事件循環 – 參考設置事件循環那章。只有在事件循環運行時,導出方法也才會被調用,隊列中的訊號才會被傳遞。
Inheriting from dbus.service.Object (繼承 dbus.service.Object)
class Example(dbus.service.Object): def __init__(self, object_path): dbus.service.Object.__init__(self, dbus.SessionBus(), path)
這個對象會自動支援 introspection ,但不做任何特別的事情。為了修正它,你需要導出一些方法和訊號。
FIXME also mention dbus.gobject.ExportedGObject once I've written it
Exporting methods with dbus.service.method (使用 dbus.service.method 導出方法)
To export a method, use the decorator dbus.service.method. For example:
為了導出方法,使用 dbus.service.method 操作,例如:
class Example(dbus.service.Object): def __init__(self, object_path): dbus.service.Object.__init__(self, dbus.SessionBus(), path) @dbus.service.method(dbus_interface='com.example.Sample', in_signature='v', out_signature='s') def StringifyVariant(self, variant): return str(variant)
The in_signature and out_signature are D-Bus signature strings as described in Data Types.
in_signature 和 out_signature 是 D-Bus 的標識字元串,描述數據的類型。
你可以找到一個簡單的例子 examples/example-service.py ,我們先前用來它來示範 examples/example-client.py 。
Finding out the caller's bus name
方法描述接受 sender_keyword 關鍵詞參數。如果你把它設置為一個字元串,發送者的唯一 bus 名稱將作為一個關鍵詞參數傳遞到描述方法。
class Example(dbus.service.Object): def __init__(self, object_path): dbus.service.Object.__init__(self, dbus.SessionBus(), path) @dbus.service.method(dbus_interface='com.example.Sample', in_signature='', out_signature='s', sender_keyword='sender') def SayHello(self, sender=None): return 'Hello, %s!' % sender # -> something like 'Hello, :1.1!'
Asynchronous method implementations (非同步方法的實現)
FIXME and also add an example, perhaps examples/example-async-service.py
Emitting signals with dbus.service.signal
class Example(dbus.service.Object): def __init__(self, object_path): dbus.service.Object.__init__(self, dbus.SessionBus(), path) @dbus.service.signal(dbus_interface='com.example.Sample', signature='us') def NumberOfBottlesChanged(self, number, contents): print "%d bottles of %s on the wall" % (number, contents) e = Example('/bottle-counter') e.NumberOfBottlesChanged(100, 'beer') # -> emits com.example.Sample.NumberOfBottlesChanged(100, 'beer') # and prints "100 bottles of beer on the wall"
Example
當發送訊號的方法之一被調用, examples/example-signal-emitter.py 會按要求發送一些訊號。
License for this document
Copyright 2006-2007 Collabora Ltd.