dbus/python/proxies.py
John (J5) Palmieri 2b9417707a * glib/dbus-gvalue-utils.c (hash_free_from_gtype): handle gdouble
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
2005-10-18 04:38:05 +00:00

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__