dbus-python的API及示例

摘要:
youuseaproxyobject.proxy=bus.get_object('org.freedesktop.NetworkManager',#Call eth0_dev_iface=dbus.Interface(proxy,

目录

Tutorial

API

1. Data types

Unlike Python, D-Bus is statically typed - each method has a certain signature representing the types of its arguments, and will not accept arguments of other types.

具体内容详见官网教程,此处不再赘述。

2. Connecting to the Bus

import dbus
session_bus = dbus.SessionBus()
system_bus = dbus.SystemBus()

3. Making method calls (同步调用)

  1. The bus name.
    This identifies which application you want to communicate with.

  2. The object path.
    To identify which one you want to interact with, you use an object path.

3.1. Proxy objects

To interact with a remote object, you use a proxy object.

proxy = bus.get_object('org.freedesktop.NetworkManager',
                       '/org/freedesktop/NetworkManager/Devices/0')

3.2. Interfaces and methods

D-Bus uses interfaces to provide a namespacing mechanism for methods. An interface is a group of related methods and signals (more on signals later), identified by a name which is a series of dot-separated components starting with a reversed domain name.

# 这里proxy作为代理对象使用,直接调用具体方法:Introspect(null)
props = proxy.Introspect(dbus_interface='org.freedesktop.DBus.Introspectable')
# props is a tuple of properties, the first of which is the object path

As a short cut, if you’re going to be calling many methods with the same interface, you can construct a dbus.Interface object and call methods on that, without needing to specify the interface again:

# 通过Interface对象间接调用
eth0_dev_iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.DBus.Introspectable')
props2 = eth0_dev_iface.Introspect()  # props2 is the same as before

你可以直接 print(props) 打印获得的反馈。但如果通过 type() 查询props,你会得到 <class 'dbus.String'> ,而不是标准的 python::str 。请参考文章开头的 Data Types 章节的陈述。

4. Making asynchronous calls(异步调用)

4.1. Setting up an event loop

To make asynchronous calls, you first need an event loop or “main loop”.

from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)  # You must do this before connecting to the bus.

# 或者直接将DBus的 mainloop 附加在 pygi 主循环中
from gi.repository import GLib

loop = GLib.MainLoop()
loop.run()

# 或者将主循环的调用通过参数传入每个connection
import dbus
from dbus.mainloop.glib import DBusGMainLoop

dbus_loop = DBusGMainLoop()
bus = dbus.SessionBus(mainloop=dbus_loop)

PyQt v4.2 and later includes support for integrating dbus-python with the Qt event loop. To connect D-Bus to this main loop, call dbus.mainloop.qt.DBusQtMainLoop instead of dbus.mainloop.glib.DBusGMainLoop. Otherwise the Qt loop is used in exactly the same way as the GLib loop.

4.2. Asynchronous method calls

To make a call asynchronous, pass two callables as keyword arguments reply_handler and error_handler to the proxy method. The proxy method will immediately return None. At some later time, when the event loop is running, one of these will happen:

  • the reply_handler will be called with the method's return values as arguments; or

  • the error_handler will be called with one argument, an instance of DBusException representing a remote exception.

    # To make an async call, use the reply_handler and error_handler kwargs
    remote_object.HelloWorld("Hello from example-async-client.py!",
                            dbus_interface='com.example.SampleInterface',
                            reply_handler=handle_hello_reply,
                            error_handler=handle_hello_error)
    
    # Interface objects also support async calls
    iface = dbus.Interface(remote_object, 'com.example.SampleInterface')
    
    iface.RaiseException(reply_handler=handle_raise_reply,
                         error_handler=handle_raise_error)
    

实现 reply_handler 和 error_handler 方法:

def handle_hello_reply(**r_args**):
    print str(r_args)

def handle_hello_error(**err_args**):
    print "HelloWorld raised an exception! That's not meant to happen..."
    print "	", str(err_args)

    if True:  # ...
        loop.quit()

5. Receiving signals

