mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2025-12-26 04:00:08 +01:00
and G_TYPE_VALUE_ARRAY (DBUS_TYPE_STRUCT) (gvalue_from_hash_value, hash_value_from_gvalue): handle gdouble * glib/dbus-gvalue.c (dbus_gvalue_to_signature): add missing DBUS_STRUCT_BEGIN_CHAR and DBUS_STRUCT_END_CHAR charaters when constructing struct signatures * python/_dbus.py (Bus): handle private connections using the private keyword in the constructor. defaults to private=False (Bus::close): new method to close a connection to the bus * python/dbus_bindings.pyx (Connection::close): renamed method was previously called disconnect (bus_get): now supports getting a private connection * python/proxies.py (ProxyMethod::__call__): check if ignore_reply keyword is set to True. if it is, execute the method without waiting for a reply (ProxyObject::_introspect_execute_queue): new method for executing all the pending methods that were waiting for the introspect to finish. this is called when introspect either succeeds or fails (ProxyObject::_introspect_error_handler): call queued methods
229 lines
8.6 KiB
Python
229 lines
8.6 KiB
Python
import dbus_bindings
|
|
import introspect_parser
|
|
import sys
|
|
from exceptions import MissingReplyHandlerException, MissingErrorHandlerException, IntrospectionParserException
|
|
|
|
class DeferedMethod:
|
|
"""A DeferedMethod
|
|
|
|
This is returned instead of ProxyMethod when we are defering DBus calls
|
|
while waiting for introspection data to be returned
|
|
|
|
This class can be used for debugging purposes
|
|
"""
|
|
def __call__(self, *args, **keywords):
|
|
return None
|
|
|
|
class ProxyMethod:
|
|
"""A proxy Method.
|
|
|
|
Typically a member of a ProxyObject. Calls to the
|
|
method produce messages that travel over the Bus and are routed
|
|
to a specific named Service.
|
|
"""
|
|
def __init__(self, connection, named_service, object_path, dbus_interface, method_name, introspect_sig):
|
|
self._connection = connection
|
|
self._named_service = named_service
|
|
self._object_path = object_path
|
|
self._method_name = method_name
|
|
self._dbus_interface = dbus_interface
|
|
self._introspect_sig = introspect_sig
|
|
|
|
def __call__(self, *args, **keywords):
|
|
dbus_interface = self._dbus_interface
|
|
if keywords.has_key('dbus_interface'):
|
|
dbus_interface = keywords['dbus_interface']
|
|
|
|
timeout = -1
|
|
if keywords.has_key('timeout'):
|
|
timeout = keywords['timeout']
|
|
|
|
reply_handler = None
|
|
if keywords.has_key('reply_handler'):
|
|
reply_handler = keywords['reply_handler']
|
|
|
|
error_handler = None
|
|
if keywords.has_key('error_handler'):
|
|
error_handler = keywords['error_handler']
|
|
|
|
ignore_reply = False
|
|
if keywords.has_key('ignore_reply'):
|
|
ignore_reply = keywords['ignore_reply']
|
|
|
|
if not(reply_handler and error_handler):
|
|
if reply_handler:
|
|
raise MissingErrorHandlerException()
|
|
elif error_handler:
|
|
raise MissingReplyHandlerException()
|
|
|
|
message = dbus_bindings.MethodCall(self._object_path, dbus_interface, self._method_name)
|
|
message.set_destination(self._named_service)
|
|
|
|
# Add the arguments to the function
|
|
iter = message.get_iter(True)
|
|
|
|
remainder = self._introspect_sig
|
|
for arg in args:
|
|
if self._introspect_sig:
|
|
(sig, remainder) = iter.parse_signature_block(remainder)
|
|
iter.append_strict(arg, sig)
|
|
else:
|
|
iter.append(arg)
|
|
|
|
if ignore_reply:
|
|
result = self._connection.send(message)
|
|
args_tuple = (result,)
|
|
elif reply_handler:
|
|
result = self._connection.send_with_reply_handlers(message, timeout, reply_handler, error_handler)
|
|
args_tuple = result
|
|
else:
|
|
reply_message = self._connection.send_with_reply_and_block(message, timeout)
|
|
args_tuple = reply_message.get_args_list()
|
|
|
|
if len(args_tuple) == 0:
|
|
return
|
|
elif len(args_tuple) == 1:
|
|
return args_tuple[0]
|
|
else:
|
|
return args_tuple
|
|
|
|
|
|
class ProxyObject:
|
|
"""A proxy to the remote Object.
|
|
|
|
A ProxyObject is provided by the Bus. ProxyObjects
|
|
have member functions, and can be called like normal Python objects.
|
|
"""
|
|
ProxyMethodClass = ProxyMethod
|
|
DeferedMethodClass = DeferedMethod
|
|
|
|
INTROSPECT_STATE_DONT_INTROSPECT = 0
|
|
INTROSPECT_STATE_INTROSPECT_IN_PROGRESS = 1
|
|
INTROSPECT_STATE_INTROSPECT_DONE = 2
|
|
|
|
def __init__(self, bus, named_service, object_path, introspect=True):
|
|
self._bus = bus
|
|
self._named_service = named_service
|
|
self._object_path = object_path
|
|
|
|
#PendingCall object for Introspect call
|
|
self._pending_introspect = None
|
|
#queue of async calls waiting on the Introspect to return
|
|
self._pending_introspect_queue = []
|
|
#dictionary mapping method names to their input signatures
|
|
self._introspect_method_map = {}
|
|
|
|
if not introspect:
|
|
self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
|
|
else:
|
|
self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS
|
|
|
|
(result, self._pending_introspect) = self._Introspect()
|
|
|
|
|
|
def connect_to_signal(self, signal_name, handler_function, dbus_interface=None, **keywords):
|
|
self._bus.add_signal_receiver(handler_function,
|
|
signal_name=signal_name,
|
|
dbus_interface=dbus_interface,
|
|
named_service=self._named_service,
|
|
path=self._object_path,
|
|
**keywords)
|
|
|
|
def _Introspect(self):
|
|
message = dbus_bindings.MethodCall(self._object_path, 'org.freedesktop.DBus.Introspectable', 'Introspect')
|
|
message.set_destination(self._named_service)
|
|
|
|
result = self._bus.get_connection().send_with_reply_handlers(message, -1,
|
|
self._introspect_reply_handler,
|
|
self._introspect_error_handler)
|
|
return result
|
|
|
|
def _introspect_execute_queue(self):
|
|
for call in self._pending_introspect_queue:
|
|
(member, iface, args, keywords) = call
|
|
|
|
introspect_sig = None
|
|
|
|
tmp_iface = ''
|
|
if iface:
|
|
tmp_iface = iface + '.'
|
|
|
|
key = tmp_iface + '.' + member
|
|
if self._introspect_method_map.has_key (key):
|
|
introspect_sig = self._introspect_method_map[key]
|
|
|
|
|
|
call_object = self.ProxyMethodClass(self._bus.get_connection(),
|
|
self._named_service,
|
|
self._object_path,
|
|
iface,
|
|
member,
|
|
introspect_sig)
|
|
|
|
call_object(args, keywords)
|
|
|
|
def _introspect_reply_handler(self, data):
|
|
try:
|
|
self._introspect_method_map = introspect_parser.process_introspection_data(data)
|
|
except IntrospectionParserException, e:
|
|
self._introspect_error_handler(e)
|
|
return
|
|
|
|
self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_DONE
|
|
#self._introspect_execute_queue()
|
|
|
|
def _introspect_error_handler(self, error):
|
|
self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
|
|
self._introspect_execute_queue()
|
|
sys.stderr.write("Introspect error: " + str(error) + "\n")
|
|
|
|
def __getattr__(self, member, **keywords):
|
|
if member == '__call__':
|
|
return object.__call__
|
|
elif member.startswith('__') and member.endswith('__'):
|
|
raise AttributeError(member)
|
|
else:
|
|
introspect_sig = None
|
|
|
|
iface = None
|
|
if keywords.has_key('dbus_interface'):
|
|
iface = keywords['dbus_interface']
|
|
|
|
if self._introspect_state == self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS:
|
|
reply_handler = None
|
|
if keywords.has_key('reply_handler'):
|
|
reply_handler = keywords['reply_handler']
|
|
|
|
error_handler = None
|
|
if keywords.has_key('error_handler'):
|
|
error_handler = keywords['error_handler']
|
|
|
|
if not reply_handler:
|
|
self._pending_introspect.block()
|
|
else:
|
|
call = (memeber, iface, args, keywords)
|
|
self._pending_introspect_queue.append(call)
|
|
|
|
ret = self.DeferedMethodClass()
|
|
return ret
|
|
|
|
if self._introspect_state == self.INTROSPECT_STATE_INTROSPECT_DONE:
|
|
tmp_iface = ''
|
|
if iface:
|
|
tmp_iface = iface + '.'
|
|
|
|
key = tmp_iface + member
|
|
if self._introspect_method_map.has_key (key):
|
|
introspect_sig = self._introspect_method_map[key]
|
|
|
|
ret = self.ProxyMethodClass(self._bus.get_connection(),
|
|
self._named_service,
|
|
self._object_path, iface, member,
|
|
introspect_sig)
|
|
return ret
|
|
|
|
def __repr__(self):
|
|
return '<ProxyObject wrapping %s %s %s at %x>'%(
|
|
self._bus, self._named_service, self._object_path , id(self))
|
|
__str__ = __repr__
|
|
|