dbus/python/proxies.py
John (J5) Palmieri ce84a7761a * python/__init__.py: Version updated (0, 43, 0)
* python/dbus_bindings.pyx:
	- Fixed type objects to have self passed into __init__
	- Added the Variant type
	- Add the ability to specify types or signatures for Array, Variant and Dictionary
	- (Connection::send_with_reply_handlers): return a PendingCall object
	- (_pending_call_notification): handle the case when an error is returned
	without an error message in the body
	- (MessageIter::get_boolean): return True or False instead of an integer
	- (MessageIter::python_value_to_dbus_sig): add direct checking of types and
	add checks for objects with embeded signatures or types (Array, Variant and
	Dictionary)
	- (MessageIter::append_byte): handle case when the value is a dbus.Byte
	- (MessageIter::append_dict): handle embeded types or signatures
	- (MessageIter::append_array): handle embeded types or signatures
	- (MessageIter::append_variant): new method

	* python/proxies.py:
	- (DeferedMethod): New. Dummy executable object used when queuing calls blocking on
	introspection data
	- (ProxyMethod::__call__): add the timeout keyword for specifying longer or
	shorter timeouts for method calls
	- (ProxyObject): Add first pass at an introspection state machine
	- (ProxyObject::__init__): Add introspect keyword for turing off an on
	introspection.
	- (ProxyObject::_Introspect): Internal Introspect call that bypasses the usual
	mechanisms for sending messages.  This is to avoid a deadlock where the Intospect
	call would be queued waiting for the Introspect call to finish ;-)
	- (ProxyObject::_introspect_reply_handler): New.  This method is called when
	introspection returns with no error
	- (ProxyObject::_introspect_error_handler): New.  This method is called when
	introspection encounters an error
	- (ProxyObject::__getattr__): Code to handle different introspection states.
	Queue async calls or block blocking calls if we are introspecting.  Pass through
	as normal if we are not or are done with introspecting.

	* python/service.py: Import signal and method from decorators.py

	* python/types.py: Add Variant type
2005-08-16 22:54:04 +00:00

175 lines
6.8 KiB
Python

import dbus_bindings
from exceptions import MissingReplyHandlerException, MissingErrorHandlerException
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):
self._connection = connection
self._named_service = named_service
self._object_path = object_path
self._method_name = method_name
self._dbus_interface = dbus_interface
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']
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)
for arg in args:
iter.append(arg)
if 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
#TODO: default introspect to False right now because it is not done yet
# make sure to default to True later
def __init__(self, bus, named_service, object_path, introspect=False):
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 = []
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):
self._bus.add_signal_receiver(handler_function,
signal_name=signal_name,
dbus_interface=dbus_interface,
named_service=self._named_service,
path=self._object_path)
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_reply_handler(self, data):
self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_DONE
for call in self._pending_introspect_queue:
(member, iface, args, keywords) = call
call_object = self.ProxyMethodClass(self._bus.get_connection(),
self._named_service,
self._object_path, iface, member)
call_object(args, keywords)
def _introspect_error_handler(self, error):
self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
def __getattr__(self, member, **keywords):
if member == '__call__':
return object.__call__
elif member.startswith('__') and member.endswith('__'):
raise AttributeError(member)
else:
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
ret = self.ProxyMethodClass(self._bus.get_connection(),
self._named_service,
self._object_path, iface, member)
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__