To receive signals, the Bus needs to be connected to an event loop. Signals will only be received while the event loop is running.

5.1. Signal matching

To respond to signals, you can use the add_signal_receiver(self, handler_function, signal_name=None, dbus_interface=None, bus_name=None, path=None, **keywords) method on Bus objects. This arranges for a callback to be called when a matching signal is received, and has the following arguments:

  • a callable (the handler_function) which will be called by the event loop when the signal is received
  • the signal name, signal_name
  • the D-Bus interface, dbus_interface
  • a sender bus name (well-known or unique), bus_name
  • a sender object path, path

add_signal_receiver() returns a SignalMatch object. Its only useful public API at the moment is a remove() method with no arguments, which removes the signal match from the connection.

def catchall_signal_handler(*args, **kwargs):
    print ("Caught signal (in catchall handler) "
           + kwargs['dbus_interface'] + "." + kwargs['member'])
    for arg in args:
        print "        " + str(arg)

def catchall_hello_signals_handler(hello_string):
    print "Received a hello signal and it says " + hello_string

def catchall_testservice_interface_handler(hello_string, dbus_message):
    print "com.example.TestService interface says " + hello_string + " when it sent signal " + dbus_message.get_member()

# catch the signal
bus = dbus.SessionBus()

bus.add_signal_receiver(catchall_signal_handler, interface_keyword='dbus_interface', member_keyword='member')
bus.add_signal_receiver(catchall_hello_signals_handler, dbus_interface="com.example.TestService", signal_name="HelloSignal")
bus.add_signal_receiver(catchall_testservice_interface_handler, dbus_interface="com.example.TestService", message_keyword='dbus_message')

5.2. Receiving signals from a proxy object

Proxy objects have a special method connect_to_signal(self, signal_name: str, handler_function, dbus_interface=None, **keywords) which arranges for a callback to be called when a signal is received from the corresponding remote object. The parameters are:

  • the name of the signal
  • a callable (the handler function) which will be called by the event loop when the signal is received
  • the handler function
  • the keyword argument dbus_interface qualifies the name with its interface

You shouldn't use proxy objects just to listen to signals, since they might activate the relevant service when created, but if you already have a proxy object in order to call methods, it's often convenient to use it to add signal matches too. (注:一个代理服务在创建时会激活相关的service,产生没必要的开销,所以应该谨慎使用Proxy)

5.3. Getting more information from a signal

You can also arrange for more information to be passed to the handler function. If you pass the keyword arguments sender_keyword, destination_keyword, interface_keyword, member_keyword or path_keyword to the connect_to_signal() method, the appropriate part of the signal message will be passed to the handler function as a keyword argument: for instance if you use:

def handler(sender=None):
    print "got signal from %r" % sender

iface.connect_to_signal("Hello", handler, sender_keyword='sender')

and a signal Hello with no arguments is received from "com.example.Foo", the handler() function will be called with sender='com.example.Foo' .

5.4. String argument matching

The handler will only be called if that argument (argN) of the signal (numbered from zero) is a D-Bus string (in particular, not an object-path or a signature) with that value.

def hello_signal_handler(hello_string):
    print ("Received signal (by connecting using remote object) and it says: " + hello_string)

proxy = bus.get_object("com.example.TestService","/com/example/TestService/object")
proxy.connect_to_signal("HelloSignal", hello_signal_handler, dbus_interface="com.example.TestService", arg0="Hello")  # String argument matching

6. Exporting objects

Objects made available to other applications over D-Bus are said to be exported. All subclasses of dbus.service.Object are automatically exported.

To export objects, the Bus needs to be connected to an event loop. Exported methods will only be called, and queued signals will only be sent, while the event loop is running.

6.1. Inheriting from dbus.service.Object

Object expects either a BusName or a Bus object, and an object-path, to be passed to its constructor: arrange for this information to be available. For example:

class Example(dbus.service.Object):
    def __init__(self, object_path):
        dbus.service.Object.__init__(self, dbus.SessionBus(), path)

This object will automatically support introspection, but won’t do anything particularly interesting. To fix that, you’ll need to export some methods and signals too.

6.2. Exporting methods with dbus.service.method

To export a method, use the decorator dbus.service.method. For example:

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.

6.2.1. Finding out the caller’s bus name

The method decorator accepts a sender_keyword keyword argument. If you set that to a string, the unique bus name of the sender will be passed to the decorated method as a keyword argument of that name:

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

class SomeObject(dbus.service.Object):

    @dbus.service.method("com.example.SampleInterface",
                         in_signature='s', out_signature='as')
    def HelloWorld(self, hello_message):
        print (str(hello_message))
        return ["Hello", " from example-service.py", "with unique name",
                session_bus.get_unique_name()]

6.3. Emitting signals with dbus.service.signal

To export a signal, use the decorator dbus.service.signal; to emit that signal, call the decorated method. The decorated method can also contain code which will be run when called, as usual. For example:

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"

The signal will be queued for sending when the decorated method returns - you can prevent the signal from being sent by raising an exception from the decorated method (for instance, if the parameters are inappropriate). The signal will only actually be sent when the event loop next runs.


7. 思考

  1. 通过Proxy调用服务难道不是一个标准模式吗?为什么官方教程在 **Receiving signals from a proxy object **一节并不推荐“仅仅为了监听信号而创建代理”?多余的开销是什么?

    答:官方解释:当创建一个对象代理时,如果代理对象中存在服务方法,那么该方法在代理创建时也将被一并激活。那么就只剩下 bus.add_signal_receiver() 方法可以使用了——这恰恰说明,该方法的实现并没有创建一个代理,而仅仅是在监听bus的服务而已~

免责声明:文章转载自《dbus-python的API及示例》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇多媒体开发之---h264中 的RTP PAYLOAD 格式oracle-session的查询及释放下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

yii框架中findall方法取数据使用总结,包括select各种条件,where条件,order by条件,limit限制等

在yii框架中可以使用映射类的find方法取出一条数据或者用findall方法取出数条数据来,那么如何按照所需条件来取数据呢,主要用到了CDbCriteria这个类,这个类是yii自带的操作数据库的支持类,可以作为参数传递给find等方法,这里用findall做个例子: 比如我要取出videoinfo表中的'v_id','title','big_class...

Handler为什么可能会造成内存泄漏以及可用的四种解决方法

在Android系统中,Handler是一个消息发送和处理机制的核心组件之一,与之配套的其他主要组件还有Looper和Message,MessageQueue。 根据官网的描述 There are two main uses for a Handler: (1) to schedule messages and runnables to be execut...

yii2框架随笔35

今天来看vendor/yiisoft/yii2/base/Event.php <?php namespace yiibase; //事件是所有事件类的基类。它封装了参数与事件相关联。 //如果一个事件处理程序集[[进行]]是真的,其余的,uninvoked处理程序将不再被称为处理事件。 //另外,添加一个事件处理程序时,额外的数据可能被传递...

用jq中jSignature做手动签名

<!DOCTYPE html><html lang="zh-CN"><head> <title>手写板签名demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <...

内存映射mmap

Table of Contents 1. 什么是mmap 2. 使用方法 2.1. mmap构造器的格式 2.2. 例子1 2.3. 例子2 3. 其它 4. 参考资料 什么是mmap通常在Unix系统里有两种操作的数据类型:内存地址和流文件(stream)。通过操作内存地址的方法涉及的操作有:pointers, malloc/free之类,...

MySQL 复制表结构

介绍  有时候我们需要原封不动的复制一张表的表结构来生成一张新表,MYSQL提供了两种便捷的方法。 例: CREATE TABLE tb_base( id INT NOT NULL PRIMARY KEY, name VARCHAR(10), KEY ix_name (name)) ENGINE='MyISAM',CHARSET=utf8,COMMENT...